TIP: You can type at any time to perform a new search.
Paraguay - Electronic Invoicing Base
l10n_py_edi_base · OCA/l10n-paraguay
- Repository
- OCA/l10n-paraguay · module folder · Try on Runboat
- Module version
- 1.0.0
- Category
- Accounting/Localizations/EDI
- Folder size
- 0.43 MB
- License
- LGPL-3
- Application
- No
- Auto-installable
- No
- Website
- https://github.com/OCA/l10n-paraguay
- Last tracking update
- 2026-08-07 08:42:53
- Authors
- Odoo Community Association (OCA), KMEE
- Maintainers
- Odoo Community Association (OCA), KMEE
- Committers
- OCA-git-bot, oca-ci, André Marcos Ferreira
- Odoo dependencies
- Python dependencies
- cryptography, pykude, qrcode, requests, python-stdnum, num2words
- System dependencies
- None
- Required by
- l10n_py_edi_sifen
- Description
# Paraguay - Electronic Invoicing Base This module provides the base functionality for electronic invoicing (facturación electrónica) in Paraguay, compliant with SET (Subsecretaría de Estado de Tributación) requirements. ## Features ### Document Types Support - **Factura Electrónica**: Electronic invoice - **Nota de Crédito Electrónica**: Electronic credit note - **Nota de Débito Electrónica**: Electronic debit note - **Nota de Remisión Electrónica**: Electronic delivery note - **Autofactura Electrónica**: Electronic self-invoice ### Core Functionality - **Data Models**: Complete models for electronic documents - **Field Extensions**: Enhanced account.move, res.partner, and res.company - **Fiscal Validation**: RUC and DV validation - **JSON Builder**: Automatic generation of JSON for SIFEN - **QR Code Generation**: Ready for KUDE (Código Único de Documento Electrónico) - **Log System**: Complete audit trail of EDI operations ### Compliance - **SIFEN Compatible**: Sistema Integrado de Facturación Electrónica Nacional - **SET Requirements**: Meets all SET regulatory requirements - **Contingency Mode**: Support for offline operation - **KUDE Support**: Ready for electronic document codes ### Integration Ready This is a base module that requires a connector: - `l10n_py_edi_factpy`: FactPy integration - `l10n_py_edi_facturasend`: FacturaSend integration ## Technical Architecture - **Provider-agnostic**: Works with multiple EDI providers - **Extensible**: Easy to add new document types - **Robust**: Error handling and retry mechanisms - **Auditable**: Complete logging of all operations ## Dependencies - `account`: Core accounting - `l10n_py_base`: Base Paraguayan localization - `l10n_py_account`: Accounting extensions (timbrado management) - `product`: Product management - `sale`: Sales management
Code Analysis ⓘ
Views touched (15)
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
kude_report_template |
kude_report_template | ir.ui.view | qweb | New |
view_account_move_send_edi_wizard |
account.move.send.edi.wizard.form | account.move.send.edi.wizard | form | New |
view_company_form_edi |
res.company.form.edi | res.company | form | Inherits base.view_company_form |
view_edi_connector_form |
l10n_py.edi.connector.form | l10n_py.edi.connector | form | New |
view_edi_connector_tree |
l10n_py.edi.connector.tree | l10n_py.edi.connector | list | New |
view_l10n_py_associated_document_tree |
l10n_py.associated.document.tree | l10n_py.associated.document | list | New |
view_l10n_py_edi_cancel_wizard |
l10n_py.edi.cancel.wizard.form | l10n_py.edi.cancel.wizard | form | New |
view_l10n_py_edi_log_form |
l10n_py.edi.log.form | l10n_py.edi.log | form | New |
view_l10n_py_edi_log_tree |
l10n_py.edi.log.tree | l10n_py.edi.log | list | New |
view_l10n_py_number_inutilization_form |
l10n_py.number.inutilization.form | l10n_py.number.inutilization | form | New |
view_l10n_py_number_inutilization_tree |
l10n_py.number.inutilization.tree | l10n_py.number.inutilization | list | New |
view_l10n_py_transport_form |
l10n_py.transport.form | l10n_py.transport | form | New |
view_l10n_py_transport_tree |
l10n_py.transport.tree | l10n_py.transport | list | New |
view_move_form_edi |
account.move.form.edi | account.move | form | Inherits account.view_move_form |
view_product_template_form_edi |
product.template.form.edi | product.template | form | Inherits product.product_template_form_view |
HTTP endpoints (0)
No HTTP endpoints found for this module.
Models touched (14)
New fields (39)
-
l10n_py_afe_constancia_controlCharsize=20string='Número de Control (EA005)' -
l10n_py_afe_constancia_numberCharsize=20string='Número de Constancia (EA004)' -
l10n_py_afe_constancia_typeSelectionstring='Tipo de Constancia (EA002)' args: [('1', 'No contribuyente'), ('2', 'Microproductor')] -
l10n_py_afe_provision_addressCharstring='Dirección Provisión (EA018)' -
l10n_py_afe_provision_cityIntegerstring='Ciudad Provisión (EA023)' -
l10n_py_afe_provision_departmentIntegerstring='Departamento Provisión (EA019)' -
l10n_py_afe_provision_districtIntegerstring='Distrito Provisión (EA021)' -
l10n_py_afe_vendor_addressCharstring='Dirección Vendedor (EA010)' -
l10n_py_afe_vendor_cityIntegerstring='Ciudad Vendedor (EA016)' -
l10n_py_afe_vendor_departmentIntegerstring='Departamento Vendedor (EA012)' -
l10n_py_afe_vendor_districtIntegerstring='Distrito Vendedor (EA014)' -
l10n_py_afe_vendor_doc_numberCharsize=20string='Nro. Doc. Vendedor (EA008)' -
l10n_py_afe_vendor_doc_typeSelectionstring='Tipo Doc. Vendedor (EA006)' args: [('1', 'Cédula paraguaya'), ('2', 'Pasaporte'), ('3', 'Cédula extranjera'), ('4', 'Carnet de residencia')] -
l10n_py_afe_vendor_houseIntegerstring='Nro. Casa Vendedor (EA011)' -
l10n_py_afe_vendor_nameCharstring='Nombre Vendedor (EA009)' -
l10n_py_associated_document_idsOne2many → l10n_py.associated.documenthelp='Documentos asociados al DTE (Grupo H del SIFEN)'string='Documentos Asociados' args: 'l10n_py.associated.document', 'move_id' -
l10n_py_cdcCharcopy=Falsehelp='Código de Control del documento electrónico'readonly=True args: 'CDC' -
l10n_py_contingency_motiveCharargs: 'Motivo de Contingencia' -
l10n_py_doc_type_codeCharcompute='_compute_l10n_py_doc_type_code' -
l10n_py_edi_batch_idCharcopy=Falsereadonly=True args: 'ID de Lote' -
l10n_py_edi_messageTextcopy=Falsereadonly=True args: 'Mensaje EDI' -
l10n_py_edi_statusSelectioncopy=Falsedefault='draft'readonly=Truestring='Estado EDI' args: [('draft', 'Borrador'), ('to_send', 'Para Enviar'), ('sent', 'Enviado'), ('processing', 'Procesando'), ('accepted', 'Aceptado'), ('rejected', 'Rechazado'), ('cancelled', 'Cancelado'), ('error', 'Error')] -
l10n_py_edi_xmlBinarycopy=Falsereadonly=True args: 'XML Firmado' -
l10n_py_edi_xml_filenameCharreadonly=True args: 'XML Filename' -
l10n_py_emission_typeSelectiondefault='1'required=Truestring='Tipo de Emisión' args: [('1', 'Normal'), ('2', 'Contingencia')] -
l10n_py_exchange_rate_conditionSelectiondefault='1'help='Condición del tipo de cambio (D015)'string='Condición Tipo de Cambio' args: [('1', 'Global'), ('2', 'Por Ítem')] -
l10n_py_kude_filenameCharreadonly=True args: 'KUDE Filename' -
l10n_py_kude_pdfBinarycopy=Falsereadonly=True args: 'KUDE (PDF)' -
l10n_py_nre_estimated_invoice_dateDatehelp='Fecha estimada de facturación para NRE sin factura asociada'string='Fecha Estimada de Facturación (E506)' -
l10n_py_nre_motiveSelectionstring='Motivo de Remisión (E501)' args: [('1', 'Traslado por venta'), ('2', 'Traslado por consignación'), ('3', 'Traslado por exportación'), ('4', 'Traslado por importación'), ('5', 'Traslado entre locales'), ('6', 'Otros')] -
l10n_py_payment_typeSelectiondefault='1'help='Tipo de pago para condición contado (E606)'string='Tipo de Pago' args: [('1', 'Efectivo'), ('2', 'Cheque'), ('3', 'Tarjeta de crédito'), ('4', 'Tarjeta de débito'), ('5', 'Transferencia'), ('6', 'Giro'), ('7', 'Billetera electrónica'), ('8', 'Tarjeta empresarial'), ('9', 'Vale'), ('10', 'Retención'), ('11', 'Anticipo'), ('12', 'Valor fiscal'), ('13', 'Valor comercial'), ('14', 'Compensación'), ('15', 'Permuta'), ('16', 'Pago bancario')] -
l10n_py_presence_typeSelectiondefault='1'string='Tipo de Presencia' args: [('1', 'Operación presencial'), ('2', 'Operación electrónica'), ('3', 'Operación telemarketing'), ('4', 'Venta a domicilio'), ('5', 'Operación bancaria')] -
l10n_py_qr_codeBinarycopy=Falsereadonly=True args: 'Código QR' -
l10n_py_qr_stringCharcopy=Falsereadonly=True args: 'String QR' -
l10n_py_receipt_idCharhelp='ID único del sistema cliente' args: 'Receipt ID' -
l10n_py_security_codeCharcopy=Falsereadonly=Truesize=9 args: 'Código de Seguridad' -
l10n_py_transaction_typeSelectiondefault='1'required=Truestring='Tipo de Transacción' args: [('1', 'Venta de mercadería'), ('2', 'Prestación de servicios'), ('3', 'Mixto (Venta de mercadería y servicios)'), ('4', 'Venta de activo fijo'), ('5', 'Venta de divisas'), ('6', 'Compra de divisas'), ('7', 'Promoción o entrega de muestras'), ('8', 'Donación'), ('9', 'Anticipo'), ('10', 'Compra de productos'), ('11', 'Compra de servicios'), ('12', 'Venta de crédito fiscal'), ('13', 'Compra de crédito fiscal')] -
l10n_py_transmission_deadlineDatetimecompute='_compute_transmission_deadline'help='Plazo máximo para transmitir el DTE (72 horas desde emisión)'store=Truestring='Plazo de Transmisión' -
l10n_py_transport_idMany2one → l10n_py.transporthelp='Datos de transporte para Nota de Remisión (Grupo G SIFEN)'string='Datos de Transporte' args: 'l10n_py.transport'
-
action_cancel_edi(self)Cancelar documento electrónico -
action_download_kude(self)Descargar KUDE (PDF) -
action_download_xml(self)Descargar XML del documento -
action_l10n_py_preview_qr(self)Genera CDC + QR (firma local) SIN transmitir, para previsualizar. Útil para verificar el QR/KuDE en pruebas. El CDC generado es de previsualización; la emisión real lo regenera al transmitir. -
action_post(self)Override para configurar estado EDI al confirmar factura. -
action_preview_kude(self)Generar KuDE (PDF) a partir del XML preview via pykude. -
action_preview_xml(self)Generar y mostrar XML sin firmar ni enviar (preview). -
action_retry_edi(self)Reintentar envío de documento -
action_send_edi(self)Enviar documento a sistema EDI
New fields (1)
-
invoice_idMany2one → account.moverequired=Truestring='Factura' args: 'account.move'
-
action_send(self)Enviar factura a EDI -
default_get(self, fields_list)@api.model
New fields (11)
-
association_typeSelectionrequired=Truestring='Tipo de Asociación (H002)' args: [('1', 'Electrónico'), ('2', 'Impreso'), ('3', 'Constancia Electrónica')] -
cdcCharhelp='Código de Control del Documento Electrónico (44 dígitos)'size=44string='CDC' -
constancia_numberCharsize=20string='Número de Constancia (H012)' -
constancia_typeSelectionstring='Tipo de Constancia (H011)' args: [('1', 'Constancia de no ser contribuyente'), ('2', 'Constancia de microproductor')] -
doc_dateDatestring='Fecha del Documento (H010)' -
doc_numberCharhelp='Número del documento (H008)'size=7string='Número de Documento' -
doc_type_codeSelectionstring='Tipo de Documento Impreso (H009)' args: [('1', 'Factura'), ('2', 'Nota de crédito'), ('3', 'Nota de débito'), ('4', 'Nota de remisión'), ('5', 'Comprobante de retención')] -
establishmentCharhelp='Código de establecimiento (H006)'size=3string='Establecimiento' -
expedition_pointCharhelp='Punto de expedición (H007)'size=3string='Punto de Expedición' -
move_idMany2one → account.moveindex=Trueondelete='cascade'required=Truestring='Factura' args: 'account.move' -
timbradoCharhelp='Número de timbrado del documento impreso (H005)'size=8
No public methods.
New fields (2)
-
invoice_idMany2one → account.moverequired=Truestring='Factura' args: 'account.move' -
motiveTextrequired=Truestring='Motivo de Cancelación'
-
action_cancel(self)Cancelar documento EDI con verificación de plazos. -
default_get(self, fields_list)@api.model
New fields (6)
-
activeBooleandefault=True -
company_idMany2one → res.companydefault=<expr>required=True args: 'res.company' -
environmentSelectiondefault='test'required=True args: [('test', 'Pruebas'), ('prod', 'Producción')] -
nameCharrequired=True -
provider_typeSelectionrequired=Trueselection=[]string='Proveedor' -
timeoutIntegerdefault=30
-
cancel_document(self, document_id, reason='')Cancel an approved document. -
check_status(self, document_id)Check document status. -
inutilize_range(self, data)Inutilize a range of document numbers. Returns dict. -
preview_document(self, invoice_data)Build XML without signing or sending. Returns XML string. -
preview_qr(self, invoice_data)Build CDC + dCarQR without transmitting. Returns {cdc, qr}. -
send_document(self, invoice_data)Send document. Returns dict with success, result, error keys. -
test_connection(self)Test connectivity. Returns notification action.
New fields (3)
-
codeCharrequired=Truesize=2string='Código' -
descriptionTextstring='Descripción'translate=True -
nameCharrequired=Truestring='Nombre'translate=True
No public methods.
New fields (19)
-
batch_idCharhelp='Identificador de lote do provedor'string='ID do Lote' -
cdcCharhelp='Código de Control del documento'index=Truestring='CDC' -
document_idMany2one → account.movehelp='Documento fiscal relacionado'index=Trueondelete='cascade'string='Documento' args: 'account.move' -
duration_humanCharcompute='_compute_duration_human'help='Duração em formato legível'string='Duração' -
endpointCharhelp='URL ou endpoint da API' -
errorBooleancompute='_compute_error'help='Indica se houve erro na operação'store=Truestring='É Erro' -
error_codeCharhelp='Código de erro do provedor'string='Código de Erro' -
error_messageTexthelp='Descrição do erro se houver'string='Mensagem de Erro' -
execution_timeFloatdigits=(10, 2)help='Tempo de execução em milissegundos'string='Tempo de Execução (ms)' -
methodSelectionstring='Método HTTP' args: [('GET', 'GET'), ('POST', 'POST'), ('PUT', 'PUT'), ('DELETE', 'DELETE'), ('PATCH', 'PATCH')] -
operation_typeSelectionindex=Truerequired=Truestring='Tipo de Operação' args: [('send', 'Envio de Documento'), ('status', 'Consulta de Status'), ('cancel', 'Cancelación'), ('event', 'Evento'), ('download_pdf', 'Download PDF'), ('download_xml', 'Download XML'), ('validate', 'Validação')] -
providerSelectionindex=Truerequired=Truestring='Provedor' args: [('factpy', 'FactPy'), ('facturasend', 'FacturaSend'), ('sifen', 'SIFEN Directo'), ('local', 'Processamento Local')] -
request_dataTexthelp='Payload da requisição'string='Dados Enviados' -
request_headersTexthelp='Headers HTTP enviados'string='Headers da Requisição' -
response_dataTexthelp='Payload da resposta'string='Resposta Recebida' -
response_headersTexthelp='Headers HTTP recebidos'string='Headers da Resposta' -
retry_countIntegerdefault=0help='Número de tentativas realizadas'string='Tentativas' -
status_codeIntegerhelp='Código de status HTTP'string='Código de Status' -
successBooleandefault=Truehelp='Indica se a operação foi bem-sucedida'index=Truestring='Sucesso'
-
action_retry_operation(self)Repetir operação (se aplicável) -
action_view_document(self)Abrir documento relacionado -
action_view_request_data(self)Exibir dados da requisição em formato legível -
action_view_response_data(self)Exibir dados da resposta em formato legível -
log_operation(self, operation_type, provider, document=None, request_data=None, response_data=None, execution_time=0, success=True, error_message=None, **kwargs)@api.modelRegistrar operação EDI Args: operation_type (str): Tipo de operação provider (str): Provedor EDI document (account.move): Documento relacionado request_data (dict): Dados da requisição response_data (dict): Dados da resposta execution_time (float): Tempo de execução em ms success (bool): Se a operação foi bem-sucedida error_message (str): Mensagem de erro (se houver) **kwargs: Campos adicionais Returns: l10n_py.edi.log: Registro de log criado
New fields (0)
No new fields.
Public methods (1)-
log_edi_operation(self, operation_type, provider, document=None, **kwargs)@contextmanagerContext manager para logging automático de operações EDI Usage: with self.log_edi_operation('send', 'factpy', document) as log_data: result = self.send_to_provider(data) log_data['response_data'] = result Args: operation_type (str): Tipo de operação provider (str): Provedor EDI document (account.move): Documento relacionado **kwargs: Dados adicionais para o log Yields: dict: Dicionário para adicionar dados durante a operação
New fields (7)
-
authorization_idMany2one → account.authorizationondelete='restrict'required=Truestring='Timbrado' args: 'account.authorization' -
company_idMany2onerelated='authorization_id.company_id'store=True -
motiveTextrequired=Truestring='Motivo' -
number_fromIntegerrequired=Truestring='Número Desde' -
number_toIntegerrequired=Truestring='Número Hasta' -
quantityIntegercompute='_compute_quantity'string='Cantidad' -
stateSelectiondefault='draft'readonly=Truestring='Estado' args: [('draft', 'Borrador'), ('sent', 'Enviado'), ('accepted', 'Aceptado'), ('rejected', 'Rechazado')]
-
action_send(self)Enviar inutilización al SIFEN a través del conector EDI.
New fields (22)
-
company_idMany2onerelated='move_id.company_id'store=True -
delivery_idsOne2many → l10n_py.transport.deliverystring='Entregas' args: 'l10n_py.transport.delivery', 'transport_id' -
departure_addressCharstring='Dirección de Salida (E920)' -
departure_cityIntegerstring='Ciudad Salida (E928)' -
departure_departmentIntegerstring='Departamento Salida (E924)' -
departure_districtIntegerstring='Distrito Salida (E926)' -
departure_houseIntegerstring='Número de Casa Salida (E921)' -
driver_doc_numberCharstring='Doc. del Chofer (E950)' -
driver_nameCharstring='Nombre del Chofer (E951)' -
freight_responsibilitySelectionstring='Responsable del Flete (E905)' args: [('1', 'Emisor de la Factura Electrónica'), ('2', 'Receptor de la Factura Electrónica'), ('3', 'Tercero'), ('4', 'Agente intermediario del transporte')] -
incotermSelectionstring='Condición de Negociación (E906)' args: [('CFR', 'CFR'), ('CIF', 'CIF'), ('CIP', 'CIP'), ('CPT', 'CPT'), ('DAP', 'DAP'), ('DAT', 'DAT'), ('DDP', 'DDP'), ('EXW', 'EXW'), ('FAS', 'FAS'), ('FCA', 'FCA'), ('FOB', 'FOB')] -
manifest_numberCharstring='Número de Manifiesto / Conocimiento (E907)' -
move_idMany2one → account.moveondelete='cascade'required=Truestring='Documento' args: 'account.move' -
transport_end_dateDatestring='Fecha Fin Transporte (E910)' -
transport_modeSelectiondefault='1'required=Truestring='Modalidad de Transporte (E901)' args: [('1', 'Terrestre'), ('2', 'Fluvial'), ('3', 'Aéreo'), ('4', 'Multimodal')] -
transport_start_dateDatestring='Fecha Inicio Transporte (E909)' -
transport_typeSelectionstring='Tipo de Transporte (E903)' args: [('1', 'Propio'), ('2', 'Tercero')] -
transporter_dvCharsize=1string='DV del Transportista (E943)' -
transporter_nameCharstring='Nombre del Transportista (E941)' -
transporter_natureSelectionstring='Naturaleza del Transportista (E940)' args: [('1', 'Contribuyente'), ('2', 'No contribuyente')] -
transporter_rucCharstring='RUC del Transportista (E942)' -
vehicle_idsOne2many → l10n_py.transport.vehiclestring='Vehículos' args: 'l10n_py.transport.vehicle', 'transport_id'
No public methods.
New fields (6)
-
addressCharrequired=Truestring='Dirección de Entrega (E930)' -
cityIntegerrequired=Truestring='Ciudad (E938)' -
departmentIntegerrequired=Truestring='Departamento (E934)' -
districtIntegerstring='Distrito (E936)' -
house_numberIntegerstring='Número de Casa (E931)' -
transport_idMany2one → l10n_py.transportondelete='cascade'required=Truestring='Transporte' args: 'l10n_py.transport'
No public methods.
New fields (4)
-
brandCharrequired=Truestring='Marca (E961)' -
plate_numberCharrequired=Truestring='Número de Identificación (E962)' -
transport_idMany2one → l10n_py.transportondelete='cascade'required=Truestring='Transporte' args: 'l10n_py.transport' -
vehicle_typeCharrequired=Truestring='Tipo de Vehículo (E960)'
No public methods.
New fields (2)
-
l10n_py_ncm_codeCharhelp='Nomenclatura Común del Mercosur (8 dígitos)'size=8string='Código NCM' -
l10n_py_unit_codeIntegerdefault=77help='Código de unidad de medida según SET (77 = UNI - Unidad)'string='Código Unidad de Medida'
No public methods.
New fields (9)
-
l10n_py_city_codeCharhelp='Código de la ciudad según SET'readonly=Truerelated='partner_id.l10n_py_city_code'store=Truestring='Código Ciudad SET' -
l10n_py_department_codeIntegerhelp='Código del departamento según SET'readonly=Truerelated='partner_id.l10n_py_department_code'store=Truestring='Código Departamento SET' -
l10n_py_district_codeIntegerhelp='Código del distrito según SET'string='Código Distrito SET' -
l10n_py_dvCharcompute='_compute_dv'help='Dígito Verificador del RUC'size=1store=Truestring='DV' -
l10n_py_economic_activityCharhelp='Descripción de la actividad económica principal'string='Descripción Actividad Económica' -
l10n_py_economic_activity_codeCharhelp='Código de actividad económica principal según SET'size=8string='Código Actividad Económica' -
l10n_py_rucCharhelp='Registro Único del Contribuyente sin dígito verificador'size=8string='RUC' -
l10n_py_ruc_fullCharcompute='_compute_ruc_full'help='RUC con dígito verificador'store=Truestring='RUC Completo' -
l10n_py_trade_nameCharhelp='Nombre comercial o de fantasía de la empresa'string='Nombre Fantasía'
No public methods.
Loading…