allow to have more than one Facturae deffinition per party. Moving the
fields from party model to address. For the company move from party to company model. Update the way that the certificate to sign xml is used, based with the way that the certificats are all load the same way.
This commit is contained in:
parent
a235054bc4
commit
a376c04bce
|
@ -1,10 +1,7 @@
|
||||||
# The COPYRIGHT file at the top level of this repository contains the full
|
# The COPYRIGHT file at the top level of this repository contains the full
|
||||||
# copyright notices and license terms.
|
# copyright notices and license terms.
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from . import account
|
from . import account, invoice, party, company, payment_type
|
||||||
from . import invoice
|
|
||||||
from . import party
|
|
||||||
from . import payment_type
|
|
||||||
from .invoice import FACTURAE_SCHEMA_VERSION
|
from .invoice import FACTURAE_SCHEMA_VERSION
|
||||||
|
|
||||||
__all__ = [FACTURAE_SCHEMA_VERSION]
|
__all__ = [FACTURAE_SCHEMA_VERSION]
|
||||||
|
@ -20,8 +17,9 @@ def register():
|
||||||
invoice.InvoiceLine,
|
invoice.InvoiceLine,
|
||||||
invoice.CreditInvoiceStart,
|
invoice.CreditInvoiceStart,
|
||||||
invoice.GenerateFacturaeStart,
|
invoice.GenerateFacturaeStart,
|
||||||
party.Party,
|
party.Address,
|
||||||
payment_type.PaymentType,
|
payment_type.PaymentType,
|
||||||
|
company.Company,
|
||||||
module='account_invoice_facturae', type_='model')
|
module='account_invoice_facturae', type_='model')
|
||||||
Pool.register(
|
Pool.register(
|
||||||
invoice.CreditInvoice,
|
invoice.CreditInvoice,
|
||||||
|
|
|
@ -77,7 +77,7 @@ class ConfigurationFacturae(ModelSQL, CompanyValueMixin):
|
||||||
facturae_certificate = fields.Many2One('certificate', "Factura-e Certificate",
|
facturae_certificate = fields.Many2One('certificate', "Factura-e Certificate",
|
||||||
help='Certificate to sign Factura-e')
|
help='Certificate to sign Factura-e')
|
||||||
facturae_service = fields.Selection([
|
facturae_service = fields.Selection([
|
||||||
(None, ''),
|
(None, 'Only Generate Facturae'),
|
||||||
], "Factura-e Service")
|
], "Factura-e Service")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -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')
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||||
|
copyright notices and license terms. -->
|
||||||
|
<tryton>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="company_view_form">
|
||||||
|
<field name="model">company.company</field>
|
||||||
|
<field name="inherit" ref="company.company_view_form"/>
|
||||||
|
<field name="name">company_form</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</tryton>
|
123
invoice.py
123
invoice.py
|
@ -14,9 +14,6 @@ from decimal import Decimal
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from operator import attrgetter
|
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.model import ModelView, fields
|
||||||
from trytond.pool import Pool, PoolMeta
|
from trytond.pool import Pool, PoolMeta
|
||||||
from trytond.pyson import Bool, Eval
|
from trytond.pyson import Bool, Eval
|
||||||
|
@ -25,6 +22,8 @@ from trytond.wizard import Wizard, StateView, StateTransition, Button
|
||||||
from trytond import backend
|
from trytond import backend
|
||||||
from trytond.i18n import gettext
|
from trytond.i18n import gettext
|
||||||
from trytond.exceptions import UserError
|
from trytond.exceptions import UserError
|
||||||
|
from trytond.modules.certificate_manager.certificate_manager import (
|
||||||
|
ENCODING_DER)
|
||||||
|
|
||||||
FACTURAE_SCHEMA_VERSION = '3.2.2'
|
FACTURAE_SCHEMA_VERSION = '3.2.2'
|
||||||
|
|
||||||
|
@ -319,8 +318,8 @@ class Invoice(metaclass=PoolMeta):
|
||||||
"Missing some tax in invoice %s" % self.id)
|
"Missing some tax in invoice %s" % self.id)
|
||||||
|
|
||||||
for field in FACe_REQUIRED_FIELDS:
|
for field in FACe_REQUIRED_FIELDS:
|
||||||
for party in [self.party, self.company.party]:
|
if (not getattr(self.invoice_address, field)
|
||||||
if not getattr(party, field):
|
or not getattr(self.company, field)):
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'account_invoice_facturae.party_facturae_fields',
|
'account_invoice_facturae.party_facturae_fields',
|
||||||
party=party.rec_name,
|
party=party.rec_name,
|
||||||
|
@ -351,7 +350,7 @@ class Invoice(metaclass=PoolMeta):
|
||||||
'account_invoice_facturae.party_vat_identifier',
|
'account_invoice_facturae.party_vat_identifier',
|
||||||
party=self.party.rec_name,
|
party=self.party.rec_name,
|
||||||
invoice=self.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):
|
and len(self.party.name.split(' ', 2)) < 2):
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'account_invoice_facturae.party_name_surname',
|
'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
|
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:
|
if not certificate:
|
||||||
certificate = Configuration(1).facturae_certificate
|
certificate = Configuration(1).facturae_certificate
|
||||||
|
@ -483,34 +483,14 @@ class Invoice(metaclass=PoolMeta):
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'account_invoice_facturae.msg_missing_certificate'))
|
'account_invoice_facturae.msg_missing_certificate'))
|
||||||
|
|
||||||
certificate_facturae = certificate.pem_certificate
|
|
||||||
certificate_password = certificate.certificate_password
|
|
||||||
|
|
||||||
logger = logging.getLogger('account_invoice_facturae')
|
logger = logging.getLogger('account_invoice_facturae')
|
||||||
|
|
||||||
with NamedTemporaryFile(suffix='.xml', delete=False) as unsigned_file:
|
def _sign_file(cert, request):
|
||||||
unsigned_file.write(xml_string)
|
key = cert.load_pem_key()
|
||||||
|
pem = cert.load_pem_certificate()
|
||||||
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)))
|
|
||||||
|
|
||||||
# DER is an ASN.1 encoding type
|
# DER is an ASN.1 encoding type
|
||||||
crt = certificate.public_bytes(serialization.Encoding.DER)
|
crt = pem.public_bytes(ENCODING_DER)
|
||||||
|
|
||||||
# Set variables values
|
# Set variables values
|
||||||
rand_min = 1
|
rand_min = 1
|
||||||
|
@ -574,10 +554,9 @@ class Invoice(metaclass=PoolMeta):
|
||||||
|
|
||||||
# Set the certificate values
|
# Set the certificate values
|
||||||
ctx = xmlsig.SignatureContext()
|
ctx = xmlsig.SignatureContext()
|
||||||
ctx.private_key = private_key
|
ctx.private_key = key
|
||||||
ctx.x509 = certificate
|
ctx.x509 = pem
|
||||||
ctx.ca_certificates = additional_certificates
|
ctx.public_key = pem.public_key()
|
||||||
ctx.public_key = certificate.public_key()
|
|
||||||
|
|
||||||
# Set the footer validation
|
# Set the footer validation
|
||||||
object_node = etree.SubElement(
|
object_node = etree.SubElement(
|
||||||
|
@ -632,11 +611,11 @@ class Invoice(metaclass=PoolMeta):
|
||||||
etree.SubElement(
|
etree.SubElement(
|
||||||
issuer_serial, etree.QName(xmlsig.constants.DSigNs,
|
issuer_serial, etree.QName(xmlsig.constants.DSigNs,
|
||||||
"X509IssuerName")
|
"X509IssuerName")
|
||||||
).text = xmlsig.utils.get_rdns_name(certificate.issuer.rdns)
|
).text = xmlsig.utils.get_rdns_name(pem.issuer.rdns)
|
||||||
etree.SubElement(
|
etree.SubElement(
|
||||||
issuer_serial, etree.QName(xmlsig.constants.DSigNs,
|
issuer_serial, etree.QName(xmlsig.constants.DSigNs,
|
||||||
"X509SerialNumber")
|
"X509SerialNumber")
|
||||||
).text = str(certificate.serial_number)
|
).text = str(pem.serial_number)
|
||||||
|
|
||||||
signature_policy_identifier = etree.SubElement(
|
signature_policy_identifier = etree.SubElement(
|
||||||
signed_signature_properties,
|
signed_signature_properties,
|
||||||
|
@ -710,11 +689,7 @@ class Invoice(metaclass=PoolMeta):
|
||||||
|
|
||||||
return etree.tostring(root, xml_declaration=True, encoding="UTF-8")
|
return etree.tostring(root, xml_declaration=True, encoding="UTF-8")
|
||||||
|
|
||||||
signed_file_content = _sign_file(
|
signed_file_content = _sign_file(certificate, xml_string)
|
||||||
certificate_facturae,
|
|
||||||
certificate_password.encode(),
|
|
||||||
xml_string,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info("Factura-e for invoice %s (%s) generated and signed",
|
logger.info("Factura-e for invoice %s (%s) generated and signed",
|
||||||
self.rec_name, self.id)
|
self.rec_name, self.id)
|
||||||
|
@ -750,8 +725,8 @@ class InvoiceLine(metaclass=PoolMeta):
|
||||||
@property
|
@property
|
||||||
def facturae_item_description(self):
|
def facturae_item_description(self):
|
||||||
return (
|
return (
|
||||||
(self.description and self.description[:2500])
|
(self.description and self.description)
|
||||||
or (self.product and self.product.rec_name[:2500])
|
or (self.product and self.product.rec_name)
|
||||||
or '#'+str(self.id)
|
or '#'+str(self.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -760,6 +735,34 @@ class InvoiceLine(metaclass=PoolMeta):
|
||||||
# TODO Issuer/ReceiverTransactionDate (sale, contract...)
|
# TODO Issuer/ReceiverTransactionDate (sale, contract...)
|
||||||
return ''
|
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
|
@property
|
||||||
def taxes_outputs(self):
|
def taxes_outputs(self):
|
||||||
"""Return list of 'impuestos repecutidos'"""
|
"""Return list of 'impuestos repecutidos'"""
|
||||||
|
@ -813,17 +816,10 @@ class GenerateFacturaeStart(ModelView):
|
||||||
'Generate Factura-e file - Start'
|
'Generate Factura-e file - Start'
|
||||||
__name__ = 'account.invoice.generate_facturae.start'
|
__name__ = 'account.invoice.generate_facturae.start'
|
||||||
service = fields.Selection([
|
service = fields.Selection([
|
||||||
(None, ''),
|
(None, 'Only generate facturae'),
|
||||||
], 'Service')
|
], 'Factura-e Service')
|
||||||
certificate_facturae = fields.Many2One('certificate',
|
certificate = fields.Many2One('certificate',
|
||||||
'Certificate Factura-e',
|
'Factura-e Certificate', depends=['service'])
|
||||||
states={
|
|
||||||
'invisible': ~Bool(Eval('service')),
|
|
||||||
}, depends=['service'])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def default_service():
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class GenerateFacturae(Wizard):
|
class GenerateFacturae(Wizard):
|
||||||
|
@ -836,11 +832,26 @@ class GenerateFacturae(Wizard):
|
||||||
])
|
])
|
||||||
generate = StateTransition()
|
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):
|
def transition_generate(self):
|
||||||
Invoice = Pool().get('account.invoice')
|
Invoice = Pool().get('account.invoice')
|
||||||
|
|
||||||
invoices = Invoice.browse(Transaction().context['active_ids'])
|
invoices = Invoice.browse(Transaction().context['active_ids'])
|
||||||
for invoice in invoices:
|
for invoice in invoices:
|
||||||
invoice.generate_facturae(certificate=self.start.certificate_facturae,
|
invoice.generate_facturae(certificate=self.start.certificate,
|
||||||
service=self.start.service)
|
service=self.start.service)
|
||||||
return 'end'
|
return 'end'
|
||||||
|
|
108
locale/ca.po
108
locale/ca.po
|
@ -38,17 +38,25 @@ msgctxt "field:account.invoice.credit.start,rectificative_reason_code:"
|
||||||
msgid "Rectificative Reason Code"
|
msgid "Rectificative Reason Code"
|
||||||
msgstr "Codi motiu rectificació"
|
msgstr "Codi motiu rectificació"
|
||||||
|
|
||||||
msgctxt "field:account.invoice.generate_facturae.start,certificate_facturae:"
|
msgctxt "field:account.invoice.generate_facturae.start,service:"
|
||||||
msgid "Certificate Factura-e"
|
msgid "Factura-e Service"
|
||||||
msgstr "Certificat"
|
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:"
|
msgctxt "field:account.invoice.generate_facturae.start,certificate_password:"
|
||||||
msgid "Certificate Password"
|
msgid "Certificate Password"
|
||||||
msgstr "Contrasenya certificat"
|
msgstr "Contrasenya certificat"
|
||||||
|
|
||||||
msgctxt "field:account.invoice.generate_facturae.start,service:"
|
msgctxt "field:account.configuration,facturae_certificate:"
|
||||||
msgid "Service"
|
msgid "Factura-e Certificate"
|
||||||
msgstr "Servei"
|
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:"
|
msgctxt "field:account.payment.type,facturae_type:"
|
||||||
msgid "Factura-e Type"
|
msgid "Factura-e Type"
|
||||||
|
@ -58,31 +66,55 @@ msgctxt "field:account.tax,report_type:"
|
||||||
msgid "Report Type"
|
msgid "Report Type"
|
||||||
msgstr "Tipus informe"
|
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:"
|
msgctxt "field:account.tax.template,report_type:"
|
||||||
msgid "Report Type"
|
msgid "Report Type"
|
||||||
msgstr "Tipus informe"
|
msgstr "Tipus informe"
|
||||||
|
|
||||||
msgctxt "field:party.party,facturae_person_type:"
|
msgctxt "field:party.address,facturae_person_type:"
|
||||||
msgid "Person Type"
|
msgid "Person Type"
|
||||||
msgstr "Tipus persona"
|
msgstr "Tipus persona"
|
||||||
|
|
||||||
msgctxt "field:party.party,facturae_residence_type:"
|
msgctxt "field:party.address,facturae_residence_type:"
|
||||||
msgid "Residence Type"
|
msgid "Residence Type"
|
||||||
msgstr "Tipus residència"
|
msgstr "Tipus residència"
|
||||||
|
|
||||||
msgctxt "field:party.party,oficina_contable:"
|
msgctxt "field:party.address,oficina_contable:"
|
||||||
msgid "Oficina contable"
|
msgid "Oficina contable"
|
||||||
msgstr "Oficina contable"
|
msgstr "Oficina contable"
|
||||||
|
|
||||||
msgctxt "field:party.party,organo_gestor:"
|
msgctxt "field:party.address,organo_gestor:"
|
||||||
msgid "Organo gestor"
|
msgid "Organo gestor"
|
||||||
msgstr "Organo gestor"
|
msgstr "Organo gestor"
|
||||||
|
|
||||||
msgctxt "field:party.party,organo_proponente:"
|
msgctxt "field:party.address,organo_proponente:"
|
||||||
msgid "Organo proponente"
|
msgid "Organo proponente"
|
||||||
msgstr "Organo proponente"
|
msgstr "Organo proponente"
|
||||||
|
|
||||||
msgctxt "field:party.party,unidad_tramitadora:"
|
msgctxt "field:party.address,unidad_tramitadora:"
|
||||||
msgid "Unidad tramitadora"
|
msgid "Unidad tramitadora"
|
||||||
msgstr "Unidad tramitadora"
|
msgstr "Unidad tramitadora"
|
||||||
|
|
||||||
|
@ -753,31 +785,43 @@ msgctxt "selection:account.tax.template,report_type:"
|
||||||
msgid "Value-Added Tax"
|
msgid "Value-Added Tax"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_person_type:"
|
msgctxt "selection:company.company,facturae_person_type:"
|
||||||
msgid ""
|
|
||||||
msgstr " "
|
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_person_type:"
|
|
||||||
msgid "Individual"
|
msgid "Individual"
|
||||||
msgstr "Persona física"
|
msgstr "Persona física"
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_person_type:"
|
msgctxt "selection:company.company,facturae_person_type:"
|
||||||
msgid "Legal Entity"
|
msgid "Legal Entity"
|
||||||
msgstr "Persona jurídica"
|
msgstr "Persona jurídica"
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_residence_type:"
|
msgctxt "selection:company.company,facturae_residence_type:"
|
||||||
msgid ""
|
|
||||||
msgstr " "
|
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_residence_type:"
|
|
||||||
msgid "Foreigner"
|
msgid "Foreigner"
|
||||||
msgstr "Estranger (Fora Unió Europea)"
|
msgstr "Estranger (Fora Unió Europea)"
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_residence_type:"
|
msgctxt "selection:company.company,facturae_residence_type:"
|
||||||
msgid "Resident in Spain"
|
msgid "Resident in Spain"
|
||||||
msgstr "Resident (a Espanya)"
|
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"
|
msgid "Resident in other EU country"
|
||||||
msgstr "Resident a la Unió Europea (excepte Espanya)"
|
msgstr "Resident a la Unió Europea (excepte Espanya)"
|
||||||
|
|
||||||
|
@ -807,7 +851,11 @@ msgctxt "view:account.tax:"
|
||||||
msgid "Factura-e"
|
msgid "Factura-e"
|
||||||
msgstr "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"
|
msgid "Factura-e"
|
||||||
msgstr "Factura-e"
|
msgstr "Factura-e"
|
||||||
|
|
||||||
|
@ -818,3 +866,11 @@ msgstr "Cancel·la"
|
||||||
msgctxt "wizard_button:account.invoice.generate_facturae,start,generate:"
|
msgctxt "wizard_button:account.invoice.generate_facturae,start,generate:"
|
||||||
msgid "Generate"
|
msgid "Generate"
|
||||||
msgstr "Genera"
|
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"
|
||||||
|
|
100
locale/es.po
100
locale/es.po
|
@ -38,17 +38,25 @@ msgctxt "field:account.invoice.credit.start,rectificative_reason_code:"
|
||||||
msgid "Rectificative Reason Code"
|
msgid "Rectificative Reason Code"
|
||||||
msgstr "Código motivo rectificación"
|
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:"
|
msgctxt "field:account.invoice.generate_facturae.start,certificate_password:"
|
||||||
msgid "Certificate Password"
|
msgid "Certificate Password"
|
||||||
msgstr "Contraseña certificado"
|
msgstr "Contraseña certificado"
|
||||||
|
|
||||||
msgctxt "field:account.invoice.generate_facturae.start,service:"
|
msgctxt "field:account.invoice.generate_facturae.start,service:"
|
||||||
msgid "Service"
|
msgid "Factura-e Service"
|
||||||
msgstr "Servicio"
|
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:"
|
msgctxt "field:account.payment.type,facturae_type:"
|
||||||
msgid "Factura-e Type"
|
msgid "Factura-e Type"
|
||||||
|
@ -62,27 +70,51 @@ msgctxt "field:account.tax.template,report_type:"
|
||||||
msgid "Report Type"
|
msgid "Report Type"
|
||||||
msgstr "Tipo informe"
|
msgstr "Tipo informe"
|
||||||
|
|
||||||
msgctxt "field:party.party,facturae_person_type:"
|
msgctxt "field:company.company,facturae_person_type:"
|
||||||
msgid "Person Type"
|
msgid "Person Type"
|
||||||
msgstr "Tipo persona"
|
msgstr "Tipo persona"
|
||||||
|
|
||||||
msgctxt "field:party.party,facturae_residence_type:"
|
msgctxt "field:company.company,facturae_residence_type:"
|
||||||
msgid "Residence Type"
|
msgid "Residence Type"
|
||||||
msgstr "Tipo residencia"
|
msgstr "Tipo residencia"
|
||||||
|
|
||||||
msgctxt "field:party.party,oficina_contable:"
|
msgctxt "field:company.company,oficina_contable:"
|
||||||
msgid "Oficina contable"
|
msgid "Oficina contable"
|
||||||
msgstr "Oficina contable"
|
msgstr "Oficina contable"
|
||||||
|
|
||||||
msgctxt "field:party.party,organo_gestor:"
|
msgctxt "field:company.company,organo_gestor:"
|
||||||
msgid "Organo gestor"
|
msgid "Organo gestor"
|
||||||
msgstr "Organo gestor"
|
msgstr "Organo gestor"
|
||||||
|
|
||||||
msgctxt "field:party.party,organo_proponente:"
|
msgctxt "field:company.company,organo_proponente:"
|
||||||
msgid "Organo proponente"
|
msgid "Organo proponente"
|
||||||
msgstr "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"
|
msgid "Unidad tramitadora"
|
||||||
msgstr "Unidad tramitadora"
|
msgstr "Unidad tramitadora"
|
||||||
|
|
||||||
|
@ -751,23 +783,43 @@ msgctxt "selection:account.tax.template,report_type:"
|
||||||
msgid "Value-Added Tax"
|
msgid "Value-Added Tax"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_person_type:"
|
msgctxt "selection:company.company,facturae_person_type:"
|
||||||
msgid "Individual"
|
msgid "Individual"
|
||||||
msgstr "Persona física"
|
msgstr "Persona física"
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_person_type:"
|
msgctxt "selection:company.company,facturae_person_type:"
|
||||||
msgid "Legal Entity"
|
msgid "Legal Entity"
|
||||||
msgstr "Persona jurídica"
|
msgstr "Persona jurídica"
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_residence_type:"
|
msgctxt "selection:company.company,facturae_residence_type:"
|
||||||
msgid "Foreigner"
|
msgid "Foreigner"
|
||||||
msgstr "Extranjero (Fuera Unión Europea)"
|
msgstr "Extranjero (Fuera Unión Europea)"
|
||||||
|
|
||||||
msgctxt "selection:party.party,facturae_residence_type:"
|
msgctxt "selection:company.company,facturae_residence_type:"
|
||||||
msgid "Resident in Spain"
|
msgid "Resident in Spain"
|
||||||
msgstr "Residente (en España)"
|
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"
|
msgid "Resident in other EU country"
|
||||||
msgstr "Residente en la Unión Europea (excepto España)"
|
msgstr "Residente en la Unión Europea (excepto España)"
|
||||||
|
|
||||||
|
@ -793,7 +845,11 @@ msgctxt "view:account.tax:"
|
||||||
msgid "Factura-e"
|
msgid "Factura-e"
|
||||||
msgstr "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"
|
msgid "Factura-e"
|
||||||
msgstr "Factura-e"
|
msgstr "Factura-e"
|
||||||
|
|
||||||
|
@ -804,3 +860,11 @@ msgstr "Cancelar"
|
||||||
msgctxt "wizard_button:account.invoice.generate_facturae,start,generate:"
|
msgctxt "wizard_button:account.invoice.generate_facturae,start,generate:"
|
||||||
msgid "Generate"
|
msgid "Generate"
|
||||||
msgstr "Generar"
|
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"
|
||||||
|
|
87
party.py
87
party.py
|
@ -1,13 +1,13 @@
|
||||||
# The COPYRIGHT file at the top level of this repository contains the full
|
# The COPYRIGHT file at the top level of this repository contains the full
|
||||||
# copyright notices and license terms.
|
# copyright notices and license terms.
|
||||||
from trytond.model import fields
|
from trytond.model import fields
|
||||||
from trytond.pool import PoolMeta
|
from trytond.pool import Pool, PoolMeta
|
||||||
|
from trytond.transaction import Transaction
|
||||||
__all__ = ['Party']
|
|
||||||
|
|
||||||
|
|
||||||
class Party(metaclass=PoolMeta):
|
class Address(metaclass=PoolMeta):
|
||||||
__name__ = 'party.party'
|
__name__ = 'party.address'
|
||||||
|
|
||||||
facturae_person_type = fields.Selection([
|
facturae_person_type = fields.Selection([
|
||||||
(None, ''),
|
(None, ''),
|
||||||
('J', 'Legal Entity'),
|
('J', 'Legal Entity'),
|
||||||
|
@ -23,3 +23,80 @@ class Party(metaclass=PoolMeta):
|
||||||
organo_gestor = fields.Char('Organo gestor')
|
organo_gestor = fields.Char('Organo gestor')
|
||||||
unidad_tramitadora = fields.Char('Unidad tramitadora')
|
unidad_tramitadora = fields.Char('Unidad tramitadora')
|
||||||
organo_proponente = fields.Char('Organo proponente')
|
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')
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
copyright notices and license terms. -->
|
copyright notices and license terms. -->
|
||||||
<tryton>
|
<tryton>
|
||||||
<data>
|
<data>
|
||||||
<record model="ir.ui.view" id="party_view_form">
|
<record model="ir.ui.view" id="address_view_form">
|
||||||
<field name="model">party.party</field>
|
<field name="model">party.address</field>
|
||||||
<field name="inherit" ref="party.party_view_form"/>
|
<field name="inherit" ref="party.address_view_form"/>
|
||||||
<field name="name">party_form</field>
|
<field name="name">address_form</field>
|
||||||
</record>
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|
|
@ -38,20 +38,20 @@
|
||||||
<Parties>
|
<Parties>
|
||||||
<SellerParty>
|
<SellerParty>
|
||||||
<TaxIdentification>
|
<TaxIdentification>
|
||||||
<PersonTypeCode>{{ invoice.company.party.facturae_person_type }}</PersonTypeCode>
|
<PersonTypeCode>{{ invoice.company.facturae_person_type }}</PersonTypeCode>
|
||||||
<ResidenceTypeCode>{{ invoice.company.party.facturae_residence_type }}</ResidenceTypeCode>
|
<ResidenceTypeCode>{{ invoice.company.facturae_residence_type }}</ResidenceTypeCode>
|
||||||
<TaxIdentificationNumber>{{ invoice.company.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
|
<TaxIdentificationNumber>{{ invoice.company.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
|
||||||
</TaxIdentification>
|
</TaxIdentification>
|
||||||
{# Optional. It could be the ID or the code #}
|
{# Optional. It could be the ID or the code #}
|
||||||
{% if invoice.company.party.code and invoice.company.party.code | length < 10 %}
|
{% if invoice.company.party.code and invoice.company.party.code | length < 10 %}
|
||||||
<PartyIdentification>{{ invoice.company.party.code|int or invoice.company.party.id }}</PartyIdentification>
|
<PartyIdentification>{{ invoice.company.party.code|int or invoice.company.party.id }}</PartyIdentification>
|
||||||
{% endif %}
|
{% 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 %}
|
||||||
<AdministrativeCentres>
|
<AdministrativeCentres>
|
||||||
{% if invoice.company.party.oficina_contable %}{{ administrative_center(invoice.company.party.oficina_contable, '01', 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.party.organo_gestor %}{{ administrative_center(invoice.company.party.organo_gestor, '02', invoice.company.party) }}{% 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.party.unidad_tramitadora %}{{ administrative_center(invoice.company.party.unidad_tramitadora, '03', invoice.company.party) }}{% 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.party.organo_proponente %}{{ administrative_center(invoice.company.party.organo_proponente, '04', invoice.company.party) }}{% 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 %}
|
||||||
</AdministrativeCentres>
|
</AdministrativeCentres>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<LegalEntity>
|
<LegalEntity>
|
||||||
|
@ -73,23 +73,23 @@
|
||||||
|
|
||||||
<BuyerParty>
|
<BuyerParty>
|
||||||
<TaxIdentification>
|
<TaxIdentification>
|
||||||
<PersonTypeCode>{{ invoice.party.facturae_person_type }}</PersonTypeCode>
|
<PersonTypeCode>{{ invoice.invoice_address.facturae_person_type }}</PersonTypeCode>
|
||||||
<ResidenceTypeCode>{{ invoice.party.facturae_residence_type }}</ResidenceTypeCode>
|
<ResidenceTypeCode>{{ invoice.invoice_address.facturae_residence_type }}</ResidenceTypeCode>
|
||||||
<TaxIdentificationNumber>{{ invoice.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
|
<TaxIdentificationNumber>{{ invoice.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
|
||||||
</TaxIdentification>
|
</TaxIdentification>
|
||||||
{# Optional. It could be the ID or the code #}
|
{# Optional. It could be the ID or the code #}
|
||||||
{% if invoice.party.code and invoice.party.code | length < 10 %}
|
{% if invoice.party.code and invoice.party.code | length < 10 %}
|
||||||
<PartyIdentification>{{ invoice.party.code|int or invoice.party.id }}</PartyIdentification>
|
<PartyIdentification>{{ invoice.party.code|int or invoice.party.id }}</PartyIdentification>
|
||||||
{% endif %}
|
{% 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 %}
|
||||||
<AdministrativeCentres>
|
<AdministrativeCentres>
|
||||||
{% if invoice.party.oficina_contable %}{{ administrative_center(invoice.party.oficina_contable, '01', 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.party.organo_gestor %}{{ administrative_center(invoice.party.organo_gestor, '02', invoice.party) }}{% 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.party.unidad_tramitadora %}{{ administrative_center(invoice.party.unidad_tramitadora, '03', invoice.party) }}{% 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.party.organo_proponente %}{{ administrative_center(invoice.party.organo_proponente, '04', invoice.party) }}{% 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 %}
|
||||||
</AdministrativeCentres>
|
</AdministrativeCentres>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if invoice.party.facturae_person_type == 'J' %}
|
{% if invoice.invoice_address.facturae_person_type == 'J' %}
|
||||||
<LegalEntity>
|
<LegalEntity>
|
||||||
<CorporateName>{{ invoice.party.name and invoice.party.name[:80] or invoice.party.code[:80] }}</CorporateName>
|
<CorporateName>{{ invoice.party.name and invoice.party.name[:80] or invoice.party.code[:80] }}</CorporateName>
|
||||||
{% if invoice.party.trade_name %}
|
{% if invoice.party.trade_name %}
|
||||||
|
@ -162,7 +162,7 @@
|
||||||
{% if invoice.currency != euro %}
|
{% if invoice.currency != euro %}
|
||||||
<ExchangeRateDetails>
|
<ExchangeRateDetails>
|
||||||
<ExchangeRate>{{ Invoice.double_up_to_eight(exchange_rate) }}</ExchangeRate>
|
<ExchangeRate>{{ Invoice.double_up_to_eight(exchange_rate) }}</ExchangeRate>
|
||||||
<ExchangeRateDate>{{ exchange_rate_date }}</ExchangeRateDate>
|
<ExchangeRateDate>{% if exchange_rate_date %}{{ exchange_rate_date.isoformat() }}{% endif %}</ExchangeRateDate>
|
||||||
</ExchangeRateDetails>
|
</ExchangeRateDetails>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
||||||
|
@ -255,7 +255,7 @@
|
||||||
- Extensions
|
- Extensions
|
||||||
#}
|
#}
|
||||||
<ReceiverTransactionReference>{{ line.facturae_receiver_transaction_reference }}</ReceiverTransactionReference>
|
<ReceiverTransactionReference>{{ line.facturae_receiver_transaction_reference }}</ReceiverTransactionReference>
|
||||||
<ItemDescription>{{ line.facturae_item_description }}</ItemDescription>
|
<ItemDescription>{{ line.facturae_item_description[:2500] }}</ItemDescription>
|
||||||
<Quantity>{{ line.quantity }}</Quantity>
|
<Quantity>{{ line.quantity }}</Quantity>
|
||||||
<UnitOfMeasure>{{ UOM_CODE2TYPE.get(line.unit.symbol, '05') if line.unit else '05' }}</UnitOfMeasure>
|
<UnitOfMeasure>{{ UOM_CODE2TYPE.get(line.unit.symbol, '05') if line.unit else '05' }}</UnitOfMeasure>
|
||||||
<UnitPriceWithoutTax>{{ Invoice.double_up_to_eight(line.unit_price) }}</UnitPriceWithoutTax>
|
<UnitPriceWithoutTax>{{ Invoice.double_up_to_eight(line.unit_price) }}</UnitPriceWithoutTax>
|
||||||
|
@ -321,10 +321,10 @@
|
||||||
</Tax>
|
</Tax>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</TaxesOutputs>
|
</TaxesOutputs>
|
||||||
{% if line.origin and line.origin.contract %}
|
{% if line.facturae_start_date %}
|
||||||
<LineItemPeriod>
|
<LineItemPeriod>
|
||||||
<StartDate>{{ line.origin.start_date }}</StartDate>
|
<StartDate>{{ line.facturae_start_date.isoformat() }}</StartDate>
|
||||||
<EndDate>{{ line.origin.end_date }}</EndDate>
|
<EndDate>{{ line.facturae_end_date.isoformat() }}</EndDate>
|
||||||
</LineItemPeriod>
|
</LineItemPeriod>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if line.taxes_additional_line_item_information or line.note %}
|
{% if line.taxes_additional_line_item_information or line.note %}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
{% macro administrative_center(centre_code, role_type_code, party) %}
|
{% macro administrative_center(centre_code, role_type_code, person_type, addrs) %}
|
||||||
<AdministrativeCentre>
|
<AdministrativeCentre>
|
||||||
<CentreCode>{{ centre_code }}</CentreCode>
|
<CentreCode>{{ centre_code }}</CentreCode>
|
||||||
<RoleTypeCode>{{ role_type_code }}</RoleTypeCode>
|
<RoleTypeCode>{{ role_type_code }}</RoleTypeCode>
|
||||||
<Name>{% 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 %}</Name>
|
<Name>{% 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 %}</Name>
|
||||||
{% if party.facturae_person_type == 'F' %}
|
{% if person_type == 'F' %}
|
||||||
<FirstSurname>{{ party.name and party.name.split(' ', 2)[1][:40] }}</FirstSurname>
|
<FirstSurname>{{ addrs.party.name and addrs.party.name.split(' ', 2)[1][:40] }}</FirstSurname>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if party.facturae_person_type == 'F' and party.name.split(' ') | length > 2 %}
|
{% if person_type == 'F' and addrs.party.name.split(' ') | length > 2 %}
|
||||||
<SecondSurname>{{ party.name and party.name.split(' ', 2)[2][:40] }}</SecondSurname>
|
<SecondSurname>{{ addrs.party.name and addrs.party.name.split(' ', 2)[2][:40] }}</SecondSurname>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if party.addresses %}{{ address(party.addresses[0]) }}{% endif %}
|
{% if addrs %}{{ address(addrs) }}{% endif %}
|
||||||
{% if party.contact_mechanisms %}{{ contact(party) }}{% endif %}
|
{% if addrs.party.contact_mechanisms %}{{ contact(addrs.party) }}{% endif %}
|
||||||
<PhysicalGLN/>
|
<PhysicalGLN/>
|
||||||
<LogicalOperationalPoint/>
|
<LogicalOperationalPoint/>
|
||||||
<CentreDescription>{{ party.name and party.name.split(' ', 2)[0][:40] or party.code[:40] }}</CentreDescription>
|
<CentreDescription>{{ addrs.party.name and addrs.party.name.split(' ', 2)[0][:40] or addrs.party.code[:40] }}</CentreDescription>
|
||||||
</AdministrativeCentre>
|
</AdministrativeCentre>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ class AccountInvoiceFacturaeTestCase(CompanyTestMixin, ModuleTestCase):
|
||||||
company.header = 'Report Header'
|
company.header = 'Report Header'
|
||||||
company.party.name = 'Seller'
|
company.party.name = 'Seller'
|
||||||
company.party.identifiers = [tax_identifier]
|
company.party.identifiers = [tax_identifier]
|
||||||
company.party.facturae_person_type = 'J'
|
company.facturae_person_type = 'J'
|
||||||
company.party.facturae_residence_type = 'R'
|
company.facturae_residence_type = 'R'
|
||||||
company.party.save()
|
company.party.save()
|
||||||
company.save()
|
company.save()
|
||||||
|
|
||||||
|
@ -108,8 +108,6 @@ class AccountInvoiceFacturaeTestCase(CompanyTestMixin, ModuleTestCase):
|
||||||
company_address.country = country
|
company_address.country = country
|
||||||
company_address.save()
|
company_address.save()
|
||||||
party = Party(name='Buyer')
|
party = Party(name='Buyer')
|
||||||
party.facturae_person_type = 'J'
|
|
||||||
party.facturae_residence_type = 'R'
|
|
||||||
tax_identifier = PartyIdentifier()
|
tax_identifier = PartyIdentifier()
|
||||||
tax_identifier.type = 'eu_vat'
|
tax_identifier.type = 'eu_vat'
|
||||||
tax_identifier.code = 'BE0897290877'
|
tax_identifier.code = 'BE0897290877'
|
||||||
|
@ -123,6 +121,8 @@ class AccountInvoiceFacturaeTestCase(CompanyTestMixin, ModuleTestCase):
|
||||||
'postal_code': '08201',
|
'postal_code': '08201',
|
||||||
'subdivision': subdivision.id,
|
'subdivision': subdivision.id,
|
||||||
'country': country.id,
|
'country': country.id,
|
||||||
|
'address.facturae_person_type': 'J',
|
||||||
|
'address.facturae_residence_type': 'R',
|
||||||
}
|
}
|
||||||
|
|
||||||
address, = Address.create([address_dict])
|
address, = Address.create([address_dict])
|
||||||
|
|
|
@ -8,10 +8,12 @@ depends:
|
||||||
extras_depend:
|
extras_depend:
|
||||||
account_bank
|
account_bank
|
||||||
account_es
|
account_es
|
||||||
|
contract
|
||||||
xml:
|
xml:
|
||||||
account.xml
|
account.xml
|
||||||
|
account_es.xml
|
||||||
|
company.xml
|
||||||
invoice.xml
|
invoice.xml
|
||||||
party.xml
|
party.xml
|
||||||
payment_type.xml
|
payment_type.xml
|
||||||
account_es.xml
|
|
||||||
message.xml
|
message.xml
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||||
copyright notices and license terms. -->
|
copyright notices and license terms. -->
|
||||||
<data>
|
<data>
|
||||||
<xpath expr="/form/notebook/page[@id='accounting']" position="after">
|
<xpath expr="/form/notebook" position="inside">
|
||||||
<page id="facturae" string="Factura-e">
|
<page id="facturae" string="Factura-e">
|
||||||
<label name="facturae_person_type"/>
|
<label name="facturae_person_type"/>
|
||||||
<field name="facturae_person_type"/>
|
<field name="facturae_person_type"/>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||||
|
copyright notices and license terms. -->
|
||||||
|
<data>
|
||||||
|
<xpath expr="/form/notebook" position="inside">
|
||||||
|
<page id="facturae" string="Factura-e">
|
||||||
|
<label name="facturae_person_type"/>
|
||||||
|
<field name="facturae_person_type"/>
|
||||||
|
<label name="facturae_residence_type"/>
|
||||||
|
<field name="facturae_residence_type"/>
|
||||||
|
<label name="oficina_contable"/>
|
||||||
|
<field name="oficina_contable"/>
|
||||||
|
<label name="organo_gestor"/>
|
||||||
|
<field name="organo_gestor"/>
|
||||||
|
<label name="unidad_tramitadora"/>
|
||||||
|
<field name="unidad_tramitadora"/>
|
||||||
|
<label name="organo_proponente"/>
|
||||||
|
<field name="organo_proponente"/>
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
|
</data>
|
|
@ -10,7 +10,7 @@
|
||||||
yalign="0.0" xalign="0.0" xexpand="1"/>
|
yalign="0.0" xalign="0.0" xexpand="1"/>
|
||||||
<label name="service"/>
|
<label name="service"/>
|
||||||
<field name="service"/>
|
<field name="service"/>
|
||||||
<label name="certificate_facturae"/>
|
<label name="certificate"/>
|
||||||
<field name="certificate_facturae"/>
|
<field name="certificate"/>
|
||||||
</group>
|
</group>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in New Issue