[IMP] l10n_in: add hsn summary to invoice report

task_id: 3196107

closes odoo/odoo#155084

Signed-off-by: Laurent Smet (las) <las@odoo.com>
Co-authored-by: Harsh Modi <hamo@odoo.com>
This commit is contained in:
Laurent Smet
2024-02-26 21:22:51 +00:00
committed by Harsh Modi
co-authored by Harsh Modi
parent 7f4e421bcb
commit a404654c18
5 changed files with 796 additions and 0 deletions
+1
View File
@@ -1132,6 +1132,7 @@ class AccountTax(models.Model):
return {'tax': tax_values['tax_repartition_line'].tax_id}
global_tax_details = {
'to_process': to_process,
'base_amount_currency': 0.0,
'base_amount': 0.0,
'tax_amount_currency': 0.0,
+117
View File
@@ -3,8 +3,11 @@
import base64
import logging
from collections import defaultdict
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError, RedirectWarning, UserError
from odoo.tools import frozendict
from odoo.tools.image import image_data_uri
_logger = logging.getLogger(__name__)
@@ -142,3 +145,117 @@ class AccountMove(models.Model):
barcode = self.env['ir.actions.report'].barcode(barcode_type="QR", value=payment_url, width=120, height=120)
return image_data_uri(base64.b64encode(barcode))
return super()._generate_qr_code(silent_errors)
def _l10n_in_get_hsn_summary_table(self):
self.ensure_one()
display_uom = self.env.user.user_has_groups('uom.group_uom')
tag_igst = self.env.ref('l10n_in.tax_tag_igst')
tag_cgst = self.env.ref('l10n_in.tax_tag_cgst')
tag_sgst = self.env.ref('l10n_in.tax_tag_sgst')
tag_cess = self.env.ref('l10n_in.tax_tag_cess')
def filter_invl_to_apply(invoice_line):
return bool(invoice_line.product_id.l10n_in_hsn_code)
def grouping_key_generator(base_line, _tax_values):
# The rate is only for SGST/CGST.
if base_line['is_refund']:
tax_rep_field = 'refund_repartition_line_ids'
else:
tax_rep_field = 'invoice_repartition_line_ids'
gst_taxes = base_line['taxes'].flatten_taxes_hierarchy()[tax_rep_field]\
.filtered(lambda tax_rep: (
tax_rep.repartition_type == 'tax'
and any(tag in tax_rep.tag_ids for tag in tag_sgst + tag_cgst + tag_igst)
))\
.tax_id
return {
'l10n_in_hsn_code': base_line['record'].product_id.l10n_in_hsn_code,
'rate': sum(gst_taxes.mapped('amount')),
'uom': base_line['record'].product_uom_id,
}
aggregated_values = self._prepare_invoice_aggregated_taxes(
filter_invl_to_apply=filter_invl_to_apply,
grouping_key_generator=grouping_key_generator,
)
results_map = {}
has_igst = False
has_gst = False
has_cess = False
for grouping_key, tax_details in aggregated_values['tax_details'].items():
values = results_map.setdefault(grouping_key, {
'quantity': 0.0,
'amount_untaxed': tax_details['base_amount_currency'],
'tax_amounts': defaultdict(lambda: 0.0),
})
# Quantity.
invoice_line_ids = set()
for invoice_line in tax_details['records']:
if invoice_line.id not in invoice_line_ids:
values['quantity'] += invoice_line.quantity
invoice_line_ids.add(invoice_line.id)
# Tax amounts.
for tax_details in tax_details['group_tax_details']:
tax_rep = tax_details['tax_repartition_line']
if tag_igst in tax_rep.tag_ids:
has_igst = True
values['tax_amounts'][tag_igst] += tax_details['tax_amount_currency']
if tag_cgst in tax_rep.tag_ids:
has_gst = True
values['tax_amounts'][tag_cgst] += tax_details['tax_amount_currency']
if tag_sgst in tax_rep.tag_ids:
has_gst = True
values['tax_amounts'][tag_sgst] += tax_details['tax_amount_currency']
if tag_cess in tax_rep.tag_ids:
has_cess = True
values['tax_amounts'][tag_cess] += tax_details['tax_amount_currency']
# In case of base_line with HSN code but no taxes, an entry in results_map should be created.
for base_line, _to_update_vals, _tax_values_list in aggregated_values['to_process']:
if base_line['taxes']:
continue
grouping_key = frozendict(grouping_key_generator(base_line, None))
results = results_map.setdefault(grouping_key, {
'quantity': 0.0,
'amount_untaxed': 0.0,
'tax_amounts': defaultdict(lambda: 0.0),
})
results['quantity'] += base_line['quantity']
results['amount_untaxed'] += base_line['price_subtotal']
nb_columns = 5
if has_igst:
nb_columns += 1
if has_gst:
nb_columns += 2
if has_cess:
nb_columns += 1
items = []
for grouping_key, values in results_map.items():
items.append({
'l10n_in_hsn_code': grouping_key['l10n_in_hsn_code'],
'quantity': values['quantity'],
'uom': grouping_key['uom'],
'rate': grouping_key['rate'],
'amount_untaxed': values['amount_untaxed'],
'tax_amount_igst': values['tax_amounts'].get(tag_igst, 0.0),
'tax_amount_cgst': values['tax_amounts'].get(tag_cgst, 0.0),
'tax_amount_sgst': values['tax_amounts'].get(tag_sgst, 0.0),
'tax_amount_cess': values['tax_amounts'].get(tag_cess, 0.0),
})
return {
'has_igst': has_igst,
'has_gst': has_gst,
'has_cess': has_cess,
'nb_columns': nb_columns,
'display_uom': display_uom,
'items': items,
}
+1
View File
@@ -0,0 +1 @@
from . import test_invoice_hsn_summary
@@ -0,0 +1,624 @@
# -*- coding: utf-8 -*-
from freezegun import freeze_time
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.fields import Command
from odoo.tests import tagged
@tagged('post_install', '-at_install', 'post_install_l10n')
class TestInvoiceHSNsummary(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls):
super().setUpClass(chart_template_ref='in')
cls.test_hsn_code_1 = '1234'
cls.test_hsn_code_2 = '4321'
cls.uom_unit = cls.env.ref('uom.product_uom_unit')
cls.uom_dozen = cls.env.ref('uom.product_uom_dozen')
cls.product_a.l10n_in_hsn_code = cls.test_hsn_code_1
cls.product_b.l10n_in_hsn_code = cls.test_hsn_code_2
cls.product_c = cls.env['product.product'].create({
'name': 'product_c',
'l10n_in_hsn_code': cls.test_hsn_code_1,
'uom_id': cls.env.ref('uom.product_uom_unit').id,
'lst_price': 1000.0,
'property_account_income_id': cls.company_data['default_account_revenue'].id,
})
cls.gst_5 = cls.env['account.chart.template'].ref('sgst_sale_5')
cls.gst_18 = cls.env['account.chart.template'].ref('sgst_sale_18')
cls.igst_0 = cls.env['account.chart.template'].ref('igst_sale_0')
cls.igst_5 = cls.env['account.chart.template'].ref('igst_sale_5')
cls.igst_18 = cls.env['account.chart.template'].ref('igst_sale_18')
cls.cess_5_plus_1591 = cls.env['account.chart.template'].ref('cess_5_plus_1591_sale')
cls.exempt_0 = cls.env['account.chart.template'].ref('exempt_sale')
cls.display_uom = cls.env.user.user_has_groups('uom.group_uom')
def assert_hsn_summary(self, invoice, expected_values):
hsn_summary = invoice._l10n_in_get_hsn_summary_table()
self.assertEqual(
{k: len(v) if k == 'items' else v for k, v in hsn_summary.items()},
{k: len(v) if k == 'items' else v for k, v in expected_values.items()},
)
self.assertEqual(len(hsn_summary['items']), len(expected_values['items']))
for item, expected_item in zip(hsn_summary['items'], expected_values['items']):
self.assertDictEqual(item, expected_item)
@freeze_time('2019-01-01')
def create_invoice(self, invoice_line_ids, **kwargs):
return self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
**kwargs,
'invoice_line_ids': invoice_line_ids,
})
def test_l10n_in_hsn_summary_1(self):
""" Test GST/IGST taxes. """
invoice = self.create_invoice(invoice_line_ids=[
Command.create({
'product_id': self.product_a.id,
'quantity': 2.0,
'price_unit': 100,
'tax_ids': [Command.set(self.gst_5.ids)], #Tax: 10
}),
Command.create({
'product_id': self.product_c.id,
'quantity': 1.0,
'price_unit': 600,
'tax_ids': [Command.set(self.gst_5.ids)], #Tax: 30
}),
Command.create({
'product_id': self.product_a.id,
# 'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 5.0,
'price_unit': 300,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set(self.gst_5.ids)], #Tax: 75
}),
Command.create({
'product_id': self.product_a.id,
'quantity': 2.0,
'price_unit': 100,
'tax_ids': [Command.set(self.gst_18.ids)], #Tax: 36
}),
Command.create({
'product_id': self.product_c.id,
'quantity': 1.0,
'price_unit': 600,
'tax_ids': [Command.set(self.gst_18.ids)], #Tax: 108
}),
Command.create({
'product_id': self.product_a.id,
# 'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 5.0,
'price_unit': 300,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set(self.gst_18.ids)], #Tax: 270
}),
])
self.assertRecordValues(invoice, [{
'amount_untaxed': 4600.0,
'amount_tax': 529.0,
'amount_total': 5129.0,
}])
self.assert_hsn_summary(invoice, {
'has_igst': False,
'has_gst': True,
'has_cess': False,
'nb_columns': 7,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 5.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 57.5,
'tax_amount_sgst': 57.5,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 207.0,
'tax_amount_sgst': 207.0,
'tax_amount_cess': 0.0,
},
],
})
# Change the UOM of the second line.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[1].id, {'product_uom_id': self.uom_dozen.id}),
]
self.assertRecordValues(invoice, [{
'amount_untaxed': 16000.0,
'amount_tax': 1099.0,
'amount_total': 17099.0,
}])
self.assert_hsn_summary(invoice, {
'has_igst': False,
'has_gst': True,
'has_cess': False,
'nb_columns': 7,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 7.0,
'uom': self.uom_unit,
'rate': 5.0,
'amount_untaxed': 1700.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 42.5,
'tax_amount_sgst': 42.5,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 1.0,
'uom': self.uom_dozen,
'rate': 5.0,
'amount_untaxed': 12000.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 300.0,
'tax_amount_sgst': 300.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 207.0,
'tax_amount_sgst': 207.0,
'tax_amount_cess': 0.0,
}
]
})
# Change GST 5% taxes to IGST.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[0].id, {'tax_ids': [Command.set(self.igst_5.ids)]}),
Command.update(invoice.invoice_line_ids[1].id, {'tax_ids': [Command.set(self.igst_5.ids)]}),
Command.update(invoice.invoice_line_ids[2].id, {'tax_ids': [Command.set(self.igst_5.ids)]}),
]
self.assertRecordValues(invoice, [{
'amount_untaxed': 16000.0,
'amount_tax': 1099.0,
'amount_total': 17099.0,
}])
self.assert_hsn_summary(invoice, {
'has_igst': True,
'has_gst': True,
'has_cess': False,
'nb_columns': 8,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 7.0,
'uom': self.uom_unit,
'rate': 5.0,
'amount_untaxed': 1700.0,
'tax_amount_igst': 85.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 1.0,
'uom': self.uom_dozen,
'rate': 5.0,
'amount_untaxed': 12000.0,
'tax_amount_igst': 600.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 207.0,
'tax_amount_sgst': 207.0,
'tax_amount_cess': 0.0,
},
],
})
# Put back the UOM of the second line to unit.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[1].id, {
'product_uom_id': self.uom_unit.id,
'price_unit': 600,
'tax_ids': [Command.set(self.igst_5.ids)],
}),
]
self.assertRecordValues(invoice, [{
'amount_untaxed': 4600.0,
'amount_tax': 529.0,
'amount_total': 5129.0,
}])
self.assert_hsn_summary(invoice, {
'has_igst': True,
'has_gst': True,
'has_cess': False,
'nb_columns': 8,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 5.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 115.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 207.0,
'tax_amount_sgst': 207.0,
'tax_amount_cess': 0.0,
},
],
})
# Change GST 18% taxes to IGST.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[3].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
Command.update(invoice.invoice_line_ids[4].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
Command.update(invoice.invoice_line_ids[5].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
]
self.assert_hsn_summary(invoice, {
'has_igst': True,
'has_gst': False,
'has_cess': False,
'nb_columns': 6,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 5.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 115.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 8.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 2300.0,
'tax_amount_igst': 414.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
],
})
def test_l10n_in_hsn_summary_2(self):
""" Test CESS taxes in combination with GST/IGST. """
invoice = self.create_invoice(invoice_line_ids=[
Command.create({
'product_id': self.product_a.id,
'quantity': 1.0,
'price_unit': 15.80,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set((self.gst_18 + self.cess_5_plus_1591).ids)],
})
])
self.assertRecordValues(invoice, [{
'amount_untaxed': 15.8,
'amount_tax': 5.22,
'amount_total': 21.02,
}])
self.assert_hsn_summary(invoice, {
'has_igst': False,
'has_gst': True,
'has_cess': True,
'nb_columns': 8,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 1.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 15.8,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 1.42,
'tax_amount_sgst': 1.42,
'tax_amount_cess': 2.38,
},
],
})
# Change GST 18% taxes to IGST.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids.id, {
'tax_ids': [Command.set((self.igst_18 + self.cess_5_plus_1591).ids)],
}),
]
self.assert_hsn_summary(invoice, {
'has_igst': True,
'has_gst': False,
'has_cess': True,
'nb_columns': 7,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 1.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 15.8,
'tax_amount_igst': 2.84,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 2.38,
},
],
})
def test_l10n_in_hsn_summary_3(self):
""" Test with mixed HSN codes. """
invoice = self.create_invoice(invoice_line_ids=[
Command.create({
'product_id': self.product_a.id,
'quantity': 1.0,
'price_unit': 100,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set(self.gst_18.ids)],
}),
Command.create({
# 'l10n_in_hsn_code': self.test_hsn_code_1,
'product_id': self.product_a.id,
'quantity': 2.0,
'price_unit': 50,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set(self.gst_18.ids)],
}),
Command.create({
'product_id': self.product_b.id,
'quantity': 1.0,
'price_unit': 100,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set(self.gst_18.ids)],
}),
Command.create({
'product_id': self.product_b.id,
# 'l10n_in_hsn_code': self.test_hsn_code_2,
'quantity': 2.0,
'price_unit': 50,
'product_uom_id': self.uom_unit.id,
'tax_ids': [Command.set(self.gst_18.ids)],
})
])
self.assertRecordValues(invoice, [{
'amount_untaxed': 400.0,
'amount_tax': 72.0,
'amount_total': 472.0,
}])
self.assert_hsn_summary(invoice, {
'has_igst': False,
'has_gst': True,
'has_cess': False,
'nb_columns': 7,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 3.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 200.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 18.0,
'tax_amount_sgst': 18.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_2,
'quantity': 3.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 200.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 18.0,
'tax_amount_sgst': 18.0,
'tax_amount_cess': 0.0,
},
],
})
# Change GST 18% taxes to IGST.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[0].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
Command.update(invoice.invoice_line_ids[1].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
Command.update(invoice.invoice_line_ids[2].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
Command.update(invoice.invoice_line_ids[3].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
]
self.assert_hsn_summary(invoice, {
'has_igst': True,
'has_gst': False,
'has_cess': False,
'nb_columns': 6,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 3.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 200.0,
'tax_amount_igst': 36.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_2,
'quantity': 3.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 200.0,
'tax_amount_igst': 36.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
],
})
def test_l10n_in_hsn_summary_4(self):
""" Zero rated GST or no taxes at all."""
invoice = self.create_invoice(invoice_line_ids=[
Command.create({
'product_id': self.product_a.id,
'quantity': 1.0,
'price_unit': 350.0,
'product_uom_id': self.uom_unit.id,
'tax_ids': [],
}),
Command.create({
'product_id': self.product_a.id,
'quantity': 1.0,
'price_unit': 350.0,
'product_uom_id': self.uom_unit.id,
'tax_ids': [],
}),
])
self.assert_hsn_summary(invoice, {
'has_igst': False,
'has_gst': False,
'has_cess': False,
'nb_columns': 5,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 2.0,
'uom': self.uom_unit,
'rate': 0.0,
'amount_untaxed': 700.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
],
})
# No tax to IGST 0%/exempt.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[0].id, {'tax_ids': [Command.set(self.igst_0.ids)]}),
Command.update(invoice.invoice_line_ids[1].id, {'tax_ids': [Command.set(self.exempt_0.ids)]}),
]
self.assert_hsn_summary(invoice, {
'has_igst': False,
'has_gst': False,
'has_cess': False,
'nb_columns': 5,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 2.0,
'uom': self.uom_unit,
'rate': 0.0,
'amount_untaxed': 700.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
],
})
# Put one IGST 18% to get a value on the IGST column.
invoice.invoice_line_ids = [
Command.update(invoice.invoice_line_ids[0].id, {'tax_ids': [Command.set(self.igst_18.ids)]}),
]
self.assert_hsn_summary(invoice, {
'has_igst': True,
'has_gst': False,
'has_cess': False,
'nb_columns': 6,
'display_uom': self.display_uom,
'items': [
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 1.0,
'uom': self.uom_unit,
'rate': 18.0,
'amount_untaxed': 350.0,
'tax_amount_igst': 63.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
{
'l10n_in_hsn_code': self.test_hsn_code_1,
'quantity': 1.0,
'uom': self.uom_unit,
'rate': 0.0,
'amount_untaxed': 350.0,
'tax_amount_igst': 0.0,
'tax_amount_cgst': 0.0,
'tax_amount_sgst': 0.0,
'tax_amount_cess': 0.0,
},
],
})
+53
View File
@@ -58,6 +58,59 @@
</h2>
</xpath>
<xpath expr="//div[@id='payment_term']" position="before">
<t t-if="o.company_id.account_fiscal_country_id.code == 'IN'">
<t t-set="hsn_summary" t-value="o._l10n_in_get_hsn_summary_table()"/>
<t t-if="hsn_summary">
<div name="l10n_in_hsn_summary" class="mt-3">
<table class="table table-sm table-borderless col-6" style="page-break-inside: avoid;">
<thead>
<th t-att-colspan="hsn_summary['nb_columns']"><h3>HSN Summary</h3></th>
</thead>
<thead>
<th>HSN/SAC</th>
<th class="text-end">Quantity</th>
<th class="text-end">Rate %</th>
<th class="text-end">Taxable Value</th>
<th class="text-end" t-if="hsn_summary['has_gst']">SGST</th>
<th class="text-end" t-if="hsn_summary['has_gst']">CGST</th>
<th class="text-end" t-if="hsn_summary['has_igst']">IGST</th>
<th class="text-end" t-if="hsn_summary['has_cess']">CESS</th>
</thead>
<tr t-foreach="hsn_summary['items']" t-as="item">
<td t-esc="item['l10n_in_hsn_code']"/>
<td class="text-end">
<span t-esc="item['quantity']"/>
<span t-if="hsn_summary['display_uom']">(<t t-esc="item['uom'].name"/>)</span>
</td>
<td class="text-end" t-esc="item['rate']"/>
<td class="text-end">
<span t-esc="item['amount_untaxed']"
t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_gst']">
<span t-esc="item['tax_amount_sgst']"
t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_gst']">
<span t-esc="item['tax_amount_cgst']"
t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_igst']">
<span t-esc="item['tax_amount_igst']"
t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_cess']">
<span t-esc="item['tax_amount_cess']"
t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
</tr>
</table>
</div>
</t>
</t>
</xpath>
</template>
<!-- Workaround for Studio reports, see odoo/odoo#60660 -->