From 94750e8caccbed45bd00a128006a7a316eba7ccc Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Tue, 26 Dec 2017 23:41:00 -0600 Subject: [PATCH] Fix al importar de Factura Libre Gambas --- source/app/controllers/util.py | 126 ++++++++++++++++++++++++++++--- source/app/models/main.py | 87 ++++++++++++++++++++- source/db/valores_iniciales.json | 3 +- 3 files changed, 201 insertions(+), 15 deletions(-) diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index 682136a..f67b6f0 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -1654,6 +1654,8 @@ class ImportFacturaLibreGambas(object): ('receptores', 'Socios'), ('cfdifacturas', 'Facturas'), ('categorias', 'Categorias'), + ('productos', 'Productos'), + ('tickets', 'Tickets'), ) for source, target in tables: data[target] = self._get_table(source) @@ -1665,38 +1667,140 @@ class ImportFacturaLibreGambas(object): def _get_table(self, table): return getattr(self, '_{}'.format(table))() - def import_productos(self): + def _tickets(self): + sql = "SELECT * FROM tickets" + self._cursor.execute(sql) + rows = self._cursor.fetchall() + + fields = ( + ('serie', 'serie'), + ('folio', 'folio'), + ('fecha', 'fecha'), + ('formadepago', 'forma_pago'), + ('subtotal', 'subtotal'), + ('descuento', 'descuento'), + ('total', 'total'), + ('notas', 'notas'), + ('factura', 'factura'), + ('cancelada', 'cancelado'), + ('vendedor', 'vendedor'), + ) + data = [] + for row in rows: + new = {t: row[s] for s, t in fields} + + new['notas'] = '' + new['estatus'] = 'Generado' + if new['cancelado']: + new['estatus'] = 'Cancelado' + new['factura'] = self._get_invoice_ticket(new['factura']) + + new['details'] = self._get_details_ticket(row['id']) + new['taxes'] = self._get_taxes_ticket(row['id']) + data.append(new) + + return data + + def _get_invoice_ticket(self, invoice): + if not invoice: + return None + + sql = "SELECT serie, folio FROM cfdifacturas WHERE id=%s" + self._cursor.execute(sql, [invoice]) + row = self._cursor.fetchone() + return dict(row) + + def _get_details_ticket(self, id): + sql = "SELECT * FROM t_detalle WHERE id_cfdi=%s" + self._cursor.execute(sql, [id]) + rows = self._cursor.fetchall() + + fields = ( + ('descripcion', 'descripcion'), + ('cantidad', 'cantidad'), + ('valorunitario', 'valor_unitario'), + ('importe', 'importe'), + ('precio', 'precio_final'), + ) + + data = [] + for row in rows: + new = {t: row[s] for s, t in fields if row[s]} + data.append(new) + + return data + + def _get_taxes_ticket(self, id): + sql = "SELECT * FROM t_impuestos WHERE id_cfdi=%s" + self._cursor.execute(sql, [id]) + rows = self._cursor.fetchall() + + tasas = { + '0': 0.0, + '16': 0.16, + '16.00': 0.16, + '11': 0.11, + '-10': 0.10, + '-2': 0.02, + '-0.5': 0.005, + '-2/3': 0.106667, + '-10.6666': 0.106667, + '-10.666666': 0.106667, + '-10.66660': 0.106667, + } + + data = [] + for row in rows: + filtro = { + 'name': row['impuesto'], + 'tasa': tasas[row['tasa']], + 'tipo': row['tipo'][0], + } + new = { + 'import': row['importe'], + 'filter': filtro + } + data.append(new) + + return data + + def _productos(self): + UNIDADES = { + 'KG': 'KGM', + 'PZA': 'H87', + } sql = "SELECT * FROM productos" self._cursor.execute(sql) rows = self._cursor.fetchall() fields = ( ('id_categoria', 'categoria'), - ('noIdentificacion', 'clave'), + ('noidentificacion', 'clave'), ('descripcion', 'descripcion'), ('unidad', 'unidad'), - ('valorUnitario', 'valor_unitario'), + ('costo', 'ultimo_costo'), + ('valorunitario', 'valor_unitario'), ('existencia', 'existencia'), + ('minimo', 'minimo'), ('inventario', 'inventario'), ('codigobarras', 'codigo_barras'), - ('CuentaPredial', 'cuenta_predial'), - ('precio_compra', 'ultimo_precio'), - ('minimo', 'minimo'), + ('cuentapredial', 'cuenta_predial'), ) data = [] sql = """ SELECT nombre, tasa, tipo - FROM impuestos, productos, productosimpuestos - WHERE productos.id=productosimpuestos.id_producto - AND productosimpuestos.id_impuesto=impuestos.id - AND productos.id = ? + FROM impuestos + WHERE id=%s """ for row in rows: new = {t: row[s] for s, t in fields} + if not new['categoria']: + new['categoria'] = None new['descripcion'] = ' '.join(new['descripcion'].split()) new['clave_sat'] = DEFAULT_SAT_PRODUCTO - self._cursor.execute(sql, (row['id'],)) + new['unidad'] = UNIDADES.get(new['unidad'], new['unidad']) + self._cursor.execute(sql, [row['id_impuesto1']]) impuestos = self._cursor.fetchall() new['impuestos'] = tuple(impuestos) data.append(new) diff --git a/source/app/models/main.py b/source/app/models/main.py index febd764..af62573 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -4910,9 +4910,90 @@ def _importar_factura_libre_gambas(conexion): data = app.import_data() - _importar_socios(data['Socios']) - _importar_facturas(data['Facturas']) - _importar_categorias(data['Categorias']) + # ~ _importar_socios(data['Socios']) + # ~ _importar_facturas(data['Facturas']) + # ~ _importar_categorias(data['Categorias']) + # ~ _importar_productos_gambas(data['Productos']) + _import_tickets(data['Tickets']) + + log.info('ImportaciĆ³n terminada...') + return + + +def _exist_ticket(row): + filters = ( + (Tickets.serie==row['serie']) & + (Tickets.folio==row['folio']) + ) + return Tickets.select().where(filters).exists() + + +def _import_tickets(rows): + log.info('\tImportando Tickets...') + for row in rows: + try: + details = row.pop('details') + taxes = row.pop('taxes') + with database_proxy.atomic() as txn: + if _exist_ticket(row): + msg = '\tTicket existente: {}{}'.format( + row['serie'], row['folio']) + log.info(msg) + continue + + if not row['factura'] is None: + row['factura'] = Facturas.get( + Facturas.serie==row['factura']['serie'], + Facturas.folio==row['factura']['folio']) + obj = Tickets.create(**row) + for detail in details: + detail['ticket'] = obj + TicketsDetalle.create(**detail) + for tax in taxes: + imp = SATImpuestos.get(**tax['filter']) + new = { + 'ticket': obj, + 'impuesto': imp, + 'importe': tax['import'], + } + TicketsImpuestos.create(**new) + except IntegrityError as e: + print (e) + msg = '\tTicket: id: {}'.format(row['serie'] + str(row['folio'])) + log.error(msg) + + log.info('\tTickets importadas...') + return + + +def _importar_productos_gambas(rows): + log.info('Importando productos...') + + KEYS = { + 'Exento': '000', + 'ISR': '001', + 'IVA': '002', + } + + for row in rows: + source_taxes = row.pop('impuestos') + row['unidad'] = SATUnidades.get(SATUnidades.key==row['unidad']) + taxes = [] + for tax in source_taxes: + w = { + 'key': KEYS[tax[0]], + 'name': tax[0], + 'tasa': float(tax[1]), + 'tipo': tax[2][0], + } + taxes.append(SATImpuestos.get_o_crea(w)) + + with database_proxy.transaction(): + try: + obj = Productos.create(**row) + obj.impuestos = taxes + except IntegrityError as e: + print (e) log.info('ImportaciĆ³n terminada...') return diff --git a/source/db/valores_iniciales.json b/source/db/valores_iniciales.json index fd4f604..acb7ad0 100644 --- a/source/db/valores_iniciales.json +++ b/source/db/valores_iniciales.json @@ -24,7 +24,8 @@ {"key": "H87", "name": "Pieza", "activo": true}, {"key": "E48", "name": "Servicio", "activo": true}, {"key": "E51", "name": "Trabajo", "activo": false}, - {"key": "ACT", "name": "Actividad", "activo": false} + {"key": "ACT", "name": "Actividad", "activo": false}, + {"key": "KGM", "name": "Kilogramo", "activo": false} ] }, {