diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py index a511f5b..9919aca 100644 --- a/source/app/controllers/main.py +++ b/source/app/controllers/main.py @@ -486,7 +486,14 @@ class AppNomina(object): def on_get(self, req, resp): values = req.params + by = values.get('by', '') req.context['result'] = self._db.get_nomina(values) + if 'download' in by: + name = req.context['result']['name'] + req.context['blob'] = req.context['result']['data'] + resp.content_type = 'application/octet-stream' + resp.append_header( + 'Content-Disposition', f'attachment; filename={name}') resp.status = falcon.HTTP_200 def on_post(self, req, resp): diff --git a/source/app/controllers/utils.py b/source/app/controllers/utils.py index 1a15abe..b15b119 100644 --- a/source/app/controllers/utils.py +++ b/source/app/controllers/utils.py @@ -21,6 +21,7 @@ import collections import datetime import math import smtplib +import zipfile from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase @@ -281,3 +282,14 @@ def parse_date(value, next_day=False): if next_day: return d + datetime.timedelta(days=1) return d + + +def to_zip(*files): + zip_buffer = BytesIO() + + with zipfile.ZipFile(zip_buffer, 'a', zipfile.ZIP_DEFLATED, False) as zip_file: + for data, file_name in files: + zip_file.writestr(file_name, data) + + return zip_buffer.getvalue() + diff --git a/source/app/middleware.py b/source/app/middleware.py index 9c873c1..24da94a 100644 --- a/source/app/middleware.py +++ b/source/app/middleware.py @@ -65,9 +65,15 @@ class JSONTranslator(object): def process_response(self, req, resp, resource): if 'result' not in req.context: return + if '/doc/' in req.path: resp.body = req.context['result'] return + + if 'blob' in req.context: + resp.body = req.context['blob'] + return + resp.body = util.dumps(req.context['result']) diff --git a/source/app/models/main.py b/source/app/models/main.py index b54bfa5..55099cd 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -8341,11 +8341,34 @@ class CfdiNomina(BaseModel): return {'ok': ok, 'msg_ok': msg, 'error': error, 'msg_error': msg_error} + def _get_by_download(self, filters): + emisor = Emisor.select()[0] + ids = util.loads(filters['ids']) + w = CfdiNomina.id.in_(ids) + rows = CfdiNomina.select().where(w) + + files = [] + for row in rows: + name = '{}{}_{}.'.format(row.serie, row.folio, row.empleado.rfc) + files.append((row.xml, name + 'xml')) + + values = self._get_not_in_xml(self, row, emisor) + data = util.get_data_from_xml(row, values) + doc = util.to_pdf(data, emisor.rfc) + files.append((doc, name + 'pdf')) + + fz = utils.to_zip(*files) + + return {'data': fz, 'name': name + 'zip'} + @classmethod def get_by(cls, values): if not values: return cls._get(cls) + if values.get('by', ''): + return getattr(cls, f"_get_by_{values['by']}")(cls, values) + if values['opt'] == 'dates': dates = util.loads(values['range']) filters = CfdiNomina.fecha.between( diff --git a/source/static/js/controller/nomina.js b/source/static/js/controller/nomina.js index 98b7244..fc74676 100644 --- a/source/static/js/controller/nomina.js +++ b/source/static/js/controller/nomina.js @@ -13,6 +13,7 @@ var nomina_controllers = { $$('cmd_nomina_delete').attachEvent('onItemClick', cmd_nomina_delete_click) $$('cmd_nomina_timbrar').attachEvent('onItemClick', cmd_nomina_timbrar_click) $$('cmd_nomina_log').attachEvent('onItemClick', cmd_nomina_log_click) + $$('cmd_nomina_download').attachEvent('onItemClick', cmd_nomina_download_click) $$('cmd_nomina_cancel').attachEvent('onItemClick', cmd_nomina_cancel_click) $$('grid_nomina').attachEvent('onItemClick', grid_nomina_click) $$('filter_year_nomina').attachEvent('onChange', filter_year_nomina_change) @@ -490,4 +491,29 @@ function cancel_nomina(id){ function cmd_nomina_log_click(){ location = '/doc/nomlog/0' -} \ No newline at end of file +} + + +function cmd_nomina_download_click(){ + var grid = $$('grid_nomina') + + if(!grid.count()){ + msg = 'Sin documentos a descargar' + msg_error(msg) + return + } + + var ids = [] + grid.eachRow(function(row){ + var r = grid.getItem(row) + ids.push(r.id) + }) + + var filters = {'by': 'download', 'ids': ids} + + webix.ajax().response('blob').get('/nomina', filters, function(text, data){ + webix.html.download(data, 'nomina.zip'); + }); + +} + diff --git a/source/static/js/ui/nomina.js b/source/static/js/ui/nomina.js index 69dcc65..5a84e74 100644 --- a/source/static/js/ui/nomina.js +++ b/source/static/js/ui/nomina.js @@ -20,6 +20,8 @@ var toolbar_nomina_util = [ type: 'iconButton', autowidth: true, icon: 'check-circle'}, {view: 'button', id: 'cmd_nomina_log', label: 'Log', type: 'iconButton', autowidth: true, icon: 'download'}, + {view: 'button', id: 'cmd_nomina_download', label: 'Descargar', + type: 'iconButton', autowidth: true, icon: 'download'}, {}, {view: 'button', id: 'cmd_nomina_cancel', label: 'Cancelar', type: 'iconButton', autowidth: true, icon: 'ban'},