From f761ab7a5a266862d93e7bb3b9eb3408e7c493c4 Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Mon, 4 Feb 2019 22:13:11 -0600 Subject: [PATCH] Mostrar cantidad de empaques en PDF --- CHANGELOG.md | 24 +++++++++++- requirements.txt | 1 + source/app/controllers/util.py | 27 +++++++++++-- source/app/controllers/utils.py | 13 +++---- source/app/models/main.py | 57 +++++++++++++++++++++------- source/static/js/controller/admin.js | 1 + 6 files changed, 96 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d17735f..4f06362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,28 @@ -v 1.28.0 [03-feb-2019] +v 1.28.0 [04-feb-2019] ---------------------- - Mejora: Manejo de empaques para mensajeria -* IMPORTANTE: Es necesario realizar una migración, despues de actualizar. +* IMPORTANTE: +Es necesario realizar una migración, despues de actualizar. + +``` +git pull origin master + +cd source/app/models + +python main.py -bk + +python main.py -m +``` + +Es necesario agregar un nuevo requerimiento. + +``` +sudo pip install cryptography +``` + +Si envias tus facturas por correo directamente, es necesario volver a capturar +la contraseña de tu servidor de correo y guardar los datos nuevamente. v 1.27.1 [23-ene-2019] diff --git a/requirements.txt b/requirements.txt index 35ebb91..21de129 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ pyqrcode pypng reportlab psycopg2-binary +cryptography diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index 3202ac7..b6d63b3 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -872,7 +872,7 @@ class LIBO(object): currency = self.CELL_STYLE.get(self._currency, 'peso') return '{}{}'.format(currency, match.groups()[1]) - def _conceptos(self, data): + def _conceptos(self, data, pakings): first = True col1 = [] col2 = [] @@ -881,8 +881,9 @@ class LIBO(object): col5 = [] col6 = [] col7 = [] + col8 = [] count = len(data) - 1 - for concepto in data: + for i, concepto in enumerate(data): key = concepto.get('noidentificacion', '') description = concepto['descripcion'] unidad = concepto['unidad'] @@ -899,6 +900,8 @@ class LIBO(object): cell_5 = self._set_cell('{valorunitario}', valor_unitario, value=True) cell_6 = self._set_cell('{importe}', importe, value=True) cell_7 = self._set_cell('{descuento}', descuento, value=True) + if pakings: + cell_8 = self._set_cell('{empaque}', pakings[i], value=True) if len(data) > 1: row = cell_1.getCellAddress().Row + 1 self._sheet.getRows().insertByIndex(row, count) @@ -912,6 +915,8 @@ class LIBO(object): col5.append((float(valor_unitario),)) col6.append((float(importe),)) col7.append((float(descuento),)) + if pakings: + col8.append((pakings[i],)) self._total_cantidades += float(cantidad) if not count: return @@ -919,6 +924,9 @@ class LIBO(object): style_5 = self._get_style(cell_5) style_6 = self._get_style(cell_6) style_7 = self._get_style(cell_7) + style_8 = '' + if pakings: + style_8 = self._get_style(cell_8) col = cell_1.getCellAddress().Column target1 = self._sheet.getCellRangeByPosition(col, row+1, col, row+count) @@ -933,9 +941,13 @@ class LIBO(object): col = cell_6.getCellAddress().Column target6 = self._sheet.getCellRangeByPosition(col, row+1, col, row+count) target7 = None + target8 = None if not cell_7 is None: col = cell_7.getCellAddress().Column target7 = self._sheet.getCellRangeByPosition(col, row+1, col, row+count) + if pakings: + col = cell_8.getCellAddress().Column + target8 = self._sheet.getCellRangeByPosition(col, row+1, col, row+count) target1.setFormulaArray(tuple(col1)) target2.setDataArray(tuple(col2)) @@ -945,6 +957,8 @@ class LIBO(object): target6.setDataArray(tuple(col6)) if not target7 is None: target7.setDataArray(tuple(col7)) + if not target8 is None: + target8.setDataArray(tuple(col8)) if style_5: cell_5.CellStyle = style_5 @@ -955,6 +969,9 @@ class LIBO(object): if style_7: cell_7.CellStyle = style_7 target7.CellStyle = style_7 + if style_8: + cell_8.CellStyle = style_8 + target8.CellStyle = style_8 return def _add_totales(self, data): @@ -1275,10 +1292,12 @@ class LIBO(object): self._currency = data['totales']['moneda'] self._pagos = data.pop('pagos', False) + pakings = data.pop('pakings', []) + self._comprobante(data['comprobante']) self._emisor(data['emisor']) self._receptor(data['receptor']) - self._conceptos(data['conceptos']) + self._conceptos(data['conceptos'], pakings) if self._pagos: self._cfdipays(data['pays']) @@ -2105,7 +2124,7 @@ def get_data_from_xml(invoice, values): data['pagos'] = values.get('pagos', False) if data['pagos']: data['pays'] = _cfdipays(doc, data, version) - + data['pakings'] = values.get('pakings', []) return data diff --git a/source/app/controllers/utils.py b/source/app/controllers/utils.py index 8f46c9f..5e2c779 100644 --- a/source/app/controllers/utils.py +++ b/source/app/controllers/utils.py @@ -18,12 +18,10 @@ import base64 import math -import os from cryptography.fernet import Fernet from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC def round_up(value): @@ -31,19 +29,18 @@ def round_up(value): def _get_key(password): - salt = os.urandom(16) - kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, - iterations=100000, backend=default_backend()) - key = base64.urlsafe_b64encode(kdf.derive(password.encode())) + digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) + digest.update(password.encode()) + key = base64.urlsafe_b64encode(digest.finalize()) return key -def encrypt(data, password) +def encrypt(data, password): f = Fernet(_get_key(password)) return f.encrypt(data.encode()).decode() -def decrypt(data, password) +def decrypt(data, password): f = Fernet(_get_key(password)) return f.decrypt(data.encode()).decode() diff --git a/source/app/models/main.py b/source/app/models/main.py index f8eb164..bd34878 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -351,6 +351,17 @@ class Configuracion(BaseModel): msg = 'No se pudo guardar la configuración' return {'ok': result, 'msg': msg} + def _save_mail(self, values): + rfc = Emisor.select()[0].rfc + values['correo_contra'] = utils.encrypt(values['correo_contra'], rfc) + + for k, v in values.items(): + obj, created = Configuracion.get_or_create(clave=k) + obj.valor = v + obj.save() + + return {'ok': True} + @classmethod def get_bool(cls, key): data = (Configuracion @@ -438,6 +449,17 @@ class Configuracion(BaseModel): values = {r.clave: util.get_bool(r.valor) for r in data} return values + def _get_correo(self): + fields = ('correo_servidor', 'correo_puerto', 'correo_ssl', + 'correo_usuario', 'correo_copia', 'correo_asunto', + 'correo_mensaje', 'correo_directo', 'correo_confirmacion') + data = (Configuracion + .select() + .where(Configuracion.clave.in_(fields)) + ) + values = {r.clave: r.valor for r in data} + return values + @classmethod def get_(cls, keys): if isinstance(keys, str): @@ -450,9 +472,12 @@ class Configuracion(BaseModel): return '' options = ('partners', - 'admin_products', 'main_products', + 'admin_products', + 'main_products', 'complements', - 'folios') + 'folios', + 'correo', + ) opt = keys['fields'] if opt in options: return getattr(cls, '_get_{}'.format(opt))(cls) @@ -513,16 +538,7 @@ class Configuracion(BaseModel): values[f] = Configuracion.get_(f) return values - if keys['fields'] == 'correo': - fields = ('correo_servidor', 'correo_puerto', 'correo_ssl', - 'correo_usuario', 'correo_contra', 'correo_copia', - 'correo_asunto', 'correo_mensaje', 'correo_directo', - 'correo_confirmacion') - data = (Configuracion - .select() - .where(Configuracion.clave.in_(fields)) - ) - elif keys['fields'] == 'path_cer': + if keys['fields'] == 'path_cer': fields = ('path_key', 'path_cer') data = (Configuracion .select() @@ -3720,6 +3736,8 @@ class Facturas(BaseModel): return {'ok': True, 'msg': 'Notas guardadas correctamente'} def _get_not_in_xml(self, invoice, emisor): + pdf_from = Configuracion.get_('make_pdf_from') or '1' + values = {} values['notas'] = invoice.notas @@ -3757,6 +3775,16 @@ class Facturas(BaseModel): for k, v in receptor.items(): values['receptor'][k] = v + use_packing = Configuracion.get_bool('chk_use_packing') + if use_packing: + w = FacturasDetalle.factura == invoice + q = (FacturasDetalle + .select(FacturasDetalle.empaques) + .where(w) + .order_by(FacturasDetalle.id.asc()) + .tuples()) + values['pakings'] = [str(int(r[0])) for r in q] + return values @classmethod @@ -4005,6 +4033,7 @@ class Facturas(BaseModel): @classmethod def send(cls, id, rfc): values = Configuracion.get_({'fields': 'correo'}) + contra = Configuracion.get_('correo_contra') in_zip = Configuracion.get_bool('chk_config_send_zip') if not values: @@ -4031,7 +4060,7 @@ class Facturas(BaseModel): 'puerto': values['correo_puerto'], 'ssl': bool(int(values['correo_ssl'])), 'usuario': values['correo_usuario'], - 'contra': values['correo_contra'], + 'contra': utils.decrypt(contra, rfc), } options = { 'para': obj.cliente.correo_facturas, @@ -8888,6 +8917,8 @@ def _migrate_tables(rfc=''): with database_proxy.atomic() as txn: migrate(*migrations) + Configuracion.add({'version': VERSION}) + log.info('Tablas migradas correctamente...') _importar_valores('', rfc) diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index 37ecb00..af868bc 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -817,6 +817,7 @@ function cmd_probar_correo_click(){ function save_config_mail(values){ + values['opt'] = 'save_mail' webix.ajax().sync().post('/config', values, { error: function(text, data, xhr) { msg = 'Error al guardar la configuración'