diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py index a5f03e5..721a503 100644 --- a/source/app/controllers/main.py +++ b/source/app/controllers/main.py @@ -80,6 +80,8 @@ class AppValues(object): req.context['result'] = self._db.validate_email(values) elif table == 'sendmail': req.context['result'] = self._db.send_email(values, session) + elif table == 'enviarprefac': + req.context['result'] = self._db.enviar_prefac(values) else: req.context['result'] = self._db.validate_cert(values, session) else: diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index 54bc86d..cbf8825 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -512,6 +512,7 @@ class LIBO(object): self._init_values() def _init_values(self): + self._es_pre = False self._ctx = None self._sm = None self._desktop = None @@ -764,6 +765,9 @@ class LIBO(object): return def _timbre(self, data): + if self._es_pre: + return + for k, v in data.items(): self._set_cell('{timbre.%s}' % k, v) pd = self._sheet.getDrawPage() @@ -779,6 +783,7 @@ class LIBO(object): def _render(self, data): self._set_search() + self._es_pre = data.pop('es_pre', False) self._comprobante(data['comprobante']) self._emisor(data['emisor']) self._receptor(data['receptor']) diff --git a/source/app/models/db.py b/source/app/models/db.py index 7dbffb5..f63f9bb 100644 --- a/source/app/models/db.py +++ b/source/app/models/db.py @@ -38,6 +38,9 @@ class StorageEngine(object): def send_email(self, values, session): return main.Facturas.send(values['id'], session['rfc']) + def enviar_prefac(self, values): + return main.PreFacturas.enviar(values['id']) + def _get_cancelinvoice(self, values): return main.Facturas.cancel(values['id']) @@ -168,11 +171,15 @@ class StorageEngine(object): if type_doc == 'xml': data, file_name = main.Facturas.get_xml(id) content_type = 'application/xml' - if type_doc == 'pdf': + elif type_doc == 'pdf': data, file_name = main.Facturas.get_pdf(id, rfc) content_type = 'application/pdf' - if type_doc == 'zip': + elif type_doc == 'zip': data, file_name = main.Facturas.get_zip(id, rfc) content_type = 'application/octet-stream' + elif type_doc == 'pdf2': + data, file_name = main.PreFacturas.get_pdf(id, rfc) + content_type = 'application/pdf' + return data, file_name, content_type diff --git a/source/app/models/main.py b/source/app/models/main.py index 7a1f0bb..2537e9c 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -1655,6 +1655,126 @@ class PreFacturas(BaseModel): class Meta: order_by = ('fecha',) + @classmethod + def enviar(cls, id): + values = Configuracion.get_({'fields': 'correo'}) + if not values: + msg = 'No esta configurado el servidor de correo de salida' + return {'ok': False, 'msg': msg} + + obj = PreFacturas.get(PreFacturas.id==id) + if not obj.cliente.correo_facturas: + msg = 'El cliente no tiene configurado el correo para facturas' + return {'ok': False, 'msg': msg} + + files = (cls.get_pdf(id),) + + fields = {} + asunto = 'Enviamos la prefactura: PRE-{}'.format(obj.folio) + server = { + 'servidor': values['correo_servidor'], + 'puerto': values['correo_puerto'], + 'ssl': bool(int(values['correo_ssl'])), + 'usuario': values['correo_usuario'], + 'contra': values['correo_contra'], + } + options = { + 'para': obj.cliente.correo_facturas, + 'copia': values['correo_copia'], + 'asunto': asunto, + 'mensaje': util.make_info_mail(values['correo_mensaje'], fields), + 'files': files, + } + data= { + 'server': server, + 'options': options, + } + result = util.send_mail(data) + if not result['ok'] or result['msg']: + return {'ok': False, 'msg': result['msg']} + + msg = 'Pre Factura enviada correctamente' + return {'ok': True, 'msg': msg} + + def _get_info_to_pdf(self, id): + data = {} + obj = PreFacturas.select().where(PreFacturas.id==id).dicts()[0] + regimen = SATRegimenes.get(SATRegimenes.key==obj['regimen_fiscal']) + usocfdi = SATUsoCfdi.get(SATUsoCfdi.key==obj['uso_cfdi']) + formapago = SATFormaPago.get(SATFormaPago.key==obj['forma_pago']) + moneda = SATMonedas.get(SATMonedas.key==obj['moneda']) + + emisor = util.get_dict(Emisor.select().dicts()[0]) + emisor['nointerior'] = emisor['no_interior'] + emisor['noexterior'] = emisor['no_exterior'] + emisor['codigopostal'] = emisor['codigo_postal'] + emisor['regimenfiscal'] = str(regimen) + + receptor = Socios.select().where(Socios.id==obj['cliente']).dicts()[0] + receptor['usocfdi'] = str(usocfdi) + receptor['nointerior'] = receptor['no_interior'] + receptor['noexterior'] = receptor['no_exterior'] + receptor['codigopostal'] = receptor['codigo_postal'] + + data['es_pre'] = True + data['cancelada'] = False + + tipos = { + 'I': 'ingreso', + 'E': 'egreso', + 'T': 'traslado', + } + mp = { + 'PUE': 'Pago en una sola exhibición', + 'PPD': 'Pago en parcialidades o diferido', + } + + data['comprobante'] = obj + data['comprobante']['version'] = CURRENT_CFDI + data['comprobante']['folio'] = '{}-{}'.format( + data['comprobante']['serie'], data['comprobante']['folio']) + data['comprobante']['fecha'] = str(data['comprobante']['fecha']) + data['comprobante']['tipodecomprobante'] = tipos.get( + data['comprobante']['tipo_comprobante']) + data['comprobante']['lugarexpedicion'] = \ + 'C.P. de Expedición: {}'.format( + data['comprobante']['lugar_expedicion']) + data['comprobante']['metododepago'] = 'Método de Pago: ({}) {}'.format( + obj['metodo_pago'], mp[obj['metodo_pago']]) + data['comprobante']['formadepago'] = str(formapago) + data['comprobante']['condicionesdepago'] = \ + data['comprobante']['condiciones_pago'] + data['comprobante']['tipocambio'] = 'Tipo de Cambio: $ {:0.2f}'.format( + data['comprobante']['tipo_cambio']) + data['comprobante']['totalenletras'] = util.to_letters( + data['comprobante']['total'], data['comprobante']['moneda']) + data['comprobante']['moneda'] = str(moneda) + + data['emisor'] = emisor + data['receptor'] = receptor + + data['conceptos'] = PreFacturasDetalle.get_(id) + data['totales'] = {} + data['totales']['moneda'] = data['comprobante']['moneda'] + data['totales']['subtotal'] = str(data['comprobante']['subtotal']) + data['totales']['total'] = str(data['comprobante']['total']) + + taxes = PreFacturasImpuestos.get_(id) + data['totales']['traslados'] = taxes['traslados'] + data['totales']['retenciones'] = taxes['retenciones'] + data['totales']['taxlocales'] = taxes['taxlocales'] + data['timbre'] = {} + + return data + + @classmethod + def get_pdf(cls, id, rfc): + obj = PreFacturas.get(PreFacturas.id==id) + name = '{}{}_{}.pdf'.format(obj.serie, obj.folio, obj.cliente.rfc) + data = cls._get_info_to_pdf(cls, id) + doc = util.to_pdf(data) + return doc, name + @classmethod def remove(cls, id): obj = PreFacturas.get(PreFacturas.id==id) @@ -1880,6 +2000,7 @@ class FacturasDetalle(BaseModel): class PreFacturasDetalle(BaseModel): factura = ForeignKeyField(PreFacturas) producto = ForeignKeyField(Productos, null=True) + descripcion = TextField(default='') cantidad = DecimalField(default=0.0, max_digits=18, decimal_places=6, auto_round=True) valor_unitario = DecimalField(default=0.0, max_digits=18, decimal_places=6, @@ -1902,6 +2023,27 @@ class PreFacturasDetalle(BaseModel): class Meta: order_by = ('factura',) + @classmethod + def get_(cls, id): + data = [] + + productos = PreFacturasDetalle.select().where( + PreFacturasDetalle.factura==id) + + for p in productos: + producto = {} + producto['noidentificacion'] = '{}\n(SAT {})'.format( + p.producto.clave, p.producto.clave_sat) + producto['descripcion'] = p.descripcion + producto['unidad'] = '{}\n({})'.format( + p.producto.unidad.name, p.producto.unidad.key) + producto['cantidad'] = str(p.cantidad) + producto['valorunitario'] = str(p.valor_unitario) + producto['importe'] = str(p.importe) + data.append(producto) + + return data + class FacturasImpuestos(BaseModel): factura = ForeignKeyField(Facturas) @@ -1932,6 +2074,29 @@ class PreFacturasImpuestos(BaseModel): (('factura', 'impuesto'), True), ) + @classmethod + def get_(cls, id): + data = { + 'traslados': [], + 'retenciones': [], + 'taxlocales': [], + } + + taxes = PreFacturasImpuestos.select().where( + PreFacturasImpuestos.factura==id) + + for tax in taxes: + if tax.impuesto.tipo == 'T': + title = 'Traslado {} {}'.format( + tax.impuesto.name, str(tax.impuesto.tasa)) + data['traslados'].append((title, str(tax.importe))) + elif tax.impuesto.tipo == 'R': + title = 'Retención {} {}'.format( + tax.impuesto.name, str(tax.impuesto.tasa)) + data['retenciones'].append((title, str(tax.importe))) + + return data + def authenticate(args): respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''} @@ -2015,6 +2180,7 @@ def test_correo(values): def _init_values(rfc): data = ( {'clave': 'version', 'valor': VERSION}, + {'clave': 'migracion', 'valor': '0'}, {'clave': 'rfc_publico', 'valor': 'XAXX010101000'}, {'clave': 'rfc_extranjero', 'valor': 'XEXX010101000'}, {'clave': 'decimales', 'valor': '2'}, diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index a936824..7fa0fd2 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -1048,3 +1048,45 @@ function cmd_facturar_preinvoice_click(id, e, node){ } }) } + + +function enviar_prefactura(id){ + msg = '¿Estás seguro de enviar por correo esta prefactura?' + webix.confirm({ + title: 'Enviar Factura', + ok: 'Si', + cancel: 'No', + type: 'confirm-error', + text: msg, + callback:function(result){ + if(result){ + webix.ajax().post('/values/enviarprefac', {'id': id}, { + error:function(text, data, XmlHttpRequest){ + msg = 'Ocurrio un error, consulta a soporte técnico' + msg_error(msg) + }, + success:function(text, data, XmlHttpRequest){ + values = data.json(); + if(values.ok){ + msg_sucess(values.msg) + }else{ + msg_error(values.msg) + } + } + }) + } + } + }) +} + + +function grid_preinvoices_click(id, e, node){ + var row = this.getItem(id) + + if(id.column == 'pdf'){ + location = '/doc/pdf2/' + row.id + }else if(id.column == 'email'){ + enviar_prefactura(row.id) + } + +} diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js index 9aef6e1..449a9f0 100644 --- a/source/static/js/controller/main.js +++ b/source/static/js/controller/main.js @@ -60,6 +60,7 @@ var controllers = { $$('prefilter_month').attachEvent('onChange', prefilter_month_change) $$('cmd_delete_preinvoice').attachEvent('onItemClick', cmd_delete_preinvoice_click) $$('cmd_facturar_preinvoice').attachEvent('onItemClick', cmd_facturar_preinvoice_click) + $$('grid_preinvoices').attachEvent('onItemClick', grid_preinvoices_click) } }