diff --git a/CHANGELOG.md b/CHANGELOG.md index 81efed2..48078ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +v 2.0.8 [30-Oct-2023] +--------------------- + - Fix: Permitir generar CFDI de egreso para facturas globales sin datos globales. + - Fix: Permitir cambiar la zona horaria para cuando se usa en servidor. + +Es necesario hacer una migración: +``` +cd /opt/empresa-libre + +git pull origin master + +cd source/app/models + +python main.py -bk + +python main.py -m -r RFC +``` + + v 2.0.7 [06-Ju1-2023] --------------------- - Fix: En tasa de retención de un Resico a una Persona Moral. diff --git a/VERSION b/VERSION index f1547e6..815e68d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.7 +2.0.8 diff --git a/source/app/controllers/cfdi_xml.py b/source/app/controllers/cfdi_xml.py index fc0aa87..d66a39d 100644 --- a/source/app/controllers/cfdi_xml.py +++ b/source/app/controllers/cfdi_xml.py @@ -27,6 +27,8 @@ from logbook import Logger log = Logger('XML') CFDI_ACTUAL = 'cfdi40' NOMINA_ACTUAL = 'nomina12' +PUBLIC = 'PUBLICO EN GENERAL' +CFDI_EGRESO = 'E' DEFAULT = { 'exportacion': '01', @@ -141,6 +143,7 @@ class CFDI(object): self._carta_porte = False self._comercio_exterior = False self._divisas = '' + self._tipo_de_comprobante = '' self.error = '' def _now(self): @@ -287,6 +290,8 @@ class CFDI(object): if not 'Exportacion' in attributes: attributes['Exportacion'] = DEFAULT['exportacion'] + self._tipo_de_comprobante = attributes['TipoDeComprobante'] + self._cfdi = ET.Element('{}:Comprobante'.format(self._pre), attributes) return @@ -317,7 +322,10 @@ class CFDI(object): return def _receptor(self, datos): - datos['Nombre'] = datos['Nombre'].upper() + receptor_name = datos['Nombre'].upper() + if receptor_name == PUBLIC and self._tipo_de_comprobante == CFDI_EGRESO: + receptor_name = datos['Nombre'] + datos['Nombre'] = receptor_name node_name = '{}:Receptor'.format(self._pre) emisor = ET.SubElement(self._cfdi, node_name, datos) return diff --git a/source/app/controllers/utils.py b/source/app/controllers/utils.py index ef100e0..00dd02e 100644 --- a/source/app/controllers/utils.py +++ b/source/app/controllers/utils.py @@ -772,7 +772,8 @@ def db_backup_local(): def now(): - return datetime.datetime.now().replace(microsecond=0) + n = datetime.datetime.now().replace(microsecond=0) + return n def get_days(date): @@ -1114,3 +1115,10 @@ def to_date(value): dt = datetime.datetime.combine(d, t) return dt + +def adjust_time(date_invoice, hours): + new_date = date_invoice + if hours: + time_change = datetime.timedelta(hours=hours) + new_date = date_invoice + time_change + return new_date diff --git a/source/app/models/main.py b/source/app/models/main.py index 86a9db1..40210b2 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -1017,6 +1017,7 @@ class Emisor(BaseModel): logo = TextField(default='') registro_patronal = TextField(default='') regimenes = ManyToManyField(SATRegimenes, related_name='emisores') + hours = IntegerField(default=0) class Meta: order_by = ('nombre',) @@ -1077,7 +1078,8 @@ class Emisor(BaseModel): 'ong_fecha_dof': obj.fecha_dof, 'token_soporte': obj.token_soporte, 'emisor_registro_patronal': obj.registro_patronal, - 'regimenes': [row.id for row in obj.regimenes] + 'regimenes': [row.id for row in obj.regimenes], + 'emisor_hours': obj.hours } else: row['emisor'] = {'emisor_rfc': rfc} @@ -1156,6 +1158,8 @@ class Emisor(BaseModel): fields['registro_patronal'] = fields.pop('emisor_registro_patronal', '') fields['regimenes'] = SATRegimenes.get_( util.loads(fields['regimenes'])) + fields['hours'] = int(fields.pop('emisor_hours', 0)) + return fields @classmethod @@ -4526,7 +4530,7 @@ class Facturas(BaseModel): version = TextField(default=PRE_DEFAULT['CFDI']['VERSION']) serie = TextField(default='') folio = BigIntegerField(default=0) - fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S']) + fecha = DateTimeField(default=utils.now, formats=['%Y-%m-%d %H:%M:%S']) fecha_timbrado = DateTimeField(null=True) forma_pago = TextField(default='') condiciones_pago = TextField(default='') @@ -5636,6 +5640,7 @@ class Facturas(BaseModel): leyendas_fiscales = utils.loads(values.pop('leyendas_fiscales', '[]')) + values['fecha'] = utils.now() date_invoice = values.pop('date') if Configuracion.get_bool('chk_config_change_date_invoice'): values['fecha'] = utils.to_date(date_invoice) @@ -5646,6 +5651,8 @@ class Facturas(BaseModel): return data emisor = Emisor.select()[0] + values['fecha'] = utils.adjust_time(values['fecha'], emisor.hours) + values['serie'] = cls._get_serie(cls, user, values['serie']) if Configuracion.get_bool('chk_folio_custom') and folio_custom: fc = {'folio': folio_custom, 'serie': values['serie']} @@ -11116,8 +11123,10 @@ def _migrate_tables(rfc=''): 'emisor', 'registro_patronal', registro_patronal)) if not 'curp' in columns: curp = TextField(default='') - migrations.append( - migrator.add_column('emisor', 'curp', curp)) + migrations.append(migrator.add_column('emisor', 'curp', curp)) + if not 'hours' in columns: + hours = IntegerField(default=0) + migrations.append(migrator.add_column('emisor', 'hours', hours)) columns = [c.name for c in database_proxy.get_columns('socios')] if not 'id_fiscal' in columns: diff --git a/source/app/settings.py b/source/app/settings.py index ca14884..77132d6 100644 --- a/source/app/settings.py +++ b/source/app/settings.py @@ -30,10 +30,7 @@ try: except ImportError: DEFAULT_PASSWORD = 'salgueiro4.0' -try: - from conf import TITLE_APP -except ImportError: - TITLE_APP = 'Empresa Libre' +TITLE_APP = 'Empresa Libre' try: from conf import NO_HTTPS @@ -42,7 +39,7 @@ except ImportError: DEBUG = DEBUG -VERSION = '2.0.7' +VERSION = '2.0.8' EMAIL_SUPPORT = ('soporte@empresalibre.mx',) TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION) diff --git a/source/db/valores_iniciales.json b/source/db/valores_iniciales.json index 9ca6de0..4049138 100644 --- a/source/db/valores_iniciales.json +++ b/source/db/valores_iniciales.json @@ -682,7 +682,7 @@ {"key": "D08", "name": "Gastos de transportación escolar obligatoria.", "activo": false}, {"key": "D09", "name": "Depósitos en cuentas para el ahorro, primas que tengan como base planes de pensiones.", "activo": false}, {"key": "D10", "name": "Pagos por servicios educativos (colegiaturas)", "activo": true}, - {"key": "P01", "name": "Por definir", "moral": true, "activo": true}, + {"key": "P01", "name": "Por definir", "moral": true, "activo": false}, {"key": "S01", "name": "Sin efectos fiscales.", "moral": true, "activo": true}, {"key": "CP01", "name": "Pagos", "moral": true, "activo": true}, {"key": "CN01", "name": "Nómina", "moral": true, "activo": true} diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index b044592..3cd16b4 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -534,9 +534,8 @@ function validate_invoice(values){ } var is_global = $$('cmd_show_global_information').isVisible() - if(is_global){ - if(values_global==''){ + if(values_global=='' && tipo_comprobante=='I'){ msg = 'Captura los datos de la Factura Global' msg_error(msg) return false @@ -999,7 +998,7 @@ function set_client(row){ } lst.setValue(lst.getPopup().getList().getFirstId()) - if(row.nombre == PUBLICO && row.rfc == RFC_PUBLICO){ + if(row.nombre.toUpperCase() == PUBLICO && row.rfc == RFC_PUBLICO){ show('cmd_show_global_information', true) }else{ show('cmd_show_global_information', false) diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index e4e1cc8..167aeda 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -176,7 +176,9 @@ var emisor_datos_fiscales = [ invalidMessage: 'El C.P. es requerido'}, {view: 'text', id: 'emisor_cp2', name: 'emisor_cp2', width: 300, label: 'C.P. de Expedición: ', attributes: {maxlength: 5}}, - {}]}, + {view: 'counter', id: 'emisor_hours', name: 'emisor_hours', value: 0, + required: false, label: 'Horas Dif.: ', step: 1, min: -1, max: 3} + ]}, {cols: [ {view: 'label', label: 'Regimenes Fiscales *', required: true}, {}]}, {cols: [{view: 'list', id: 'lst_emisor_regimen', select: 'multiselect',