[FIX] l10n_in_edi: global discount - Line item/HSN effect
Before this commit =============== Global discount with Tax effect been developed in such a way that it calculates discount based on tax groups and brings correct tax liabilities to comply. Where in it drops lines with minus in invoice form, While doing E Invoice in India - Government portal not entertain product with minus lines to reduce liability. After this commit =============== Refactored invoice form for E-Invoice in India post-global discount implementation. Adjusted discount sign to address the government portal's restriction on negative lines. The fix ensures the portal now accepts discount lines, aligning with regulatory requirements. closes odoo/odoo#146163 Task: 3454674 Signed-off-by: Josse Colpaert <jco@odoo.com>
This commit is contained in:
@@ -77,6 +77,9 @@ class AccountEdiFormat(models.Model):
|
||||
result = "".join(matches)
|
||||
return result
|
||||
|
||||
def _l10n_in_is_global_discount(self, line):
|
||||
return not line.tax_ids and line.price_subtotal < 0 or False
|
||||
|
||||
def _check_move_configuration(self, move):
|
||||
if self.code != "in_einvoice_1_03":
|
||||
return super()._check_move_configuration(move)
|
||||
@@ -86,7 +89,7 @@ class AccountEdiFormat(models.Model):
|
||||
if not re.match("^.{1,16}$", move.name):
|
||||
error_message.append(_("Invoice number should not be more than 16 characters"))
|
||||
all_base_tags = self._get_l10n_in_base_tags()
|
||||
for line in move.invoice_line_ids.filtered(lambda line: line.display_type not in ('line_note', 'line_section', 'rounding')):
|
||||
for line in move.invoice_line_ids.filtered(lambda line: line.display_type not in ('line_note', 'line_section', 'rounding') and not self._l10n_in_is_global_discount(line)):
|
||||
if line.price_subtotal < 0:
|
||||
# Line having a negative amount is not allowed.
|
||||
if not move._l10n_in_edi_is_managing_invoice_negative_lines_allowed():
|
||||
@@ -476,9 +479,12 @@ class AccountEdiFormat(models.Model):
|
||||
is_intra_state = invoice.l10n_in_state_id == invoice.company_id.state_id
|
||||
is_overseas = invoice.l10n_in_gst_treatment == "overseas"
|
||||
lines = invoice.invoice_line_ids.filtered(lambda line: line.display_type not in ('line_note', 'line_section', 'rounding'))
|
||||
global_discount_line = lines.filtered(self._l10n_in_is_global_discount)
|
||||
lines -= global_discount_line
|
||||
tax_details_per_record = tax_details.get("tax_details_per_record")
|
||||
sign = invoice.is_inbound() and -1 or 1
|
||||
rounding_amount = sum(line.balance for line in invoice.line_ids if line.display_type == 'rounding') * sign
|
||||
global_discount_amount = sum(line.balance for line in global_discount_line) * sign * -1
|
||||
json_payload = {
|
||||
"Version": "1.1",
|
||||
"TranDtls": {
|
||||
@@ -498,7 +504,7 @@ class AccountEdiFormat(models.Model):
|
||||
for index, line in enumerate(lines, start=1)
|
||||
],
|
||||
"ValDtls": {
|
||||
"AssVal": self._l10n_in_round_value(tax_details.get("base_amount")),
|
||||
"AssVal": self._l10n_in_round_value(tax_details.get("base_amount") + global_discount_amount),
|
||||
"CgstVal": self._l10n_in_round_value(tax_details_by_code.get("cgst_amount", 0.00)),
|
||||
"SgstVal": self._l10n_in_round_value(tax_details_by_code.get("sgst_amount", 0.00)),
|
||||
"IgstVal": self._l10n_in_round_value(tax_details_by_code.get("igst_amount", 0.00)),
|
||||
@@ -510,6 +516,7 @@ class AccountEdiFormat(models.Model):
|
||||
tax_details_by_code.get("state_cess_amount", 0.00)
|
||||
+ tax_details_by_code.get("state_cess_non_advol_amount", 0.00)),
|
||||
),
|
||||
"Discount": self._l10n_in_round_value(global_discount_amount),
|
||||
"RndOffAmt": self._l10n_in_round_value(
|
||||
rounding_amount),
|
||||
"TotInvVal": self._l10n_in_round_value(
|
||||
|
||||
@@ -144,21 +144,21 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
"TranDtls": {"TaxSch": "GST", "SupTyp": "B2B", "RegRev": "N", "IgstOnIntra": "N"},
|
||||
"DocDtls": {"Typ": "INV", "No": "INV/2019/00001", "Dt": "01/01/2019"},
|
||||
"SellerDtls": {
|
||||
"LglNm": "company_1_data",
|
||||
"Addr1": "Block no. 401",
|
||||
"Addr2": "Street 2",
|
||||
"Loc": "City 1",
|
||||
"Pin": 500001,
|
||||
"Stcd": "36",
|
||||
"Addr2": "Street 2",
|
||||
"LglNm": "company_1_data",
|
||||
"GSTIN": "36AABCT1332L011"},
|
||||
"BuyerDtls": {
|
||||
"LglNm": "partner_a",
|
||||
"Addr1": "Block no. 401",
|
||||
"Addr2": "Street 2",
|
||||
"Loc": "City 2",
|
||||
"Pin": 500001,
|
||||
"Stcd": "36",
|
||||
"Addr2": "Street 2",
|
||||
"POS": "36",
|
||||
"LglNm": "partner_a",
|
||||
"GSTIN": "36BBBFF5679L8ZR"},
|
||||
"ItemList": [
|
||||
{
|
||||
@@ -178,7 +178,7 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
],
|
||||
"ValDtls": {
|
||||
"AssVal": 1800.0, "CgstVal": 76.5, "SgstVal": 76.5, "IgstVal": 0.0, "CesVal": 46.59,
|
||||
"StCesVal": 0.0, "RndOffAmt": 0.0, "TotInvVal": 1999.59
|
||||
"StCesVal": 0.0, "Discount": 0.0, "RndOffAmt": 0.0, "TotInvVal": 1999.59
|
||||
}
|
||||
}
|
||||
self.assertDictEqual(json_value, expected, "Indian EDI send json value is not matched")
|
||||
@@ -194,7 +194,7 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
"CesNonAdvlAmt": 0.0, "StateCesRt": 0.0, "StateCesAmt": 0.0, "StateCesNonAdvlAmt": 0.0,
|
||||
"OthChrg": 0.0, "TotItemVal": 0.0}],
|
||||
"ValDtls": {"AssVal": 0.0, "CgstVal": 0.0, "SgstVal": 0.0, "IgstVal": 0.0, "CesVal": 0.0,
|
||||
"StCesVal": 0.0, "RndOffAmt": 0.0, "TotInvVal": 0.0}
|
||||
"StCesVal": 0.0, "Discount": 0.0, "RndOffAmt": 0.0, "TotInvVal": 0.0}
|
||||
})
|
||||
self.assertDictEqual(json_value, expected, "Indian EDI with 100% discount sent json value is not matched")
|
||||
|
||||
@@ -233,7 +233,7 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
],
|
||||
"ValDtls": {
|
||||
"AssVal": 1600.0, "CgstVal": 75.0, "SgstVal": 75.0, "IgstVal": 0.0, "CesVal": 51.59,
|
||||
"StCesVal": 0.0, "RndOffAmt": 0.0, "TotInvVal": 1801.59
|
||||
"StCesVal": 0.0, "Discount": 0.0, "RndOffAmt": 0.0, "TotInvVal": 1801.59
|
||||
},
|
||||
})
|
||||
self.assertDictEqual(json_value, expected, "Indian EDI with negative unit price sent json value is not matched")
|
||||
@@ -257,7 +257,7 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
}],
|
||||
"ValDtls": {
|
||||
"AssVal": 600.0, "CgstVal": 15.0, "SgstVal": 15.0, "IgstVal": 0.0, "CesVal": 0.0,
|
||||
"StCesVal": 0.0, "RndOffAmt": 0.0, "TotInvVal": 630.0
|
||||
"StCesVal": 0.0, "Discount": 0.0, "RndOffAmt": 0.0, "TotInvVal": 630.0
|
||||
},
|
||||
})
|
||||
json_value = self.env["account.edi.format"]._l10n_in_edi_generate_invoice_json(self.invoice_negative_with_discount)
|
||||
@@ -281,7 +281,7 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
}],
|
||||
"ValDtls": {
|
||||
"AssVal": 900.0, "CgstVal": 22.5, "SgstVal": 22.5, "IgstVal": 0.0, "CesVal": 0.0,
|
||||
"StCesVal": 0.0, "RndOffAmt": 0.0, "TotInvVal": 945.0
|
||||
"StCesVal": 0.0, "Discount": 0.0, "RndOffAmt": 0.0, "TotInvVal": 945.0
|
||||
},
|
||||
})
|
||||
json_value = self.env['account.edi.format']._l10n_in_edi_generate_invoice_json(self.invoice_negative_more_than_max_line)
|
||||
@@ -292,6 +292,6 @@ class TestEdiJson(AccountTestInvoicingCommon):
|
||||
"DocDtls": {"Typ": "INV", "No": "INV/2019/00009", "Dt": "01/01/2019"},
|
||||
"ValDtls": {
|
||||
"AssVal": 1800.0, "CgstVal": 76.5, "SgstVal": 76.5, "IgstVal": 0.0, "CesVal": 46.59,
|
||||
"StCesVal": 0.0, "RndOffAmt": 0.41, "TotInvVal": 2000.00
|
||||
"StCesVal": 0.0, "Discount": 0.0, "RndOffAmt": 0.41, "TotInvVal": 2000.00
|
||||
}})
|
||||
self.assertDictEqual(json_value, expected_copy_rounding, "Indian EDI with cash rounding sent json value is not matched")
|
||||
|
||||
Reference in New Issue
Block a user