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,31 +54,37 @@ 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()
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(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
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()
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
......
......@@ -115,11 +115,3 @@ class BadInterval(Exception):
def __str__(self):
return f"The interval '{self.interval}' is not valid"
\ No newline at end of file
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
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 **/
......@@ -172,11 +195,10 @@ class Div {
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}`]
);
}
......
......@@ -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,88 +4,99 @@
<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">
<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 verán como lo que diga el campo 'Por defecto' al final de la página.
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 type="text" name="patente" value="{{ data['header']['patente'] }}">
Patente <input sub="header" type="text" name="patente">
<br>
Fecha <input type="text" name="fecha" value="{{ data['header']['fecha'] }}">
Fecha <input sub="header" type="text" name="fecha">
<br>
<h1>Alineador:</h1>
Eje Delantero <input type="text" name="eje_delantero" value="{{ data['alineador']['eje_delantero'] }}">
Eje Delantero <input sub="alineador" type="text" name="eje_delantero">
<br>
<h1>Suspensión:</h1>
{% for eje in data['suspension'] %}
{% for eje in range(2) %}
Rendimiento Izquerdo <input type="text" name="rendimiento_izquierdo" value="{{ eje['rendimiento_izquierdo'] }}">
<h3>Eje {{ eje + 1 }}</h3>
Rendimiento Izquerdo <input sub="suspension" type="text" name="rendimiento_izquierdo_{{ eje + 1 }}">
<br>
Rendimiento Derecho <input type="text" name="rendimiento_derecho" value="{{ eje['rendimiento_derecho'] }}">
Rendimiento Derecho <input sub="suspension" type="text" name="rendimiento_derecho_{{ eje + 1 }}">
<br>
Peso Estático (Total) <input type="text" name="peso_estatico" value="{{ eje['peso_estatico'] }}">
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 data['frenos'] %}
{% for eje in range(4) %}
Fuerza Izquierda <input type="text" name="fuerza_izquierda" value="{{ eje['fuerza_izquierda'] }}">
<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>
Fuerza Derecha <input type="text" name="fuerza_derecha" value="{{ eje['fuerza_derecha'] }}">
Resistencia Izquierda <input sub="frenos" type="text" name="resistencia_izquierda_{{ eje + 1 }}">
<br>
Resistencia Izquierda <input type="text" name="resistencia_izquierda" value="{{ eje['resistencia_izquierda'] }}">
Resistencia Derecha <input sub="frenos" type="text" name="resistencia_derecha_{{ eje + 1 }}">
<br>
Resistencia Derecha <input type="text" name="resistencia_derecha" value="{{ eje['resistencia_derecha'] }}">
Ovalidad Izquierda <input sub="frenos" type="text" name="ovalidad_izquierda_{{ eje + 1 }}">
<br>
Ovalidad Izquierda <input type="text" name="ovalidad_izquierda" value="{{ eje['ovalidad_izquierda'] }}">
Ovalidad Derecha <input sub="frenos" type="text" name="ovalidad_derecha_{{ eje + 1 }}">
<br>
Ovalidad Derecha <input type="text" name="ovalidad_derecha" value="{{ eje['ovalidad_derecha'] }}">
Peso Estático (Total) <input sub="frenos" type="text" name="peso_estatico_{{ eje + 1 }}">
<br>
Peso Estático (Total) <input type="text" name="peso_estatico" value="{{ eje['peso_estatico'] }}">
Peso Dinámico (Báscula) <input sub="frenos" type="text" name="peso_dinamico_{{ eje + 1 }}">
<br>
<br>
{% endfor %}
<h1>Freno Trasero:</h1>
Fuerza Izquierda <input type="text" name="fuerza_izquierda" value="{{ data['trasero']['fuerza_izquierda'] }}">
Fuerza Izquierda <input sub="trasero" type="text" name="fuerza_izquierda">
<br>
Fuerza Derecha <input sub="trasero" type="text" name="fuerza_derecha">
<br>
Fuerza Derecha <input type="text" name="fuerza_derecha" value="{{ data['trasero']['fuerza_derecha'] }}">
Eje Nº <input sub="trasero" type="text" name="eje">
<br>
<h1>Gases y Humos</h1>
Opacidad Logarítmica <input type="text" name="opacidad_logaritmica" value="{{ data['gaseshumos']['opacidad_logaritmica'] }}">
Opacidad Logarítmica <input sub="gaseshumos" type="text" name="opacidad_logaritmica">
<br>
CO <input type="text" name="co" value="{{ data['gaseshumos']['co'] }}">
CO <input sub="gaseshumos" type="text" name="co">
<br>
HC <input type="text" name="hc" value="{{ data['gaseshumos']['hc'] }}">
HC <input sub="gaseshumos" type="text" name="hc">
<br>
<br>
<br>
Por defecto: <input type="text" name="defecto" value="0.000">
Por defecto: <input type="text" name="defecto" value="0.00">
<br>
<div class="PDFButtonContainer">
<button class="PDFButton" onclick=
"window.open(
compile(
(new PDF1()).pdf( {{ data }} ),
(new PDF1()).pdf( collectToConvert() ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
......@@ -97,7 +108,7 @@
<button class="PDFButton" onclick=
"window.open(
compile(
(new PDF2()).pdf( {{ data }} ),
(new PDF2()).pdf( collectToConvert() ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
......@@ -107,5 +118,40 @@
</button>
<img id="maha" src="{{ url_for('static', filename = 'assets/maha.png') }}" style="display: none;">
</div>
</div>
<div id="form" style="height: 100%; display: {% if bypass %} none {% else %} block {% endif %}">
<h1>Generación de PDF:</h1>
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!