Commit 4ed27883 by Luciano Barletta

entregable

- terminada la compilacion del segundo pdf
- hecho el manual de usuario
- llenado el README para programadores
- pulido de comportamientos no deseados
1 parent b59686f2
# Generación de PDF
## Instalación
El server corre en `python3` y cuenta con las siguientes dependencias:
- pip3 (para instalar cosas en python3)
- Flask
- Selenium
Para instalar estos paquetes se deben correr estos comandos siendo administrador:
```sh
apt-get install python3-pip
pip3 install flask
pip3 install selenium
```
## Inicialización
Para comenzar a usar el servidor, correr el siguiente comando en la carpeta del código (siendo administrador):
```sh
python3 deploy.py
```
## Uso
El servidor cuenta con dos direcciones:
### X.X.X.X:5000
Esta es la dirección principal. Aquí se tomarán usuario, contraseña y dominio a buscar. Además se tomarán los rendimientos de los ejes de suspensión. Todos los campos son obligatorios y no se puede avanzar sin ellos. Una vez que se hayan completado el formulario, presionar Buscar.
Luego de una espera de entre 10 y 20 segundos se mostrará un formulario con los datos recolectados. Aquí se pueden cambiar o llenar todos los datos que se quiera. Si ha habido un error, el mismo se mostrará y el formulario detrás estará vacío, disponible para ser llenado de todos modos.
Al fondo de la página habrá un campo "Por defecto" que contiene el texto que tendrán los campos vacíos o con un signo de pregunta '?'*. El valor por defecto puede ser modificado.
Al terminar de escribir los datos, se pueden convertir a PDF con los dos botones del final. La conversión a PDF se puede realizar tantas veces como se quiera, modificando datos cada vez si hubo un error. Tener en cuenta que realizar la recolección de datos de la misma patente cambiará algunos datos generados automáticamente.
El botón 1 genera el documento simplificado, el botón 2 genera el documento complejo. Cualquiera (o los dos) pueden ser generados. Luego de generados se pueden guardar o imprimir.
*Nota: El signo de pregunta significa que no se pudo recoletar el dato de la página.
### X.X.X.X:5000/manual
En esta dirección se saltea el paso de recolectar datos, simplemente muestra un formulario vacío para llenar manualmente.
Se recomienda que al llenar los campos, se alterne entre ellos rápidamente con el botón TAB para avanzar y SHIFT+TAB para retroceder.
## Detención
Para detener el servicio basta abrir la consola donde está corriendo y presionar CTRL+C.
\ No newline at end of file
# Generación de PDF
## Python
Hay dos archivos de Python:
### deploy.py
[link](./deploy.py)
Contiene la aplicación y los procesos abstractos de recolección de datos y valores default. Cada parte del proceso puede fallar por algún motivo, en cuyo caso devolverá un string con el error. Sino, devolverá un JSON con los datos.
La app cuenta con 3 direcciones:
1. / \[GET] -> llama al form con bypass = false
2. /manual \[GET] -> llama al form con bypass = true
3. /pdf \[POST] -> dados los datos del form, recolecta los datos
### iselenium.py
[link](./iselenium.py)
Es la clase con utilidades para manejar Selenium con código corto, además cuenta con dos clases de Exception para dos casos:
1. NoSuchDriver -> el driver no está soportado por la interfaz
2. BadInterval -> error en el parsing de intervalos en las funciones find*
## HTML
Hay un solo [archivo](./templates/form.html), que cuenta con dos secciones:
1. form -> formulario que llama a /pdf y recolecta los datos
2. results -> muestra los datos y tiene botones para convertir a pdf
Hay una variable bypass que elige si mostrar el form o saltar a los resultados (vacíos)
## JavaScript
1. [Ajax](./static/src/ajax.js) -> utilidades de ajax
2. Sistema simil [html](./static/src/div.js) -> clases de para compilar posiciones relativas a padres de forma porcentual*
3. [Formularios](./static/src/forms.js) -> lee y llena formularios y hace consultas a /pdf
4. Compilación de [PDF1](./static/src/pdf1.js) y [PDF2](./static/src/pdf2.js) -> clases con métodos de dibujado que usan el punto 2 como interfaz
*Se forma un árbol y se llama recursivamente a los métodos draw(jsPDF pdf) de las clases
## Manual
[link](./Manual.md)
Manual de usuario para instalar, correr, usar y detener el servicio. Orientado a usuarios con experiencia en Linux y búsqueda por IP de páginas web
\ No newline at end of file
#-*- coding: utf-8 -*-
from flask import Flask, render_template, request, url_for
from iselenium import SeleniumInterface as SI
import random
import random, json
app = Flask(__name__)
data = {
"header" : {
"patente" : "?",
"fecha" : "?",
"hora" : "?"
},
"alineador" : {
"eje_delantero" : "?"
},
"suspension" : [
{
"rendimiento_izquierdo" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?",
"rendimiento_derecho" : "?"
},
{
"rendimiento_izquierdo" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?",
"rendimiento_derecho" : "?"
}
],
"frenos" : [
{
"fuerza_izquierda" : "?",
"resistencia_izquierda" : "?",
"ovalidad_izquierda" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?",
"fuerza_derecha" : "?",
"resistencia_derecha" : "?",
"ovalidad_derecha" : "?"
},
{
"fuerza_izquierda" : "?",
"resistencia_izquierda" : "?",
"ovalidad_izquierda" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?",
"fuerza_derecha" : "?",
"resistencia_derecha" : "?",
"ovalidad_derecha" : "?"
},
{
"fuerza_izquierda" : "?",
"resistencia_izquierda" : "?",
"ovalidad_izquierda" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?",
"fuerza_derecha" : "?",
"resistencia_derecha" : "?",
"ovalidad_derecha" : "?"
},
{
"fuerza_izquierda" : "?",
"resistencia_izquierda" : "?",
"ovalidad_izquierda" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?",
"fuerza_derecha" : "?",
"resistencia_derecha" : "?",
"ovalidad_derecha" : "?"
}
],
"trasero" : {
"fuerza_izquierda" : "?",
"fuerza_derecha" : "?",
"peso_estatico" : "?",
"peso_dinamico" : "?"
},
"gaseshumos" : {
"co" : "?",
"hc" : "?",
"opacidad_logaritmica" : "?"
}
}
@app.route('/')
def main():
return render_template(
"form.html",
bypass = False
)
@app.route('/manual')
def pdf():
def manual():
return render_template(
"resultados.html",
data = data
"form.html",
bypass = True
)
@app.route('/')
def main():
plate = "JPY149"
@app.route('/pdf', methods = ['POST'])
def pdf():
d = request.json
plate = d['header']['patente']
s = SI(SI.Chrome)
form = [
{
"rendimiento_izquierdo" : "0",
"rendimiento_derecho" : "0",
},
{
"rendimiento_izquierdo" : "0",
"rendimiento_derecho" : "0",
}
]
answer = {
"header" : {},
"alineador" : {},
"suspension" : [],
"frenos" : [],
"suspension" : d['suspension'],
"frenos" : {},
"trasero" : {},
"gaseshumos" : {},
}
......@@ -118,7 +37,12 @@ def main():
answer['header']['patente'] = plate.upper()
try:
answer = login(s, answer)
answer = login(
d['credenciales']['usuario'],
d['credenciales']['contrasena'],
s,
answer
)
except:
return "Error en el login."
try:
......@@ -130,30 +54,36 @@ def main():
except:
return f"Error leyendo datos de la patente '{plate}'."
try:
answer = extradata(form, answer)
answer = rnddata(answer)
except:
return f"Error completando datos extra de la patente '{plate}'."
print(answer)
del s
return render_template(
"resultados.html",
data = answer
)
return json.dumps(answer)
def login(s, r):
def login(u, p, s, r):
s.get("https://rto.cent.gov.ar/rto")
login = s.find(SI.By.NAME, "j_username")
s.write(login, "salvatellih")
s.write(login, u)
psw = s.find(SI.By.NAME, "j_password")
s.write(psw, "3")
s.write(psw, p)
button = s.find(SI.By.ID, "submit")
button.click()
return r
reach = lambda s: s.find(SI.By.NAME, "j_username")
login = attempt_do(reach, default = "?")(s)
# login succeeded
if login == "?":
return r
# still in login page
else:
raise Exception("Fallo del login")
def gototec(s, r):
s.get("https://rto.cent.gov.ar/rto/RTO/listaDePlanillas")
......@@ -191,27 +121,29 @@ def readdata(s, r):
# suspension
for i in range(2):
sus = {}
sus['peso_estatico'] = empty_for_question(attempt_do(reach(f"pesoBascula-{i}"), default = "?")(s))
sus[f'peso_dinamico_{i + 1}'] = empty_for_question(attempt_do(reach(f"pesoBascula-{i}"), default = "?")(s))
sus[f'peso_estatico_{i + 1}'] = empty_for_question(attempt_do(reach(f"pesoMaximo-{i}"), default = "?")(s))
r['suspension'].append(sus)
r['suspension'].update(sus)
# frenos
frenos = s.find(SI.By.XPATH, "//table[@class='tabla_ensayo']/tbody//tr[@class='odd' or @class='even']","1-4")
for i in range(len(frenos)):
for i in range(4):
fre = {}
fre['peso_estatico'] = empty_for_question(attempt_do(reach(f"pesoBascula-{i}"), default = "?")(s))
fre['peso_dinamico'] = empty_for_question(attempt_do(reach(f"pesoMaximo-{i}"), default = "?")(s))
fre['fuerza_izquierda'] = empty_for_question(attempt_do(reach(f"fuerzaIzq-{i}"), default = "?")(s))
fre['fuerza_derecha'] = empty_for_question(attempt_do(reach(f"fuerzaDer-{i}"), default = "?")(s))
fre[f'peso_dinamico_{i + 1}'] = empty_for_question(attempt_do(reach(f"pesoBascula-{i}"), default = "?")(s))
fre[f'peso_estatico_{i + 1}'] = empty_for_question(attempt_do(reach(f"pesoMaximo-{i}"), default = "?")(s))
fre[f'fuerza_izquierda_{i + 1}'] = empty_for_question(attempt_do(reach(f"fuerzaIzq-{i}"), default = "?")(s))
fre[f'fuerza_derecha_{i + 1}'] = empty_for_question(attempt_do(reach(f"fuerzaDer-{i}"), default = "?")(s))
r['frenos'].append(fre)
r['frenos'].update(fre)
# freno trasero
r['trasero']['peso_estatico'] = empty_for_question(attempt_do(reach(f"pesoBasculaEst-0"), default = "?")(s))
r['trasero']['peso_dinamico'] = empty_for_question(attempt_do(reach(f"pesoMaximoEst-0"), default = "?")(s))
r['trasero']['peso_dinamico'] = empty_for_question(attempt_do(reach(f"pesoBasculaEst-0"), default = "?")(s))
r['trasero']['peso_estatico'] = empty_for_question(attempt_do(reach(f"pesoMaximoEst-0"), default = "?")(s))
r['trasero']['fuerza_izquierda'] = empty_for_question(attempt_do(reach(f"fuerzaIzqEst-0"), default = "?")(s))
r['trasero']['fuerza_derecha'] = empty_for_question(attempt_do(reach(f"fuerzaDerEst-0"), default = "?")(s))
r['trasero']['eje'] = empty_for_question(attempt_do(reach(f"nroEjeEst-0"), default = "?")(s))
# gases y humos
......@@ -221,20 +153,21 @@ def readdata(s, r):
return r
def extradata(form, r):
def rnddata(r):
res = lambda: round(random.random() * 0.9 + 0.05, 2)
ov = lambda: round(random.random() * 39 + 0.5, 2)
for i in range(len(r['suspension'])):
r['suspension'][i]['rendimiento_izquierdo'] = form[i]['rendimiento_izquierdo']
r['suspension'][i]['rendimiento_derecho'] = form[i]['rendimiento_derecho']
for i in range(len(r['frenos'])):
r['frenos'][i]['resistencia_izquierda'] = res()
r['frenos'][i]['resistencia_derecha'] = res()
r['frenos'][i]['ovalidad_izquierda'] = ov()
r['frenos'][i]['ovalidad_derecha'] = ov()
for i in range(4):
f = r['frenos']; j = i+1; gen = False
# If any values were found, it means the axis exists, random values will be generated.
if f[f'fuerza_izquierda_{j}'] != "?" or f[f'fuerza_derecha_{j}'] != "?" or f[f'peso_estatico_{j}'] != "?":
gen = True
f[f'resistencia_izquierda_{j}'] = res() if gen else "?"
f[f'resistencia_derecha_{j}'] = res() if gen else "?"
f[f'ovalidad_izquierda_{j}'] = ov() if gen else "?"
f[f'ovalidad_derecha_{j}'] = ov() if gen else "?"
return r
......
......@@ -114,12 +114,4 @@ class BadInterval(Exception):
self.interval = interval
def __str__(self):
return f"The interval '{self.interval}' is not valid"
class NotEditable(Exception):
def __init__(self, plate):
self.plate = plate
def __str__(self):
return f"The plate '{self.plate}' is not editable"
\ No newline at end of file
return f"The interval '{self.interval}' is not valid"
\ No newline at end of file
class Ajax {
constructor(object){
if (typeof object !== "object")
this.data = {};
else
this.data = object;
this.http = new XMLHttpRequest();
}
default(){
if (("url" in this.data) === false) {
throw "URL not set";
}
if (("async" in this.data) === false){
this.data.async = true;
}
if ( "success" in this.data ){
this.http.onload = () => {
if (this.http.status == 200)
this.data.success(this.http.response);
}
}
if ( "error" in this.data ){
this.http.onerror = () => this.data.error(this.http.response);
}
if (this.data.async === false && "timeout" in this.data){
this.http.timeout = this.data.timeout;
if ("ontimeout" in this.data)
this.http.ontimeout = (this.data.ontimeout).bind(this.http);
}
}
post(){
this.default();
this.http.open("POST", this.data.url, this.data.async);
if ("contentType" in this.data) {
this.http.setRequestHeader('Content-Type', this.data.contentType);
}
if ("data" in this.data) {
this.http.send(JSON.stringify(this.data.data));
}
else {
this.http.send();
}
}
get(){
this.default();
if ("contentType" in this.data) {
this.http.setRequestHeader('Content-Type', this.data.contentType);
}
if ("data" in this.data) {
this.http.open("GET", this.data.url + "?" + this.data.data, this.data.async);
}
else {
this.http.open("GET", this.data.url, this.data.async);
}
this.http.send();
}
}
\ No newline at end of file
......@@ -44,12 +44,12 @@ class Vector {
class Line {
/**
* @param {Vector} position
* @param {Vector} size
* @param {Vector} beg
* @param {Vector} end
*/
constructor(position, size) {
this.position = position;
this.size = size;
constructor(beg, end) {
this.beg = beg;
this.end = end;
}
/**
......@@ -57,10 +57,10 @@ class Line {
*/
draw(pdf) {
pdf.line(
this.position.x,
this.position.y,
this.size.x,
this.size.y
this.beg.x,
this.beg.y,
this.end.x,
this.end.y
);
}
}
......@@ -152,11 +152,34 @@ class Div {
* @param {Vector} size
* @param {bool} draw
*/
constructor(position, size, draw = false) {
constructor(position, size, draw = false, log = false) {
this.position = position;
this.size = size;
this.drawOutline = draw;
this.logChildren = log;
this.children = [];
const t = this;
this.acceptedProperties = [
{
"prop" : "position",
"func" : (v) => t._getCoordinates(v)
},
{
"prop" : "size",
"func" : (v) => t._getSize(v)
},
{
"prop" : "beg",
"func" : (v) => t._getCoordinates(v)
},
{
"prop" : "end",
"func" : (v) => t._getCoordinates(v)
},
];
}
/** Allows any position you want **/
......@@ -171,13 +194,12 @@ class Div {
addRelativeChild(child) {
if ("draw" in child === false)
console.error("the object passed needs to have a 'draw' method that takes a jsPDF object");
if ("position" in child)
child.position = this._getDrawCoordinates(child.position);
if ("size" in child)
child.size = this._getSizeCoordinates(child.size);
this.acceptedProperties.forEach( (p) => {
if (p.prop in child)
child[ p.prop ] = p.func( child[ p.prop ] );
});
this.children.push(child);
return this.children[this.children.length - 1];
}
......@@ -195,44 +217,45 @@ class Div {
}
/** Allows any position you want relative to the position of this Div. Percentage based **/
getAbsoluteVector(vector) {
getAbsoluteVector(v) {
return this.position.addxy(
(this.size.x * vector.x / 100),
(this.size.y * vector.y / 100)
(this.size.x * v.x / 100),
(this.size.y * v.y / 100)
);
}
/**
* Compiles the true position coordinates based on percentage relative to parent element
* Assumes the elements grow to the right and down
* @param {Vector} position
* @param {Vector} v
*/
_getDrawCoordinates(position) {
if (position.x < 0 || position.x > 100 || position.y < 0 || position.y > 100)
_getCoordinates(v) {
if (v.x < 0 || v.x > 100 || v.y < 0 || v.y > 100)
console.error("position components need to be real numbers in the range [0;100]");
return this.position.addxy(
(this.size.x * position.x / 100),
(this.size.y * position.y / 100)
(this.size.x * v.x / 100),
(this.size.y * v.y / 100)
);
}
/**
* Compiles the true size based on percentage relative to parent element
* Compiles the size coordinates based on percentage relative to parent element
* Assumes the elements grow to the right and down
* @param {Vector?} size
* @param {Vector} s
*/
_getSizeCoordinates(size) {
if (size.x < 0 || size.x > 100 || size.y < 0 || size.y > 100)
console.error("size components need to be real numbers in the range [0;100]");
_getSize(s) {
if (s.x < 0 || s.x > 100 || s.y < 0 || s.y > 100)
console.error("position components need to be real numbers in the range [0;100]");
return new Vector (
this.size.x * size.x / 100,
this.size.y * size.y / 100,
(this.size.x * s.x / 100),
(this.size.y * s.y / 100)
);
}
draw(pdf) {
/** Draw the confines of the div **/
if (this.drawOutline) {
/** Upper **/
......@@ -257,8 +280,13 @@ class Div {
));
}
/** Log Children **/
if (this.logChildren) {
console.log(this.children);
}
/** Recursion **/
this.children.forEach( child => child.draw(pdf) );
this.children.forEach( child => child.draw(pdf));
}
}
......
function collectToSearch() {
f = document.getElementById("form");
inputs = f.getElementsByTagName("input");
data = {};
function BadInputException(input) {
this.error = "badinput";
this.input = input;
}
Array.from(inputs).forEach( input => {
if (input.checkValidity() === false){
input.reportValidity("Por favor llene este campo");
throw BadInputException(input);
}
sub = input.getAttribute("sub");
if ( (sub in data) === false ) {
data[sub] = {}
}
data[sub][input.name] = input.value;
});
message("Espere...");
console.log(data);
const obj = {
"url" : "/pdf",
"contentType" : "application/json",
"async" : true,
"data" : data,
"success" : (response) => {
let r;
try {
r = JSON.parse(response);
document.getElementById("message").click();
} catch (error) {
message(response);
}
document.getElementById("results").style.display = "block";
document.getElementById("form").style.display = "none";
fillResults(r);
},
"error" : (response) => message(response),
"timeout" : 120000,
"ontimeout" : (response) => message("La conexión tardó demasiado.")
}
ajax = new Ajax(obj);
ajax.post();
}
function collectToConvert() {
r = document.getElementById("results")
inputs = r.getElementsByTagName("input");
data = {};
defecto = document.getElementsByName("defecto")[0].value;
Array.from(inputs).forEach(input => {
if (input.name == "defecto") return;
sub = input.getAttribute("sub");
if ((sub in data) === false) {
data[sub] = {}
}
data[sub][input.name] = (input.value == "?" || input.value == "" ? defecto : input.value);
});
return data;
}
function message(msg) {
let m = document.getElementById("message");
m.style.display = "block";
m = document.getElementById("msg");
m.innerHTML = msg;
}
function fillResults(results) {
r = document.getElementById("results")
inputs = r.getElementsByTagName("input");
Array.from(inputs).forEach(input => {
if (input.name == "defecto") return;
sub = input.getAttribute("sub");
input.value = results[sub][input.name];
});
}
\ No newline at end of file
function getAncestorByAttribute(elem, attr, val) {
while (elem.getAttribute(attr) != val || elem == null) elem = elem.parentElement;
return elem;
}
function getDescendantByAttribute(elem, attr, val) {
if (elem == null || elem.getAttribute(attr) == val) return elem;
return Array.from(elem.children).reduce((a, b) => {
let x = getDescendantByAttribute(a, attr, val);
let y = getDescendantByAttribute(b, attr, val);
return x == null ? y : x;
}, null);
}
function getAncestorByTag(elem, val) {
while (elem.nodeName != val.toUpperCase() || elem == null) elem = elem.parentElement;
return elem;
}
function getDescendantByTag(elem, val) {
if (elem == null || elem.nodeName == val.toUpperCase()) return elem;
return Array.from(elem.children).reduce((a, b) => {
let x = getDescendantByTag(a, val);
let y = getDescendantByTag(b, val);
return x == null ? y : x;
}, null);
}
\ No newline at end of file
......@@ -105,14 +105,13 @@ class PDF1 {
]);
};
for (let i = 0; i < ejes.length; i++) {
const x = data[i];
for (let i = 0; i < 2; i++) {
table(
ejes[i],
i + 1,
x["rendimiento_izquierdo"],
x["peso_estatico"],
x["rendimiento_derecho"]
data[`rendimiento_izquierdo_${i+1}`],
data[`peso_estatico_${i+1}`],
data[`rendimiento_derecho_${i+1}`]
);
}
......@@ -169,18 +168,16 @@ class PDF1 {
};
for (let i = 0; i < ejes.length; i++) {
const x = data[i];
if (x == undefined) continue;
table(
ejes[i],
i + 1,
x["fuerza_izquierda"],
x["resistencia_izquierda"],
x["ovalidad_izquierda"],
x["peso_estatico"],
x["fuerza_derecha"],
x["resistencia_derecha"],
x["ovalidad_derecha"]
data[`fuerza_izquierda_${i + 1}`],
data[`resistencia_izquierda_${i + 1}`],
data[`ovalidad_izquierda_${i + 1}`],
data[`peso_estatico_${i + 1}`],
data[`fuerza_derecha_${i + 1}`],
data[`resistencia_derecha_${i + 1}`],
data[`ovalidad_derecha_${i + 1}`]
);
}
......
......@@ -10,13 +10,52 @@ class PDF2 {
);
this.containerSize = 86;
this.font = {
this.body = {
"font": "times",
"type": "normal",
"size": 10
};
this.title = {
"font": "times",
"type": "bold",
"size": 11
};
this.subtitle = {
"font": "times",
"type": "bold",
"size": 10
};
this.line = () => new Line(
new Vector(Pos.beg_margin, Pos.end),
new Vector(Pos.end_margin + 3, Pos.end)
);
}
_getdata(data, op, n) {
switch (op.toLowerCase()) {
case "fi":
op = "fuerza_izquierda";break;
case "fd":
op = "fuerza_derecha";break;
case "ri":
op = "resistencia_izquierda";break;
case "rd":
op = "resistencia_derecha";break;
case "oi":
op = "ovalidad_izquierda";break;
case "od":
op = "ovalidad_derecha";break;
case "pe":
op = "peso_estatico";break;
case "pd":
op = "peso_dinamico";break;
}
return data[op + "_" + n];
}
pdf(data) {
/**
......@@ -30,9 +69,9 @@ class PDF2 {
(pointer, data) => pdfthis.headerToPDF(pointer, data['header']),
(pointer, data) => pdfthis.alineadorToPDF(pointer, data['alineador']),
(pointer, data) => pdfthis.suspensionToPDF(pointer, data['suspension']),
(pointer, data) => pdfthis.frenosToPDF(pointer, data['frenos']),
(pointer, data) => pdfthis.traseroToPDF(pointer, data['trasero']),
(pointer, data) => pdfthis.gaseshumosToPDF(pointer, data['gaseshumos'])
(pointer, data) => pdfthis.frenosToPDF(pointer, data),
(pointer, data) => pdfthis.gaseshumosToPDF(pointer, data['gaseshumos']),
(pointer, data) => pdfthis.footerToPDF(pointer, data)
];
/**
......@@ -53,49 +92,411 @@ class PDF2 {
maha.addRelativeChildren([
new Line(
new Vector(Pos.beg_margin, Pos.end),
new Vector(Pos.end_margin, Pos.end)
),
this.line(),
new Text(
["MAHA","EUROSYSTEM","Bitte hier Ihre","Anschrift eintragen"],
new Vector(Pos.middle, Pos.quarter),
this.font,
this.body,
"center"
),
new Text(
["EUROSYSTEM","V 3.18.009",data['fecha']],
new Vector(Pos.three_quarters, Pos.middle),
this.font,
new Vector(Pos.end_margin - 7, Pos.third + 5),
this.body,
"right"
),
new Image(
document.getElementById("maha"),
new Vector(Pos.end - 10, Pos.beg_margin),
new Vector(10, Pos.end_margin)
new Vector(Pos.end - 12, Pos.beg_margin),
new Vector(10, Pos.end_margin - 5)
)
]);
return pointer.addxy(0,6);
}
headerToPDF(pointer, data) {
const header = this.A4.addRelativeChild(new Div(pointer, new Vector(Pos.end, 10)));
const body_black = {
"font" : "times",
"type" : "bold",
"size" : 9
};
header.addRelativeChildren([
this.line(),
new Text(
[
"Nombre/Empresa:",
"Calle:",
"CP:Ciudad:",
"Teléfono:",
`Fecha de Prueba:\t${data['fecha']}`,
"Hora de Prueba:",
"Estado de Carga:\tVacio"
],
new Vector(Pos.beg_margin + 5, Pos.beg_margin + 10),
body_black
),
new Text(
[
`Matrícula:\t${data['patente']}`,
"Kilometraje:",
"Matriculación:",
"Fabricante:",
"Tipo de Vehic.:",
"Nº motor:",
"Cantidad de Ejes:\t0"
],
new Vector(Pos.two_thirds, Pos.beg_margin + 10),
body_black
)
]);
return pointer.addxy(0, 10);
}
alineadorToPDF(pointer, data) {
const alineador = this.A4.addRelativeChild(new Div(pointer, new Vector(Pos.end, 6)));
alineador.addRelativeChildren([
this.line(),
new Text(
"Alineador al Paso",
new Vector(Pos.beg_margin + 5, Pos.third),
this.title
),
new Text(
`Eje delantero\t${data['eje_delantero']} m/km\t\tEje trasero\t--- m/km`,
new Vector(Pos.beg_margin + 5, Pos.two_thirds),
this.body
)
]);
return pointer.addxy(0, 6);
}
suspensionToPDF(pointer, data) {
const suspension = this.A4.addRelativeChild(new Div(pointer, new Vector(Pos.end, 8)));
const tiny_body = {
"font" : "times",
"type" : "normal",
"size" : 9
}
suspension.addRelativeChildren([
this.line(),
new Text(
"Bco. de Suspensiones",
new Vector(Pos.beg_margin + 5, Pos.third),
this.title
),
new Text(
["Eje delantero", "Eje trasero"],
new Vector(Pos.beg_margin + 5, Pos.two_thirds),
this.subtitle
),
new Text(
["Izq.", "0 Mm", "0 Mm"],
new Vector(25, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["Der.", "0 Mm", "0 Mm"],
new Vector(35, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["Dif.", "0 %", "0 %"],
new Vector(45, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["Izq.", "0 %", "0 %"],
new Vector(55, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["Der.", "0 %", "0 %"],
new Vector(65, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["Dif.", "0 %", "0 %"],
new Vector(75, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["estat.", `${data['peso_estatico_1']} kg`, `${data['peso_dinamico_1']} kg`],
new Vector(85, Pos.middle + 5),
tiny_body,
"center"
),
new Text(
["dinam.", `${data['peso_estatico_2']} kg`, `${data['peso_dinamico_2']} kg`],
new Vector(95, Pos.middle + 5),
tiny_body,
"center"
)
]);
return pointer.addxy(0, 8);
}
frenosToPDF(pointer, data) {
}
traseroToPDF(pointer, data) {
const frenos = this.A4.addRelativeChild(new Div(pointer, new Vector(Pos.end, 30)));
frenos.addRelativeChild(this.line());
const pruebas = frenos.addRelativeChild(new Div(new Vector(Pos.beg, Pos.beg), new Vector(Pos.end, Pos.middle + 10)));
const evaluacion = frenos.addRelativeChild(new Div(new Vector(Pos.beg, Pos.middle + 10), new Vector(Pos.end, Pos.middle - 10)));
const tiny_body = {
"font": "times",
"type": "normal",
"size": 9
}
pruebas.addRelativeChildren([
new Text(
"Frenómetro",
new Vector(Pos.beg_margin + 5, Pos.beg_margin + 5),
this.title
),
new Text(
"Prueba de Frenado",
new Vector(Pos.beg_margin + 5, Pos.beg_margin + 15),
this.subtitle
),
new Line(
new Vector(Pos.beg_margin + 5, Pos.quarter + 18),
new Vector(Pos.end_margin - 5, Pos.quarter + 18)
),
new Text(
["","", "1.FS", "2.FS", "3.FS", "4.FS", `${data['trasero']['eje']}.FE`],
new Vector(Pos.beg_margin + 5, Pos.quarter + 12),
tiny_body
),
new Text(
"Resist.Rodadura [kN]",
new Vector(21, Pos.quarter + 5),
tiny_body
),
new Text(
"Fuerza de Frenado [kN]",
new Vector(40, Pos.quarter + 5),
tiny_body
),
new Text(
"Ovalidad [kN]",
new Vector(60.5, Pos.quarter + 5),
tiny_body
),
new Text(
"Peso [kg]",
new Vector(79, Pos.quarter + 5),
tiny_body
),
]);
const freno = (title, data, access, position) => {
const f = data['frenos'];
const t = data['trasero'][access] === undefined ? "---" : data['trasero'][access];
return new Text(
[title, "", f[access + "_1"], f[access + "_2"], f[access + "_3"], f[access + "_4"], t],
position,
tiny_body,
"center"
)
}
const eje = (data, position) => {
const sum = (data, access1, access2) => (parseFloat(data[access1]) + parseFloat(data[access2])).toFixed(2);
const f = data['frenos'];
const t = data['trasero'];
return new Text(
[
"Eje", "",
`${sum(f,"fuerza_izquierda_1","fuerza_derecha_1")}`,
`${sum(f,"fuerza_izquierda_2","fuerza_derecha_2")}`,
`${sum(f,"fuerza_izquierda_3","fuerza_derecha_3")}`,
`${sum(f,"fuerza_izquierda_4","fuerza_derecha_4")}`,
`${sum(t,"fuerza_izquierda","fuerza_derecha")}`,
],
position,
tiny_body,
"center"
)
}
const fuerzas = eje(data, new Vector(53, Pos.quarter + 12));
const estat = freno("estat.", data, "peso_estatico", new Vector(78, Pos.quarter + 12));
const dinam = freno("dinam.", data, "peso_dinamico", new Vector(86, Pos.quarter + 12));
pruebas.addRelativeChildren([
freno("Izq.", data, "resistencia_izquierda", new Vector(24, Pos.quarter + 12)),
freno("Der.", data, "resistencia_derecha", new Vector(30, Pos.quarter + 12)),
freno("Izq.", data, "fuerza_izquierda", new Vector(42, Pos.quarter + 12)),
freno("Der.", data, "fuerza_derecha", new Vector(48, Pos.quarter + 12)),
fuerzas,
freno("Izq.", data, "ovalidad_derecha", new Vector(62, Pos.quarter + 12)),
freno("Der.", data, "ovalidad_derecha", new Vector(68, Pos.quarter + 12)),
estat,
dinam
]);
const sumtext = (text) =>
`${
(parseFloat(text[2]) +
parseFloat(text[3]) +
parseFloat(text[4]) +
parseFloat(text[5])).toFixed(2)
}`
evaluacion.addRelativeChildren([
new Text(
"Evaluación Final",
new Vector(Pos.beg_margin + 5, Pos.beg_margin),
this.subtitle
),
new Text(
["Freno de Servicio (FS)", "Freno de Estacionamiento (FE)"],
new Vector(Pos.beg_margin + 5, Pos.quarter + 10),
this.body
),
new Text(
[
"Fuerza de frenado máx. [kN]",
sumtext(fuerzas.text),
fuerzas.text[6]
],
new Vector(Pos.middle, Pos.quarter),
this.body,
"center"
),
new Text(
`Peso estático:\t${sumtext(estat.text)} kg\tPeso dinámico:\t${sumtext(dinam.text)} kg`,
new Vector(Pos.beg_margin + 5, Pos.three_quarters),
this.body
)
]);
return pointer.addxy(0, 30);
}
gaseshumosToPDF(pointer, data) {
const gases = this.A4.addRelativeChild(new Div(pointer, new Vector(Pos.end, 6)));
const tiny_body = {
"font": "times",
"type": "normal",
"size": 9
}
gases.addRelativeChildren([
this.line(),
new Text(
"Opacímetro",
new Vector(Pos.beg_margin + 5, Pos.third),
this.title
),
new Text(
`k medio\t${data['opacidad_logaritmica']} l/m\tOC:\t${data['oc']}\tHC:\t${data['hc']}`,
new Vector(Pos.beg_margin + 5, Pos.two_thirds),
tiny_body
),
]);
return pointer.addxy(0,6);
}
footerToPDF(pointer, data) {
const footer = this.A4.addRelativeChild(new Div(pointer, new Vector(Pos.end, 30)));
footer.addRelativeChildren([
this.line(),
new Text(
"Inspector:",
new Vector(Pos.quarter - 5, Pos.end_margin),
this.subtitle,
"center"
),
new Text(
"Firma:.........................",
new Vector(Pos.three_quarters, Pos.end_margin),
this.subtitle,
"center"
)
]);
return pointer.addxy(0,30);
}
}
\ No newline at end of file
......@@ -15,11 +15,6 @@ td{
width: 33.33%;
}
table {
width: 100%;
font-size: var(--FontSize);
}
.header {
width: 50%;
}
......@@ -35,12 +30,7 @@ table {
margin-bottom: 3%;
width: 100%;
text-align: center;
}
#pdf {
border: dashed;
border-color: grey;
margin: 1%;
bottom: 0px;
}
.PDFButton {
......@@ -71,13 +61,42 @@ input {
font-weight: normal;
}
.Message {
font-size: 20;
.MessageContainer {
background-color: rgba(150, 150, 150, 0.5);
width: 100%;
height: 100%;
position: fixed;
right: 50;
top: 50;
top: 0;
left: 0;
}
.Message, .MessageFixed {
max-width: 33%;
padding: 1%;
font-size: 20;
border: 2px solid gray;
background-color: rgba(200, 150, 250, 0.5);
width: 30%;
background-color: rgb(200, 150, 250);
}
.Message {
min-width: 10%;
min-height: 10%;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.MessageFixed {
position: absolute;
top: 50;
right: 50;
}
.X {
position: absolute;
top: 3;
right: 3;
font-weight: bolder;
font-family: Arial, Helvetica, sans-serif;
}
\ No newline at end of file
......@@ -4,108 +4,154 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js"></script>
<script src="{{ url_for('static', filename = 'src/ajax.js') }}"></script>
<script src="{{ url_for('static', filename = 'src/div.js') }}"></script>
<script src="{{ url_for('static', filename = 'src/getters.js') }}"></script>
<script src="{{ url_for('static', filename = 'src/pdf1.js') }}"></script>
<script src="{{ url_for('static', filename = 'src/pdf2.js') }}"></script>
<script src="{{ url_for('static', filename = 'src/forms.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename = 'styles/general.css') }}">
<!--INCLUIMOS LA FUENTE-->
<link rel="stylesheet" media="screen" href="https://fontlibrary.org/face/cmu-typewriter" type="text/css" />
<title>Pruebas de Alineamiento</title>
</head>
<body>
<div class="Message">
Los datos con signo de pregunta '?' son datos no encontrados o faltantes.<br>
Pueden ser completados a mano antes de convertir a PDF.<br>
De no ser completados, se verán como lo que diga el campo 'Por defecto' al final de la página.
</div>
<h1>Datos Generales:</h1>
Patente <input type="text" name="patente" value="{{ data['header']['patente'] }}">
<br>
Fecha <input type="text" name="fecha" value="{{ data['header']['fecha'] }}">
<br>
<h1>Alineador:</h1>
Eje Delantero <input type="text" name="eje_delantero" value="{{ data['alineador']['eje_delantero'] }}">
<br>
<h1>Suspensión:</h1>
{% for eje in data['suspension'] %}
Rendimiento Izquerdo <input type="text" name="rendimiento_izquierdo" value="{{ eje['rendimiento_izquierdo'] }}">
<br>
Rendimiento Derecho <input type="text" name="rendimiento_derecho" value="{{ eje['rendimiento_derecho'] }}">
<br>
Peso Estático (Total) <input type="text" name="peso_estatico" value="{{ eje['peso_estatico'] }}">
<div id="results" style="display: {% if bypass %} block {% else %} none {% endif %};">
<div class="MessageFixed">
Los datos con signo de pregunta '?' son datos no encontrados o faltantes.<br>
Pueden ser completados a mano antes de convertir a PDF.<br>
De no ser completados, se completaran automáticamente con el valor del campo 'Por defecto' al final de la página.
</div>
<h1>Datos Generales:</h1>
Patente <input sub="header" type="text" name="patente">
<br>
Fecha <input sub="header" type="text" name="fecha">
<br>
<h1>Alineador:</h1>
Eje Delantero <input sub="alineador" type="text" name="eje_delantero">
<br>
{% endfor %}
<h1>Frenos:</h1>
{% for eje in data['frenos'] %}
<h1>Suspensión:</h1>
{% for eje in range(2) %}
<h3>Eje {{ eje + 1 }}</h3>
Rendimiento Izquerdo <input sub="suspension" type="text" name="rendimiento_izquierdo_{{ eje + 1 }}">
<br>
Rendimiento Derecho <input sub="suspension" type="text" name="rendimiento_derecho_{{ eje + 1 }}">
<br>
Peso Estático (Total) <input sub="suspension" type="text" name="peso_estatico_{{ eje + 1 }}">
<br>
Peso Dinámico (Báscula) <input sub="suspension" type="text" name="peso_dinamico_{{ eje + 1 }}">
<br>
<br>
{% endfor %}
<h1>Frenos:</h1>
{% for eje in range(4) %}
<h3>Eje {{ eje + 1 }}</h3>
Fuerza Izquierda <input sub="frenos" type="text" name="fuerza_izquierda_{{ eje + 1 }}">
<br>
Fuerza Derecha <input sub="frenos" type="text" name="fuerza_derecha_{{ eje + 1 }}">
<br>
Resistencia Izquierda <input sub="frenos" type="text" name="resistencia_izquierda_{{ eje + 1 }}">
<br>
Resistencia Derecha <input sub="frenos" type="text" name="resistencia_derecha_{{ eje + 1 }}">
<br>
Ovalidad Izquierda <input sub="frenos" type="text" name="ovalidad_izquierda_{{ eje + 1 }}">
<br>
Ovalidad Derecha <input sub="frenos" type="text" name="ovalidad_derecha_{{ eje + 1 }}">
<br>
Peso Estático (Total) <input sub="frenos" type="text" name="peso_estatico_{{ eje + 1 }}">
<br>
Peso Dinámico (Báscula) <input sub="frenos" type="text" name="peso_dinamico_{{ eje + 1 }}">
<br>
<br>
{% endfor %}
Fuerza Izquierda <input type="text" name="fuerza_izquierda" value="{{ eje['fuerza_izquierda'] }}">
<h1>Freno Trasero:</h1>
Fuerza Izquierda <input sub="trasero" type="text" name="fuerza_izquierda">
<br>
Fuerza Derecha <input type="text" name="fuerza_derecha" value="{{ eje['fuerza_derecha'] }}">
Fuerza Derecha <input sub="trasero" type="text" name="fuerza_derecha">
<br>
Resistencia Izquierda <input type="text" name="resistencia_izquierda" value="{{ eje['resistencia_izquierda'] }}">
Eje Nº <input sub="trasero" type="text" name="eje">
<br>
Resistencia Derecha <input type="text" name="resistencia_derecha" value="{{ eje['resistencia_derecha'] }}">
<h1>Gases y Humos</h1>
Opacidad Logarítmica <input sub="gaseshumos" type="text" name="opacidad_logaritmica">
<br>
Ovalidad Izquierda <input type="text" name="ovalidad_izquierda" value="{{ eje['ovalidad_izquierda'] }}">
CO <input sub="gaseshumos" type="text" name="co">
<br>
Ovalidad Derecha <input type="text" name="ovalidad_derecha" value="{{ eje['ovalidad_derecha'] }}">
HC <input sub="gaseshumos" type="text" name="hc">
<br>
Peso Estático (Total) <input type="text" name="peso_estatico" value="{{ eje['peso_estatico'] }}">
<br>
<br>
{% endfor %}
<h1>Freno Trasero:</h1>
Fuerza Izquierda <input type="text" name="fuerza_izquierda" value="{{ data['trasero']['fuerza_izquierda'] }}">
<br>
Fuerza Derecha <input type="text" name="fuerza_derecha" value="{{ data['trasero']['fuerza_derecha'] }}">
<br>
<h1>Gases y Humos</h1>
Opacidad Logarítmica <input type="text" name="opacidad_logaritmica" value="{{ data['gaseshumos']['opacidad_logaritmica'] }}">
<br>
CO <input type="text" name="co" value="{{ data['gaseshumos']['co'] }}">
<br>
HC <input type="text" name="hc" value="{{ data['gaseshumos']['hc'] }}">
<br>
<br>
<br>
Por defecto: <input type="text" name="defecto" value="0.000">
<br>
Por defecto: <input type="text" name="defecto" value="0.00">
<br>
<div class="PDFButtonContainer">
<button class="PDFButton" onclick=
"window.open(
compile(
(new PDF1()).pdf( collectToConvert() ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
)";
>
Convertir a PDF - 1
</button>
<button class="PDFButton" onclick=
"window.open(
compile(
(new PDF2()).pdf( collectToConvert() ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
)";
>
Convertir a PDF - 2
</button>
<img id="maha" src="{{ url_for('static', filename = 'assets/maha.png') }}" style="display: none;">
</div>
</div>
<div class="PDFButtonContainer">
<button class="PDFButton" onclick=
"window.open(
compile(
(new PDF1()).pdf( {{ data }} ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
)";
>
Convertir a PDF - 1
</button>
<div id="form" style="height: 100%; display: {% if bypass %} none {% else %} block {% endif %}">
<h1>Generación de PDF:</h1>
<button class="PDFButton" onclick=
"window.open(
compile(
(new PDF2()).pdf( {{ data }} ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
)";
>
Convertir a PDF - 2
</button>
<img id="maha" src="{{ url_for('static', filename = 'assets/maha.png') }}" style="display: none;">
Usuario <input required type="text" sub="credenciales" name="usuario">
<br>
Contraseña <input required type="password" sub="credenciales" name="contrasena">
<br>
Patente <input required type="text" sub="header" name="patente">
<br>
<h1>Datos Extra:</h1>
Rendimiento Izquierdo - Eje 1 <input required type="number" step="any" sub="suspension" name="rendimiento_izquierdo_1">
<br>
Rendimiento Derecho - Eje 1 <input required type="number" step="any" sub="suspension" name="rendimiento_derecho_1">
<br>
Rendimiento Izquierdo - Eje 2 <input required type="number" step="any" sub="suspension" name="rendimiento_izquierdo_2">
<br>
Rendimiento Derecho - Eje 2 <input required type="number" step="any" sub="suspension" name="rendimiento_derecho_2">
<br>
<div class="PDFButtonContainer">
<button class="PDFButton" onclick="collectToSearch()">
Buscar
</button>
</div>
</div>
<div id="message" class="MessageContainer" onclick="this.style.display = 'none'" style="display: none;">
<div class="Message" style="text-align: center;">
<p id = "msg"></p>
<span class = "X">x<span>
</div>
</div>
</body>
</html>
\ No newline at end of file
{% macro header(dom,fecha) %}
<table class="header">
<tr>
<td>Dominio: {{ dom }}</td> <td>Fecha: {{ fecha }}</td>
</tr>
</table>
{% endmacro %}
{% macro alineador(eje_delan) %}
&ensp; Resultado Pruebas de Alineador al Paso
<br>
<br>
&ensp; Eje Delantero &ensp; {{ eje_delan }}
{% endmacro %}
{% macro suspension(eje, ren_izq, peso, ren_der) %}
&ensp; Resultado Pruebas en Banco de Suspensión - Eje {{ eje }}
<table>
<tr>
<td>Rendimiento Izquierdo</td> <td>Peso Total del Eje</td> <td>Rendimiento Derecho</td>
</tr>
<tr>
<td>{{ ren_izq }}</td> <td>{{ peso }}</td> <td>{{ ren_der }}</td>
</tr>
</table>
{% endmacro %}
{% macro frenos(eje , f_izq, res_izq, ov_izq, peso, f_der, res_der, ov_der) %}
&ensp; Diagnóstico de Frenos - Eje {{ eje }}
<table>
<tr>
<td>Fuerza IZ</td> <td>Peso del Eje</td> <td>Fuerza DE</td>
</tr>
<tr>
<td>{{ f_izq }}</td> <td>{{ peso }}</td> <td>{{ f_der }}</td>
</tr>
<tr>
<td>Res. Rodadura IZ</td> <td></td> <td>Res. Rodadura IZ</td>
</tr>
<tr>
<td>{{ res_izq }}</td> <td></td> <td>{{ res_der }}</td>
</tr>
<tr>
<td>Ovalidad IZ</td> <td></td> <td>Ovalidad DE</td>
</tr>
<tr>
<td>{{ ov_izq }}</td> <td></td> <td>{{ ov_der }}</td>
<tr>
</table>
{% endmacro %}
{% macro trasero(f_izq, f_der) %}
&ensp; Diagnóstico de Frenos - Eje Trasero - Freno de Mano
<table>
<tr>
<td>Fuerza IZ</td> <td></td> <td>Fuerza DE</td>
</tr>
<tr>
<td>{{ f_izq }}</td> <td></td> <td>{{ f_der }}</td>
</tr>
</table>
{% endmacro %}
{% macro gaseshumos(co, hc, med) %}
<table style="width: 60%; float: left;">
<tr>
<td style="width: 66%">
Resultado Analizador de Gases
</td>
</tr>
<tr>
<td>
CO {{ co }} %
</td>
<td>
HC {{ hc }} ppm
</td>
</tr>
</table>
<table style="width: 40%; float: left;">
<tr>
<td>
Resultado Analizador de Humos
</td>
</tr>
<tr>
<td>
Medición {{ med }}
</td>
</tr>
</table>
{% endmacro %}
\ No newline at end of file
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!