Skip to content

Commit

Permalink
[FIX] account_edi_ubl_cii: invert negative unit price with quantity
Browse files Browse the repository at this point in the history
Currently, when we use eCommerce with automatic invoicing enabled, and
we have the Peppol format enabled in the invoicing settings, there is
an issue when coupons or discount codes are applied.

These discounts create a sale order line (and afterwards a move line)
with a negative unit price. Since UBL BIS3 does not allow negative unit
prices, the automatic generation of the e-invoice is not executed and
the customer receives a "proforma invoice" PDF instead (which has no
official value). A message is logged in the chatter, but the user has no
notification or anything.

We can do better, and instead invert both the unit price and quantity
fields (since UBL BIS3 does allow negative quantities), to have the same
result when generating the e-invoice.

task-3916181

closes odoo#164735

Signed-off-by: Julien Van Roy (juvr) <juvr@odoo.com>
  • Loading branch information
dylankiss committed May 7, 2024
1 parent 6a8bf12 commit ded04d5
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 5 deletions.
11 changes: 6 additions & 5 deletions addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ def _get_invoice_line_vals(self, line, taxes_vals):
vals['currency_dp'] = 2
vals['price_vals']['currency_dp'] = 2

if line.currency_id.compare_amounts(vals['price_vals']['price_amount'], 0) == -1:
# We can't have negative unit prices, so we invert the signs of
# the unit price and quantity, resulting in the same amount in the end
vals['price_vals']['price_amount'] *= -1
vals['invoiced_quantity'] *= -1

return vals

def _export_invoice_vals(self, invoice):
Expand Down Expand Up @@ -375,11 +381,6 @@ def _invoice_constraints_cen_en16931_ubl(self, invoice, vals):
break

for line in invoice.invoice_line_ids.filtered(lambda x: x.display_type not in ('line_note', 'line_section')):
if invoice.currency_id.compare_amounts(line.price_unit, 0) == -1:
# [BR-27]-The Item net price (BT-146) shall NOT be negative.
constraints.update({'cen_en16931_positive_item_net_price': _(
"The invoice contains line(s) with a negative unit price, which is not allowed."
" You might need to set a negative quantity instead.")})
if len(line.tax_ids.flatten_taxes_hierarchy().filtered(lambda t: t.amount_type != 'fixed')) != 1:
# [UBL-SR-48]-Invoice lines shall have one and only one classified tax category.
# /!\ exception: possible to have any number of ecotaxes (fixed tax) with a regular percentage tax
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>___ignore___</cbc:ID>
<cbc:IssueDate>2017-01-01</cbc:IssueDate>
<cbc:DueDate>2017-02-28</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>test narration</cbc:Note>
<cbc:DocumentCurrencyCode>USD</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>ref_partner_2</cbc:BuyerReference>
<cac:OrderReference>
<cbc:ID>___ignore___</cbc:ID>
</cac:OrderReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="9925">BE0202239951</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>partner_1</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Chauss&#233;e de Namur 40</cbc:StreetName>
<cbc:CityName>Ramillies</cbc:CityName>
<cbc:PostalZone>1367</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>BE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>BE0202239951</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>partner_1</cbc:RegistrationName>
<cbc:CompanyID>BE0202239951</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>partner_1</cbc:Name>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="9925">BE0477472701</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>partner_2</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Rue des Bourlottes 9</cbc:StreetName>
<cbc:CityName>Ramillies</cbc:CityName>
<cbc:PostalZone>1367</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>BE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>BE0477472701</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>partner_2</cbc:RegistrationName>
<cbc:CompanyID>BE0477472701</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>partner_2</cbc:Name>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="credit transfer">30</cbc:PaymentMeansCode>
<cbc:PaymentID>___ignore___</cbc:PaymentID>
<cac:PayeeFinancialAccount>
<cbc:ID>BE15001559627230</cbc:ID>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>30% Advance End of Following Month</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="USD">15.75</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">75.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">15.75</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>21.0</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="USD">75.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="USD">75.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="USD">90.75</cbc:TaxInclusiveAmount>
<cbc:PrepaidAmount currencyID="USD">0.00</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="USD">90.75</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>___ignore___</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">1.0</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>product_a</cbc:Description>
<cbc:Name>product_a</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>21.0</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="USD">100.0</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>___ignore___</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">-1.0</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="USD">-25.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>product_a</cbc:Description>
<cbc:Name>product_a</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>21.0</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="USD">25.0</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>
24 changes: 24 additions & 0 deletions addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,3 +559,27 @@ def test_import_fixed_taxes(self):
list_line_subtotals=[178.2], currency_id=self.currency_data['currency'].id, list_line_price_unit=[99],
list_line_discount=[10], list_line_taxes=[tax_21+self.recupel], move_type='out_invoice',
)

def test_inverting_negative_price_unit(self):
""" We can not have negative unit prices, so we try to invert the unit price and quantity.
"""
invoice = self._generate_move(
self.partner_1,
self.partner_2,
move_type='out_invoice',
invoice_line_ids=[
{
'product_id': self.product_a.id,
'quantity': 1,
'price_unit': 100.0,
'tax_ids': [(6, 0, self.tax_21.ids)],
},
{
'product_id': self.product_a.id,
'quantity': 1,
'price_unit': -25.0,
'tax_ids': [(6, 0, self.tax_21.ids)],
}
],
)
self._assert_invoice_attachment(invoice, None, 'from_odoo/bis3_out_invoice_negative_unit_price.xml')

0 comments on commit ded04d5

Please sign in to comment.