fusion devis et facture dans un chantier

This commit is contained in:
2024-03-25 10:57:22 +01:00
parent 58371d3b84
commit 86889f33ce
9 changed files with 179 additions and 115 deletions

View File

@@ -2,57 +2,55 @@ Metadata-Version: 2.1
Name: mondumas Name: mondumas
Version: 1.0 Version: 1.0
Summary: mondumas Summary: mondumas
Home-page: UNKNOWN Home-page:
Author: Author:
Author-email: Author-email:
License: UNKNOWN
Description: # README #
Cette application web permet aux collaborateurs de l'entreprise Dumas :
- de consulter et de gérer les dossiers des clients depuis leur tablette
- de créer un rapport de fuite et le faire signer par le client
Elle est développée avec les composants open source suivants :
## Backend
- [Python](https://www.python.org/downloads/) 3.7
- [Pyramid web framework](https://trypyramid.com/) 1.10
- [MySQL server](https://mysql.com/) 5.7 sur Windows Server 2008 R2 Standard
- [Apache web server](https://apache.org/) 2.4 sur Debian GNU/Linux 9 (stretch)
## Frontend
- [Bootstrap framework](https://getbootstrap.com/) for CSS 3.3.7
- [Jquery](https://jquery.com/download/) for JavaScript 3.2.1
- Chameleon templates
- [FormValidation](https://formvalidation.io/) form validator 0.7.0
## Jquery Plugins
- [DataTables](https://datatables.net/) 1.10.20
- [Fullcalendar](https://fullcalendar.io/) 3.9.0
- [fullcalendar Scheduler](https://fullcalendar.io/) 1.9.4
- [Jquery-ui et jquery-ui-themes](https://jqueryui.com/) 1.12.1
- [jSignature](https://willowsystems.github.io/jSignature)
- [less.js](http://lesscss.org/) 3.11.1
- [moment.js](https://momentjs.com/) with-locales.min.js
[Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
0.0
---
- Initial version
Keywords: web wsgi bfg pylons pyramid Keywords: web wsgi bfg pylons pyramid
Platform: UNKNOWN
Classifier: Programming Language :: Python Classifier: Programming Language :: Python
Classifier: Framework :: Pyramid Classifier: Framework :: Pyramid
Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
Provides-Extra: testing Provides-Extra: testing
# README #
Cette application web permet aux collaborateurs de l'entreprise Dumas :
- de consulter et de gérer les dossiers des clients depuis leur tablette
- de créer un rapport de fuite et le faire signer par le client
Elle est développée avec les composants open source suivants :
## Backend
- [Python](https://www.python.org/downloads/) 3.7
- [Pyramid web framework](https://trypyramid.com/) 1.10
- [MySQL server](https://mysql.com/) 5.7 sur Windows Server 2008 R2 Standard
- [Apache web server](https://apache.org/) 2.4 sur Debian GNU/Linux 9 (stretch)
## Frontend
- [Bootstrap framework](https://getbootstrap.com/) for CSS 3.3.7
- [Jquery](https://jquery.com/download/) for JavaScript 3.2.1
- Chameleon templates
- [FormValidation](https://formvalidation.io/) form validator 0.7.0
## Jquery Plugins
- [DataTables](https://datatables.net/) 1.10.20
- [Fullcalendar](https://fullcalendar.io/) 3.9.0
- [fullcalendar Scheduler](https://fullcalendar.io/) 1.9.4
- [Jquery-ui et jquery-ui-themes](https://jqueryui.com/) 1.12.1
- [jSignature](https://willowsystems.github.io/jSignature)
- [less.js](http://lesscss.org/) 3.11.1
- [moment.js](https://momentjs.com/) with-locales.min.js
[Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
0.0
---
- Initial version

View File

@@ -1,4 +1,2 @@
[paste.app_factory] [paste.app_factory]
main = mondumas:main main = mondumas:main
[console_scripts]

View File

@@ -8,7 +8,7 @@ SQLAlchemy==1.2.19
transaction transaction
zope.sqlalchemy==1.1 zope.sqlalchemy==1.1
waitress waitress
mysqlclient==2.1 mysqlclient==1.4
docutils docutils
pdfkit pdfkit
python-dateutil python-dateutil

View File

@@ -25,19 +25,23 @@ def execute_query(request, query, params):
mark_changed(request.dbsession) mark_changed(request.dbsession)
transaction.commit() transaction.commit()
def get_devis_byName(request, societe, name):
numero = to_int(name) def get_dossiers_byName(request, societe, name):
# lires tous les dossiers d'un chantier
if numero > 0: query = """select * from (
query = """SELECT date,'DE' AS TYPE, LPAD(no_id,6,'0') AS numero, nomcli, CONCAT(c_nom,'; ',c_adr,'; ',c_ville) AS chantier, COALESCE(totalht,0) AS montant, status, nosin, nopol, nochantier, web SELECT date,'DD' AS TYPE, LPAD(no_id,6,'0') AS numero, nomcli, CONCAT(c_nom,'; ',c_adr,'; ',c_ville) AS chantier, 0 AS montant, status, nosin, societe , no_id as nochantier
FROM devis WHERE societe=:societe AND no_id >=:name AND web = 'W' LIMIT 300;;""" % (societe, name) FROM dem_devis WHERE societe=:societe AND c_nom LIKE :name
elif len(name) == 0: UNION
query = """SELECT date,'DE' AS TYPE, LPAD(no_id,6,'0') AS numero, nomcli, CONCAT(c_nom,'; ',c_adr,'; ',c_ville) AS chantier, COALESCE(totalht,0) AS montant, status, nosin, nopol, nochantier, web SELECT date,'DE' AS TYPE, LPAD(no_id,6,'0') AS numero, nomcli, CONCAT(c_nom,'; ',c_adr,'; ',c_ville) AS chantier, COALESCE(totalht,0) AS montant, status, nosin, societe , nochantier
FROM devis WHERE societe=:societe AND web = 'W' ORDER BY no_id DESC LIMIT 300;""" FROM devis WHERE societe=:societe AND c_nom LIKE :name
else: UNION
query = """(SELECT date,'DE' AS TYPE, LPAD(no_id,6,'0') AS numero, nomcli, CONCAT(c_nom,'; ',c_adr,'; ',c_ville) AS chantier, COALESCE(totalht,0) AS montant, status, nosin, nopol , nochantier, web SELECT date,'FA' AS TYPE, LPAD(no_id,6,'0') AS numero, nomcli, CONCAT(c_nom,'; ',c_adr,'; ',c_ville) AS chantier, COALESCE(totalht,0) AS montant, status, nosin, societe , nochantier
FROM devis WHERE societe=:societe AND c_nom LIKE ':name%' AND web = 'W' LIMIT 500)""" FROM facture WHERE societe=:societe AND c_nom LIKE :name
results = request.dbsession.execute(query, {'societe': societe, 'name': name}).fetchall() ) a
order by date, TYPE
"""
results = request.dbsession.execute(query, {'societe': societe, 'name': name+'%'}).fetchall()
return results return results
def get_devfac_by_no(request,nodossier): def get_devfac_by_no(request,nodossier):
@@ -235,3 +239,14 @@ def update_devis_cloture(request, nodevis, status, logged_in):
query = "UPDATE devis SET STATUS = :status, USERMAJ = :logged_in WHERE societe=:societe AND no_id=:nochantier;" query = "UPDATE devis SET STATUS = :status, USERMAJ = :logged_in WHERE societe=:societe AND no_id=:nochantier;"
execute_query(request, query, {'societe': societe, 'nochantier': nochantier, 'status': status, 'logged_in': logged_in}) execute_query(request, query, {'societe': societe, 'nochantier': nochantier, 'status': status, 'logged_in': logged_in})
def update_devis_nochantier(request, societe, no_devis, nochantier):
# extraire type de doc et no de doc à mettre à jour
type = no_devis[0:2]
no_id = no_devis[3:]
if type == 'DE':
# maj le numero du dossier du devis
query = "UPDATE devis SET nochantier = :nochantier WHERE societe=:societe AND no_id=:no_id;"
else:
# maj le numero du dossier de la facture
query = "UPDATE facture SET nochantier = :nochantier WHERE societe=:societe AND no_id=:no_id;"
execute_query(request, query, {'societe': societe, 'nochantier': nochantier, 'no_id': no_id})

View File

@@ -22,8 +22,9 @@ def includeme(config):
# devis # devis
config.add_route('devis_ligne', '/devis_ligne/{type_ligne}/{nodevis}/{nolig}') config.add_route('devis_ligne', '/devis_ligne/{type_ligne}/{nodevis}/{nolig}')
config.add_route('devis_lig_mv', '/devis_lig_mv/{move}/{nodevis}/{nolig}') config.add_route('devis_lig_mv', '/devis_lig_mv/{move}/{nodevis}/{nolig}')
config.add_route('devis_list', '/devis_list') config.add_route('devis_list', '/devis_list/{societe}/{nodevis}')
config.add_route('devis_create', '/devis_create/{nodossier}') config.add_route('devis_create', '/devis_create/{nodossier}')
config.add_route('devis_nochantier', '/devis_nochantier/{societe}/{nodevis}/{nochantier}')
config.add_route('devis_web', '/devis_web/{nodevis}') config.add_route('devis_web', '/devis_web/{nodevis}')
config.add_route('devis_view', '/devis_view/{nodevis}') config.add_route('devis_view', '/devis_view/{nodevis}')
config.add_route('devis_preview', '/devis_preview/{nodevis}') config.add_route('devis_preview', '/devis_preview/{nodevis}')

View File

@@ -133,11 +133,11 @@
</a> </a>
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
<a href="${request.application_url}/devis_list" tal:condition="logged_in == 'CAO'"> <a href="${request.application_url}/devis_list/PE/0" tal:condition="logged_in == 'CAO'">
<div class="info-box bg-prod"> <div class="info-box bg-prod">
<span class="info-box-icon"><i class="glyphicon glyphicon-text-height"></i></span> <span class="info-box-icon"><i class="glyphicon glyphicon-search"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-number">E-DEVIS</span> <span class="info-box-number">RECHERCHE DEVIS</span>
</div> </div>
</div> </div>
</a> </a>

View File

@@ -27,10 +27,9 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">Nom ou numéro du chantier</label> <label class="col-sm-4 control-label">Numéro du devis</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input type="text" class="form-control" name="name" value="${name}" <input type="text" class="form-control" name="nodevis" value="${nodevis}" >
placeholder="Le nom ou le numéro doit avoir de 2 à 30 caractères de long" >
</div> </div>
</div> </div>
@@ -53,19 +52,20 @@
<th>Client</th> <th>Client</th>
<th>Chantier</th> <th>Chantier</th>
<th class="text-right">Montant</th> <th class="text-right">Montant</th>
<th>Sinistre</th> <th>No chantier</th>
<th class="text-center">Statut</th> <th class="text-center">Action</th>
</tr> </tr>
<tr tal:repeat="detail devis"> <tr tal:repeat="detail dossiers">
<td> <td>${detail.TYPE}-${detail.numero}</td>
<a href="/devis_web/${societe}-DE${detail.numero}">${societe}-${detail.numero}-W</a>
</td>
<td>${detail.date.strftime('%d-%m-%Y')}</td> <td>${detail.date.strftime('%d-%m-%Y')}</td>
<td>${detail.nomcli}</td> <td>${detail.nomcli}</td>
<td>${detail.chantier}</td> <td>${detail.chantier}</td>
<td class="text-right">${layout.to_euro(detail.montant)}</td> <td class="text-right">${layout.to_euro(detail.montant)}</td>
<td>${detail.nosin}</td> <td>${detail.nochantier}</td>
<td class="text-center">${detail.status}</td> <td class="text-center">
<a tal:condition="detail.nochantier == 0" id="modalButton" href="#confirmCreate"
data-toggle="modal" data-societe="${detail.societe}" data-nodevis="${detail.TYPE}-${detail.numero}">Joindre</a>
</td>
</tr> </tr>
</thead> </thead>
@@ -74,26 +74,53 @@
<br /> <br />
</div> </div>
<!-- Modal : Confirmation CREATION -->
<div class="modal fade" id="confirmCreate" role="dialog" aria-labelledby="confirmCreateLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Ajouter le nochantier dans le </h4>
</div>
<div class="modal-body">
<!-- The form is placed inside the body of modal -->
<form id="add_justif-form" class="form-horizontal" action="${url}" method="post">
<div class="form-group">
<label class="control-label col-xs-4">Document No:</label>
<div class="col-xs-8">
<input type="text" name="md_nodevis" id="md_nodevis" value="" readonly/>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-4">Chantier No :</label>
<div class="col-xs-8">
<input type="text" name="md_nochantier" id="md_nochantier" value=""/>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-4">Société:</label>
<div class="col-xs-8">
<input type="text" name="md_societe" id="md_societe" value="" readonly/>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-success" name="form.joined">Ajouter</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $('#confirmCreate').on('show.bs.modal', function(e) {
$('#devis-search-form').formValidation({ var societe = $(e.relatedTarget).data('societe');
framework: 'bootstrap', var nodevis = $(e.relatedTarget).data('nodevis');
message: 'This value is not valid', $(e.currentTarget).find('input[name="md_societe"]').val(societe);
icon: { $(e.currentTarget).find('input[name="md_nodevis"]').val(nodevis);
valid: 'glyphicon glyphicon-ok', });
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
});
$('form input').on('keypress', function(e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
// simuler clic bouton submit
document.getElementById("submitButton").click();
}
});
</script> </script>
</div> </div>

View File

@@ -21,35 +21,49 @@ from ..models.devis import *
@view_config(route_name='devis_list', renderer='../templates/devis/devis_list.pt', permission='view') @view_config(route_name='devis_list', renderer='../templates/devis/devis_list.pt', permission='view')
def devis_list(request): def devis_list(request):
societe = request.matchdict['societe']
nodevis = request.matchdict['nodevis']
try:
int(nodevis)
except:
message = "Numero de Devis incorrect : %s" % societe + '-' + nodevis
url = request.route_url('devis_list')
logged_in = request.authenticated_userid.upper()
message = '' message = ''
member = get_member_by_id(request, logged_in) dossiers=None
societe_defaut = member.societe
societe = societe_defaut
access_defaut = member.access
liste=[]
name = ''
cb_tous = "non"
if 'form.submitted' in request.params: if 'form.submitted' in request.params:
name = request.params['name']
societe = request.params['societe'] societe = request.params['societe']
nodevis = request.params['nodevis']
# lire les devis
devis = get_devis_byName(request, societe, name) if 'form.joined' in request.params:
if len(devis) == 0: md_nochantier = request.params['md_nochantier']
message = "Devis non trouvé : %s" % name md_nodevis = request.params['md_nodevis']
md_societe = request.params['md_societe']
# modifier un devis à partir d'un dossier
update_devis_nochantier(request, md_societe, md_nodevis, md_nochantier)
message = "Le devis %s a été modifié avec succès : " % md_nodevis
url = request.route_url('devis_list', societe=societe, nodevis=nodevis)
if nodevis != '0':
# lire le devis
devis = get_devis_by_no(request, societe + '-DE' + nodevis)
if devis == None:
message = "Devis non trouvé : %s" % societe + '-' + nodevis
else:
# lire tous les dossiers du chantiers
dossiers = get_dossiers_byName(request, societe, devis.C_NOM)
return { return {
'page_title': "Rechercher un devis", 'page_title': "Rechercher un devis",
'url': url, 'url': url,
'message': message, 'message': message,
'devis': devis, 'dossiers': dossiers,
'societe': societe, 'societe': societe,
'name': name, 'nodevis': nodevis,
} }
@view_config(route_name='devis_create', permission='view') @view_config(route_name='devis_create', permission='view')
@@ -64,6 +78,17 @@ def devis_create(request):
request.session.flash(u"Le devis %s a été créé avec succès" % no_devis.last_insert_id, 'success') request.session.flash(u"Le devis %s a été créé avec succès" % no_devis.last_insert_id, 'success')
return HTTPFound(location=request.route_url("dossier_view", nodossier=nodossier) + '#tab_documents') return HTTPFound(location=request.route_url("dossier_view", nodossier=nodossier) + '#tab_documents')
@view_config(route_name='devis_nochantier', permission='view')
def devis_nochantier(request):
societe = request.matchdict['societe']
nodevis = request.matchdict['nodevis']
nochantier = request.matchdict['nochantier']
# modifier un devis à partir d'un dossier
update_devis_nochantier(request, societe, nodevis, nochantier)
request.session.flash(u"Le devis %s a été modifié avec succès : " + nodevis, 'success')
return HTTPFound(location=request.route_url("devis_list", societe=societe, nodevis=nodevis))
@view_config(route_name='devis_view', renderer='../templates/devis/devis_view.pt', permission='view') @view_config(route_name='devis_view', renderer='../templates/devis/devis_view.pt', permission='view')

View File

@@ -19,7 +19,7 @@ requires = [
'transaction', 'transaction',
'zope.sqlalchemy == 1.1', 'zope.sqlalchemy == 1.1',
'waitress', 'waitress',
'mysqlclient == 2.1', 'mysqlclient == 1.4',
'docutils', 'docutils',
'pdfkit', 'pdfkit',
'python-dateutil', 'python-dateutil',