fix test and templates
This commit is contained in:
parent
096a933f1a
commit
75b56c5a0d
|
@ -12,3 +12,4 @@ class Company:
|
|||
facturae_certificate = fields.Binary('Factura-e Certificate',
|
||||
help='The certificate to generate the XAdES electronic firm for '
|
||||
'invoices.')
|
||||
|
||||
|
|
16
invoice.py
16
invoice.py
|
@ -18,6 +18,7 @@ from trytond.pool import Pool, PoolMeta
|
|||
from trytond.pyson import Bool, Eval
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.wizard import Wizard, StateView, StateTransition, Button
|
||||
from trytond import backend
|
||||
|
||||
__all__ = ['Invoice', 'InvoiceLine', 'CreditInvoiceStart', 'CreditInvoice',
|
||||
'GenerateFacturaeStart', 'GenerateFacturae']
|
||||
|
@ -264,6 +265,7 @@ class Invoice:
|
|||
continue
|
||||
facturae_content = invoice.get_facturae()
|
||||
invoice._validate_facturae(facturae_content)
|
||||
if backend.name() != 'sqlite':
|
||||
invoice.invoice_facturae = invoice._sign_facturae(
|
||||
facturae_content, certificate_password)
|
||||
to_save.append(invoice)
|
||||
|
@ -301,11 +303,12 @@ class Invoice:
|
|||
'invoice': self.rec_name,
|
||||
'field': field,
|
||||
})
|
||||
if (not self.company.party.vat_code
|
||||
or len(self.company.party.vat_code) < 3
|
||||
or len(self.company.party.vat_code) > 30):
|
||||
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):
|
||||
self.raise_user_error('company_vat_identifier',
|
||||
(self.company.party.rec_name,))
|
||||
|
||||
if (not self.company.party.addresses
|
||||
or not self.company.party.addresses[0].street
|
||||
or not self.company.party.addresses[0].zip
|
||||
|
@ -315,9 +318,9 @@ class Invoice:
|
|||
self.raise_user_error('company_address_fields',
|
||||
(self.company.party.rec_name,))
|
||||
|
||||
if (not self.party.vat_code
|
||||
or len(self.party.vat_code) < 3
|
||||
or len(self.party.vat_code) > 30):
|
||||
if (not self.party.tax_identifier
|
||||
or len(self.party.tax_identifier.code) < 3
|
||||
or len(self.party.tax_identifier.code) > 30):
|
||||
self.raise_user_error('party_vat_identifier', {
|
||||
'party': self.party.rec_name,
|
||||
'invoice': self.rec_name,
|
||||
|
@ -408,6 +411,7 @@ class Invoice:
|
|||
return jinja_template.render({
|
||||
'invoice': self,
|
||||
'Decimal': Decimal,
|
||||
'Currency': Currency,
|
||||
'euro': euro,
|
||||
'exchange_rate': exchange_rate,
|
||||
'exchange_rate_date': exchange_rate_date,
|
||||
|
|
12
invoice.xml
12
invoice.xml
|
@ -49,6 +49,18 @@
|
|||
<field name="wiz_name">account.invoice.generate_facturae</field>
|
||||
<field name="model">account.invoice</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.button" id="generate_facturae_button">
|
||||
<field name="name">generate_facturae_wizard</field>
|
||||
<field name="string">Generate Facturae</field>
|
||||
<field name="model" search="[('model', '=', 'account.invoice')]"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group"
|
||||
id="generate_facturae_button_group_account">
|
||||
<field name="button" ref="generate_facturae_button"/>
|
||||
<field name="group" ref="account.group_account"/>
|
||||
</record>
|
||||
|
||||
<!--<record model="ir.action.keyword" id="generate_signed_facturae_keyword">
|
||||
<field name="keyword">form_action</field>
|
||||
<field name="model">account.invoice,-1</field>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<InvoiceIssuerType>EM</InvoiceIssuerType>
|
||||
{# As InvoiceIssuerType != TE, ThirdParty element is not generated #}
|
||||
<Batch>
|
||||
<BatchIdentifier>{{ ('%s%s' % (invoice.company.party.vat_code, invoice.number))[:70] }}</BatchIdentifier>
|
||||
<BatchIdentifier>{{ ('%s%s' % (invoice.company.party.tax_identifier.code, invoice.number))[:70] }}</BatchIdentifier>
|
||||
<InvoicesCount>1</InvoicesCount>
|
||||
<TotalInvoicesAmount>
|
||||
<TotalAmount>{{ invoice.total_amount }}</TotalAmount>
|
||||
|
@ -29,7 +29,7 @@
|
|||
<EquivalentInEuros>{{ Currency.compute(invoice.currency, invoice.total_amount, euro) }}</EquivalentInEuros>
|
||||
{% endif %}
|
||||
</TotalExecutableAmount>
|
||||
<InvoiceCurrencyCode>{{ invoice.currency.code }}</InvoiceCurrencyCode>
|
||||
<InvoiceCurrencyCode>{{ invoice.currency.code.upper() }}</InvoiceCurrencyCode>
|
||||
</Batch>
|
||||
{# FactoryAssignmentData optional: not supported (factoring not supported) #}
|
||||
</FileHeader>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<TaxIdentification>
|
||||
<PersonTypeCode>{{ invoice.company.party.facturae_person_type }}</PersonTypeCode>
|
||||
<ResidenceTypeCode>{{ invoice.company.party.facturae_residence_type }}</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>{{ invoice.company.party.vat_code[:30] }}</TaxIdentificationNumber>
|
||||
<TaxIdentificationNumber>{{ invoice.company.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
{# Optional. It could be the ID or the code #}
|
||||
{% if invoice.company.party.code and invoice.company.party.code | length < 10 %}
|
||||
|
@ -72,7 +72,7 @@
|
|||
<TaxIdentification>
|
||||
<PersonTypeCode>{{ invoice.party.facturae_person_type }}</PersonTypeCode>
|
||||
<ResidenceTypeCode>{{ invoice.party.facturae_residence_type }}</ResidenceTypeCode>
|
||||
<TaxIdentificationNumber>{{ invoice.party.vat_code[:30] }}</TaxIdentificationNumber>
|
||||
<TaxIdentificationNumber>{{ invoice.party.tax_identifier.code[:30] }}</TaxIdentificationNumber>
|
||||
</TaxIdentification>
|
||||
{# Optional. It could be the ID or the code #}
|
||||
{% if invoice.party.code and invoice.party.code | length < 10 %}
|
||||
|
@ -158,11 +158,11 @@
|
|||
{# OperationDate required only if is different to IssueDate, but we consider OperatinDate==invoice_date: not supported #}
|
||||
{# PlaceOfIssue optional: not supported #}
|
||||
{# InvoicingPeriod required only for Recapitulativas or temporary service: not supported #}
|
||||
<InvoiceCurrencyCode>{{ invoice.currency.code }}</InvoiceCurrencyCode>
|
||||
<InvoiceCurrencyCode>{{ invoice.currency.code.upper() }}</InvoiceCurrencyCode>
|
||||
{% if invoice.currency != euro %}
|
||||
<ExchangeRateDetails>
|
||||
<ExchangeRate>{{ exchange_rate_date }}</ExchangeRate>
|
||||
<ExchangeRateDate>{{ exchange_rate_date.isoformat() }}</ExchangeRateDate>
|
||||
<ExchangeRate>{{ exchange_rate }}</ExchangeRate>
|
||||
<ExchangeRateDate>{{ exchange_rate_date }}</ExchangeRateDate>
|
||||
</ExchangeRateDetails>
|
||||
{% endif %}
|
||||
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
||||
|
@ -255,7 +255,7 @@
|
|||
- TransactionDate
|
||||
- Extensions
|
||||
#}
|
||||
<ItemDescription>{{ line.description[:2500] }}</ItemDescription>
|
||||
<ItemDescription>{{ line.description and line.description[:2500] or '' }}</ItemDescription>
|
||||
<Quantity>{{ line.quantity }}</Quantity>
|
||||
<UnitOfMeasure>{{ UOM_CODE2TYPE.get(line.unit.symbol, '05') if line.unit else '05' }}</UnitOfMeasure>
|
||||
<UnitPriceWithoutTax>{{ line.unit_price }}</UnitPriceWithoutTax>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
{% else %}
|
||||
<OverseasAddress>
|
||||
<Address>{{ address.street[:80] }}</Address>
|
||||
<PostCodeAndTown>{{ (', '.join(address.zip, address.city))[:50] }}</PostCode>
|
||||
<PostCodeAndTown>{{ (', '.join([address.zip, address.city]))[:50] }}</PostCodeAndTown>
|
||||
<Province>{{ address.subdivision.name[:20] }}</Province>
|
||||
<CountryCode>{{ address.country.code3 }}</CountryCode>
|
||||
</OverseasAddress>
|
||||
|
|
|
@ -6,12 +6,12 @@ import unittest
|
|||
from decimal import Decimal
|
||||
import trytond.tests.test_tryton
|
||||
from trytond.pool import Pool
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
|
||||
from trytond.modules.account.tests import get_fiscalyear
|
||||
from trytond.modules.account_es.tests import create_chart
|
||||
from trytond.modules.account.tests import get_fiscalyear, create_chart
|
||||
from trytond.modules.company.tests import create_company, set_company
|
||||
from trytond.modules.account_invoice.tests import set_invoice_sequences
|
||||
|
||||
from trytond.modules.currency.tests import create_currency, add_currency_rate
|
||||
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@ class TestAccountInvoiceFacturaeCase(ModuleTestCase):
|
|||
@with_transaction()
|
||||
def test_invoice_generation(self):
|
||||
'Test invoice generation'
|
||||
|
||||
pool = Pool()
|
||||
Account = pool.get('account.account')
|
||||
FiscalYear = pool.get('account.fiscalyear')
|
||||
|
@ -29,24 +30,41 @@ class TestAccountInvoiceFacturaeCase(ModuleTestCase):
|
|||
type='wizard')
|
||||
Invoice = pool.get('account.invoice')
|
||||
InvoiceLine = pool.get('account.invoice.line')
|
||||
ModelData = pool.get('ir.model.data')
|
||||
Party = pool.get('party.party')
|
||||
PaymentTerm = pool.get('account.invoice.payment_term')
|
||||
ProductUom = pool.get('product.uom')
|
||||
ProductTemplate = pool.get('product.template')
|
||||
Product = pool.get('product.product')
|
||||
Tax = pool.get('account.tax')
|
||||
Address = pool.get('party.address')
|
||||
PartyIdentifier = pool.get('party.identifier')
|
||||
Country = pool.get('country.country')
|
||||
Subdivision = pool.get('country.subdivision')
|
||||
PaymentType = pool.get('account.payment.type')
|
||||
|
||||
revenue_template_id = ModelData.get_id('account_es', 'pgc_7000_child')
|
||||
expense_template_id = ModelData.get_id('account_es', 'pgc_600_child')
|
||||
vat21_template_id = ModelData.get_id('account_es', 'iva_rep_21')
|
||||
country = Country(name='Country', code='ES', code3='ESP')
|
||||
country.save()
|
||||
subdivision = Subdivision(
|
||||
name='Subdivision', country=country, code='SUB', type='area')
|
||||
subdivision.save()
|
||||
|
||||
company = create_company()
|
||||
currency = create_currency('EUR')
|
||||
add_currency_rate(currency, 1.0)
|
||||
|
||||
tax_identifier = PartyIdentifier()
|
||||
tax_identifier.type = 'eu_vat'
|
||||
tax_identifier.code = 'BE0897290877'
|
||||
company.party.identifiers = [tax_identifier]
|
||||
company.party.facturae_person_type = 'J'
|
||||
company.party.facturae_residence_type = 'R'
|
||||
company.party.save()
|
||||
company.save()
|
||||
|
||||
# Save certificate into company
|
||||
with open(os.path.join(
|
||||
CURRENT_PATH, 'certificate.pfx'), 'rb') as cert_file:
|
||||
company.facturae_certificate = cert_file.read()
|
||||
company.save()
|
||||
|
||||
payment_term, = PaymentTerm.create([{
|
||||
'name': '20 days, 40 days',
|
||||
|
@ -79,13 +97,55 @@ class TestAccountInvoiceFacturaeCase(ModuleTestCase):
|
|||
fiscalyear.save()
|
||||
FiscalYear.create_period([fiscalyear])
|
||||
|
||||
revenue, = Account.search([('template', '=', revenue_template_id)])
|
||||
expense, = Account.search([('template', '=', expense_template_id)])
|
||||
vat21, = Tax.search([('template', '=', vat21_template_id)])
|
||||
payment_receivable, = PaymentType.create([{
|
||||
'name': 'Payment Receivable',
|
||||
'kind': 'receivable',
|
||||
'company': company.id,
|
||||
'facturae_type': '01',
|
||||
}])
|
||||
revenue, = Account.search([('kind', '=', 'revenue')])
|
||||
expense, = Account.search([('kind', '=', 'expense')])
|
||||
tax_account, = Account.search([
|
||||
('name', '=', 'Main Tax'),
|
||||
])
|
||||
with Transaction().set_user(0):
|
||||
vat21 = Tax()
|
||||
vat21.name = vat21.description = '21% VAT'
|
||||
vat21.type = 'percentage'
|
||||
vat21.rate = Decimal('0.21')
|
||||
vat21.invoice_account = tax_account
|
||||
vat21.report_type = '05'
|
||||
vat21.credit_note_account = tax_account
|
||||
|
||||
vat21.save()
|
||||
|
||||
company_address, = company.party.addresses
|
||||
company_address.street = 'street'
|
||||
company_address.zip = '08201'
|
||||
company_address.city = 'City'
|
||||
company_address.subdivision = subdivision
|
||||
company_address.country = country
|
||||
company_address.save()
|
||||
party = Party(name='Party')
|
||||
party.facturae_person_type = 'J'
|
||||
party.facturae_residence_type = 'R'
|
||||
tax_identifier = PartyIdentifier()
|
||||
tax_identifier.type = 'eu_vat'
|
||||
tax_identifier.code = 'BE0897290877'
|
||||
party.identifiers = [tax_identifier]
|
||||
party.save()
|
||||
|
||||
address_dict = {
|
||||
'party': party.id,
|
||||
'street': 'St sample, 15',
|
||||
'city': 'City',
|
||||
'zip': '08201',
|
||||
'subdivision': subdivision.id,
|
||||
'country': country.id,
|
||||
}
|
||||
|
||||
address, = Address.create([address_dict])
|
||||
|
||||
term, = PaymentTerm.create([{
|
||||
'name': 'Payment term',
|
||||
'lines': [
|
||||
|
@ -116,12 +176,19 @@ class TestAccountInvoiceFacturaeCase(ModuleTestCase):
|
|||
product.template = template
|
||||
product.save()
|
||||
|
||||
currency = create_currency('Eur')
|
||||
add_currency_rate(currency, 1)
|
||||
|
||||
with Transaction().set_user(0):
|
||||
invoice = Invoice()
|
||||
invoice.type = 'out'
|
||||
invoice.on_change_type()
|
||||
invoice.party = party
|
||||
invoice.on_change_party()
|
||||
invoice.payment_type = payment_receivable
|
||||
invoice.payment_term = term
|
||||
invoice.currency = currency
|
||||
invoice.company = company
|
||||
|
||||
line1 = InvoiceLine()
|
||||
line1.product = product
|
||||
|
@ -133,26 +200,19 @@ class TestAccountInvoiceFacturaeCase(ModuleTestCase):
|
|||
line2 = InvoiceLine()
|
||||
line2.account = revenue
|
||||
line2.on_change_account()
|
||||
line2.product = product
|
||||
line2.on_change_product()
|
||||
line2.description = 'Test'
|
||||
line2.quantity = 1
|
||||
line2.unit_price = Decimal(20)
|
||||
|
||||
invoice.lines = [line1, line2]
|
||||
invoice.on_change_lines()
|
||||
invoice.save()
|
||||
# invoice.untaxed_amount == Decimal('220.00')
|
||||
# invoice.tax_amount == Decimal('20.00')
|
||||
# invoice.total_amount == Decimal('240.00')
|
||||
|
||||
invoice.save()
|
||||
Invoice.post([invoice])
|
||||
|
||||
session_id, _, _ = GenerateSignedFacturae.create()
|
||||
generate_signed_facturae = GenerateSignedFacturae(session_id)
|
||||
generate_signed_facturae.account.certificate_password = (
|
||||
'privatepassword')
|
||||
generate_signed_facturae.transition_generate()
|
||||
|
||||
self.assertIsNotNone(invoice.invoice_facturae)
|
||||
Invoice.generate_facturae_default([invoice], 'privatepassword')
|
||||
|
||||
|
||||
def suite():
|
||||
|
|
Loading…
Reference in New Issue