diff --git a/__init__.py b/__init__.py
index 85e7df6..415abe4 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,10 +1,7 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from trytond.pool import Pool
-from . import account
-from . import invoice
-from . import party
-from . import payment_type
+from . import account, invoice, party, company, payment_type
from .invoice import FACTURAE_SCHEMA_VERSION
__all__ = [FACTURAE_SCHEMA_VERSION]
@@ -20,8 +17,9 @@ def register():
invoice.InvoiceLine,
invoice.CreditInvoiceStart,
invoice.GenerateFacturaeStart,
- party.Party,
+ party.Address,
payment_type.PaymentType,
+ company.Company,
module='account_invoice_facturae', type_='model')
Pool.register(
invoice.CreditInvoice,
diff --git a/account.py b/account.py
index a0698e4..d529ca3 100644
--- a/account.py
+++ b/account.py
@@ -77,7 +77,7 @@ class ConfigurationFacturae(ModelSQL, CompanyValueMixin):
facturae_certificate = fields.Many2One('certificate', "Factura-e Certificate",
help='Certificate to sign Factura-e')
facturae_service = fields.Selection([
- (None, ''),
+ (None, 'Only Generate Facturae'),
], "Factura-e Service")
@staticmethod
diff --git a/company.py b/company.py
new file mode 100644
index 0000000..4964f3c
--- /dev/null
+++ b/company.py
@@ -0,0 +1,24 @@
+# The COPYRIGHT file at the top level of this repository contains the full
+# copyright notices and license terms.
+from trytond.model import fields
+from trytond.pool import PoolMeta
+
+
+class Company(metaclass=PoolMeta):
+ __name__ = 'company.company'
+
+ facturae_person_type = fields.Selection([
+ (None, ''),
+ ('J', 'Legal Entity'),
+ ('F', 'Individual'),
+ ], 'Person Type', sort=False)
+ facturae_residence_type = fields.Selection([
+ (None, ''),
+ ('R', 'Resident in Spain'),
+ ('U', 'Resident in other EU country'),
+ ('E', 'Foreigner'),
+ ], 'Residence Type', sort=False)
+ oficina_contable = fields.Char('Oficina contable')
+ organo_gestor = fields.Char('Organo gestor')
+ unidad_tramitadora = fields.Char('Unidad tramitadora')
+ organo_proponente = fields.Char('Organo proponente')
diff --git a/company.xml b/company.xml
new file mode 100644
index 0000000..89ab3fa
--- /dev/null
+++ b/company.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ company.company
+
+ company_form
+
+
+
diff --git a/invoice.py b/invoice.py
index bd9ff57..762e94a 100644
--- a/invoice.py
+++ b/invoice.py
@@ -14,9 +14,6 @@ from decimal import Decimal
from jinja2 import Environment, FileSystemLoader
from lxml import etree
from operator import attrgetter
-from tempfile import NamedTemporaryFile
-from cryptography.hazmat.primitives import serialization
-from cryptography.hazmat.primitives.serialization import pkcs12
from trytond.model import ModelView, fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval
@@ -25,6 +22,8 @@ from trytond.wizard import Wizard, StateView, StateTransition, Button
from trytond import backend
from trytond.i18n import gettext
from trytond.exceptions import UserError
+from trytond.modules.certificate_manager.certificate_manager import (
+ ENCODING_DER)
FACTURAE_SCHEMA_VERSION = '3.2.2'
@@ -319,13 +318,13 @@ class Invoice(metaclass=PoolMeta):
"Missing some tax in invoice %s" % self.id)
for field in FACe_REQUIRED_FIELDS:
- for party in [self.party, self.company.party]:
- if not getattr(party, field):
- raise UserError(gettext(
- 'account_invoice_facturae.party_facturae_fields',
- party=party.rec_name,
- invoice=self.rec_name,
- field=field))
+ if (not getattr(self.invoice_address, field)
+ or not getattr(self.company, field)):
+ raise UserError(gettext(
+ 'account_invoice_facturae.party_facturae_fields',
+ party=party.rec_name,
+ invoice=self.rec_name,
+ field=field))
if (not self.company.party.tax_identifier
or len(self.company.party.tax_identifier.code) < 3
or len(self.company.party.tax_identifier.code) > 30):
@@ -351,7 +350,7 @@ class Invoice(metaclass=PoolMeta):
'account_invoice_facturae.party_vat_identifier',
party=self.party.rec_name,
invoice=self.rec_name))
- if (self.party.facturae_person_type == 'F'
+ if (self.invoice_address.facturae_person_type == 'F'
and len(self.party.name.split(' ', 2)) < 2):
raise UserError(gettext(
'account_invoice_facturae.party_name_surname',
@@ -475,7 +474,8 @@ class Invoice(metaclass=PoolMeta):
"""
Inspired by https://github.com/pedrobaeza/l10n-spain/blob/d01d049934db55130471e284012be7c860d987eb/l10n_es_facturae/wizard/create_facturae.py
"""
- Configuration = Pool().get('account.configuration')
+ pool = Pool()
+ Configuration = pool.get('account.configuration')
if not certificate:
certificate = Configuration(1).facturae_certificate
@@ -483,34 +483,14 @@ class Invoice(metaclass=PoolMeta):
raise UserError(gettext(
'account_invoice_facturae.msg_missing_certificate'))
- certificate_facturae = certificate.pem_certificate
- certificate_password = certificate.certificate_password
-
logger = logging.getLogger('account_invoice_facturae')
- with NamedTemporaryFile(suffix='.xml', delete=False) as unsigned_file:
- unsigned_file.write(xml_string)
-
- with NamedTemporaryFile(suffix='.pfx', delete=False) as cert_file:
- cert_file.write(certificate_facturae)
-
- def _sign_file(cert, password, request):
- # get key and certificates from PCK12 file
- try:
- (
- private_key,
- certificate,
- additional_certificates,
- ) = pkcs12.load_key_and_certificates(cert, password)
- except ValueError as e:
- logger.warning("Error load_key_and_certificates file",
- exc_info=True)
- raise UserError(gettext(
- 'account_invoice_facturae.msg_certificate_error',
- error=str(e)))
+ def _sign_file(cert, request):
+ key = cert.load_pem_key()
+ pem = cert.load_pem_certificate()
# DER is an ASN.1 encoding type
- crt = certificate.public_bytes(serialization.Encoding.DER)
+ crt = pem.public_bytes(ENCODING_DER)
# Set variables values
rand_min = 1
@@ -574,10 +554,9 @@ class Invoice(metaclass=PoolMeta):
# Set the certificate values
ctx = xmlsig.SignatureContext()
- ctx.private_key = private_key
- ctx.x509 = certificate
- ctx.ca_certificates = additional_certificates
- ctx.public_key = certificate.public_key()
+ ctx.private_key = key
+ ctx.x509 = pem
+ ctx.public_key = pem.public_key()
# Set the footer validation
object_node = etree.SubElement(
@@ -632,11 +611,11 @@ class Invoice(metaclass=PoolMeta):
etree.SubElement(
issuer_serial, etree.QName(xmlsig.constants.DSigNs,
"X509IssuerName")
- ).text = xmlsig.utils.get_rdns_name(certificate.issuer.rdns)
+ ).text = xmlsig.utils.get_rdns_name(pem.issuer.rdns)
etree.SubElement(
issuer_serial, etree.QName(xmlsig.constants.DSigNs,
"X509SerialNumber")
- ).text = str(certificate.serial_number)
+ ).text = str(pem.serial_number)
signature_policy_identifier = etree.SubElement(
signed_signature_properties,
@@ -710,11 +689,7 @@ class Invoice(metaclass=PoolMeta):
return etree.tostring(root, xml_declaration=True, encoding="UTF-8")
- signed_file_content = _sign_file(
- certificate_facturae,
- certificate_password.encode(),
- xml_string,
- )
+ signed_file_content = _sign_file(certificate, xml_string)
logger.info("Factura-e for invoice %s (%s) generated and signed",
self.rec_name, self.id)
@@ -750,8 +725,8 @@ class InvoiceLine(metaclass=PoolMeta):
@property
def facturae_item_description(self):
return (
- (self.description and self.description[:2500])
- or (self.product and self.product.rec_name[:2500])
+ (self.description and self.description)
+ or (self.product and self.product.rec_name)
or '#'+str(self.id)
)
@@ -760,6 +735,34 @@ class InvoiceLine(metaclass=PoolMeta):
# TODO Issuer/ReceiverTransactionDate (sale, contract...)
return ''
+ @property
+ def facturae_start_date(self):
+ try:
+ pool = Pool()
+ Consumption = pool.get('contract.consumption')
+ except:
+ Consumption = None
+
+ if (self.origin and Consumption
+ and isinstance(self.origin, Consumption)):
+ return self.origin.start_date
+ return None
+
+ @property
+ def facturae_end_date(self):
+ try:
+ pool = Pool()
+ Consumption = pool.get('contract.consumption')
+ except:
+ Consumption = None
+
+ if (self.origin and Consumption
+ and isinstance(self.origin, Consumption)):
+ return self.origin.end_date
+ elif self.facturae_start_date:
+ return self.facturae_start_date
+ return None
+
@property
def taxes_outputs(self):
"""Return list of 'impuestos repecutidos'"""
@@ -813,17 +816,10 @@ class GenerateFacturaeStart(ModelView):
'Generate Factura-e file - Start'
__name__ = 'account.invoice.generate_facturae.start'
service = fields.Selection([
- (None, ''),
- ], 'Service')
- certificate_facturae = fields.Many2One('certificate',
- 'Certificate Factura-e',
- states={
- 'invisible': ~Bool(Eval('service')),
- }, depends=['service'])
-
- @staticmethod
- def default_service():
- return None
+ (None, 'Only generate facturae'),
+ ], 'Factura-e Service')
+ certificate = fields.Many2One('certificate',
+ 'Factura-e Certificate', depends=['service'])
class GenerateFacturae(Wizard):
@@ -836,11 +832,26 @@ class GenerateFacturae(Wizard):
])
generate = StateTransition()
+ def default_start(self, fields):
+ pool = Pool()
+ Configuration = pool.get('account.configuration')
+
+ default = {
+ 'service': None,
+ 'certificate': None,
+ }
+
+ config = Configuration(1)
+ if config.facturae_certificate:
+ default['certificate'] = config.facturae_certificate.id
+
+ return default
+
def transition_generate(self):
Invoice = Pool().get('account.invoice')
invoices = Invoice.browse(Transaction().context['active_ids'])
for invoice in invoices:
- invoice.generate_facturae(certificate=self.start.certificate_facturae,
+ invoice.generate_facturae(certificate=self.start.certificate,
service=self.start.service)
return 'end'
diff --git a/locale/ca.po b/locale/ca.po
index 8423479..a941c7d 100644
--- a/locale/ca.po
+++ b/locale/ca.po
@@ -38,17 +38,25 @@ msgctxt "field:account.invoice.credit.start,rectificative_reason_code:"
msgid "Rectificative Reason Code"
msgstr "Codi motiu rectificació"
-msgctxt "field:account.invoice.generate_facturae.start,certificate_facturae:"
-msgid "Certificate Factura-e"
-msgstr "Certificat"
+msgctxt "field:account.invoice.generate_facturae.start,service:"
+msgid "Factura-e Service"
+msgstr "Servei Factura-e"
+
+msgctxt "field:account.invoice.generate_facturae.start,certificate:"
+msgid "Factura-e Certificate"
+msgstr "Certificat Factura-e"
msgctxt "field:account.invoice.generate_facturae.start,certificate_password:"
msgid "Certificate Password"
msgstr "Contrasenya certificat"
-msgctxt "field:account.invoice.generate_facturae.start,service:"
-msgid "Service"
-msgstr "Servei"
+msgctxt "field:account.configuration,facturae_certificate:"
+msgid "Factura-e Certificate"
+msgstr "Certificat Factura-e"
+
+msgctxt "field:account.configuration,facturae_service:"
+msgid "Factura-e Service"
+msgstr "Servei Factura-e"
msgctxt "field:account.payment.type,facturae_type:"
msgid "Factura-e Type"
@@ -58,31 +66,55 @@ msgctxt "field:account.tax,report_type:"
msgid "Report Type"
msgstr "Tipus informe"
+msgctxt "field:company.company,facturae_person_type:"
+msgid "Person Type"
+msgstr "Tipus persona"
+
+msgctxt "field:company.company,facturae_residence_type:"
+msgid "Residence Type"
+msgstr "Tipus residència"
+
+msgctxt "field:company.company,oficina_contable:"
+msgid "Oficina contable"
+msgstr "Oficina contable"
+
+msgctxt "field:company.company,organo_gestor:"
+msgid "Organo gestor"
+msgstr "Organo gestor"
+
+msgctxt "field:company.company,organo_proponente:"
+msgid "Organo proponente"
+msgstr "Organo proponente"
+
+msgctxt "field:company.company,unidad_tramitadora:"
+msgid "Unidad tramitadora"
+msgstr "Unidad tramitadora"
+
msgctxt "field:account.tax.template,report_type:"
msgid "Report Type"
msgstr "Tipus informe"
-msgctxt "field:party.party,facturae_person_type:"
+msgctxt "field:party.address,facturae_person_type:"
msgid "Person Type"
msgstr "Tipus persona"
-msgctxt "field:party.party,facturae_residence_type:"
+msgctxt "field:party.address,facturae_residence_type:"
msgid "Residence Type"
msgstr "Tipus residència"
-msgctxt "field:party.party,oficina_contable:"
+msgctxt "field:party.address,oficina_contable:"
msgid "Oficina contable"
msgstr "Oficina contable"
-msgctxt "field:party.party,organo_gestor:"
+msgctxt "field:party.address,organo_gestor:"
msgid "Organo gestor"
msgstr "Organo gestor"
-msgctxt "field:party.party,organo_proponente:"
+msgctxt "field:party.address,organo_proponente:"
msgid "Organo proponente"
msgstr "Organo proponente"
-msgctxt "field:party.party,unidad_tramitadora:"
+msgctxt "field:party.address,unidad_tramitadora:"
msgid "Unidad tramitadora"
msgstr "Unidad tramitadora"
@@ -753,31 +785,43 @@ msgctxt "selection:account.tax.template,report_type:"
msgid "Value-Added Tax"
msgstr ""
-msgctxt "selection:party.party,facturae_person_type:"
-msgid ""
-msgstr " "
-
-msgctxt "selection:party.party,facturae_person_type:"
+msgctxt "selection:company.company,facturae_person_type:"
msgid "Individual"
msgstr "Persona física"
-msgctxt "selection:party.party,facturae_person_type:"
+msgctxt "selection:company.company,facturae_person_type:"
msgid "Legal Entity"
msgstr "Persona jurídica"
-msgctxt "selection:party.party,facturae_residence_type:"
-msgid ""
-msgstr " "
-
-msgctxt "selection:party.party,facturae_residence_type:"
+msgctxt "selection:company.company,facturae_residence_type:"
msgid "Foreigner"
msgstr "Estranger (Fora Unió Europea)"
-msgctxt "selection:party.party,facturae_residence_type:"
+msgctxt "selection:company.company,facturae_residence_type:"
msgid "Resident in Spain"
msgstr "Resident (a Espanya)"
-msgctxt "selection:party.party,facturae_residence_type:"
+msgctxt "selection:company.company,facturae_residence_type:"
+msgid "Resident in other EU country"
+msgstr "Resident a la Unió Europea (excepte Espanya)"
+
+msgctxt "selection:party.address,facturae_person_type:"
+msgid "Individual"
+msgstr "Persona física"
+
+msgctxt "selection:party.address,facturae_person_type:"
+msgid "Legal Entity"
+msgstr "Persona jurídica"
+
+msgctxt "selection:party.address,facturae_residence_type:"
+msgid "Foreigner"
+msgstr "Estranger (Fora Unió Europea)"
+
+msgctxt "selection:party.address,facturae_residence_type:"
+msgid "Resident in Spain"
+msgstr "Resident (a Espanya)"
+
+msgctxt "selection:party.address,facturae_residence_type:"
msgid "Resident in other EU country"
msgstr "Resident a la Unió Europea (excepte Espanya)"
@@ -807,7 +851,11 @@ msgctxt "view:account.tax:"
msgid "Factura-e"
msgstr "Factura-e"
-msgctxt "view:party.party:"
+msgctxt "view:company.company:"
+msgid "Factura-e"
+msgstr "Factura-e"
+
+msgctxt "view:party.address:"
msgid "Factura-e"
msgstr "Factura-e"
@@ -818,3 +866,11 @@ msgstr "Cancel·la"
msgctxt "wizard_button:account.invoice.generate_facturae,start,generate:"
msgid "Generate"
msgstr "Genera"
+
+msgctxt "selection:account.configuration.facturae,facturae_service:"
+msgid "Only Generate Facturae"
+msgstr "Només genera la Factura-e"
+
+msgctxt "selection:account.invoice.generate_facturae.start,service:"
+msgid "Only Generate Facturae"
+msgstr "Només genera la Factura-e"
diff --git a/locale/es.po b/locale/es.po
index 29f743b..6f70587 100644
--- a/locale/es.po
+++ b/locale/es.po
@@ -38,17 +38,25 @@ msgctxt "field:account.invoice.credit.start,rectificative_reason_code:"
msgid "Rectificative Reason Code"
msgstr "Código motivo rectificación"
-msgctxt "field:account.invoice.generate_facturae.start,certificate_facturae:"
-msgid "Certificate Factura-e"
-msgstr "Certificado Factura-e"
-
msgctxt "field:account.invoice.generate_facturae.start,certificate_password:"
msgid "Certificate Password"
msgstr "Contraseña certificado"
msgctxt "field:account.invoice.generate_facturae.start,service:"
-msgid "Service"
-msgstr "Servicio"
+msgid "Factura-e Service"
+msgstr "Servicio Factura-e"
+
+msgctxt "field:account.invoice.generate_facturae.start,certificate:"
+msgid "Factura-e Certificate"
+msgstr "Certificado Factura-e"
+
+msgctxt "field:account.configuration,facturae_certificate:"
+msgid "Factura-e Certificate"
+msgstr "Certificado Factura-e"
+
+msgctxt "field:account.configuration,facturae_service:"
+msgid "Factura-e Service"
+msgstr "Servicio Factura-e"
msgctxt "field:account.payment.type,facturae_type:"
msgid "Factura-e Type"
@@ -62,27 +70,51 @@ msgctxt "field:account.tax.template,report_type:"
msgid "Report Type"
msgstr "Tipo informe"
-msgctxt "field:party.party,facturae_person_type:"
+msgctxt "field:company.company,facturae_person_type:"
msgid "Person Type"
msgstr "Tipo persona"
-msgctxt "field:party.party,facturae_residence_type:"
+msgctxt "field:company.company,facturae_residence_type:"
msgid "Residence Type"
msgstr "Tipo residencia"
-msgctxt "field:party.party,oficina_contable:"
+msgctxt "field:company.company,oficina_contable:"
msgid "Oficina contable"
msgstr "Oficina contable"
-msgctxt "field:party.party,organo_gestor:"
+msgctxt "field:company.company,organo_gestor:"
msgid "Organo gestor"
msgstr "Organo gestor"
-msgctxt "field:party.party,organo_proponente:"
+msgctxt "field:company.company,organo_proponente:"
msgid "Organo proponente"
msgstr "Organo proponente"
-msgctxt "field:party.party,unidad_tramitadora:"
+msgctxt "field:company.company,unidad_tramitadora:"
+msgid "Unidad tramitadora"
+msgstr "Unidad tramitadora"
+
+msgctxt "field:party.address,facturae_person_type:"
+msgid "Person Type"
+msgstr "Tipo persona"
+
+msgctxt "field:party.address,facturae_residence_type:"
+msgid "Residence Type"
+msgstr "Tipo residencia"
+
+msgctxt "field:party.address,oficina_contable:"
+msgid "Oficina contable"
+msgstr "Oficina contable"
+
+msgctxt "field:party.address,organo_gestor:"
+msgid "Organo gestor"
+msgstr "Organo gestor"
+
+msgctxt "field:party.address,organo_proponente:"
+msgid "Organo proponente"
+msgstr "Organo proponente"
+
+msgctxt "field:party.address,unidad_tramitadora:"
msgid "Unidad tramitadora"
msgstr "Unidad tramitadora"
@@ -751,23 +783,43 @@ msgctxt "selection:account.tax.template,report_type:"
msgid "Value-Added Tax"
msgstr ""
-msgctxt "selection:party.party,facturae_person_type:"
+msgctxt "selection:company.company,facturae_person_type:"
msgid "Individual"
msgstr "Persona física"
-msgctxt "selection:party.party,facturae_person_type:"
+msgctxt "selection:company.company,facturae_person_type:"
msgid "Legal Entity"
msgstr "Persona jurídica"
-msgctxt "selection:party.party,facturae_residence_type:"
+msgctxt "selection:company.company,facturae_residence_type:"
msgid "Foreigner"
msgstr "Extranjero (Fuera Unión Europea)"
-msgctxt "selection:party.party,facturae_residence_type:"
+msgctxt "selection:company.company,facturae_residence_type:"
msgid "Resident in Spain"
msgstr "Residente (en España)"
-msgctxt "selection:party.party,facturae_residence_type:"
+msgctxt "selection:company.company,facturae_residence_type:"
+msgid "Resident in other EU country"
+msgstr "Residente en la Unión Europea (excepto España)"
+
+msgctxt "selection:party.address,facturae_person_type:"
+msgid "Individual"
+msgstr "Persona física"
+
+msgctxt "selection:party.address,facturae_person_type:"
+msgid "Legal Entity"
+msgstr "Persona jurídica"
+
+msgctxt "selection:party.address,facturae_residence_type:"
+msgid "Foreigner"
+msgstr "Extranjero (Fuera Unión Europea)"
+
+msgctxt "selection:party.address,facturae_residence_type:"
+msgid "Resident in Spain"
+msgstr "Residente (en España)"
+
+msgctxt "selection:party.address,facturae_residence_type:"
msgid "Resident in other EU country"
msgstr "Residente en la Unión Europea (excepto España)"
@@ -793,7 +845,11 @@ msgctxt "view:account.tax:"
msgid "Factura-e"
msgstr "Factura-e"
-msgctxt "view:party.party:"
+msgctxt "view:company.company:"
+msgid "Factura-e"
+msgstr "Factura-e"
+
+msgctxt "view:party.address:"
msgid "Factura-e"
msgstr "Factura-e"
@@ -804,3 +860,11 @@ msgstr "Cancelar"
msgctxt "wizard_button:account.invoice.generate_facturae,start,generate:"
msgid "Generate"
msgstr "Generar"
+
+msgctxt "selection:account.configuration.facturae,service:"
+msgid "Only Generate Facturae"
+msgstr "Solo genera la Factura-e"
+
+msgctxt "selection:account.invoice.generate_facturae.start,service:"
+msgid "Only Generate Facturae"
+msgstr "Solo genera la Factura-e"
diff --git a/party.py b/party.py
index 40a974a..3c9d024 100644
--- a/party.py
+++ b/party.py
@@ -1,13 +1,13 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from trytond.model import fields
-from trytond.pool import PoolMeta
-
-__all__ = ['Party']
+from trytond.pool import Pool, PoolMeta
+from trytond.transaction import Transaction
-class Party(metaclass=PoolMeta):
- __name__ = 'party.party'
+class Address(metaclass=PoolMeta):
+ __name__ = 'party.address'
+
facturae_person_type = fields.Selection([
(None, ''),
('J', 'Legal Entity'),
@@ -23,3 +23,80 @@ class Party(metaclass=PoolMeta):
organo_gestor = fields.Char('Organo gestor')
unidad_tramitadora = fields.Char('Unidad tramitadora')
organo_proponente = fields.Char('Organo proponente')
+
+ @classmethod
+ def __register__(cls, module_name):
+ pool = Pool()
+ Party = pool.get('party.party')
+ address_table = cls.__table__()
+ party_table = Party.__table__()
+ party = Party.__table_handler__()
+ cursor = Transaction().connection.cursor()
+
+ super().__register__(module_name)
+
+ # Migrat facturae fields from party to invoice addresses or in case of
+ # missing the fist address.
+ if party.column_exist('facturae_person_type'):
+ cursor.execute(*party_table.select(
+ party_table.id,
+ where=party_table.facturae_person_type != None))
+ addresses_update = []
+ for party_id in cursor.fetchall():
+ cursor.execute(*address_table.select(
+ address_table.id, address_table.invoice,
+ where=address_table.party.in_(party_id)))
+ addresses = cursor.fetchall()
+ addresses = {a[0]: a[1] for a in addresses}
+ if not addresses:
+ continue
+ if len(addresses) == 1:
+ addresses_update.append(next(iter(addresses)))
+ else:
+ for address, invoice in addresses.items():
+ if invoice:
+ addresses_update.append(address)
+ if not any(addresses.values()):
+ addresses_update.extend(addresses)
+
+ for address_update in addresses_update:
+ cursor.execute(*address_table.select(
+ address_table.party,
+ where=address_table.id == address_update))
+ party_id = cursor.fetchone()
+
+ cursor.execute(*party_table.select(
+ party_table.facturae_person_type,
+ party_table.facturae_residence_type,
+ party_table.oficina_contable,
+ party_table.organo_gestor,
+ party_table.unidad_tramitadora,
+ party_table.organo_proponente,
+ where=party_table.id == party_id))
+ party_values = cursor.fetchone()
+
+ cursor.execute(*address_table.update(
+ columns=[
+ address_table.facturae_person_type,
+ address_table.facturae_residence_type,
+ address_table.oficina_contable,
+ address_table.organo_gestor,
+ address_table.unidad_tramitadora,
+ address_table.organo_proponente
+ ],
+ values=[
+ party_values[0],
+ party_values[1],
+ party_values[2],
+ party_values[3],
+ party_values[4],
+ party_values[5],
+ ],
+ where=address_table.id == address_update))
+
+ party.drop_column('facturae_person_type')
+ party.drop_column('facturae_residence_type')
+ party.drop_column('oficina_contable')
+ party.drop_column('organo_gestor')
+ party.drop_column('unidad_tramitadora')
+ party.drop_column('organo_proponente')
diff --git a/party.xml b/party.xml
index ddc1806..05dbf51 100644
--- a/party.xml
+++ b/party.xml
@@ -3,10 +3,10 @@
copyright notices and license terms. -->
-
- party.party
-
- party_form
+
+ party.address
+
+ address_form
diff --git a/template_facturae_3.2.2.xml b/template_facturae_3.2.2.xml
index 2570764..1b24574 100644
--- a/template_facturae_3.2.2.xml
+++ b/template_facturae_3.2.2.xml
@@ -38,20 +38,20 @@
- {{ invoice.company.party.facturae_person_type }}
- {{ invoice.company.party.facturae_residence_type }}
+ {{ invoice.company.facturae_person_type }}
+ {{ invoice.company.facturae_residence_type }}
{{ invoice.company.party.tax_identifier.code[:30] }}
{# Optional. It could be the ID or the code #}
{% if invoice.company.party.code and invoice.company.party.code | length < 10 %}
{{ invoice.company.party.code|int or invoice.company.party.id }}
{% endif %}
- {% if invoice.company.party.oficina_contable or invoice.company.party.organo_gestor or invoice.company.party.unidad_tramitadora or invoice.company.party.organo_proponente %}
+ {% if invoice.company.oficina_contable or invoice.company.organo_gestor or invoice.company.unidad_tramitadora or invoice.company.organo_proponente %}
- {% if invoice.company.party.oficina_contable %}{{ administrative_center(invoice.company.party.oficina_contable, '01', invoice.company.party) }}{% endif %}
- {% if invoice.company.party.organo_gestor %}{{ administrative_center(invoice.company.party.organo_gestor, '02', invoice.company.party) }}{% endif %}
- {% if invoice.company.party.unidad_tramitadora %}{{ administrative_center(invoice.company.party.unidad_tramitadora, '03', invoice.company.party) }}{% endif %}
- {% if invoice.company.party.organo_proponente %}{{ administrative_center(invoice.company.party.organo_proponente, '04', invoice.company.party) }}{% endif %}
+ {% if invoice.company.oficina_contable %}{{ administrative_center(invoice.company.oficina_contable, '01', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
+ {% if invoice.company.organo_gestor %}{{ administrative_center(invoice.company.organo_gestor, '02', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
+ {% if invoice.company.unidad_tramitadora %}{{ administrative_center(invoice.company.unidad_tramitadora, '03', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
+ {% if invoice.company.organo_proponente %}{{ administrative_center(invoice.company.organo_proponente, '04', invoice.company.facturae_person_type, invoice.company.party.address_get('invoice')) }}{% endif %}
{% endif %}
@@ -73,23 +73,23 @@
- {{ invoice.party.facturae_person_type }}
- {{ invoice.party.facturae_residence_type }}
+ {{ invoice.invoice_address.facturae_person_type }}
+ {{ invoice.invoice_address.facturae_residence_type }}
{{ invoice.party.tax_identifier.code[:30] }}
{# Optional. It could be the ID or the code #}
{% if invoice.party.code and invoice.party.code | length < 10 %}
{{ invoice.party.code|int or invoice.party.id }}
{% endif %}
- {% if invoice.party.oficina_contable or invoice.party.organo_gestor or invoice.party.unidad_tramitadora or invoice.party.organo_proponente %}
+ {% if invoice.invoice_address.oficina_contable or invoice.invoice_address.organo_gestor or invoice.invoice_address.unidad_tramitadora or invoice.invoice_address.organo_proponente %}
- {% if invoice.party.oficina_contable %}{{ administrative_center(invoice.party.oficina_contable, '01', invoice.party) }}{% endif %}
- {% if invoice.party.organo_gestor %}{{ administrative_center(invoice.party.organo_gestor, '02', invoice.party) }}{% endif %}
- {% if invoice.party.unidad_tramitadora %}{{ administrative_center(invoice.party.unidad_tramitadora, '03', invoice.party) }}{% endif %}
- {% if invoice.party.organo_proponente %}{{ administrative_center(invoice.party.organo_proponente, '04', invoice.party) }}{% endif %}
+ {% if invoice.invoice_address.oficina_contable %}{{ administrative_center(invoice.invoice_address.oficina_contable, '01', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
+ {% if invoice.invoice_address.organo_gestor %}{{ administrative_center(invoice.invoice_address.organo_gestor, '02', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
+ {% if invoice.invoice_address.unidad_tramitadora %}{{ administrative_center(invoice.invoice_address.unidad_tramitadora, '03', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
+ {% if invoice.invoice_address.organo_proponente %}{{ administrative_center(invoice.invoice_address.organo_proponente, '04', invoice.invoice_address.facturae_person_type, invoice.invoice_address) }}{% endif %}
{% endif %}
- {% if invoice.party.facturae_person_type == 'J' %}
+ {% if invoice.invoice_address.facturae_person_type == 'J' %}
{{ invoice.party.name and invoice.party.name[:80] or invoice.party.code[:80] }}
{% if invoice.party.trade_name %}
@@ -162,7 +162,7 @@
{% if invoice.currency != euro %}
{{ Invoice.double_up_to_eight(exchange_rate) }}
- {{ exchange_rate_date }}
+ {% if exchange_rate_date %}{{ exchange_rate_date.isoformat() }}{% endif %}
{% endif %}
EUR
@@ -255,7 +255,7 @@
- Extensions
#}
{{ line.facturae_receiver_transaction_reference }}
- {{ line.facturae_item_description }}
+ {{ line.facturae_item_description[:2500] }}
{{ line.quantity }}
{{ UOM_CODE2TYPE.get(line.unit.symbol, '05') if line.unit else '05' }}
{{ Invoice.double_up_to_eight(line.unit_price) }}
@@ -321,10 +321,10 @@
{% endfor %}
- {% if line.origin and line.origin.contract %}
+ {% if line.facturae_start_date %}
- {{ line.origin.start_date }}
- {{ line.origin.end_date }}
+ {{ line.facturae_start_date.isoformat() }}
+ {{ line.facturae_end_date.isoformat() }}
{% endif %}
{% if line.taxes_additional_line_item_information or line.note %}
diff --git a/template_facturae_macros.xml b/template_facturae_macros.xml
index fa9964c..341d557 100644
--- a/template_facturae_macros.xml
+++ b/template_facturae_macros.xml
@@ -1,19 +1,19 @@
-{% macro administrative_center(centre_code, role_type_code, party) %}
+{% macro administrative_center(centre_code, role_type_code, person_type, addrs) %}
{{ centre_code }}
{{ role_type_code }}
- {% if party.facturae_person_type == 'J' %}{{ party.name and party.name[:40] }}{% else %}{{ party.name and party.name.split(' ', 2)[0][:40] or party.code[:40] }}{% endif %}
- {% if party.facturae_person_type == 'F' %}
- {{ party.name and party.name.split(' ', 2)[1][:40] }}
+ {% if person_type == 'J' %}{{ addrs.party.name and addrs.party.name[:40] }}{% else %}{{ addrs.party.name and addrs.party.name.split(' ', 2)[0][:40] or addrs.party.code[:40] }}{% endif %}
+ {% if person_type == 'F' %}
+ {{ addrs.party.name and addrs.party.name.split(' ', 2)[1][:40] }}
{% endif %}
- {% if party.facturae_person_type == 'F' and party.name.split(' ') | length > 2 %}
- {{ party.name and party.name.split(' ', 2)[2][:40] }}
+ {% if person_type == 'F' and addrs.party.name.split(' ') | length > 2 %}
+ {{ addrs.party.name and addrs.party.name.split(' ', 2)[2][:40] }}
{% endif %}
- {% if party.addresses %}{{ address(party.addresses[0]) }}{% endif %}
- {% if party.contact_mechanisms %}{{ contact(party) }}{% endif %}
+ {% if addrs %}{{ address(addrs) }}{% endif %}
+ {% if addrs.party.contact_mechanisms %}{{ contact(addrs.party) }}{% endif %}
- {{ party.name and party.name.split(' ', 2)[0][:40] or party.code[:40] }}
+ {{ addrs.party.name and addrs.party.name.split(' ', 2)[0][:40] or addrs.party.code[:40] }}
{% endmacro %}
diff --git a/tests/test_module.py b/tests/test_module.py
index fd85cf7..54f530a 100644
--- a/tests/test_module.py
+++ b/tests/test_module.py
@@ -58,8 +58,8 @@ class AccountInvoiceFacturaeTestCase(CompanyTestMixin, ModuleTestCase):
company.header = 'Report Header'
company.party.name = 'Seller'
company.party.identifiers = [tax_identifier]
- company.party.facturae_person_type = 'J'
- company.party.facturae_residence_type = 'R'
+ company.facturae_person_type = 'J'
+ company.facturae_residence_type = 'R'
company.party.save()
company.save()
@@ -108,8 +108,6 @@ class AccountInvoiceFacturaeTestCase(CompanyTestMixin, ModuleTestCase):
company_address.country = country
company_address.save()
party = Party(name='Buyer')
- party.facturae_person_type = 'J'
- party.facturae_residence_type = 'R'
tax_identifier = PartyIdentifier()
tax_identifier.type = 'eu_vat'
tax_identifier.code = 'BE0897290877'
@@ -123,6 +121,8 @@ class AccountInvoiceFacturaeTestCase(CompanyTestMixin, ModuleTestCase):
'postal_code': '08201',
'subdivision': subdivision.id,
'country': country.id,
+ 'address.facturae_person_type': 'J',
+ 'address.facturae_residence_type': 'R',
}
address, = Address.create([address_dict])
diff --git a/tryton.cfg b/tryton.cfg
index c229770..fca33e2 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -8,10 +8,12 @@ depends:
extras_depend:
account_bank
account_es
+ contract
xml:
account.xml
+ account_es.xml
+ company.xml
invoice.xml
party.xml
payment_type.xml
- account_es.xml
message.xml
diff --git a/view/party_form.xml b/view/address_form.xml
similarity index 91%
rename from view/party_form.xml
rename to view/address_form.xml
index 05ac85b..0f2fab7 100644
--- a/view/party_form.xml
+++ b/view/address_form.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/view/company_form.xml b/view/company_form.xml
new file mode 100644
index 0000000..0f2fab7
--- /dev/null
+++ b/view/company_form.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/generate_facturae_start_form.xml b/view/generate_facturae_start_form.xml
index c0696d4..8a90e8d 100644
--- a/view/generate_facturae_start_form.xml
+++ b/view/generate_facturae_start_form.xml
@@ -10,7 +10,7 @@
yalign="0.0" xalign="0.0" xexpand="1"/>
-
-
+
+