Commit e5892f4d by Luciano Barletta

added anomalies data recollection and pdf generation

1 parent 59ee44ea
#-*- coding: utf-8 -*-
from flask import Flask, render_template, request, url_for, make_response, redirect
from iselenium import SeleniumInterface as SI
import random, json, os
import random, json, os, datetime
app = Flask(__name__)
......@@ -23,8 +23,7 @@ def usersave(usr, psw):
content = {}
content[usr] = psw
u.write( json.dumps(content) )
u.write( json.dumps(content) )
def userget(usr):
create()
......@@ -39,14 +38,14 @@ def userget(usr):
@app.route('/')
def main():
if "login" in request.cookies:
return render_template(
"form.html",
bypass = False
)
else:
if "login" not in request.cookies:
return redirect(url_for("login"))
return render_template(
"form.html",
bypass = False
)
@app.route('/login', methods = ['GET', 'POST'])
def login():
if request.method == "GET":
......@@ -75,21 +74,69 @@ def login():
request.json['usuario'],
request.json['contrasena']
)
s.driver.close()
s.driver.quit()
return r
except:
s.driver.close()
s.driver.quit()
return "Error en el login"
@app.route('/manual')
def manual():
if "login" not in request.cookies:
return redirect(url_for("login"))
return render_template(
"form.html",
bypass = True
)
@app.route('/pdf', methods = ['POST'])
def pdf():
@app.route('/anomalies', methods = ['POST'])
def anomalies():
if "login" not in request.cookies:
return redirect(url_for("login"))
d = request.json
plate = d['header']['patente']
s = SI(SI.Chrome)
anom = {
"header" : {
"patente" : plate
}
}
try:
login(
request.cookies["login"],
userget(
request.cookies["login"]
),
s
)
except:
s.driver.quit()
return f"Error en el login"
try:
gototec(s, d)
except:
s.driver.quit()
return f"Error yendo a las especificaciones técnicas del dominio '{plate}'."
try:
anom = fetchAnomalies(s, anom)
except:
s.driver.quit()
return f"Fallo en la recolección de anomalías del dominio '{plate}'."
try:
anom = gotoadmin(s, anom)
except:
return f"Error yendo a los datos administrativos del dominio '{plate}'."
s.driver.quit()
anom['header']['patente'] = plate
anom['header']['fecha'] = datetime.datetime.now().strftime("%d/%m/%Y")
return render_template("anomalies.html", anomalies = anom)
@app.route('/report', methods = ['POST'])
def report():
if "login" not in request.cookies:
return redirect(url_for("login"))
......@@ -117,25 +164,25 @@ def pdf():
s
)
except:
s.driver.close()
s.driver.quit()
return f"Error en el login"
try:
answer = gototec(s, answer)
except:
s.driver.close()
s.driver.quit()
return f"Error yendo a las especificaciones técnicas del dominio '{plate}'."
#try:
answer = readdata(s, answer)
#except:
#s.driver.close()
#return f"Error leyendo datos de la patente '{plate}'."
try:
answer = readdata(s, answer)
except:
s.driver.quit()
return f"Error leyendo datos de la patente '{plate}'."
try:
answer = rnddata(answer)
except:
s.driver.close()
s.driver.quit()
return f"Error completando datos extra de la patente '{plate}'."
s.driver.close()
s.driver.quit()
return json.dumps(answer)
def login(u, p, s):
......@@ -150,10 +197,10 @@ def login(u, p, s):
button = s.find(SI.By.ID, "submit")
button.click()
login = _attempt(lambda s: s.find(SI.By.NAME, "j_username"), "?")(s)
login = s.find(SI.By.NAME, "j_username")
# login succeeded
if login == "?":
if login == None:
return True
# still in login page
......@@ -187,6 +234,20 @@ def gototec(s, r):
return r
# Assumes already in tec
def gotoadmin(s, r):
s.find(SI.By.XPATH, "//a/span[@class='externo']/parent::*", "1-")[0].click()
s.find(SI.By.XPATH, "//a[@href='#titularOperador']").click()
rsocial = s.find(SI.By.XPATH, "//div[@id='datosOperador']//fieldset[2]/div")
cp = s.find(SI.By.XPATH, "//div[@id='datosOperador']//fieldset[3]/div[4]")
r['header']['rsocial'] = rsocial.get_attribute("innerText").split(":")[1].strip()
r['header']['cp'] = cp.get_attribute("innerText").split(":")[1].strip()
return r
def readdata(s, r):
reach = lambda id: lambda s: s.readInput( s.find(s.By.ID, id) )
......@@ -248,6 +309,55 @@ def rnddata(r):
return r
def fetchAnomalies(s, r):
def checked(Maybe_checkbox):
if Maybe_checkbox == None:
return False
return Maybe_checkbox.is_selected()
def severity(row):
hig = s.findFromElement(row[1], SI.By.XPATH, "input[@type='checkbox']")
med = s.findFromElement(row[2], SI.By.XPATH, "input[@type='checkbox']")
if checked(hig):
return "Grave"
elif checked(med):
return "Moderada"
else:
return "Leve"
def anomalyType(row):
return row[4].get_attribute('innerText').split('>')[0].strip()
def description(row):
textarea = s.findFromElement(row[5], SI.By.TAG_NAME, "textarea")
return textarea.get_attribute("value")
result = {}
# Click Anomalies tab
s.find(SI.By.ID, "ui-id-2").click()
# Anomaly table, if one exists
rows = s.children( s.find(SI.By.XPATH, "//div[@id='tableAnomaliaRevisionGuardadaDiv']/div/div/table/tbody") )
if rows == None:
return r
# Complete return data
for row in rows:
c = s.children(row)
t = anomalyType(c)
if t not in result:
result[t] = []
result[ t ].append({
'severity' : severity(c),
'description' : description(c)
})
r['anomalies'] = result
return r
# Executes the lambda with the arguments, with try except
def _attempt(f, default = "", error = ""):
def inner(*args, **kwargs):
......
......@@ -3,6 +3,7 @@ from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait as Wait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import time
class SeleniumInterface:
......@@ -35,7 +36,13 @@ class SeleniumInterface:
return self.findFromElement(element, SeleniumInterface.By.XPATH, "child::*", "1-")
def findFromElement(self, element, by, lookup, select = "1"):
self._wait(element, (by, lookup))
if element == None:
return None
try:
self._wait(element, (by, lookup))
except TimeoutException:
return None
elements = element.find_elements(by, lookup)
array = []
......
"use strict";
function collectToSearch() {
function collectToSearch(option) {
const f = document.getElementById("form");
const inputs = f.getElementsByTagName("input");
const defecto = document.getElementsByName("defecto")[0].value;
......@@ -28,12 +28,17 @@ function collectToSearch() {
message("Espere...");
const obj = {
"url" : "/pdf",
"contentType" : "application/json",
"async" : true,
"data" : data,
"success" : (response) => {
let send = {
"contentType": "application/json",
"async": true,
"data": data,
"error": (response) => message(response),
"timeout": 120000,
"ontimeout": (response) => message("La conexión tardó demasiado.")
}
if (option == "data") {
send['url'] = "/report";
send['success'] = (response) => {
let r;
try {
r = JSON.parse(response);
......@@ -41,21 +46,27 @@ function collectToSearch() {
} catch (error) {
message(response);
}
document.getElementById("results").style.display = "block";
document.getElementById("report").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.")
};
}
let ajax = new Ajax(obj);
else if (option == "anomalies") {
send['url'] = "/anomalies";
send['success'] = (response) => {
document.getElementById("message").click();
document.getElementById("anomalies").style.display = "block";
document.getElementById("anomalies").innerHTML = response;
document.getElementById("form").style.display = "none";
};
}
let ajax = new Ajax(send);
ajax.post();
}
function collectToConvert() {
const r = document.getElementById("results")
const r = document.getElementById("report")
const inputs = r.getElementsByTagName("input");
let data = {};
......@@ -82,7 +93,7 @@ function message(msg) {
}
function fillResults(results) {
const r = document.getElementById("results")
const r = document.getElementById("report")
const inputs = r.getElementsByTagName("input");
Array.from(inputs).forEach(input => {
......
class PDF3 {
"use strict";
constructor() {
/** Coordinate container that occupies the whole page **/
this.A4 = new Div(
new Vector(0, 0),
new Vector(595, 842)
);
this.containerSize = 86;
this.body = {
"font": "times",
"type": "normal",
"size": 9
};
this.title = {
"font": "times",
"type": "bold",
"size": 13
};
this.subtitle = {
"font": "times",
"type": "bold",
"size": 8
};
this.line = () => new Line(
new Vector(Pos.beg_margin, Pos.end),
new Vector(Pos.end_margin, Pos.end)
);
}
pdf(data) {
let pointer = new Vector(0,0);
pointer = this.header(pointer, data['header']);
Object.keys(data['anomalies']).forEach( title =>
pointer = this.table(
pointer, title, data['anomalies'][title]
)
);
return this.A4;
}
header(pointer, data) {
const header = this.A4.addRelativeChild( new Div(pointer, new Vector(Pos.end, 10)) );
header.addRelativeChildren([
this.line(),
new Text(
"Informe para Taller de Mantenimiento",
new Vector(Pos.middle, Pos.third),
this.title,
"center"
),
new Text(
`Fecha: ${data['fecha']}`,
new Vector(Pos.end_margin, Pos.two_thirds),
this.body,
"right"
),
new Text(
[`Razon social: ${data['cp']} - ${data['rsocial']}`, `Patente: ${data['patente']}`],
new Vector(Pos.beg_margin, Pos.two_thirds),
this.body
)
])
return pointer.addxy(0,10);
}
table(pointer, title, data) {
const table = this.A4.addRelativeChild( new Div(pointer.addxy(5,1), new Vector(90, 2 * (data.length + 1))) );
const left = table.addRelativeChild( new Div(new Vector(0,0), new Vector(30, 100)) );
const right = table.addRelativeChild( new Div(new Vector(30,0), new Vector(70, 100)) );
left.drawOutline = true;
right.drawOutline = true;
left.addRelativeChild(
new Text(
title,
new Vector(Pos.middle, Pos.middle + 10),
this.subtitle,
"center"
)
)
let subpointer = right.position.addxy(5, 0.025 * this.A4.size.y);
data.forEach( entry => {
right.addAbsoluteChild(
new Text(
`${entry['description']} - ${entry['severity']}`,
subpointer,
this.body,
)
);
subpointer = subpointer.addxy(0, 0.02 * this.A4.size.y);
});
return pointer.addxy(0, 2 * (data.length + 1) + 1);
}
}
\ No newline at end of file
<html lang="en">
<head>
<meta charset="UTF-8">
<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/pdf3.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>
<style>
table {
width: 75%;
border: 2px solid black;
}
th,
td {
width: 50%;
border: none;
text-align: center;
padding: 1%;
}
th {
width: 50%;
border-right: 2px solid black;
}
tr {
border-right: 2px solid black;
}
</style>
<div>
<h1>Informe para Taller de Mantenimiento</h1>
Fecha: {{ anomalies['header']['fecha'] }}
<br>
Razón Social: {{ anomalies['header']['cp'] }} - {{ anomalies['header']['rsocial'] }}
<br>
Patente: {{ anomalies['header']['patente'] }}
<br>
{% for a in anomalies['anomalies'] %}
<table>
<tr>
<th rowspan="{{ (anomalies['anomalies'][a] | length) + 1 }}">{{ a }}</th>
</tr>
{% for e in anomalies['anomalies'][a] %}
<tr>
<td>{{ e['description'] }} - {{ e['severity'] }}</td>
</tr>
{% endfor %}
</table>
<br>
</div>
{% endfor %}
<div class="PDFButtonContainerFixed" style="top: 50px;">
<button class="PDFButton"
onclick="window.open(
compile(
(new PDF3()).pdf( {{ anomalies }} ),
new jsPDF('portrait', 'pt', 'a4')
)
.output('bloburl')
);">
Generar PDF
</button>
</div>
<div class="PDFButtonContainerFixed" style="top: 200px;">
<button class="PDFButton" onclick="location.reload()">
Volver
</button>
</div>
</body>
\ No newline at end of file
......@@ -8,6 +8,7 @@
<script src="{{ url_for('static', filename = 'src/div.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/pdf3.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-->
......@@ -15,7 +16,7 @@
<title>Pruebas de Alineamiento</title>
</head>
<body>
<div id="results" style="display: {% if bypass %} block {% else %} none {% endif %};">
<div id="report" 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>
......@@ -125,6 +126,10 @@
</div>
</div>
<div id="anomalies" class="DataCard" style="height: auto; display: none;">
</div>
<div id="form" class="DataCard" style="height: auto; display: {% if bypass %} none {% else %} block {% endif %};">
<h1>Generación de PDF</h1>
......@@ -145,8 +150,12 @@
Por defecto: <input name="defecto" type="text" value="---">
<div class="PDFButtonContainer">
<button class="PDFButton" onclick="collectToSearch()">
Buscar
<button class="PDFButton" onclick="collectToSearch('data')">
Datos
</button>
<button class="PDFButton" onclick="collectToSearch('anomalies')">
Anomalías
</button>
</div>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!