finition générer dossier à partir d'un email

This commit is contained in:
2020-01-13 17:14:17 +01:00
parent 703791fe4d
commit a490992988
10 changed files with 498 additions and 296 deletions

View File

@@ -22,13 +22,14 @@ pyramid.includes =
sqlalchemy.url = mysql://phuoc:phuoc!@localhost/bddevfac?charset=utf8 sqlalchemy.url = mysql://phuoc:phuoc!@localhost/bddevfac?charset=utf8
# sqlalchemy.url = mysql://root:cni/@srvbd/bddevfac?charset=utf8 # sqlalchemy.url = mysql://root:cni/@srvbd/bddevfac?charset=utf8
mondumas.admin_email = phuoc@caotek.fr mondumas.admin_email = cao.thien-phuoc@orange.fr
mondumas.devfac_url = mondumas:static/DEVFAC/ mondumas.devfac_url = mondumas:static/DEVFAC/
mondumas.devfac_dir = /DEVFAC14/DOCS_ATTACHES mondumas.devfac_dir = /DEVFAC14/DOCS_ATTACHES
# Mailer configuration # Mailer configuration
mail.host = smtp.free.fr mail.host = smtp.orange.fr
mail.port = 25 mail.port = 25
mail.username = cao.thien-phuoc@orange.fr
[server:main] [server:main]
use = egg:waitress#main use = egg:waitress#main

View File

@@ -29,7 +29,10 @@ def get_dossier_by_no(request,nodossier):
societe = nodossier[0:2] societe = nodossier[0:2]
no_id = nodossier[3:] no_id = nodossier[3:]
query = """ query = """
SELECT d.*, c.*, a.NOM as nom_cabinet, e.NOM as nom_expert FROM dem_devis d SELECT d.*, a.NOM as nom_cabinet, e.NOM as nom_expert,
c.QUALITE AS cli_QUALITE, c.NOM AS cli_NOM, c.ADRESSE AS cli_ADRESSE, c.ADRESSE2 AS cli_ADRESSE2, c.CP AS cli_CP, c.VILLE AS cli_VILLE,
c.TEL1 AS cli_TEL1, c.TEL2 AS cli_TEL2, c.TELP AS cli_TELP, c.FAX AS cli_FAX, c.NOMRESP AS cli_NOMRESP
FROM dem_devis d
INNER JOIN clients c ON d.societe = c.societe and d.cd_cli = c.cd_cli INNER JOIN clients c ON d.societe = c.societe and d.cd_cli = c.cd_cli
INNER JOIN p_cabinet a ON d.cabinet = a.code INNER JOIN p_cabinet a ON d.cabinet = a.code
INNER JOIN p_experts e ON d.cabinet = e.code_cab and d.expert = e.code_exp INNER JOIN p_experts e ON d.cabinet = e.code_cab and d.expert = e.code_exp
@@ -38,7 +41,7 @@ where d.societe = '%s' and d.no_id=%s;""" % (societe, no_id);
return results return results
def get_dossier_by_sinistre(request,societe, nosin): def get_dossier_by_sinistre(request,societe, nosin):
query = "SELECT * FROM dem_devis WHERE societe = '%s' and nosin = '%s';" % (societe, nosin); query = "SELECT * FROM dem_devis WHERE societe = '%s' and LEFT(REPLACE(nosin,' ', ''),11) = LEFT(REPLACE('%s',' ', ''),11);" % (societe, nosin);
results = request.dbsession.execute(query).first() results = request.dbsession.execute(query).first()
return results return results
@@ -181,6 +184,9 @@ def update_dossier(request, nodossier, new_values):
s = '' s = ''
for param in new_values.keys(): for param in new_values.keys():
if param == 'C_VILLE':
new_values['C_VILLE'] = new_values['C_VILLE'].upper()
if s: if s:
s += ",%s=:%s" % (param, param) s += ",%s=:%s" % (param, param)
else: else:
@@ -282,4 +288,17 @@ def insert_dossier(request, societe, cd_cli, c_nom, c_adr, c_adr2, c_cp, c_ville
query = "SELECT no_id FROM dem_devis WHERE societe = :societe AND date = curdate() AND cd_cli = :cd_cli ORDER BY no_id desc LIMIT 1;" query = "SELECT no_id FROM dem_devis WHERE societe = :societe AND date = curdate() AND cd_cli = :cd_cli ORDER BY no_id desc LIMIT 1;"
results = request.dbsession.execute(query, {'societe': societe, 'cd_cli': cd_cli}).first() results = request.dbsession.execute(query, {'societe': societe, 'cd_cli': cd_cli}).first()
return results.no_id return results.no_id
def get_cabinet(request, code):
query = "SELECT * FROM p_cabinet where code = :code;"
results = request.dbsession.execute(query, {'code': code}).first()
return results
def get_experts(request, code_cab, code_exp):
if code_exp == 0:
query = "SELECT * FROM p_experts where code_cab = :code_cab;"
results = request.dbsession.execute(query, {'code_cab': code_cab}).fetchall()
else:
query = "SELECT * FROM p_experts where code_cab = :code_cab AND code_exp = :code_exp;"
results = request.dbsession.execute(query, {'code_cab': code_cab, 'code_exp': code_exp}).first()
return results

View File

@@ -189,6 +189,7 @@
-o-animation: spin 2s infinite linear; -o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear; animation: spin 2s infinite linear;
} }
@-moz-keyframes spin { @-moz-keyframes spin {
0% { 0% {
-moz-transform: rotate(0deg); -moz-transform: rotate(0deg);

View File

@@ -1,45 +1,36 @@
<metal:block use-macro="main_template"> <metal:block use-macro="main_template">
<div metal:fill-slot="content"> <div metal:fill-slot="content">
<br />
<div tal:condition="message" tal:content="message" class="alert alert-success" />
<div class="row"> <div class="row">
<form id="demandes_form" action="${url}" class="form-horizontal" method="post" <table id="demandes" class="table table-striped table-bordered">
data-fv-framework="bootstrap" <thead>
data-fv-icon-valid="glyphicon glyphicon-ok" <tr>
data-fv-icon-invalid="glyphicon glyphicon-remove" <th>Société</th>
data-fv-icon-validating="glyphicon glyphicon-refresh"> <th>Date</th>
<th>Expéditeur</th>
<div class="form-group"> <th>Objet</th>
<label class="control-label col-xs-4" for="societe">Société</label> </tr>
<div class="col-xs-8"> </thead>
<select class="form-control" id="societe" name="societe" onChange="$('#demandes_form').submit()" > </table>
<div tal:repeat="item societes">
<option value="${item}" tal:attributes="selected societe==item and 'selected' or None">${item}</option>
</div>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<a href="${request.application_url}/" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
<button class="btn btn-success" type="submit" name="form.submitted" tal:condition="msglus">
<span class="glyphicon glyphicon-download-alt"></span>&nbsp;Générer les dossiers</button>
</div>
</div>
</form>
</div> </div>
<div class="row"> <div class="row">
<table id="demandes" class="table table-striped table-bordered"> <form id="demandes_form" action="${url}" class="form-horizontal" method="post"
<thead> data-fv-framework="bootstrap"
<tr> data-fv-icon-valid="glyphicon glyphicon-ok"
<th>No</th> data-fv-icon-invalid="glyphicon glyphicon-remove"
<th>Date</th> data-fv-icon-validating="glyphicon glyphicon-refresh">
<th>Expéditeur</th>
<th>Destinataire</th> <div class="form-group">
<th>Objet</th> <div class="col-sm-offset-4 col-sm-8">
</tr> <a href="${request.application_url}/" class="btn btn-default btn-lg" role="button">
</thead> <span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
</table> <button id="generateButton" class="btn btn-success btn-lg" type="submit" name="form.submitted" tal:condition="msglus">
<i class="glyphicon glyphicon-refresh"></i>&nbsp;Générer les dossiers</button>
</div>
</div>
</form>
</div> </div>
<br /> <br />
@@ -60,12 +51,27 @@
url: 'https://cdn.datatables.net/plug-ins/1.10.16/i18n/French.json' url: 'https://cdn.datatables.net/plug-ins/1.10.16/i18n/French.json'
}, },
columnDefs: [ columnDefs: [
{ className: "text-right", "targets": [0] }, { className: "text-center", "targets": [0] },
], ],
createdRow: function( row, data, dataIndex ) {
if ( data[0] == "ME" ) {
$('td', row).eq(0).css('background-color', 'Gold');
} else if ( data[0] == "PE" ) {
$('td', row).eq(0).css('background-color', 'LightYellow');
} else if ( data[0] == "PL" ) {
$('td', row).eq(0).css('background-color', 'LightGreen');
}
},
}); });
}); });
</script> </script>
<script type="text/javascript">
$('#generateButton').on('click', function(){
$('i.gly-spin').removeClass('gly-spin');
$('i').addClass('gly-spin');
});
</script>
</div><!-- content --> </div><!-- content -->
</metal:block> </metal:block>

View File

@@ -8,18 +8,54 @@
data-fv-icon-invalid="glyphicon glyphicon-remove" data-fv-icon-invalid="glyphicon glyphicon-remove"
data-fv-icon-validating="glyphicon glyphicon-refresh"> data-fv-icon-validating="glyphicon glyphicon-refresh">
<h3 class="text-primary">ADRESSE</h3>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Adresse email</label> <label class="control-label col-xs-4" for="C_ADR">Adresse</label>
<div class="col-sm-8"> <div class="col-xs-8">
<input class="form-control" type="text" name="C_EMAIL" <input class="form-control" type="text" id="C_ADR" name="C_ADR" value="${dossier.C_ADR}"
value="${dossier.C_EMAIL}" placeholder="50 caractères maximum" placeholder="40 caractères maximum"
data-fv-emailaddress="true" data-fv-stringlength="true"
data-fv-emailaddress-message="L'adresse email n'est pas valide" /> data-fv-stringlength-max="40"
data-fv-stringlength-message="40 caractères maximum" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-4" for="C_ADR2">Adresse 2</label>
<div class="col-xs-8">
<input class="form-control" type="text" id="C_ADR2" name="C_ADR2" value="${dossier.C_ADR2}"
placeholder="40 caractères maximum"
data-fv-stringlength="true"
data-fv-stringlength-max="40"
data-fv-stringlength-message="40 caractères maximum" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-4" for="C_CP">Code postal</label>
<div class="col-xs-5">
<input class="form-control" type="text" id="C_CP" name="C_CP" value="${dossier.C_CP}"
placeholder="5 caractères maximum"
data-fv-notempty="true"
data-fv-notempty-message="Le code postal est obligatoire"
data-fv-stringlength="true"
data-fv-stringlength-max="5"
data-fv-stringlength-message="5 caractères maximum" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-4" for="C_VILLE">Ville</label>
<div class="col-xs-5">
<input class="form-control" type="text" id="C_VILLE" name="C_VILLE" value="${dossier.C_VILLE}"
placeholder="45 caractères maximum"
data-fv-notempty="true"
data-fv-notempty-message="La Ville est obligatoire"
data-fv-stringlength="true"
data-fv-stringlength-max="25"
data-fv-stringlength-message="25 caractères maximum" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Etage</label> <label class="col-sm-4 control-label">Etage</label>
<div class="col-sm-8"> <div class="col-sm-5">
<input class="form-control" type="text" name="C_ETAGE" <input class="form-control" type="text" name="C_ETAGE"
value="${dossier.C_ETAGE}" placeholder="10 caractères maximum" value="${dossier.C_ETAGE}" placeholder="10 caractères maximum"
data-fv-stringlength="true" data-fv-stringlength="true"
@@ -29,7 +65,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Code d'accès</label> <label class="col-sm-4 control-label">Code d'accès</label>
<div class="col-sm-8"> <div class="col-sm-5">
<input class="form-control" type="text" name="C_CODE" <input class="form-control" type="text" name="C_CODE"
value="${dossier.C_CODE}" placeholder="20 caractères maximum" value="${dossier.C_CODE}" placeholder="20 caractères maximum"
data-fv-stringlength="true" data-fv-stringlength="true"
@@ -37,9 +73,20 @@
data-fv-stringlength-message="20 caractères maximum" /> data-fv-stringlength-message="20 caractères maximum" />
</div> </div>
</div> </div>
<h3 class="text-primary">EMAIL et TELEPHONES</h3>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Téléphone fixe</label> <label class="col-sm-4 control-label">Adresse email</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input class="form-control" type="text" name="C_EMAIL"
value="${dossier.C_EMAIL}" placeholder="50 caractères maximum"
data-fv-emailaddress="true"
data-fv-emailaddress-message="L'adresse email n'est pas valide" />
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Téléphone fixe</label>
<div class="col-sm-5">
<input class="form-control" type="text" name="C_TEL1" <input class="form-control" type="text" name="C_TEL1"
value="${dossier.C_TEL1}" placeholder="20 caractères maximum" value="${dossier.C_TEL1}" placeholder="20 caractères maximum"
data-fv-phone="true" data-fv-phone="true"
@@ -49,7 +96,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Téléphone prof.</label> <label class="col-sm-4 control-label">Téléphone prof.</label>
<div class="col-sm-8"> <div class="col-sm-5">
<input class="form-control" type="text" name="C_TEL2" <input class="form-control" type="text" name="C_TEL2"
value="${dossier.C_TEL2}" placeholder="20 caractères maximum" value="${dossier.C_TEL2}" placeholder="20 caractères maximum"
data-fv-phone="true" data-fv-phone="true"
@@ -59,7 +106,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Téléphone mobile</label> <label class="col-sm-4 control-label">Téléphone mobile</label>
<div class="col-sm-8"> <div class="col-sm-5">
<input class="form-control" type="text" name="C_TELP" <input class="form-control" type="text" name="C_TELP"
value="${dossier.C_TELP}" placeholder="20 caractères maximum" value="${dossier.C_TELP}" placeholder="20 caractères maximum"
data-fv-phone="true" data-fv-phone="true"
@@ -69,7 +116,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Téléphone fax</label> <label class="col-sm-4 control-label">Téléphone fax</label>
<div class="col-sm-8"> <div class="col-sm-5">
<input class="form-control" type="text" name="C_FAX" <input class="form-control" type="text" name="C_FAX"
value="${dossier.C_FAX}" placeholder="20 caractères maximum" value="${dossier.C_FAX}" placeholder="20 caractères maximum"
data-fv-phone="true" data-fv-phone="true"
@@ -77,6 +124,25 @@
data-fv-phone-message="Ce numéro de téléphone n'est pas vailde" /> data-fv-phone-message="Ce numéro de téléphone n'est pas vailde" />
</div> </div>
</div> </div>
<h3 class="text-primary">CABINET / EXPERT</h3>
<div class="form-group">
<label class="control-label col-sm-4">Cabinet</label>
<div class="col-sm-8">
<p class="form-control-static">${dossier.nom_cabinet}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="EXPERT">Expert</label>
<div class="col-sm-8">
<select class="form-control" id="EXPERT" name="EXPERT">
<div tal:repeat="item experts">
<option value="${item.CODE_EXP}" tal:attributes="selected dossier.EXPERT==item.CODE_EXP and 'selected' or None">${item.NOM}</option>
</div>
</select>
</div>
</div>
<br />
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-4 col-sm-8"> <div class="col-sm-offset-4 col-sm-8">
<a class="btn btn-default" href="${request.application_url}/dossier_view/${nodossier}"> <a class="btn btn-default" href="${request.application_url}/dossier_view/${nodossier}">

View File

@@ -53,6 +53,7 @@
<th class="text-right">Montant</th> <th class="text-right">Montant</th>
<th>Sinistre</th> <th>Sinistre</th>
<th class="text-center">Statut</th> <th class="text-center">Statut</th>
<th>Uti.</th>
</tr> </tr>
</thead> </thead>
</table> </table>
@@ -76,6 +77,7 @@
}, },
order: [[0, order_option]], order: [[0, order_option]],
columnDefs: [ columnDefs: [
{ className: "text-right", "targets": [4] },
{ "targets": 0, { "targets": 0,
"render": function (data, type, full, meta) { "render": function (data, type, full, meta) {
// ajouter un link vers le formulaire // ajouter un link vers le formulaire

View File

@@ -72,10 +72,10 @@
${dossier.CD_CLI} ${dossier.CD_CLI}
</td> </td>
<td> <td>
<h4>${dossier.QUALITE} ${dossier.NOM}</h4> <h4>${dossier.cli_QUALITE} ${dossier.cli_NOM}</h4>
${dossier.ADRESSE}<br /> ${dossier.cli_ADRESSE}<br />
<span tal:condition="dossier.ADRESSE2">${dossier.ADRESSE2}<br /></span> <span tal:condition="dossier.cli_ADRESSE2">${dossier.cli_ADRESSE2}<br /></span>
${dossier.CP} ${dossier.VILLE}<br /> ${dossier.cli_CP} ${dossier.cli_VILLE}<br />
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -85,14 +85,17 @@
Tél. mobile - fax Tél. mobile - fax
</td> </td>
<td> <td>
${dossier.NOMRESP}<br /> ${dossier.cli_NOMRESP}<br />
${dossier.TEL1} - ${dossier.TEL2}<br /> ${dossier.cli_TEL1} - ${dossier.cli_TEL2}<br />
${dossier.TELP} - ${dossier.FAX} ${dossier.cli_TELP} - ${dossier.cli_FAX}
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
<div class="col-md-6">
<h4>Statut : ${dossier.STATUS}</h4> <h4>Statut : ${dossier.STATUS}</h4>
Dernière modif. le <b>${dossier.DATEMAJ.strftime('%d/%m/%Y à %H:%M')}</b> par <b>${dossier.USERMAJ}</b>
</div>
</div> <!-- row --> </div> <!-- row -->
<!-- PANEL DOSSIERS SIMILAIRES --> <!-- PANEL DOSSIERS SIMILAIRES -->

View File

@@ -7,7 +7,7 @@
<div class="row text-center"> <div class="row text-center">
<div class="col-sm-3"> <div class="col-sm-3">
<span class="fas fa-desktop logo-primary"></span> <span class="fas fa-desktop logo-primary"></span>
<h4>21 ordinateurs</h4> <h4>15 ordinateurs</h4>
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<span class="fas fa-laptop logo-primary"></span> <span class="fas fa-laptop logo-primary"></span>
@@ -15,7 +15,7 @@
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<span class="fas fa-print logo-primary"></span> <span class="fas fa-print logo-primary"></span>
<h4>10 imprimantes</h4> <h4>4 imprimantes réseau</h4>
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<span class="fas fa-tablet-alt logo-small"></span> <span class="fas fa-tablet-alt logo-small"></span>
@@ -25,30 +25,94 @@
</div> </div>
<br /> <br />
<h3 class="text-center">SERVEURS</h3> <h3 class="text-center">SERVEURS WINDOWS</h3>
<br />
<div id="jquery" class="container-fluid"> <div id="jquery" class="container-fluid">
<div class="row text-center"> <div class="row text-center">
<div class="col-sm-3">
<span class="fas fa-server logo-primary"></span>
<h4>SVRTSE</h4>
</div>
<div class="col-sm-3">
<span class="fas fa-server logo-primary"></span>
<h4>SRVBD</h4>
</div>
<div class="col-sm-3">
<span class="fas fa-server logo-primary"></span>
<h4>SRV</h4>
</div>
<div class="col-sm-3"> <div class="col-sm-3">
<span class="fas fa-server logo-small"></span> <span class="fas fa-server logo-small"></span>
<h4>SRV</h4> <h4>SRV2012</h4>
Serveur HYPER-V
</div>
<div class="col-sm-3">
<span class="fas fa-hdd logo-primary"></span>
<h4>SRVTSE</h4>
Serveur Accès à Distance
</div>
<div class="col-sm-3">
<span class="fas fa-hdd logo-primary"></span>
<h4>SRVBD / DC</h4>
Serveur Base de données
</div>
<div class="col-sm-3">
<span class="far fa-hdd logo-primary"></span>
<h4>SECOURS</h4>
Serveur de secours
</div> </div>
</div> </div>
</div> </div>
<br /> <br />
<h3 class="text-center">SERVEUR LINUX</h3>
<div id="jquery" class="container-fluid">
<div class="row text-center">
<div class="col-sm-12">
<span class="fas fa-hdd logo-small"></span>
<h4>SRVWEB</h4>
</div>
</div>
</div>
<br />
<h3 class="text-center">CONNECTION INTERNET</h3>
<div id="jquery" class="container-fluid">
<div class="row text-center">
<div class="col-sm-12">
<span class="fas fa-globe logo-primary"></span>
</div>
</div>
<br />
<div class="row text-center">
<div class="col-sm-3">
<h4>Routeur SFR Fibre 10 Mbps</h4>
</div>
<div class="col-sm-3">
<span class="far fa-hdd logo-small"></span>
</div>
<div class="col-sm-3">
<span class="far fa-hdd logo-small"></span>
</div>
<div class="col-sm-3">
<h4>Router ORANGE ADSL2</h4>
</div>
</div>
<br />
<div class="row text-center">
<div class="col-sm-12">
<span class="far fa-hdd logo-small"></span>
</div>
</div>
<br />
<br />
<div class="row text-center">
<div class="col-sm-3">
<span class="fas fa-server logo-primary"></span>
<h4>Serveurs</h4>
</div>
<div class="col-sm-3">
<span class="fas fa-desktop logo-primary"></span>
<h4>Ordinateurs</h4>
</div>
<div class="col-sm-3">
<span class="fas fa-print logo-primary"></span>
<h4>Imprimantes</h4>
</div>
<div class="col-sm-3">
<span class="fas fa-wifi logo-primary"></span>
<h4>Bornes Wifi</h4>
</div>
</div>
</div>
<br /> <br />
</div><!-- content --> </div><!-- content -->

View File

@@ -83,7 +83,7 @@ def dossier_lookup(request):
# construire la liste # construire la liste
for item in chantiers: for item in chantiers:
d = ('%s-%s' % (societe, item.numero),item.date.strftime('%d-%m-%Y'), item.nomcli, item.chantier, to_euro(item.montant), d = ('%s-%s' % (societe, item.numero),item.date.strftime('%d-%m-%Y'), item.nomcli, item.chantier, to_euro(item.montant),
item.nosin, item.status) item.nosin, item.status, item.usermaj)
liste.append(d) liste.append(d)
if len(name) == 0 : if len(name) == 0 :
@@ -258,7 +258,10 @@ def dossier_edit(request):
if not dossier: if not dossier:
request.session.flash(u"Le dossier no %s est introuvable" % (nodossier), 'danger') request.session.flash(u"Le dossier no %s est introuvable" % (nodossier), 'danger')
return HTTPFound(location=request.route_url('dossier_lookup')) return HTTPFound(location=request.route_url('dossier_lookup'))
# lire table expert
experts = get_experts(request, dossier.CABINET, 0)
if 'form.submitted' in request.params: if 'form.submitted' in request.params:
new_values = {} new_values = {}
for param, db_value in dossier.items(): for param, db_value in dossier.items():
@@ -275,6 +278,7 @@ def dossier_edit(request):
'url': url, 'url': url,
'dossier': dossier, 'dossier': dossier,
'nodossier': nodossier, 'nodossier': nodossier,
'experts': experts,
} }
@view_config(route_name='upload_doc', renderer='../templates/dossier/upload_doc.pt', permission='view') @view_config(route_name='upload_doc', renderer='../templates/dossier/upload_doc.pt', permission='view')
@@ -533,7 +537,7 @@ def rdf_view(request):
# lire tous les photos attachées # lire tous les photos attachées
photos = get_photos(request, rapport.nochantier, norapport) photos = get_photos(request, rapport.nochantier, norapport)
if 'form.generate' in request.params: if 'form.generate' in request.params:
options = { options = {
'page-size': 'A4', 'page-size': 'A4',
'margin-top': '0.65in', 'margin-top': '0.65in',
@@ -550,7 +554,7 @@ def rdf_view(request):
dest = "mondumas/static/DEVFAC/DOCS_ATTACHES/PL/%s/%s" % (str(rapport.nochantier), filename) dest = "mondumas/static/DEVFAC/DOCS_ATTACHES/PL/%s/%s" % (str(rapport.nochantier), filename)
# developpement ou production # developpement ou production
if request.registry.settings["mail.host"] == "smtp.orange.fr": if request.registry.settings["mail.username"] == "sas.dumas@orange.fr":
origin = 'https://gestion.entreprise-dumas.com/rdf_rapport/%s' % norapport origin = 'https://gestion.entreprise-dumas.com/rdf_rapport/%s' % norapport
pdfkit.from_url(origin, dest, options=options) pdfkit.from_url(origin, dest, options=options)
else: else:
@@ -683,229 +687,248 @@ def rdf_bill(request):
@view_config(route_name='demandes', renderer='../templates/dossier/demandes.pt', permission='view') @view_config(route_name='demandes', renderer='../templates/dossier/demandes.pt', permission='view')
def demandes(request): def demandes(request):
logged_in = request.authenticated_userid.upper()
url = request.route_url('demandes')
societes = ['PE','ME','PL'] def mailbox_connect(societe):
societe = 'PE' # connecter au serveur IMAP de la societe
# prendre en compte les paramètres de saisie if societe == 'PE':
if 'societe' in request.params: mbx_name = 'peinture-dumas@entreprise-dumas.com'
societe = request.params["societe"] mbx_pwd = 'sasdumas'
elif societe == 'ME':
# sélection du mailbox selon la societe mbx_name = 'menuiserie-dumas@entreprise-dumas.com'
if societe == 'PE': mbx_pwd = 'sasdumas'
mbx_name = 'peinture-dumas@entreprise-dumas.com' elif societe == 'PL':
mbx_pwd = 'sasdumas' mbx_name = 'versanit-dumas@entreprise-dumas.com'
elif societe == 'ME': mbx_pwd = 'sasdumas'
mbx_name = 'menuiserie-dumas@entreprise-dumas.com' else:
mbx_pwd = 'sasdumas' request.session.flash("Cette société est inconnue ou non traitée : %s" % societe, 'danger')
elif societe == 'PL':
mbx_name = 'versanit-dumas@entreprise-dumas.com'
mbx_pwd = 'sasdumas'
else:
mbx_name = 'polynet-dumas@entreprise-dumas.com'
mbx_pwd = 'sasdumas'
# lire les demandes d'interventions arrivées par email
mbx_search1 = 'FROM gestionsinistre@maif.fr SUBJECT "Missionnement r"'
mbx_search2 = 'FROM service.sinistres@domus-services.fr SUBJECT "Ordre de mission DOMUS - Dossier"'
conn = imaplib.IMAP4_SSL('imap.entreprise-dumas.com')
try:
# se connecter à la mailbox
conn.login(mbx_name, mbx_pwd)
except imaplib.IMAP4.error:
request.session.flash("ERREUR connexion au compte %s" % mbx_name, 'danger')
return HTTPFound(location=request.route_url('home'))
# lire le INBOX
rv, data = conn.select('INBOX', readonly =True)
# if 'form.submitted' in request.params:
# traiter les demandes de la MAIF puis de DOMUS
# demandes_generer(request, conn, societe, mbx_search1)
# demandes_generer(request, conn, societe, mbx_search2)
liste=[]
# lire les demandes de la MAIF puis de DOMUS
demandes_afficher(conn, mbx_name, mbx_search1, liste)
demandes_afficher(conn, mbx_name, mbx_search2, liste)
# messages lus
msglus = bool(liste)
conn.logout()
return {
'page_title': 'Liste des demandes pour la société ' + societe,
'url': url,
'societe': societe,
'societes': societes,
'dt_data': json.dumps(liste),
'msglus': msglus,
}
def demandes_afficher(conn, mbx_name, search_criteria, liste):
# créer la liste des entêtes des messages à afficher
rv, data = conn.search(None, search_criteria)
if rv != 'OK':
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger')
return HTTPFound(location=request.route_url('home'))
mail_ids = data[0]
for num in mail_ids.split():
rv, msg_data = conn.fetch(num, '(RFC822)')
if rv != 'OK':
request.session.flash("ERREUR de lecture du message %s" % num, 'danger')
return HTTPFound(location=request.route_url('home')) return HTTPFound(location=request.route_url('home'))
msg = email.message_from_bytes(msg_data[0][1]) conn = imaplib.IMAP4_SSL('imap.entreprise-dumas.com')
hdr = email.header.make_header(email.header.decode_header(msg['Subject'])) try:
email_subject = str(hdr) # se connecter à la mailbox
email_from = email.utils.parseaddr(msg['from'])[1] conn.login(mbx_name, mbx_pwd)
# Now convert to local date-time except imaplib.IMAP4.error:
date_tuple = email.utils.parsedate_tz(msg['Date']) request.session.flash("ERREUR connexion au compte %s" % mbx_name, 'danger')
if date_tuple: return HTTPFound(location=request.route_url('home'))
email_date = datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
else:
email_date = datetime.now()
d = (str(int(num)), email_date.strftime('%d-%m-%Y %H:%M:%S'), email_from, mbx_name.replace('entreprise-dumas.com', ''), email_subject)
liste.append(d)
return liste
def demandes_generer(request, conn, societe, mbx_search):
def generer_mission(request, societe, mbx_search, extracted_file, temp_file_path):
if 'maif.fr' in mbx_search: return conn
def demandes_lister(societe, search_criteria):
# connecter au serveur de mail
conn = mailbox_connect(societe)
# select INBOX
rv, data = conn.select('INBOX', readonly =True)
# créer la liste des entêtes des messages à afficher
liste = []
for criteria in search_criteria:
rv, data = conn.search(None, criteria)
if rv != 'OK':
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger')
return HTTPFound(location=request.route_url('home'))
mail_ids = data[0]
for num in mail_ids.split():
rv, msg_data = conn.fetch(num, '(RFC822)')
if rv != 'OK':
request.session.flash("ERREUR de lecture du message %s" % num, 'danger')
return HTTPFound(location=request.route_url('home'))
msg = email.message_from_bytes(msg_data[0][1])
hdr = email.header.make_header(email.header.decode_header(msg['Subject']))
email_subject = str(hdr)
email_from = email.utils.parseaddr(msg['from'])[1]
# Now convert to local date-time
date_tuple = email.utils.parsedate_tz(msg['Date'])
if date_tuple:
email_date = datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
else:
email_date = datetime.now()
d = (societe, email_date.strftime('%d-%m-%Y %H:%M:%S'), email_from, email_subject)
liste.append(d)
# deconnexion du serveur
conn.close()
conn.logout()
return liste
def demandes_generer(request, societe, search_criteria):
def generer_mission(request, societe, mbx_search, extracted_file, temp_file_path):
if 'maif.fr' in mbx_search:
# extraire les infos de la demmande MAIF
dem_info = get_pdf_infos1(extracted_file)
if societe == 'PE':
cd_cli = 2813
elif societe == 'ME':
cd_cli = 3428
else:
# VERSANIT
cd_cli = 1743
elif 'domus-services.fr' in mbx_search:
# extraire les infos de la demmande DOMUS
dem_info = get_pdf_infos2(extracted_file)
if societe == 'PE':
cd_cli = 8991
elif societe == 'ME':
cd_cli = 5276
else:
# VERSANIT
cd_cli = 3209
# extraction OK ? oui, créer une dem_devis et récupèrer son no_id
if dem_info['c_nom'] != '':
nochantier = insert_dossier(request, societe, cd_cli, dem_info['c_nom'], dem_info['c_adr'], dem_info['c_adr2'], \
dem_info['c_cp'], dem_info['c_ville'], dem_info['c_telp'], dem_info['no_sinistre'], dem_info['c_obs'], dem_info['tx_trav'])
nodossier = "%s-%s" % (societe, nochantier)
# récupère le nom du fichier et ajouter le no de dossier
filename = os.path.basename(temp_file_path)
filename = '%s-DD%s-%s' % (societe, nochantier, filename)
tempFile2Dossier(request, societe, nochantier, '0', temp_file_path, filename, 'EMAIL')
return
def generer_annul_maif(request, societe, extracted_file, temp_file_path):
# extraire les infos de la demmande MAIF # extraire les infos de la demmande MAIF
dem_info = get_pdf_infos1(extracted_file) dem_info = get_pdf_infos1(extracted_file)
if societe == 'PE': # extraction OK ? oui, rechercher la dem_devis concerné
cd_cli = 2813
elif societe == 'ME':
cd_cli = 3428
else:
# VERSANIT
cd_cli = 1743
elif 'domus-services.fr' in mbx_search:
# extraire les infos de la demmande DOMUS
dem_info = get_pdf_infos2(extracted_file)
if societe == 'PE':
cd_cli = 8991
elif societe == 'ME':
cd_cli = 5276
else:
# VERSANIT
cd_cli = 3209
# extraction OK ? oui, créer une dem_devis et récupèrer son no_id
if dem_info['c_nom'] != '':
nochantier = insert_dossier(request, societe, cd_cli, dem_info['c_nom'], dem_info['c_adr'], dem_info['c_adr2'], \
dem_info['c_cp'], dem_info['c_ville'], dem_info['c_telp'], dem_info['no_sinistre'], dem_info['c_obs'], dem_info['tx_trav'])
nodossier = "%s-%s" % (societe, nochantier)
# récupère le nom du fichier et ajouter le no de dossier # import pdb;pdb.set_trace()
filename = os.path.basename(temp_file_path) if dem_info['c_nom'] != '':
filename = '%s-DD%s-%s' % (societe, nochantier, filename) # oui, rechercher la dem_devis concerné par le no de sinistre
tempFile2Dossier(request, societe, nochantier, '0', temp_file_path, filename, 'AUTO') nosin = dem_info['no_sinistre']
dem_devis = get_dossier_by_sinistre(request,societe, nosin)
return if dem_devis:
nodossier = "%s-%s" % (societe, dem_devis.NO_ID)
# récupère le nom du fichier et ajouter le no de dossier
filename = '%s-DD%s-%s' % (societe, dem_devis.NO_ID, 'ANNULATION.pdf')
tempFile2Dossier(request, societe, dem_devis.NO_ID, '0', temp_file_path, filename, 'EMAIL')
# insérer une ligne de suivi ANNULATION
insert_suivi(request, nodossier, '!!MISSION ANNULEE PAR la MAIF')
return
def generer_annulation1(request, societe, extracted_file, temp_file_path): def generer_annul_domus(request, societe, nosin, temp_file_path):
# import pdb;pdb.set_trace()
# extraire les infos de la demmande MAIF
dem_info = get_pdf_infos1(extracted_file)
# extraction OK ? oui, rechercher la dem_devis concerné
if dem_info['c_nom'] != '':
# oui, rechercher la dem_devis concerné par le no de sinistre # oui, rechercher la dem_devis concerné par le no de sinistre
dem_devis = get_dossier_by_sinistre(request,societe, nosin) dem_devis = get_dossier_by_sinistre(request,societe, nosin)
nodossier = "%s-%s" % (societe, dem_devis.NO_ID) if dem_devis:
nodossier = "%s-%s" % (societe, dem_devis.NO_ID)
# récupère le nom du fichier et ajouter le no de dossier
filename = '%s-DD%s-%s' % (societe, dem_devis.NO_ID, 'ANNULATION.pdf')
tempFile2Dossier(request, societe, dem_devis.NO_ID, '0', temp_file_path, filename, 'EMAIL')
# insérer une ligne de suivi ANNULATION
insert_suivi(request, nodossier, '!!MISSION ANNULEE PAR DOMUS')
return
# connecter au serveur de mail
conn = mailbox_connect(societe)
# select INBOX
rv, data = conn.select('INBOX', readonly =True)
for criteria in search_criteria:
# rechercher les emails de demandes dans le INBOX
rv, data = conn.search(None, criteria)
if rv != 'OK':
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger')
return HTTPFound(location=request.route_url('home'))
# récupère le nom du fichier et ajouter le no de dossier mail_ids = data[0]
filename = '%s-DD%s-%s' % (societe, dem_devis.NO_ID, 'ANNULATION.pdf') nbMessages = len(mail_ids)
tempFile2Dossier(request, societe, dem_devis.NO_ID, '0', temp_file_path, filename, 'AUTO') for num in mail_ids.split():
# insérer une ligne de suivi ANNULATION rv, msg_data = conn.fetch(num, '(RFC822)')
insert_suivi(request, nodossier, '!!MISSION ANNULEE PAR la MAIF') if rv != 'OK':
return request.session.flash("ERREUR de lecture du message %s" % num, 'danger')
return HTTPFound(location=request.route_url('home'))
def generer_annulation2(request, societe, nosin, temp_file_path):
raw_email = msg_data[0][1]
# converts byte literal to string removing b''
raw_email_string = raw_email.decode('utf-8')
email_message = email.message_from_string(raw_email_string)
# oui, rechercher la dem_devis concerné par le no de sinistre # get the message's body
dem_devis = get_dossier_by_sinistre(request,societe, nosin) body = ''
nodossier = "%s-%s" % (societe, dem_devis.NO_ID) for part in email_message.walk():
ctype = part.get_content_type()
cdispo = str(part.get('Content-Disposition'))
# skip any text/plain (txt) attachments
if ctype == 'text/html' and 'attachment' not in cdispo:
body = part.get_payload(decode=True) # decode
break
# downloading attachment
temp_file_path = download_pdf_to_tmp(email_message)
# récupère le nom du fichier et ajouter le no de dossier # convertir le fichier pdf en texte
filename = '%s-DD%s-%s' % (societe, dem_devis.NO_ID, 'ANNULATION.pdf') texte, extracted_file = pdf_convert_to_txt(temp_file_path)
tempFile2Dossier(request, societe, dem_devis.NO_ID, '0', temp_file_path, filename, 'AUTO')
# insérer une ligne de suivi ANNULATION # mission annulée ?
insert_suivi(request, nodossier, '!!MISSION ANNULEE PAR DOMUS') if 'Objet : ANNULATION MISSION' in texte :
return # genere ANNULATION mission MAIF
# import pdb;pdb.set_trace()
# rechercher les emails de demandes dans le INBOX generer_annul_maif(request, societe, extracted_file, temp_file_path)
rv, data = conn.search(None, mbx_search) # conn.store(num, '+FLAGS', r'(\Deleted)')
if rv != 'OK': elif 'ANNULATION ORDRE DE MISSION' in texte:
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger') # genere ANNULATION mission DOMUS
return HTTPFound(location=request.route_url('home')) nosin = str(body)[84:95]
# import pdb;pdb.set_trace()
mail_ids = data[0] generer_annul_domus(request, societe, nosin, temp_file_path)
for num in mail_ids.split(): # conn.store(num, '+FLAGS', r'(\Deleted)')
rv, msg_data = conn.fetch(num, '(RFC822)') else:
if rv != 'OK': # genere le dossier d'après le mail
request.session.flash("ERREUR de lecture du message %s" % num, 'danger') # import pdb;pdb.set_trace()
return HTTPFound(location=request.route_url('home')) generer_mission(request, societe, criteria, extracted_file, temp_file_path)
# marquer le message comme supprimé
# conn.store(num, '+FLAGS', r'(\Deleted)')
raw_email = msg_data[0][1] conn.expunge()
# converts byte literal to string removing b'' conn.close()
raw_email_string = raw_email.decode('utf-8') # deconnexion du serveur
email_message = email.message_from_string(raw_email_string) conn.logout()
# get the message's body
body = ''
for part in email_message.walk():
ctype = part.get_content_type()
cdispo = str(part.get('Content-Disposition'))
# skip any text/plain (txt) attachments
if ctype == 'text/html' and 'attachment' not in cdispo:
body = part.get_payload(decode=True) # decode
break
# downloading attachment
temp_file_path = download_pdf_to_tmp(email_message)
# convertir le fichier pdf en texte
texte, extracted_file = pdf_convert_to_txt(temp_file_path)
# mission annulée ? return nbMessages
if 'Objet : ANNULATION MISSION' in texte :
# genere ANNULATION mission MAIF
generer_annulation1(request, societe, extracted_file, temp_file_path)
elif 'ANNULATION ORDRE DE MISSION' in texte:
# genere ANNULATION mission DOMUS
nosin = str(body)[84:95]
generer_annulation2(request, societe, nosin, temp_file_path)
else:
# genere le dossier d'après le mail
generer_mission(request, societe, mbx_search, extracted_file, temp_file_path)
return
def resize_photos(image_file): # ------- main -------
# using the Python Image Library (PIL) to resize an image logged_in = request.authenticated_userid.upper()
img_org = Image.open(image_file) url = request.route_url('demandes')
# get the size of the original image message = ''
width_org, height_org = img_org.size
# set the resizing factor so the aspect ratio can be retained societes = ['PE','ME','PL']
# factor > 1.0 increases size
# factor < 1.0 decreases size # critères de recherche des demandes d'interventions de la MAIF
factor = 1 # search_criteria = ['FROM service.sinistres@domus-services.fr SUBJECT "Ordre de mission DOMUS - Dossier"']
width = int(width_org * factor) search_criteria = ['FROM gestionsinistre@maif.fr SUBJECT "Intervention entreprise partenaire"',
height = int(height_org * factor) 'FROM service.sinistres@domus-services.fr SUBJECT "Ordre de mission DOMUS - Dossier"']
# best down-sizing filter
img_anti = img_org.resize((width, height), Image.ANTIALIAS) if 'form.submitted' in request.params:
# split image filename into name and extension # traiter les demandes de la MAIF puis de DOMUS pour toutes les sociétes
name, ext = os.path.splitext(image_file) nbMessages = 0
# create a new file name for saving the result for societe in societes:
img_anti.save(image_file) nb = demandes_generer(request, societe, search_criteria)
nbMessages = nbMessages + nb
message = "%s demandes de devis a été crées." % nbMessages
liste=[]
# lister les demandes par societe
for societe in societes:
liste = liste + demandes_lister(societe, search_criteria)
# messages lus
msglus = bool(liste)
return {
'page_title': "Liste des emails de demandes d'intervention",
'url': url,
'dt_data': json.dumps(liste),
'msglus': msglus,
'message': message,
}
return
def downloadFile2Temp(input_file, input_name, ext_allowed): def downloadFile2Temp(input_file, input_name, ext_allowed):
# récupère son extension # récupère son extension
@@ -999,7 +1022,7 @@ def pdf_convert_to_txt(path):
fh.close() fh.close()
# ecrire le texte dans un fichier # ecrire le texte dans un fichier
extracted_file = '/tmp/log_file.txt' extracted_file = '/tmp/log_file.txt'
with open(extracted_file, "w") as my_log: with open(extracted_file, "w", encoding="utf-8") as my_log:
my_log.write(extracted_text) my_log.write(extracted_text)
my_log.close() my_log.close()
@@ -1008,11 +1031,11 @@ def pdf_convert_to_txt(path):
def get_pdf_infos1(extracted_file): def get_pdf_infos1(extracted_file):
# à partir du fichier texte du pdf # à partir du fichier texte du pdf
# parcourir les lignes pour retrouver les infos utiles # parcourir les lignes pour retrouver les infos utiles
with open(extracted_file) as fp: with open(extracted_file, encoding="utf-8") as fp:
cnt = 1 cnt = 1
line = fp.readline() line = fp.readline()
# première ligne doit être "MAIF" # première ligne doit être "MAIF"
if line[:-1] != 'MAIF': if line[:-1] not in ['MAIF', 'FILIA-MAIF']:
return {'c_nom': ''} return {'c_nom': ''}
c_obs = '' c_obs = ''
@@ -1074,7 +1097,7 @@ def get_pdf_infos1(extracted_file):
def get_pdf_infos2(extracted_file): def get_pdf_infos2(extracted_file):
# à partir du fichier texte du pdf de DOMUS # à partir du fichier texte du pdf de DOMUS
# parcourir les lignes pour retrouver les infos utiles # parcourir les lignes pour retrouver les infos utiles
with open(extracted_file) as fp: with open(extracted_file, encoding="utf-8") as fp:
cnt = 1 cnt = 1
line = fp.readline() line = fp.readline()
# première ligne doit être : # première ligne doit être :
@@ -1130,6 +1153,23 @@ def get_pdf_infos2(extracted_file):
'no_sinistre': no_sinistre, 'no_sinistre': no_sinistre,
} }
def resize_photos(image_file):
# using the Python Image Library (PIL) to resize an image
img_org = Image.open(image_file)
# get the size of the original image
width_org, height_org = img_org.size
# set the resizing factor so the aspect ratio can be retained
# factor > 1.0 increases size
# factor < 1.0 decreases size
factor = 1
width = int(width_org * factor)
height = int(height_org * factor)
# best down-sizing filter
img_anti = img_org.resize((width, height), Image.ANTIALIAS)
# split image filename into name and extension
name, ext = os.path.splitext(image_file)
# create a new file name for saving the result
img_anti.save(image_file)
return

View File

@@ -20,7 +20,7 @@ pyramid.includes =
sqlalchemy.url = mysql://root:cni/@srvbd/bddevfac?charset=utf8 sqlalchemy.url = mysql://root:cni/@srvbd/bddevfac?charset=utf8
sqlalchemy.pool_recycle = 3600 sqlalchemy.pool_recycle = 3600
mondumas.admin_email = phuoc@caotek.fr mondumas.admin_email = sas.dumas@orange.fr
mondumas.devfac_url = mondumas:static/DEVFAC/ mondumas.devfac_url = mondumas:static/DEVFAC/
mondumas.devfac_dir = /DEVFAC14/DOCS_ATTACHES mondumas.devfac_dir = /DEVFAC14/DOCS_ATTACHES