fix: Tax breakup based on items, missing GST fields (#27524)

* fix: Tax breakup based on items

* fix: added gst fields,warehouse validation to pos inv,patch

* fix: tax breakup test fix, eway bill hsn fix

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
This commit is contained in:
Subin Tom 2021-09-17 10:39:03 +05:30 committed by GitHub
parent 41f11eca72
commit d49346ac45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 18 deletions

View File

@ -40,6 +40,7 @@ class POSInvoice(SalesInvoice):
self.validate_change_amount() self.validate_change_amount()
self.validate_change_account() self.validate_change_account()
self.validate_item_cost_centers() self.validate_item_cost_centers()
self.validate_warehouse()
self.validate_serialised_or_batched_item() self.validate_serialised_or_batched_item()
self.validate_stock_availablility() self.validate_stock_availablility()
self.validate_return_items_qty() self.validate_return_items_qty()

View File

@ -1420,15 +1420,22 @@ class TestSalesInvoice(unittest.TestCase):
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si) itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
expected_itemised_tax = { expected_itemised_tax = {
"999800": { "_Test Item": {
"Service Tax": { "Service Tax": {
"tax_rate": 10.0, "tax_rate": 10.0,
"tax_amount": 1500.0 "tax_amount": 1000.0
}
},
"_Test Item 2": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 500.0
} }
} }
} }
expected_itemised_taxable_amount = { expected_itemised_taxable_amount = {
"999800": 15000.0 "_Test Item": 10000.0,
"_Test Item 2": 5000.0
} }
self.assertEqual(itemised_tax, expected_itemised_tax) self.assertEqual(itemised_tax, expected_itemised_tax)

View File

@ -307,4 +307,5 @@ erpnext.patches.v14_0.delete_shopify_doctypes
erpnext.patches.v13_0.replace_supplier_item_group_with_party_specific_item erpnext.patches.v13_0.replace_supplier_item_group_with_party_specific_item
erpnext.patches.v13_0.update_dates_in_tax_withholding_category erpnext.patches.v13_0.update_dates_in_tax_withholding_category
erpnext.patches.v14_0.update_opportunity_currency_fields erpnext.patches.v14_0.update_opportunity_currency_fields
erpnext.patches.v13_0.gst_fields_for_pos_invoice
erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes

View File

@ -0,0 +1,44 @@
from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'}, fields=['name'])
if not company:
return
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description',
allow_on_submit=1, print_hide=1, fetch_if_empty=1)
nil_rated_exempt = dict(fieldname='is_nil_exempt', label='Is Nil Rated or Exempted',
fieldtype='Check', fetch_from='item_code.is_nil_exempt', insert_after='gst_hsn_code',
print_hide=1)
is_non_gst = dict(fieldname='is_non_gst', label='Is Non GST',
fieldtype='Check', fetch_from='item_code.is_non_gst', insert_after='is_nil_exempt',
print_hide=1)
taxable_value = dict(fieldname='taxable_value', label='Taxable Value',
fieldtype='Currency', insert_after='base_net_amount', hidden=1, options="Company:company:default_currency",
print_hide=1)
sales_invoice_gst_fields = [
dict(fieldname='billing_address_gstin', label='Billing Address GSTIN',
fieldtype='Data', insert_after='customer_address', read_only=1,
fetch_from='customer_address.gstin', print_hide=1),
dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address_name',
fetch_from='shipping_address_name.gstin', print_hide=1),
dict(fieldname='place_of_supply', label='Place of Supply',
fieldtype='Data', insert_after='customer_gstin',
print_hide=1, read_only=1),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
fetch_from='company_address.gstin', print_hide=1, read_only=1),
]
custom_fields = {
'POS Invoice': sales_invoice_gst_fields,
'POS Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
}
create_custom_fields(custom_fields, update=True)

View File

@ -483,6 +483,7 @@ def make_custom_fields(update=True):
'Purchase Order': purchase_invoice_gst_fields, 'Purchase Order': purchase_invoice_gst_fields,
'Purchase Receipt': purchase_invoice_gst_fields, 'Purchase Receipt': purchase_invoice_gst_fields,
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields, 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields,
'POS Invoice': sales_invoice_gst_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category, 'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
'Payment Entry': payment_entry_fields, 'Payment Entry': payment_entry_fields,
'Journal Entry': journal_entry_fields, 'Journal Entry': journal_entry_fields,
@ -501,6 +502,7 @@ def make_custom_fields(update=True):
'Sales Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Sales Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Delivery Note Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Delivery Note Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], 'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
'POS Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], 'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],

View File

@ -117,7 +117,7 @@ def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
else: else:
return [_("Item"), _("Taxable Amount")] + tax_accounts return [_("Item"), _("Taxable Amount")] + tax_accounts
def get_itemised_tax_breakup_data(doc, account_wise=False): def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise) itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise)
itemised_taxable_amount = get_itemised_taxable_amount(doc.items) itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
@ -125,28 +125,29 @@ def get_itemised_tax_breakup_data(doc, account_wise=False):
if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'): if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
return itemised_tax, itemised_taxable_amount return itemised_tax, itemised_taxable_amount
item_hsn_map = frappe._dict() if hsn_wise:
for d in doc.items: item_hsn_map = frappe._dict()
item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code")) for d in doc.items:
item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
hsn_tax = {} hsn_tax = {}
for item, taxes in itemised_tax.items(): for item, taxes in itemised_tax.items():
hsn_code = item_hsn_map.get(item) item_or_hsn = item if not hsn_wise else item_hsn_map.get(item)
hsn_tax.setdefault(hsn_code, frappe._dict()) hsn_tax.setdefault(item_or_hsn, frappe._dict())
for tax_desc, tax_detail in taxes.items(): for tax_desc, tax_detail in taxes.items():
key = tax_desc key = tax_desc
if account_wise: if account_wise:
key = tax_detail.get('tax_account') key = tax_detail.get('tax_account')
hsn_tax[hsn_code].setdefault(key, {"tax_rate": 0, "tax_amount": 0}) hsn_tax[item_or_hsn].setdefault(key, {"tax_rate": 0, "tax_amount": 0})
hsn_tax[hsn_code][key]["tax_rate"] = tax_detail.get("tax_rate") hsn_tax[item_or_hsn][key]["tax_rate"] = tax_detail.get("tax_rate")
hsn_tax[hsn_code][key]["tax_amount"] += tax_detail.get("tax_amount") hsn_tax[item_or_hsn][key]["tax_amount"] += tax_detail.get("tax_amount")
# set taxable amount # set taxable amount
hsn_taxable_amount = frappe._dict() hsn_taxable_amount = frappe._dict()
for item in itemised_taxable_amount: for item in itemised_taxable_amount:
hsn_code = item_hsn_map.get(item) item_or_hsn = item if not hsn_wise else item_hsn_map.get(item)
hsn_taxable_amount.setdefault(hsn_code, 0) hsn_taxable_amount.setdefault(item_or_hsn, 0)
hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item) hsn_taxable_amount[item_or_hsn] += itemised_taxable_amount.get(item)
return hsn_tax, hsn_taxable_amount return hsn_tax, hsn_taxable_amount
@ -440,7 +441,7 @@ def get_ewb_data(dt, dn):
data.itemList = [] data.itemList = []
data.totalValue = doc.total data.totalValue = doc.total
data = get_item_list(data, doc) data = get_item_list(data, doc, hsn_wise=True)
disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total') disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total')
data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total
@ -551,7 +552,7 @@ def get_address_details(data, doc, company_address, billing_address, dispatch_ad
return data return data
def get_item_list(data, doc): def get_item_list(data, doc, hsn_wise=False):
for attr in ['cgstValue', 'sgstValue', 'igstValue', 'cessValue', 'OthValue']: for attr in ['cgstValue', 'sgstValue', 'igstValue', 'cessValue', 'OthValue']:
data[attr] = 0 data[attr] = 0
@ -563,7 +564,7 @@ def get_item_list(data, doc):
'cess_account': ['cessRate', 'cessValue'] 'cess_account': ['cessRate', 'cessValue']
} }
item_data_attrs = ['sgstRate', 'cgstRate', 'igstRate', 'cessRate', 'cessNonAdvol'] item_data_attrs = ['sgstRate', 'cgstRate', 'igstRate', 'cessRate', 'cessNonAdvol']
hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True) hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True, hsn_wise=hsn_wise)
for hsn_code, taxable_amount in hsn_taxable_amount.items(): for hsn_code, taxable_amount in hsn_taxable_amount.items():
item_data = frappe._dict() item_data = frappe._dict()
if not hsn_code: if not hsn_code: