diff --git a/source/app/models/db.py b/source/app/models/db.py
index c45a566..9faffbf 100644
--- a/source/app/models/db.py
+++ b/source/app/models/db.py
@@ -416,3 +416,9 @@ class StorageEngine(object):
# ~ Revisado
def get_invoicepay(self, values):
return main.FacturasPagos.get_values(values)
+
+ def get_cfdipay(self, values):
+ return main.CfdiPagos.get_values(values)
+
+ def cfdipay(self, values):
+ return main.CfdiPagos.post(values)
diff --git a/source/app/models/main.py b/source/app/models/main.py
index 6feecc0..abeafb5 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -34,7 +34,8 @@ from controllers import util
from settings import log, DEBUG, VERSION, PATH_CP, COMPANIES, PRE, CURRENT_CFDI, \
INIT_VALUES, DEFAULT_PASSWORD, DECIMALES, IMPUESTOS, DEFAULT_SAT_PRODUCTO, \
CANCEL_SIGNATURE, PUBLIC, DEFAULT_SERIE_TICKET, CURRENT_CFDI_NOMINA, \
- DEFAULT_SAT_NOMINA, DECIMALES_TAX, TITLE_APP, MV, DECIMALES_PRECIOS
+ DEFAULT_SAT_NOMINA, DECIMALES_TAX, TITLE_APP, MV, DECIMALES_PRECIOS, \
+ DEFAULT_SERIE_CFDIPAY
FORMAT = '{0:.2f}'
@@ -891,6 +892,7 @@ class Certificado(BaseModel):
rfc = TextField(default='')
desde = DateTimeField(null=True)
hasta = DateTimeField(null=True)
+ es_fiel = BooleanField(default=False)
def __str__(self):
return self.serie
@@ -1947,33 +1949,6 @@ class MovimientosBanco(BaseModel):
return {'ok': True, 'rows': rows}
-class CfdiPagos(BaseModel):
- movimiento = ForeignKeyField(MovimientosBanco)
- serie = TextField(default='')
- folio = IntegerField(default=0)
- fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
- fecha_timbrado = DateTimeField(null=True)
- lugar_expedicion = TextField(default='')
- tipo_relacion = TextField(default='')
- uuid_relacionado = UUIDField(null=True)
- xml = TextField(default='')
- uuid = UUIDField(null=True)
- estatus = TextField(default='Guardado')
- estatus_sat = TextField(default='')
- notas = TextField(default='')
- cancelado = BooleanField(default=False)
-
- class Meta:
- order_by = ('movimiento',)
-
- @classmethod
- def new(cls, id_mov):
-
- row = {}
- data = {'ok': True, 'row': row}
- return data
-
-
class SATUsoCfdi(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
@@ -5266,6 +5241,115 @@ class FacturasPagos(BaseModel):
return getattr(cls, '_get_{}'.format(opt))(cls, values)
+class CfdiPagos(BaseModel):
+ movimiento = ForeignKeyField(MovimientosBanco)
+ socio = ForeignKeyField(Socios)
+ serie = TextField(default='')
+ folio = IntegerField(default=0)
+ fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
+ fecha_timbrado = DateTimeField(null=True)
+ lugar_expedicion = TextField(default='')
+ tipo_relacion = TextField(default='')
+ uuid_relacionado = UUIDField(null=True)
+ xml = TextField(default='')
+ uuid = UUIDField(null=True)
+ estatus = TextField(default='Guardada')
+ estatus_sat = TextField(default='')
+ notas = TextField(default='')
+ error = TextField(default='')
+ cancelado = BooleanField(default=False)
+
+ class Meta:
+ order_by = ('movimiento',)
+
+ @classmethod
+ def post(cls, values):
+ opt = values.pop('opt')
+ return getattr(cls, '_{}'.format(opt))(cls, values)
+
+ def _get_folio(self, serie):
+ folio = int(Configuracion.get_('txt_config_cfdipay_folio') or '0')
+ start = (CfdiPagos
+ .select(fn.Max(CfdiPagos.folio).alias('mf'))
+ .where(CfdiPagos.serie==serie)
+ .order_by(SQL('mf'))
+ .scalar())
+
+ if start is None:
+ next_folio = 1
+ else:
+ next_folio = start + 1
+
+ if folio > next_folio:
+ next_folio = folio
+
+ return next_folio
+
+ def _new(self, values):
+ id_mov = int(values['id_mov'])
+
+ filters = (FacturasPagos.movimiento==id_mov)
+ related = FacturasPagos.select().where(filters)
+ if not related:
+ msg = 'El pago no tiene facturas relacionadas'
+ data = {'ok': False, 'msg': msg}
+ return data
+
+ partner = tuple(set([f.factura.cliente.id for f in related]))
+ if len(partner) > 1:
+ msg = 'Facturas relacionadas a diferentes clientes'
+ data = {'ok': False, 'msg': msg}
+ return data
+
+ partner = partner[0]
+ partner_name = related[0].factura.cliente.nombre
+
+ filters = (
+ (CfdiPagos.movimiento==id_mov) &
+ (CfdiPagos.cancelado==False)
+ )
+ previous = CfdiPagos.select().where(filters)
+ if previous:
+ msg = 'Hay una factura activa, es necesario cancelarla primero'
+ data = {'ok': False, 'msg': msg}
+ return data
+
+ emisor = Emisor.select()[0]
+ serie = Configuracion.get_('txt_config_cfdipay_serie') or DEFAULT_SERIE_CFDIPAY
+ fields = {}
+ fields['movimiento'] = id_mov
+ fields['socio'] = partner
+ fields['serie'] = serie
+ fields['folio'] = self._get_folio(self, serie)
+ fields['lugar_expedicion'] = emisor.cp_expedicion or emisor.codigo_postal
+
+ # ~ with database_proxy.atomic() as txn:
+ # ~ obj = CfdiPagos.create(**fields)
+
+ # ~ row = {
+ # ~ 'id': obj.id,
+ # ~ 'serie': obj.serie,
+ # ~ 'folio': obj.folio,
+ # ~ 'uuid': obj.uuid,
+ # ~ 'fecha': obj.fecha,
+ # ~ 'tipo_comprobante': 'P',
+ # ~ 'estatus': obj.estatus,
+ # ~ 'cliente': partner_name,
+ # ~ }
+ row = {
+ 'id': 1,
+ 'serie': 'FP',
+ 'folio': 1,
+ 'uuid': '',
+ 'fecha': util.now(),
+ 'tipo_comprobante': 'P',
+ 'estatus': 'Timbrada',
+ 'cliente': partner_name,
+ }
+ data = {'ok': True, 'row': row}
+ return data
+
+
class PreFacturasImpuestos(BaseModel):
factura = ForeignKeyField(PreFacturas)
impuesto = ForeignKeyField(SATImpuestos)
@@ -7532,18 +7616,27 @@ def _migrate_tables():
if 'cancelado' in columns:
migrations.append(migrator.drop_column('facturaspagos', 'cancelado'))
+ columns = [c.name for c in database_proxy.get_columns('certificado')]
+ if not 'es_fiel' in columns:
+ es_fiel = BooleanField(default=False)
+ migrations.append(migrator.add_column('certificado', 'es_fiel', es_fiel))
+
columns = [c.name for c in database_proxy.get_columns('cfdipagos')]
if not 'serie' in columns:
+ socio = ForeignKeyField(Socios, null=True, to_field=Socios.id)
serie = TextField(default='')
folio = IntegerField(default=0)
lugar_expedicion = TextField(default='')
+ error = TextField(default='')
tipo_relacion = TextField(default='')
uuid_relacionado = UUIDField(null=True)
migrations.append(migrator.add_column('cfdipagos', 'serie', serie))
migrations.append(migrator.add_column('cfdipagos', 'folio', folio))
migrations.append(migrator.add_column('cfdipagos', 'lugar_expedicion', lugar_expedicion))
+ migrations.append(migrator.add_column('cfdipagos', 'error', error))
migrations.append(migrator.add_column('cfdipagos', 'tipo_relacion', tipo_relacion))
migrations.append(migrator.add_column('cfdipagos', 'uuid_relacionado', uuid_relacionado))
+ migrations.append(migrator.add_column('cfdipagos', 'socio_id', socio))
if migrations:
with database_proxy.atomic() as txn:
diff --git a/source/app/settings.py b/source/app/settings.py
index 9e07c20..0d1ed66 100644
--- a/source/app/settings.py
+++ b/source/app/settings.py
@@ -154,6 +154,7 @@ IMPUESTOS = {
}
DEFAULT_SAT_PRODUCTO = '01010101'
DEFAULT_SERIE_TICKET = 'T'
+DEFAULT_SERIE_CFDIPAY = 'FP'
DIR_FACTURAS = 'facturas'
USAR_TOKEN = False
CANCEL_SIGNATURE = False
diff --git a/source/static/js/controller/bancos.js b/source/static/js/controller/bancos.js
index 288062b..a683c70 100644
--- a/source/static/js/controller/bancos.js
+++ b/source/static/js/controller/bancos.js
@@ -38,6 +38,10 @@ var bancos_controllers = {
$$('filter_cuenta_year').attachEvent('onChange', filter_cuenta_change)
$$('filter_cuenta_month').attachEvent('onChange', filter_cuenta_change)
$$('filter_cuenta_dates').attachEvent('onChange', filter_cuenta_dates_change)
+
+ $$('cmd_pay_stamp').attachEvent('onItemClick', cmd_pay_stamp_click)
+ $$('cmd_pay_cancel').attachEvent('onItemClick', cmd_pay_cancel_click)
+
set_year_month()
}
}
@@ -693,7 +697,7 @@ function filter_cuenta_dates_change(range){
function set_data_pay(row){
- var form = $$('form_banco_pagos')
+ var form = $$('form_bank_pay')
var dt = row.fecha.split(' ')
var grid = $$('grid_pay_related')
grid.clearAll()
@@ -745,5 +749,65 @@ function cmd_complemento_pago_click(){
}
set_data_pay(row)
- $$('multi_bancos').setValue('banco_pagos')
+ $$('multi_bancos').setValue('bank_pay')
+}
+
+
+function validate_cfdi_pay(form){
+ if(!form.validate()) {
+ msg_error('Valores inválidos')
+ return false
+ }
+
+ return true
+}
+
+
+function save_cfdi_pay(form){
+ var values = form.getValues()
+ var data = {'opt': 'new', 'id_mov': values.id_mov}
+
+ webix.ajax().sync().post('cfdipay', data, {
+ error:function(text, data, XmlHttpRequest){
+ msg = 'Ocurrio un error, consulta a soporte técnico'
+ msg_error(msg)
+ },
+ success:function(text, data, XmlHttpRequest){
+ result = data.json();
+ if(result.ok){
+ msg_ok('Factura guardada correctamente
Enviando a timbrar...')
+ $$('grid_cfdi_pay').add(result.row)
+ }else{
+ msg_error(result.msg)
+ }
+ }
+ })
+}
+
+
+function cmd_pay_stamp_click(){
+ var form = $$('form_bank_pay')
+ var title = 'Timbrar Factura de Pago'
+ msg = '¿Estás seguro de enviar a timbrar este pago?'
+
+ if (!validate_cfdi_pay(form)){
+ return
+ }
+
+ webix.confirm({
+ title: title,
+ ok: 'Si',
+ cancel: 'No',
+ type: 'confirm-error',
+ text: msg,
+ callback:function(result){
+ if(result){
+ save_cfdi_pay(form)
+ }
+ }
+ })
+}
+
+
+function cmd_pay_cancel_click(){
}
diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js
index 248f6d2..7936869 100644
--- a/source/static/js/ui/admin.js
+++ b/source/static/js/ui/admin.js
@@ -233,18 +233,38 @@ var emisor_otros_datos= [
]
-var emisor_certificado = [
+var col_sello = {rows: [
{template: 'Certificado actual', type: 'section'},
{view: 'form', id: 'form_cert', rows: [
{cols: [{view: 'text', id: 'cert_rfc', name: 'cert_rfc',
- label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}, {}]},
+ label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}]},
{cols: [{view: 'text', id: 'cert_serie', name: 'cert_serie',
- label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}, {}]},
+ label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}]},
{cols: [{view: 'text', id: 'cert_desde', name: 'cert_desde',
- label: 'Vigente desde: ', readonly: true}, {}]},
+ label: 'Vigente desde: ', readonly: true}]},
{cols: [{view: 'text', id: 'cert_hasta', name: 'cert_hasta',
- label: 'Vigente hasta: ', readonly: true}, {}]},
- ]},
+ label: 'Vigente hasta: ', readonly: true}]},
+ ]}
+]}
+
+
+var col_fiel = {rows: [
+ {template: 'Fiel actual', type: 'section'},
+ {view: 'form', id: 'form_fiel', rows: [
+ {cols: [{view: 'text', id: 'fiel_rfc', name: 'fiel_rfc',
+ label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}]},
+ {cols: [{view: 'text', id: 'fiel_serie', name: 'fiel_serie',
+ label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}]},
+ {cols: [{view: 'text', id: 'fiel_desde', name: 'fiel_desde',
+ label: 'Vigente desde: ', readonly: true}]},
+ {cols: [{view: 'text', id: 'fiel_hasta', name: 'fiel_hasta',
+ label: 'Vigente hasta: ', readonly: true}]},
+ ]}
+]}
+
+
+var emisor_certificado = [
+ {cols: [col_sello, col_fiel]},
{template: 'Cargar Certificado', type: 'section'},
{view: 'form', id: 'form_upload', rows: [
{cols: [{},
diff --git a/source/static/js/ui/bancos.js b/source/static/js/ui/bancos.js
index 5247687..32cd3be 100644
--- a/source/static/js/ui/bancos.js
+++ b/source/static/js/ui/bancos.js
@@ -130,10 +130,7 @@ var grid_cfdi_pago_cols = [
adjust: 'header', sort: 'string'},
{id: "estatus", header: ["Estatus"],
adjust: "data", sort:"string"},
- {id: 'total_mn', header: ['Total M.N.'], width: 150, sort: 'int',
- format: webix.i18n.priceFormat, css: 'right'},
- {id: 'cliente', header: ['Razón Social'],
- fillspace: true, sort: 'string', footer: {text: '$ 0.00', colspan: 2}},
+ {id: 'cliente', header: ['Razón Social'], fillspace: true},
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
{id: 'email', header: '', adjust: 'data', template: get_icon('email')}
@@ -205,9 +202,9 @@ var grid_cfdi_este_deposito = {
}
-var grid_cfdi_pago = {
+var grid_cfdi_pay = {
view: 'datatable',
- id: 'grid_cfdi_pago',
+ id: 'grid_cfdi_pay',
select: 'row',
autoConfig: false,
adjust: true,
@@ -266,12 +263,12 @@ var toolbar_banco_deposito = [
]
-var toolbar_banco_pagos = [
+var toolbar_bank_pay = [
{view: 'label', label: 'Factura de pago'},
{},
- {view: 'button', id: 'cmd_pago_timbrar', label: 'Timbrar',
+ {view: 'button', id: 'cmd_pay_stamp', label: 'Timbrar',
type: 'iconButton', autowidth: true, icon: 'ticket'},
- {view: 'button', id: 'cmd_pago_cancelar', label: 'Cancelar',
+ {view: 'button', id: 'cmd_pay_cancel', label: 'Cancelar',
type: 'iconButton', autowidth: true, icon: 'ban'},
{},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
@@ -349,8 +346,8 @@ var controls_banco_deposito = [
]
-var controls_banco_pagos = [
- {view: 'toolbar', elements: toolbar_banco_pagos},
+var controls_bank_pay = [
+ {view: 'toolbar', elements: toolbar_bank_pay},
{view: 'label', label: 'Este depósito: '},
{cols: [
{view: 'datepicker', id: 'pay_date', name: 'pay_date',
@@ -378,7 +375,7 @@ var controls_banco_pagos = [
labelWidth: 125, height: 70, readonly: true},
]},
{view: 'label', label: 'Facturas de pago de este depósito: '},
- grid_cfdi_pago,
+ grid_cfdi_pay,
{view: 'label', label: 'Facturas relacionadas en este pago: '},
grid_pay_related
]
@@ -410,15 +407,15 @@ var form_banco_deposito = {
}
-var form_banco_pagos = {
+var form_bank_pay = {
type: 'space',
responsive: true,
cols: [{
view: 'form',
- id: 'form_banco_pagos',
+ id: 'form_bank_pay',
complexData: true,
scroll: true,
- elements: controls_banco_pagos,
+ elements: controls_bank_pay,
}],
}
@@ -435,7 +432,7 @@ var multi_bancos = {
]},
{id: 'banco_retiro', rows: [form_banco_retiro]},
{id: 'banco_deposito', rows: [form_banco_deposito]},
- {id: 'banco_pagos', rows: [form_banco_pagos]}
+ {id: 'bank_pay', rows: [form_bank_pay]}
],
}