def purchase_ncf_validate(self): if not self.journal_id.purchase_type == 'normal': return number = self.move_name if self.move_name else None if not ncf.is_valid(number): raise UserError( _("NCF mal digitado\n\n" "El comprobante *{}* no tiene la estructura correcta " "valide si lo ha digitado correctamente".format(number))) if number[-10:-8] not in ('01', '03', '04', '11', '12', '13', '14', '15'): raise ValidationError( _("NCF *{}* NO corresponde con el tipo de documento\n\n" "Verifique lo ha digitado correctamente y que no sea un " "Comprobante Consumidor Final (02)".format(number))) if self.id: ncf_in_draft = self.search_count([ ('id', '!=', self.id), ('partner_id', '=', self.partner_id.id), ('move_name', '=', number), ('state', 'in', ('draft', 'cancel')) ]) else: ncf_in_draft = self.search_count([ ('partner_id', '=', self.partner_id.id), ('move_name', '=', number), ('state', 'in', ('draft', 'cancel')) ]) if ncf_in_draft: raise UserError( _("NCF en Factura Borrador o Cancelada\n\n" "El comprobante *{}* ya se encuentra " "registrado con este mismo proveedor en una factura " "en borrador o cancelada".format(number))) ncf_exist = self.search_count([('partner_id', '=', self.partner_id.id), ('number', '=', number), ('state', 'in', ('open', 'paid'))]) if ncf_exist: raise UserError( _("NCF Duplicado\n\n" "El comprobante *{}* ya se encuentra registrado con el" " mismo proveedor en otra factura".format(number))) if self.journal_id.ncf_remote_validation and not ncf.check_dgii( self.partner_id.vat, number): raise UserError( _(u"NCF NO pasó validación en DGII\n\n" u"¡El número de comprobante *{}* del proveedor " u"*{}* no pasó la validación en " "DGII! Verifique que el NCF y el RNC del " u"proveedor estén correctamente " u"digitados, o si los números de ese NCF se " "le agotaron al proveedor".format(number, self.partner_id.name)))
def invoice_refund(self): active_id = self._context.get("active_id", False) if active_id: invoice = self.env["account.invoice"].browse(active_id) if self.supplier_ncf: if self.filter_refund == 'debit' and self.supplier_ncf[ -10:-8] != '03': raise ValidationError( _(u"Las Notas de Débito deben ser tipo 03, este NCF no es de este tipo." )) elif self.filter_refund != 'debit' and self.supplier_ncf[ -10:-8] != '04': raise ValidationError( _(u"Las Notas de Crédito deben ser tipo 04, este NCF no es de este tipo." )) if self.supplier_ncf and invoice.journal_id.ncf_remote_validation: if not ncf.check_dgii(invoice.partner_id.vat, self.supplier_ncf): raise UserError( _(u"NCF NO pasó validación en DGII\n\n" u"¡El número de comprobante *{}* del proveedor " u"*{}* no pasó la validación en " "DGII! Verifique que el NCF y el RNC del " u"proveedor estén correctamente " u"digitados, o si los números de ese NCF se " "le agotaron al proveedor".format( self.supplier_ncf, invoice.partner_id.name))) return super(AccountInvoiceRefund, self).invoice_refund()
def _check_fiscal_purchase(self): for rec in self.filtered( lambda r: r.company_id.country_id == self.env.ref("base.do") and r.l10n_latam_document_type_id.l10n_do_ncf_type is not False and r.type == "in_invoice" and r.l10n_latam_document_number): l10n_latam_document_number = rec.l10n_latam_document_number l10n_latam_document_type = rec.l10n_latam_document_type_id.l10n_do_ncf_type if l10n_latam_document_number and l10n_latam_document_type == "fiscal": if l10n_latam_document_number[-10:-8] == "02": raise ValidationError( _("NCF *{}* does not correspond with the fiscal type\n\n" "You cannot register Consumo NCF (02) for purchases" ).format(l10n_latam_document_number)) try: from stdnum.do import ncf as ncf_validation if len(l10n_latam_document_number ) == "11" and not ncf_validation.check_dgii( rec.partner_id.vat, l10n_latam_document_number): raise ValidationError( _("NCF rejected by DGII\n\n" "NCF *{}* of supplier *{}* was rejected by DGII's " "validation service. Please validate if the NCF and " "the supplier RNC are type correctly. Otherwhise " "your supplier might not have this sequence approved " "yet.").format(l10n_latam_document_number, rec.partner_id.name)) except (ImportError, IOError) as err: _logger.debug(err)
def validate_fiscal_purchase(self): for inv in self.filtered( lambda i: i.type == "in_invoice" and i.state == "draft"): ncf = inv.reference if inv.reference else None if ncf and ncf_dict.get(inv.fiscal_type_id.prefix) == "fiscal": if ncf[-10:-8] == "02" or ncf[1:3] == "32": raise ValidationError( _("NCF *{}* does not correspond with the fiscal type\n\n" "You cannot register Consumo (02 or 32) for purchases" ).format(ncf)) elif inv.fiscal_type_id.requires_document and not inv.partner_id.vat: raise ValidationError( _("Partner [{}] {} doesn't have RNC/Céd, " "is required for NCF type {}").format( inv.partner_id.id, inv.partner_id.name, inv.fiscal_type_id.name, )) elif not ncf_validation.is_valid(ncf): raise UserError( _("NCF wrongly typed\n\n" "This NCF *{}* does not have the proper structure, " "please validate if you have typed it correctly."). format(ncf)) # TODO move this to l10n_do_external_validation_ncf elif (self.journal_id.l10n_do_ncf_remote_validation and not ncf_validation.check_dgii(self.partner_id.vat, ncf)): raise ValidationError( _("NCF rejected by DGII\n\n" "NCF *{}* of supplier *{}* was rejected by DGII's " "validation service. Please validate if the NCF and " "the supplier RNC are type correctly. Otherwhise " "your supplier might not have this sequence approved " "yet.").format(ncf, self.partner_id.name)) ncf_in_invoice = (inv.search_count([ ("id", "!=", inv.id), ("company_id", "=", inv.company_id.id), ("partner_id", "=", inv.partner_id.id), ("reference", "=", ncf), ("state", "in", ("draft", "open", "paid", "cancel")), ("type", "in", ("in_invoice", "in_refund")), ]) if inv.id else inv.search_count([ ("partner_id", "=", inv.partner_id.id), ("company_id", "=", inv.company_id.id), ("reference", "=", ncf), ("state", "in", ("draft", "open", "paid", "cancel")), ("type", "in", ("in_invoice", "in_refund")), ])) if ncf_in_invoice: raise ValidationError( _("NCF already used in another invoice\n\n" "The NCF *{}* has already been registered in another " "invoice with the same supplier. Look for it in " "invoices with canceled or draft states").format( ncf))
def validate_fiscal_purchase(self): NCF = self.reference if self.reference else None if NCF and self.journal_id.purchase_type == 'normal': if NCF[-10:-8] == '02': raise ValidationError( _("NCF *{}* NO corresponde con el tipo de documento\n\n" "No puede registrar Comprobantes Consumidor Final (02)"). format(NCF)) elif not ncf_validation.is_valid(NCF): raise UserError( _("NCF mal digitado\n\n" "El comprobante *{}* no tiene la estructura correcta " "valide si lo ha digitado correctamente").format(NCF)) elif not self.partner_id.vat: raise ValidationError( _(u"Proveedor sin RNC/Céd\n\n" u"El proveedor *{}* no tiene RNC o Cédula y es requerido " u"para registrar compras Fiscales").format( self.partner_id.name)) elif (self.journal_id.ncf_remote_validation and not ncf_validation.check_dgii(self.partner_id.vat, NCF)): raise ValidationError( _(u"NCF NO pasó validación en DGII\n\n" u"¡El número de comprobante *{}* del proveedor " u"*{}* no pasó la validación en " "DGII! Verifique que el NCF y el RNC del " u"proveedor estén correctamente " u"digitados, o si los números de ese NCF se " "le agotaron al proveedor").format( NCF, self.partner_id.name)) ncf_in_invoice = self.search_count([ ('id', '!=', self.id), ('company_id', '=', self.company_id.id), ('partner_id', '=', self.partner_id.id), ('reference', '=', NCF), ('state', 'in', ('draft', 'open', 'paid', 'cancel')), ('type', 'in', ('in_invoice', 'in_refund')) ]) if self.id else self.search_count([('partner_id', '=', self.partner_id.id), ('company_id', '=', self.company_id.id), ('reference', '=', NCF), ('state', 'in', ('draft', 'open', 'paid', 'cancel')), ('type', 'in', ('in_invoice', 'in_refund'))]) if ncf_in_invoice: raise ValidationError( _("NCF Duplicado en otra Factura\n\n" "El comprobante *{}* ya se encuentra " "registrado con este mismo proveedor en una factura " "en borrador o cancelada").format(NCF))
def test_check_dgii(self): """Test stdnum.do.ncf.check_dgii()""" # Test a normal valid number result = ncf.check_dgii('130546312', 'A010010011500000038') self.assertTrue(result) self.assertIn('name', result.keys()) self.assertIn('rnc', result.keys()) self.assertIn('ncf', result.keys()) self.assertIn('validation_message', result.keys()) self.assertEqual(result['rnc'], '130546312') self.assertEqual(result['ncf'], 'A010010011500000038') # Test an invalid combination self.assertIsNone(ncf.check_dgii('501620371', 'A010010011500000038')) # Another valid example self.assertTrue(ncf.check_dgii('1-31-56633-2', 'A010010010100000001')) self.assertTrue(ncf.check_dgii('1-31-56633-2', 'A010010010100000100')) # These types have not been requested with the regulator self.assertFalse(ncf.check_dgii('1-31-56633-2', 'A030010010100000001')) self.assertFalse(ncf.check_dgii('1-31-56633-2', 'A010020010100000001')) # Test the new format result = ncf.check_dgii('130546312', 'B0100000005') self.assertTrue(result) self.assertIn('name', result.keys()) self.assertIn('rnc', result.keys()) self.assertIn('ncf', result.keys()) self.assertIn('validation_message', result.keys()) self.assertEqual(result['rnc'], '130546312') self.assertEqual(result['ncf'], 'B0100000005')
def test_check_dgii(self): """Test stdnum.do.ncf.check_dgii()""" # Test a normal valid number result = ncf.check_dgii('130546312', 'A010010011500000038') self.assertTrue(result) self.assertIn('name', result.keys()) self.assertIn('rnc', result.keys()) self.assertIn('ncf', result.keys()) self.assertIn('validation_message', result.keys()) self.assertEqual(result['rnc'], '130546312') self.assertEqual(result['ncf'], 'A010010011500000038') # Test an invalid combination self.assertIsNone(ncf.check_dgii('501620371', 'A010010011500000038')) # Another valid example self.assertTrue(ncf.check_dgii('1-31-56633-2', 'A010010010100000001')) self.assertTrue(ncf.check_dgii('1-31-56633-2', 'A010010010100000100')) # These types have not been requested with the regulator self.assertFalse(ncf.check_dgii('1-31-56633-2', 'A030010010100000001')) self.assertFalse(ncf.check_dgii('1-31-56633-2', 'A010020010100000001')) # Test the new format result = ncf.check_dgii('130546312', 'B0100000005') self.assertTrue(result) self.assertIn('name', result.keys()) self.assertIn('rnc', result.keys()) self.assertIn('ncf', result.keys()) self.assertIn('validation_message', result.keys()) self.assertEqual(result['rnc'], '130546312') self.assertEqual(result['ncf'], 'B0100000005') # Test the ENCF result = ncf.check_dgii('101010632', 'E310049533639', buyer_rnc='22400559690', security_code='hnI63Q') self.assertTrue(result) self.assertIn('status', result.keys()) self.assertEqual(result['issuing_rnc'], '101010632') self.assertEqual(result['buyer_rnc'], '22400559690') self.assertEqual(result['ncf'], 'E310049533639') self.assertIn('issuing_date', result.keys()) self.assertIn('signature_date', result.keys()) self.assertIn('total', result.keys()) self.assertIn('total_itbis', result.keys()) self.assertIn('validation_message', result.keys())
def invoice_refund(self): active_id = self._context.get("active_id", False) if active_id: invoice = self.env["account.invoice"].browse(active_id) # TODO if self.refund_reference and self.is_fiscal_refund: ncf = self.refund_reference[0:3] ncf_digits = len(self.refund_reference) # TODO: Hacer las validaciones con el tipo de comprobante y no directo # en e codigo. if (self._context.get("debit_note") and ncf not in ("B03", "E33")): raise UserError( _("Debit Notes must be type B03 or E33, this NCF " "structure does not comply.")) elif ncf not in ("B04", "E34"): raise UserError( _(("Credit Notes must be type B04 or E34, this NCF (Type %s)" " structure does not comply.") % ncf)) elif (ncf_digits != 11 and ncf == 'B04') \ or (ncf_digits != 13 and ncf == 'E34'): raise UserError( _(("The number of fiscal sequence in this voucher is " "incorrect, please double check the fiscal sequence" ))) # TODO move this to l10n_do_external_validation_ncf elif (len(self.refund_reference) == 11 and invoice.journal_id.l10n_do_ncf_remote_validation and not ncf_validation.check_dgii( invoice.partner_id.vat, self.refund_reference)): raise ValidationError( _("NCF rejected by DGII\n\n" "NCF *{}* of supplier *{}* was rejected by DGII's " "validation service. Please validate if the NCF and " "the supplier RNC are type correctly. Otherwhise " "your supplier might not have this sequence approved " "yet.").format(self.refund_reference, self.partner_id.name)) return super(AccountInvoiceRefund, self).invoice_refund()