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 #164966

X-original-commit: 6f0642d
Signed-off-by: Julien Van Roy (juvr) <juvr@odoo.com>
Signed-off-by: Dylan Kiss (dyki) <dyki@odoo.com>
  • Loading branch information
dylankiss committed May 12, 2024
1 parent d978878 commit 3f75327
Show file tree
Hide file tree
Showing 3 changed files with 195 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 @@ -240,6 +240,12 @@ def _get_invoice_line_vals(self, line, line_id, 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['line_quantity'] *= -1

return vals

def _export_invoice_vals(self, invoice):
Expand Down Expand Up @@ -324,11 +330,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,165 @@
<?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:AdditionalDocumentReference>
<cbc:ID>___ignore___</cbc:ID>
<cbc:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="___ignore___" filename="___ignore___">
___ignore___
</cbc:EmbeddedDocumentBinaryObject>
</cbc:Attachment>
</cac:AdditionalDocumentReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="0208">0202239951</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="0208">0477472701</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:Delivery>
<cac:DeliveryLocation>
<cac:Address>
<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:Address>
</cac:DeliveryLocation>
</cac:Delivery>
<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>Payment terms: 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 @@ -306,6 +306,30 @@ def test_rounding_price_unit(self):
)
self._assert_invoice_attachment(invoice.ubl_cii_xml_id, None, 'from_odoo/bis3_out_invoice_rounding.xml')

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.ubl_cii_xml_id, None, 'from_odoo/bis3_out_invoice_negative_unit_price.xml')

def test_export_with_fixed_taxes_case1(self):
# CASE 1: simple invoice with a recupel tax
invoice = self._generate_move(
Expand Down

0 comments on commit 3f75327

Please sign in to comment.