blob: 48e17516a5d5034f82ba1d6dc8ac0dd781cda7b2 [file] [log] [blame]
Chillar Anand915b3432021-09-02 16:44:59 +05301import json
2import re
3
4import frappe
Rushabh Mehtab3c8f442017-06-21 17:22:38 +05305from frappe import _
Chillar Anand915b3432021-09-02 16:44:59 +05306from frappe.model.utils import get_fetch_values
7from frappe.utils import cint, cstr, date_diff, flt, getdate, nowdate
Chillar Anand915b3432021-09-02 16:44:59 +05308
Shreya Shah4fa600a2018-06-05 11:27:53 +05309from erpnext.controllers.accounts_controller import get_taxes_and_charges
Chillar Anand915b3432021-09-02 16:44:59 +053010from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +053011from erpnext.hr.utils import get_salary_assignment
Anurag Mishra289c8222020-06-19 19:17:57 +053012from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
Chillar Anand915b3432021-09-02 16:44:59 +053013from erpnext.regional.india import number_state_mapping, state_numbers, states
Ankush Menat7c4c42a2021-03-03 14:56:19 +053014
Ankush Menat494bd9e2022-03-28 18:52:46 +053015GST_INVOICE_NUMBER_FORMAT = re.compile(r"^[a-zA-Z0-9\-/]+$") # alphanumeric and - /
16GSTIN_FORMAT = re.compile(
17 "^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$"
18)
Ankush Menat7c4c42a2021-03-03 14:56:19 +053019GSTIN_UIN_FORMAT = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
20PAN_NUMBER_FORMAT = re.compile("[A-Z]{5}[0-9]{4}[A-Z]{1}")
21
22
Rushabh Mehtab3c8f442017-06-21 17:22:38 +053023def validate_gstin_for_india(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +053024 if hasattr(doc, "gst_state"):
Deepesh Garg363e6762022-03-21 16:28:17 +053025 set_gst_state_and_state_number(doc)
26
Ankush Menat494bd9e2022-03-28 18:52:46 +053027 if not hasattr(doc, "gstin") or not doc.gstin:
Rushabh Mehtab3c8f442017-06-21 17:22:38 +053028 return
29
Deepesh Garg459155f2019-06-14 12:01:34 +053030 gst_category = []
31
Ankush Menat494bd9e2022-03-28 18:52:46 +053032 if hasattr(doc, "gst_category"):
Anuja Pawar59c31bb2021-10-22 19:26:31 +053033 if len(doc.links):
34 link_doctype = doc.links[0].get("link_doctype")
35 link_name = doc.links[0].get("link_name")
Deepesh Garg459155f2019-06-14 12:01:34 +053036
Anuja Pawar59c31bb2021-10-22 19:26:31 +053037 if link_doctype in ["Customer", "Supplier"]:
Ankush Menat494bd9e2022-03-28 18:52:46 +053038 gst_category = frappe.db.get_value(link_doctype, {"name": link_name}, ["gst_category"])
Deepesh Garg459155f2019-06-14 12:01:34 +053039
Sagar Vorad75095b2019-01-23 14:40:01 +053040 doc.gstin = doc.gstin.upper().strip()
Ankush Menat494bd9e2022-03-28 18:52:46 +053041 if not doc.gstin or doc.gstin == "NA":
Sagar Vora07cf4e82019-01-10 11:07:51 +053042 return
Rushabh Mehtab3c8f442017-06-21 17:22:38 +053043
Sagar Vora07cf4e82019-01-10 11:07:51 +053044 if len(doc.gstin) != 15:
Saqib93203162021-04-12 17:55:46 +053045 frappe.throw(_("A GSTIN must have 15 characters."), title=_("Invalid GSTIN"))
Rushabh Mehtab3c8f442017-06-21 17:22:38 +053046
Ankush Menat494bd9e2022-03-28 18:52:46 +053047 if gst_category and gst_category == "UIN Holders":
Ankush Menat7c4c42a2021-03-03 14:56:19 +053048 if not GSTIN_UIN_FORMAT.match(doc.gstin):
Ankush Menat494bd9e2022-03-28 18:52:46 +053049 frappe.throw(
50 _(
51 "The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers"
52 ),
53 title=_("Invalid GSTIN"),
54 )
Deepesh Garg459155f2019-06-14 12:01:34 +053055 else:
Ankush Menat7c4c42a2021-03-03 14:56:19 +053056 if not GSTIN_FORMAT.match(doc.gstin):
Ankush Menat494bd9e2022-03-28 18:52:46 +053057 frappe.throw(
58 _("The input you've entered doesn't match the format of GSTIN."), title=_("Invalid GSTIN")
59 )
Rushabh Mehta7231f292017-07-13 15:00:56 +053060
Deepesh Garg459155f2019-06-14 12:01:34 +053061 validate_gstin_check_digit(doc.gstin)
Rushabh Mehtab3c8f442017-06-21 17:22:38 +053062
Anurag Mishra1e396dc2021-01-13 14:01:57 +053063 if not doc.gst_state:
Saqib93203162021-04-12 17:55:46 +053064 frappe.throw(_("Please enter GST state"), title=_("Invalid State"))
Anurag Mishra1e396dc2021-01-13 14:01:57 +053065
Deepesh Garg459155f2019-06-14 12:01:34 +053066 if doc.gst_state_number != doc.gstin[:2]:
Ankush Menat494bd9e2022-03-28 18:52:46 +053067 frappe.throw(
68 _("First 2 digits of GSTIN should match with State number {0}.").format(doc.gst_state_number),
69 title=_("Invalid GSTIN"),
70 )
71
Sagar Vora07cf4e82019-01-10 11:07:51 +053072
Deepesh Gargbb8cd1c2021-02-22 19:28:45 +053073def validate_pan_for_india(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +053074 if doc.get("country") != "India" or not doc.get("pan"):
Deepesh Gargbb8cd1c2021-02-22 19:28:45 +053075 return
76
Ankush Menat7c4c42a2021-03-03 14:56:19 +053077 if not PAN_NUMBER_FORMAT.match(doc.pan):
Deepesh Gargbb8cd1c2021-02-22 19:28:45 +053078 frappe.throw(_("Invalid PAN No. The input you've entered doesn't match the format of PAN."))
79
Ankush Menat494bd9e2022-03-28 18:52:46 +053080
Deepesh Gargd07447a2020-11-24 08:09:17 +053081def validate_tax_category(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +053082 if doc.get("gst_state") and frappe.db.get_value(
83 "Tax Category",
84 {
85 "gst_state": doc.gst_state,
86 "is_inter_state": doc.is_inter_state,
87 "is_reverse_charge": doc.is_reverse_charge,
88 },
89 ):
Deepesh Gargd07447a2020-11-24 08:09:17 +053090 if doc.is_inter_state:
Ankush Menat494bd9e2022-03-28 18:52:46 +053091 frappe.throw(
92 _("Inter State tax category for GST State {0} already exists").format(doc.gst_state)
93 )
Deepesh Gargd07447a2020-11-24 08:09:17 +053094 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +053095 frappe.throw(
96 _("Intra State tax category for GST State {0} already exists").format(doc.gst_state)
97 )
98
Deepesh Gargd07447a2020-11-24 08:09:17 +053099
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530100def update_gst_category(doc, method):
Deepesh Garga38aca52021-11-19 11:03:13 +0530101 for link in doc.links:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530102 if link.link_doctype in ["Customer", "Supplier"]:
Deepesh Garga38aca52021-11-19 11:03:13 +0530103 meta = frappe.get_meta(link.link_doctype)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530104 if doc.get("gstin") and meta.has_field("gst_category"):
105 frappe.db.set_value(
106 link.link_doctype,
107 {"name": link.link_name, "gst_category": "Unregistered"},
108 "gst_category",
109 "Registered Regular",
110 )
111
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530112
Nabin Hait34c551d2019-07-03 10:34:31 +0530113def set_gst_state_and_state_number(doc):
Deepesh Garg363e6762022-03-21 16:28:17 +0530114 if not doc.gst_state and doc.state:
Nabin Hait34c551d2019-07-03 10:34:31 +0530115 state = doc.state.lower()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530116 states_lowercase = {s.lower(): s for s in states}
Nabin Hait34c551d2019-07-03 10:34:31 +0530117 if state in states_lowercase:
118 doc.gst_state = states_lowercase[state]
119 else:
120 return
Deepesh Garg363e6762022-03-21 16:28:17 +0530121 doc.gst_state_number = state_numbers.get(doc.gst_state)
Nabin Hait34c551d2019-07-03 10:34:31 +0530122
Ankush Menat494bd9e2022-03-28 18:52:46 +0530123
124def validate_gstin_check_digit(gstin, label="GSTIN"):
125 """Function to validate the check digit of the GSTIN."""
karthikeyan52825b922019-01-09 19:15:10 +0530126 factor = 1
127 total = 0
Ankush Menat494bd9e2022-03-28 18:52:46 +0530128 code_point_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
karthikeyan52825b922019-01-09 19:15:10 +0530129 mod = len(code_point_chars)
Sagar Vora07cf4e82019-01-10 11:07:51 +0530130 input_chars = gstin[:-1]
karthikeyan52825b922019-01-09 19:15:10 +0530131 for char in input_chars:
132 digit = factor * code_point_chars.find(char)
Sagar Vora07cf4e82019-01-10 11:07:51 +0530133 digit = (digit // mod) + (digit % mod)
karthikeyan52825b922019-01-09 19:15:10 +0530134 total += digit
135 factor = 2 if factor == 1 else 1
Sagar Vora07cf4e82019-01-10 11:07:51 +0530136 if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530137 frappe.throw(
138 _(
139 """Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly."""
140 ).format(label)
141 )
142
Rushabh Mehta7231f292017-07-13 15:00:56 +0530143
Nabin Haitb962fc12017-07-17 18:02:31 +0530144def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530145 hsn_wise_in_gst_settings = frappe.db.get_single_value("GST Settings", "hsn_wise_tax_breakup")
146 if frappe.get_meta(item_doctype).has_field("gst_hsn_code") and hsn_wise_in_gst_settings:
Subin Tom530de122021-10-11 17:33:41 +0530147 return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
148 else:
149 return [_("Item"), _("Taxable Amount")] + tax_accounts
Nabin Haitb95ecd72018-02-16 13:19:04 +0530150
Ankush Menat494bd9e2022-03-28 18:52:46 +0530151
Subin Tomd49346a2021-09-17 10:39:03 +0530152def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
Nabin Hait34c551d2019-07-03 10:34:31 +0530153 itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise)
Nabin Haitb962fc12017-07-17 18:02:31 +0530154
155 itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
Nabin Haitb95ecd72018-02-16 13:19:04 +0530156
Ankush Menat494bd9e2022-03-28 18:52:46 +0530157 if not frappe.get_meta(doc.doctype + " Item").has_field("gst_hsn_code"):
Nabin Haitb962fc12017-07-17 18:02:31 +0530158 return itemised_tax, itemised_taxable_amount
159
Ankush Menat494bd9e2022-03-28 18:52:46 +0530160 hsn_wise_in_gst_settings = frappe.db.get_single_value("GST Settings", "hsn_wise_tax_breakup")
Subin Tom530de122021-10-11 17:33:41 +0530161
162 tax_breakup_hsn_wise = hsn_wise or hsn_wise_in_gst_settings
163 if tax_breakup_hsn_wise:
Subin Tomd49346a2021-09-17 10:39:03 +0530164 item_hsn_map = frappe._dict()
165 for d in doc.items:
166 item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
Nabin Haitb962fc12017-07-17 18:02:31 +0530167
168 hsn_tax = {}
169 for item, taxes in itemised_tax.items():
Subin Tom530de122021-10-11 17:33:41 +0530170 item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
Subin Tomd49346a2021-09-17 10:39:03 +0530171 hsn_tax.setdefault(item_or_hsn, frappe._dict())
Nabin Hait34c551d2019-07-03 10:34:31 +0530172 for tax_desc, tax_detail in taxes.items():
173 key = tax_desc
174 if account_wise:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530175 key = tax_detail.get("tax_account")
Subin Tomd49346a2021-09-17 10:39:03 +0530176 hsn_tax[item_or_hsn].setdefault(key, {"tax_rate": 0, "tax_amount": 0})
177 hsn_tax[item_or_hsn][key]["tax_rate"] = tax_detail.get("tax_rate")
178 hsn_tax[item_or_hsn][key]["tax_amount"] += tax_detail.get("tax_amount")
Nabin Haitb962fc12017-07-17 18:02:31 +0530179
180 # set taxable amount
181 hsn_taxable_amount = frappe._dict()
Nabin Hait34c551d2019-07-03 10:34:31 +0530182 for item in itemised_taxable_amount:
Subin Tom530de122021-10-11 17:33:41 +0530183 item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
Subin Tomd49346a2021-09-17 10:39:03 +0530184 hsn_taxable_amount.setdefault(item_or_hsn, 0)
185 hsn_taxable_amount[item_or_hsn] += itemised_taxable_amount.get(item)
Nabin Haitb962fc12017-07-17 18:02:31 +0530186
187 return hsn_tax, hsn_taxable_amount
188
Ankush Menat494bd9e2022-03-28 18:52:46 +0530189
Shreya Shah4fa600a2018-06-05 11:27:53 +0530190def set_place_of_supply(doc, method=None):
191 doc.place_of_supply = get_place_of_supply(doc, doc.doctype)
Nabin Haitb95ecd72018-02-16 13:19:04 +0530192
Ankush Menat494bd9e2022-03-28 18:52:46 +0530193
Ankush Menata44df632021-03-01 17:12:53 +0530194def validate_document_name(doc, method=None):
195 """Validate GST invoice number requirements."""
Nabin Hait10c61372021-04-13 15:46:01 +0530196
Ankush Menata44df632021-03-01 17:12:53 +0530197 country = frappe.get_cached_value("Company", doc.company, "country")
198
Ankush Menat7c4c42a2021-03-03 14:56:19 +0530199 # Date was chosen as start of next FY to avoid irritating current users.
Ankush Menata44df632021-03-01 17:12:53 +0530200 if country != "India" or getdate(doc.posting_date) < getdate("2021-04-01"):
201 return
202
203 if len(doc.name) > 16:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530204 frappe.throw(
205 _(
206 "Maximum length of document number should be 16 characters as per GST rules. Please change the naming series."
207 )
208 )
Ankush Menata44df632021-03-01 17:12:53 +0530209
Ankush Menat7c4c42a2021-03-03 14:56:19 +0530210 if not GST_INVOICE_NUMBER_FORMAT.match(doc.name):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530211 frappe.throw(
212 _(
213 "Document name should only contain alphanumeric values, dash(-) and slash(/) characters as per GST rules. Please change the naming series."
214 )
215 )
216
Ankush Menata44df632021-03-01 17:12:53 +0530217
Rushabh Mehta7231f292017-07-13 15:00:56 +0530218# don't remove this function it is used in tests
219def test_method():
Ankush Menat494bd9e2022-03-28 18:52:46 +0530220 """test function"""
221 return "overridden"
222
Shreya Shah4fa600a2018-06-05 11:27:53 +0530223
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530224def get_place_of_supply(party_details, doctype):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530225 if not frappe.get_meta("Address").has_field("gst_state"):
226 return
Shreya Shah4fa600a2018-06-05 11:27:53 +0530227
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530228 if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
Deepesh Gargeacfd792020-10-30 22:12:24 +0530229 address_name = party_details.customer_address or party_details.shipping_address_name
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530230 elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
231 address_name = party_details.shipping_address or party_details.supplier_address
Shreya Shah4fa600a2018-06-05 11:27:53 +0530232
233 if address_name:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530234 address = frappe.db.get_value(
235 "Address", address_name, ["gst_state", "gst_state_number", "gstin"], as_dict=1
236 )
Rohit Waghchaureb6a735e2018-10-11 10:40:34 +0530237 if address and address.gst_state and address.gst_state_number:
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530238 party_details.gstin = address.gstin
Nabin Hait2390da62018-08-30 16:16:35 +0530239 return cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
Shreya Shah4fa600a2018-06-05 11:27:53 +0530240
Ankush Menat494bd9e2022-03-28 18:52:46 +0530241
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530242@frappe.whitelist()
pateljannat1d5d8632020-11-19 20:11:45 +0530243def get_regional_address_details(party_details, doctype, company):
Ankush Menat8fe5feb2021-11-04 19:48:32 +0530244 if isinstance(party_details, str):
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530245 party_details = json.loads(party_details)
246 party_details = frappe._dict(party_details)
Shreya Shah4fa600a2018-06-05 11:27:53 +0530247
Deepesh Garga7670852020-12-04 18:07:46 +0530248 update_party_details(party_details, doctype)
249
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530250 party_details.place_of_supply = get_place_of_supply(party_details, doctype)
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530251
252 if is_internal_transfer(party_details, doctype):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530253 party_details.taxes_and_charges = ""
Deepesh Gargb4be2922021-01-28 13:09:56 +0530254 party_details.taxes = []
pateljannatcd05b342020-11-19 11:37:08 +0530255 return party_details
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530256
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530257 if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
Shreya Shah4fa600a2018-06-05 11:27:53 +0530258 master_doctype = "Sales Taxes and Charges Template"
Ankush Menat494bd9e2022-03-28 18:52:46 +0530259 tax_template_by_category = get_tax_template_based_on_category(
260 master_doctype, company, party_details
261 )
Shreya Shah4fa600a2018-06-05 11:27:53 +0530262
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530263 elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
264 master_doctype = "Purchase Taxes and Charges Template"
Ankush Menat494bd9e2022-03-28 18:52:46 +0530265 tax_template_by_category = get_tax_template_based_on_category(
266 master_doctype, company, party_details
267 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530268
Deepesh Garg35e2bd82021-12-02 17:17:56 +0530269 if tax_template_by_category:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530270 party_details["taxes_and_charges"] = tax_template_by_category
Deepesh Garg532961f2022-03-30 19:33:44 +0530271 party_details["taxes"] = get_taxes_and_charges(master_doctype, tax_template_by_category)
Deepesh Garg466e5492022-01-02 17:53:15 +0530272 return party_details
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530273
Ankush Menat494bd9e2022-03-28 18:52:46 +0530274 if not party_details.place_of_supply:
275 return party_details
276 if not party_details.company_gstin:
277 return party_details
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530278
Ankush Menat494bd9e2022-03-28 18:52:46 +0530279 if (
280 doctype in ("Sales Invoice", "Delivery Note", "Sales Order")
281 and party_details.company_gstin
282 and party_details.company_gstin[:2] != party_details.place_of_supply[:2]
283 ) or (
284 doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt")
285 and party_details.supplier_gstin
286 and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2]
287 ):
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530288 default_tax = get_tax_template(master_doctype, company, 1, party_details.company_gstin[:2])
Shreya Shah4fa600a2018-06-05 11:27:53 +0530289 else:
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530290 default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
Shreya Shah4fa600a2018-06-05 11:27:53 +0530291
292 if not default_tax:
pateljannatcd05b342020-11-19 11:37:08 +0530293 return party_details
Deepesh Garg35e2bd82021-12-02 17:17:56 +0530294
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530295 party_details["taxes_and_charges"] = default_tax
Deepesh Garg532961f2022-03-30 19:33:44 +0530296 party_details["taxes"] = get_taxes_and_charges(master_doctype, default_tax)
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530297
pateljannatcd05b342020-11-19 11:37:08 +0530298 return party_details
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530299
Ankush Menat494bd9e2022-03-28 18:52:46 +0530300
Deepesh Garga7670852020-12-04 18:07:46 +0530301def update_party_details(party_details, doctype):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530302 for address_field in [
303 "shipping_address",
304 "company_address",
305 "supplier_address",
306 "shipping_address_name",
307 "customer_address",
308 ]:
Deepesh Garga7670852020-12-04 18:07:46 +0530309 if party_details.get(address_field):
310 party_details.update(get_fetch_values(doctype, address_field, party_details.get(address_field)))
311
Ankush Menat494bd9e2022-03-28 18:52:46 +0530312
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530313def is_internal_transfer(party_details, doctype):
314 if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
315 destination_gstin = party_details.company_gstin
316 elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
317 destination_gstin = party_details.supplier_gstin
318
Deepesh Gargda47fe22021-09-30 13:28:53 +0530319 if not destination_gstin or party_details.gstin:
320 return False
321
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530322 if party_details.gstin == destination_gstin:
323 return True
324 else:
325 False
326
Ankush Menat494bd9e2022-03-28 18:52:46 +0530327
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530328def get_tax_template_based_on_category(master_doctype, company, party_details):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530329 if not party_details.get("tax_category"):
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530330 return
331
Ankush Menat494bd9e2022-03-28 18:52:46 +0530332 default_tax = frappe.db.get_value(
333 master_doctype, {"company": company, "tax_category": party_details.get("tax_category")}, "name"
334 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530335
Deepesh Garg35e2bd82021-12-02 17:17:56 +0530336 return default_tax
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530337
Ankush Menat494bd9e2022-03-28 18:52:46 +0530338
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530339def get_tax_template(master_doctype, company, is_inter_state, state_code):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530340 tax_categories = frappe.get_all(
341 "Tax Category",
342 fields=["name", "is_inter_state", "gst_state"],
343 filters={"is_inter_state": is_inter_state, "is_reverse_charge": 0},
344 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530345
Ankush Menat494bd9e2022-03-28 18:52:46 +0530346 default_tax = ""
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530347
348 for tax_category in tax_categories:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530349 if tax_category.gst_state == number_state_mapping[state_code] or (
350 not default_tax and not tax_category.gst_state
351 ):
352 default_tax = frappe.db.get_value(
353 master_doctype, {"company": company, "disabled": 0, "tax_category": tax_category.name}, "name"
354 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530355 return default_tax
356
Ankush Menat494bd9e2022-03-28 18:52:46 +0530357
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530358def calculate_annual_eligible_hra_exemption(doc):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530359 basic_component, hra_component = frappe.db.get_value(
360 "Company", doc.company, ["basic_component", "hra_component"]
361 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530362 if not (basic_component and hra_component):
363 frappe.throw(_("Please mention Basic and HRA component in Company"))
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530364 annual_exemption, monthly_exemption, hra_amount = 0, 0, 0
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530365 if hra_component and basic_component:
Nabin Hait04e7bf42019-04-25 18:44:10 +0530366 assignment = get_salary_assignment(doc.employee, nowdate())
Nabin Hait04e7bf42019-04-25 18:44:10 +0530367 if assignment:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530368 hra_component_exists = frappe.db.exists(
369 "Salary Detail",
370 {
371 "parent": assignment.salary_structure,
372 "salary_component": hra_component,
373 "parentfield": "earnings",
374 "parenttype": "Salary Structure",
375 },
376 )
Nabin Hait6b9d64c2019-05-16 11:23:04 +0530377
Nabin Hait04e7bf42019-04-25 18:44:10 +0530378 if hra_component_exists:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530379 basic_amount, hra_amount = get_component_amt_from_salary_slip(
380 doc.employee, assignment.salary_structure, basic_component, hra_component
381 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530382 if hra_amount:
383 if doc.monthly_house_rent:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530384 annual_exemption = calculate_hra_exemption(
385 assignment.salary_structure,
386 basic_amount,
387 hra_amount,
388 doc.monthly_house_rent,
389 doc.rented_in_metro_city,
390 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530391 if annual_exemption > 0:
392 monthly_exemption = annual_exemption / 12
393 else:
394 annual_exemption = 0
Nabin Hait6b9d64c2019-05-16 11:23:04 +0530395
Nabin Hait04e7bf42019-04-25 18:44:10 +0530396 elif doc.docstatus == 1:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530397 frappe.throw(
398 _("Salary Structure must be submitted before submission of Tax Ememption Declaration")
399 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530400
Ankush Menat494bd9e2022-03-28 18:52:46 +0530401 return frappe._dict(
402 {
403 "hra_amount": hra_amount,
404 "annual_exemption": annual_exemption,
405 "monthly_exemption": monthly_exemption,
406 }
407 )
408
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530409
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530410def get_component_amt_from_salary_slip(employee, salary_structure, basic_component, hra_component):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530411 salary_slip = make_salary_slip(
412 salary_structure, employee=employee, for_preview=1, ignore_permissions=True
413 )
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530414 basic_amt, hra_amt = 0, 0
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530415 for earning in salary_slip.earnings:
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530416 if earning.salary_component == basic_component:
417 basic_amt = earning.amount
418 elif earning.salary_component == hra_component:
419 hra_amt = earning.amount
420 if basic_amt and hra_amt:
421 return basic_amt, hra_amt
Ranjith Kurungadam14e94f82018-07-16 16:12:46 +0530422 return basic_amt, hra_amt
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530423
Ankush Menat494bd9e2022-03-28 18:52:46 +0530424
425def calculate_hra_exemption(
426 salary_structure, basic, monthly_hra, monthly_house_rent, rented_in_metro_city
427):
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530428 # TODO make this configurable
429 exemptions = []
430 frequency = frappe.get_value("Salary Structure", salary_structure, "payroll_frequency")
431 # case 1: The actual amount allotted by the employer as the HRA.
432 exemptions.append(get_annual_component_pay(frequency, monthly_hra))
Nabin Hait04e7bf42019-04-25 18:44:10 +0530433
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530434 actual_annual_rent = monthly_house_rent * 12
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530435 annual_basic = get_annual_component_pay(frequency, basic)
Nabin Hait04e7bf42019-04-25 18:44:10 +0530436
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530437 # case 2: Actual rent paid less 10% of the basic salary.
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530438 exemptions.append(flt(actual_annual_rent) - flt(annual_basic * 0.1))
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530439 # case 3: 50% of the basic salary, if the employee is staying in a metro city (40% for a non-metro city).
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530440 exemptions.append(annual_basic * 0.5 if rented_in_metro_city else annual_basic * 0.4)
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530441 # return minimum of 3 cases
442 return min(exemptions)
443
Ankush Menat494bd9e2022-03-28 18:52:46 +0530444
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530445def get_annual_component_pay(frequency, amount):
446 if frequency == "Daily":
447 return amount * 365
448 elif frequency == "Weekly":
449 return amount * 52
450 elif frequency == "Fortnightly":
451 return amount * 26
452 elif frequency == "Monthly":
453 return amount * 12
454 elif frequency == "Bimonthly":
455 return amount * 6
456
Ankush Menat494bd9e2022-03-28 18:52:46 +0530457
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530458def validate_house_rent_dates(doc):
459 if not doc.rented_to_date or not doc.rented_from_date:
460 frappe.throw(_("House rented dates required for exemption calculation"))
Nabin Hait04e7bf42019-04-25 18:44:10 +0530461
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530462 if date_diff(doc.rented_to_date, doc.rented_from_date) < 14:
463 frappe.throw(_("House rented dates should be atleast 15 days apart"))
Nabin Hait04e7bf42019-04-25 18:44:10 +0530464
Ankush Menat494bd9e2022-03-28 18:52:46 +0530465 proofs = frappe.db.sql(
466 """
Nabin Hait04e7bf42019-04-25 18:44:10 +0530467 select name
468 from `tabEmployee Tax Exemption Proof Submission`
469 where
Nabin Hait49446ba2019-04-25 19:54:20 +0530470 docstatus=1 and employee=%(employee)s and payroll_period=%(payroll_period)s
471 and (rented_from_date between %(from_date)s and %(to_date)s or rented_to_date between %(from_date)s and %(to_date)s)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530472 """,
473 {
474 "employee": doc.employee,
475 "payroll_period": doc.payroll_period,
476 "from_date": doc.rented_from_date,
477 "to_date": doc.rented_to_date,
478 },
479 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530480
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530481 if proofs:
Nabin Hait49446ba2019-04-25 19:54:20 +0530482 frappe.throw(_("House rent paid days overlapping with {0}").format(proofs[0][0]))
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530483
Ankush Menat494bd9e2022-03-28 18:52:46 +0530484
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530485def calculate_hra_exemption_for_period(doc):
486 monthly_rent, eligible_hra = 0, 0
487 if doc.house_rent_payment_amount:
488 validate_house_rent_dates(doc)
489 # TODO receive rented months or validate dates are start and end of months?
490 # Calc monthly rent, round to nearest .5
Ankush Menat494bd9e2022-03-28 18:52:46 +0530491 factor = flt(date_diff(doc.rented_to_date, doc.rented_from_date) + 1) / 30
492 factor = round(factor * 2) / 2
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530493 monthly_rent = doc.house_rent_payment_amount / factor
494 # update field used by calculate_annual_eligible_hra_exemption
495 doc.monthly_house_rent = monthly_rent
496 exemptions = calculate_annual_eligible_hra_exemption(doc)
497
498 if exemptions["monthly_exemption"]:
499 # calc total exemption amount
500 eligible_hra = exemptions["monthly_exemption"] * factor
Ranjith Kurungadam4f9744a2018-06-20 11:10:56 +0530501 exemptions["monthly_house_rent"] = monthly_rent
502 exemptions["total_eligible_hra_exemption"] = eligible_hra
503 return exemptions
Prasann Shah829172c2019-06-06 12:08:09 +0530504
Ankush Menat494bd9e2022-03-28 18:52:46 +0530505
Nabin Hait34c551d2019-07-03 10:34:31 +0530506def get_ewb_data(dt, dn):
Nabin Hait34c551d2019-07-03 10:34:31 +0530507
508 ewaybills = []
509 for doc_name in dn:
510 doc = frappe.get_doc(dt, doc_name)
511
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530512 validate_doc(doc)
Nabin Hait34c551d2019-07-03 10:34:31 +0530513
Ankush Menat494bd9e2022-03-28 18:52:46 +0530514 data = frappe._dict(
515 {
516 "transporterId": "",
517 "TotNonAdvolVal": 0,
518 }
519 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530520
521 data.userGstin = data.fromGstin = doc.company_gstin
Ankush Menat494bd9e2022-03-28 18:52:46 +0530522 data.supplyType = "O"
Nabin Hait34c551d2019-07-03 10:34:31 +0530523
Ankush Menat494bd9e2022-03-28 18:52:46 +0530524 if dt == "Delivery Note":
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530525 data.subSupplyType = 1
Ankush Menat494bd9e2022-03-28 18:52:46 +0530526 elif doc.gst_category in ["Registered Regular", "SEZ"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530527 data.subSupplyType = 1
Ankush Menat494bd9e2022-03-28 18:52:46 +0530528 elif doc.gst_category in ["Overseas", "Deemed Export"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530529 data.subSupplyType = 3
530 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530531 frappe.throw(_("Unsupported GST Category for E-Way Bill JSON generation"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530532
Ankush Menat494bd9e2022-03-28 18:52:46 +0530533 data.docType = "INV"
534 data.docDate = frappe.utils.formatdate(doc.posting_date, "dd/mm/yyyy")
Nabin Hait34c551d2019-07-03 10:34:31 +0530535
Ankush Menat494bd9e2022-03-28 18:52:46 +0530536 company_address = frappe.get_doc("Address", doc.company_address)
537 billing_address = frappe.get_doc("Address", doc.customer_address)
Nabin Hait34c551d2019-07-03 10:34:31 +0530538
Ankush Menat494bd9e2022-03-28 18:52:46 +0530539 # added dispatch address
540 dispatch_address = (
541 frappe.get_doc("Address", doc.dispatch_address_name)
542 if doc.dispatch_address_name
543 else company_address
544 )
545 shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
Nabin Hait34c551d2019-07-03 10:34:31 +0530546
Subin Tom5265ba32021-07-13 14:58:17 +0530547 data = get_address_details(data, doc, company_address, billing_address, dispatch_address)
Nabin Hait34c551d2019-07-03 10:34:31 +0530548
549 data.itemList = []
Smit Vorae2d866d2021-11-01 15:55:19 +0530550 data.totalValue = doc.net_total
Nabin Hait34c551d2019-07-03 10:34:31 +0530551
Subin Tomd49346a2021-09-17 10:39:03 +0530552 data = get_item_list(data, doc, hsn_wise=True)
Nabin Hait34c551d2019-07-03 10:34:31 +0530553
Ankush Menat494bd9e2022-03-28 18:52:46 +0530554 disable_rounded = frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
Nabin Hait34c551d2019-07-03 10:34:31 +0530555 data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total
556
557 data = get_transport_details(data, doc)
558
559 fields = {
560 "/. -": {
Ankush Menat494bd9e2022-03-28 18:52:46 +0530561 "docNo": doc.name,
562 "fromTrdName": doc.company,
563 "toTrdName": doc.customer_name,
564 "transDocNo": doc.lr_no,
Nabin Hait34c551d2019-07-03 10:34:31 +0530565 },
566 "@#/,&. -": {
Ankush Menat494bd9e2022-03-28 18:52:46 +0530567 "fromAddr1": company_address.address_line1,
568 "fromAddr2": company_address.address_line2,
569 "fromPlace": company_address.city,
570 "toAddr1": shipping_address.address_line1,
571 "toAddr2": shipping_address.address_line2,
572 "toPlace": shipping_address.city,
573 "transporterName": doc.transporter_name,
574 },
Nabin Hait34c551d2019-07-03 10:34:31 +0530575 }
576
577 for allowed_chars, field_map in fields.items():
578 for key, value in field_map.items():
579 if not value:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530580 data[key] = ""
Nabin Hait34c551d2019-07-03 10:34:31 +0530581 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530582 data[key] = re.sub(r"[^\w" + allowed_chars + "]", "", value)
Nabin Hait34c551d2019-07-03 10:34:31 +0530583
584 ewaybills.append(data)
585
Ankush Menat494bd9e2022-03-28 18:52:46 +0530586 data = {"version": "1.0.0421", "billLists": ewaybills}
Nabin Hait34c551d2019-07-03 10:34:31 +0530587
588 return data
589
Ankush Menat494bd9e2022-03-28 18:52:46 +0530590
Nabin Hait34c551d2019-07-03 10:34:31 +0530591@frappe.whitelist()
592def generate_ewb_json(dt, dn):
Deepesh Garg00ea59b2020-04-27 10:50:40 +0530593 dn = json.loads(dn)
594 return get_ewb_data(dt, dn)
Nabin Hait34c551d2019-07-03 10:34:31 +0530595
Ankush Menat494bd9e2022-03-28 18:52:46 +0530596
Deepesh Garg00ea59b2020-04-27 10:50:40 +0530597@frappe.whitelist()
598def download_ewb_json():
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530599 data = json.loads(frappe.local.form_dict.data)
600 frappe.local.response.filecontent = json.dumps(data, indent=4, sort_keys=True)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530601 frappe.local.response.type = "download"
Nabin Hait34c551d2019-07-03 10:34:31 +0530602
Ankush Menat494bd9e2022-03-28 18:52:46 +0530603 filename_prefix = "Bulk"
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530604 docname = frappe.local.form_dict.docname
605 if docname:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530606 if docname.startswith("["):
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530607 docname = json.loads(docname)
608 if len(docname) == 1:
609 docname = docname[0]
Deepesh Garg00ea59b2020-04-27 10:50:40 +0530610
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530611 if not isinstance(docname, list):
612 # removes characters not allowed in a filename (https://stackoverflow.com/a/38766141/4767738)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530613 filename_prefix = re.sub(r"[^\w_.)( -]", "", docname)
Nabin Hait34c551d2019-07-03 10:34:31 +0530614
Ankush Menat494bd9e2022-03-28 18:52:46 +0530615 frappe.local.response.filename = "{0}_e-WayBill_Data_{1}.json".format(
616 filename_prefix, frappe.utils.random_string(5)
617 )
618
Nabin Hait34c551d2019-07-03 10:34:31 +0530619
Prasann Shah829172c2019-06-06 12:08:09 +0530620@frappe.whitelist()
621def get_gstins_for_company(company):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530622 company_gstins = []
Prasann Shah829172c2019-06-06 12:08:09 +0530623 if company:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530624 company_gstins = frappe.db.sql(
625 """select
Prasann Shah829172c2019-06-06 12:08:09 +0530626 distinct `tabAddress`.gstin
627 from
628 `tabAddress`, `tabDynamic Link`
629 where
630 `tabDynamic Link`.parent = `tabAddress`.name and
631 `tabDynamic Link`.parenttype = 'Address' and
632 `tabDynamic Link`.link_doctype = 'Company' and
Ankush Menat494bd9e2022-03-28 18:52:46 +0530633 `tabDynamic Link`.link_name = %(company)s""",
634 {"company": company},
635 )
Prasann Shah829172c2019-06-06 12:08:09 +0530636 return company_gstins
637
Ankush Menat494bd9e2022-03-28 18:52:46 +0530638
Subin Tom5265ba32021-07-13 14:58:17 +0530639def get_address_details(data, doc, company_address, billing_address, dispatch_address):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530640 data.fromPincode = validate_pincode(company_address.pincode, "Company Address")
641 data.fromStateCode = validate_state_code(company_address.gst_state_number, "Company Address")
642 data.actualFromStateCode = validate_state_code(
643 dispatch_address.gst_state_number, "Dispatch Address"
644 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530645
646 if not doc.billing_address_gstin or len(doc.billing_address_gstin) < 15:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530647 data.toGstin = "URP"
Nabin Hait34c551d2019-07-03 10:34:31 +0530648 set_gst_state_and_state_number(billing_address)
649 else:
650 data.toGstin = doc.billing_address_gstin
651
Ankush Menat494bd9e2022-03-28 18:52:46 +0530652 data.toPincode = validate_pincode(billing_address.pincode, "Customer Address")
653 data.toStateCode = validate_state_code(billing_address.gst_state_number, "Customer Address")
Nabin Hait34c551d2019-07-03 10:34:31 +0530654
655 if doc.customer_address != doc.shipping_address_name:
656 data.transType = 2
Ankush Menat494bd9e2022-03-28 18:52:46 +0530657 shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
Nabin Hait34c551d2019-07-03 10:34:31 +0530658 set_gst_state_and_state_number(shipping_address)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530659 data.toPincode = validate_pincode(shipping_address.pincode, "Shipping Address")
660 data.actualToStateCode = validate_state_code(
661 shipping_address.gst_state_number, "Shipping Address"
662 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530663 else:
664 data.transType = 1
665 data.actualToStateCode = data.toStateCode
666 shipping_address = billing_address
Deepesh Gargd07447a2020-11-24 08:09:17 +0530667
Ankush Menat494bd9e2022-03-28 18:52:46 +0530668 if doc.gst_category == "SEZ":
Smit Vorabbe49332020-11-18 20:58:59 +0530669 data.toStateCode = 99
Nabin Hait34c551d2019-07-03 10:34:31 +0530670
671 return data
672
Ankush Menat494bd9e2022-03-28 18:52:46 +0530673
Subin Tomd49346a2021-09-17 10:39:03 +0530674def get_item_list(data, doc, hsn_wise=False):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530675 for attr in ["cgstValue", "sgstValue", "igstValue", "cessValue", "OthValue"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530676 data[attr] = 0
677
678 gst_accounts = get_gst_accounts(doc.company, account_wise=True)
679 tax_map = {
Ankush Menat494bd9e2022-03-28 18:52:46 +0530680 "sgst_account": ["sgstRate", "sgstValue"],
681 "cgst_account": ["cgstRate", "cgstValue"],
682 "igst_account": ["igstRate", "igstValue"],
683 "cess_account": ["cessRate", "cessValue"],
Nabin Hait34c551d2019-07-03 10:34:31 +0530684 }
Ankush Menat494bd9e2022-03-28 18:52:46 +0530685 item_data_attrs = ["sgstRate", "cgstRate", "igstRate", "cessRate", "cessNonAdvol"]
686 hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(
687 doc, account_wise=True, hsn_wise=hsn_wise
688 )
Smit Vora520f33b2021-11-14 08:10:53 +0530689 for item_or_hsn, taxable_amount in hsn_taxable_amount.items():
Nabin Hait34c551d2019-07-03 10:34:31 +0530690 item_data = frappe._dict()
Smit Vora520f33b2021-11-14 08:10:53 +0530691 if not item_or_hsn:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530692 frappe.throw(_("GST HSN Code does not exist for one or more items"))
Smit Vora520f33b2021-11-14 08:10:53 +0530693 item_data.hsnCode = int(item_or_hsn) if hsn_wise else item_or_hsn
Nabin Hait34c551d2019-07-03 10:34:31 +0530694 item_data.taxableAmount = taxable_amount
695 item_data.qtyUnit = ""
696 for attr in item_data_attrs:
697 item_data[attr] = 0
698
Smit Vora520f33b2021-11-14 08:10:53 +0530699 for account, tax_detail in hsn_wise_charges.get(item_or_hsn, {}).items():
Ankush Menat494bd9e2022-03-28 18:52:46 +0530700 account_type = gst_accounts.get(account, "")
Nabin Hait34c551d2019-07-03 10:34:31 +0530701 for tax_acc, attrs in tax_map.items():
702 if account_type == tax_acc:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530703 item_data[attrs[0]] = tax_detail.get("tax_rate")
704 data[attrs[1]] += tax_detail.get("tax_amount")
Nabin Hait34c551d2019-07-03 10:34:31 +0530705 break
706 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530707 data.OthValue += tax_detail.get("tax_amount")
Nabin Hait34c551d2019-07-03 10:34:31 +0530708
709 data.itemList.append(item_data)
710
711 # Tax amounts rounded to 2 decimals to avoid exceeding max character limit
Ankush Menat494bd9e2022-03-28 18:52:46 +0530712 for attr in ["sgstValue", "cgstValue", "igstValue", "cessValue"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530713 data[attr] = flt(data[attr], 2)
714
715 return data
716
Ankush Menat494bd9e2022-03-28 18:52:46 +0530717
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530718def validate_doc(doc):
Nabin Hait34c551d2019-07-03 10:34:31 +0530719 if doc.docstatus != 1:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530720 frappe.throw(_("E-Way Bill JSON can only be generated from submitted document"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530721
722 if doc.is_return:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530723 frappe.throw(_("E-Way Bill JSON cannot be generated for Sales Return as of now"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530724
725 if doc.ewaybill:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530726 frappe.throw(_("e-Way Bill already exists for this document"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530727
Ankush Menat494bd9e2022-03-28 18:52:46 +0530728 reqd_fields = [
729 "company_gstin",
730 "company_address",
731 "customer_address",
732 "shipping_address_name",
733 "mode_of_transport",
734 "distance",
735 ]
Nabin Hait34c551d2019-07-03 10:34:31 +0530736
737 for fieldname in reqd_fields:
738 if not doc.get(fieldname):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530739 frappe.throw(
740 _("{} is required to generate E-Way Bill JSON").format(doc.meta.get_label(fieldname))
741 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530742
743 if len(doc.company_gstin) < 15:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530744 frappe.throw(_("You must be a registered supplier to generate e-Way Bill"))
745
Nabin Hait34c551d2019-07-03 10:34:31 +0530746
747def get_transport_details(data, doc):
748 if doc.distance > 4000:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530749 frappe.throw(_("Distance cannot be greater than 4000 kms"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530750
751 data.transDistance = int(round(doc.distance))
752
Ankush Menat494bd9e2022-03-28 18:52:46 +0530753 transport_modes = {"Road": 1, "Rail": 2, "Air": 3, "Ship": 4}
Nabin Hait34c551d2019-07-03 10:34:31 +0530754
Ankush Menat494bd9e2022-03-28 18:52:46 +0530755 vehicle_types = {"Regular": "R", "Over Dimensional Cargo (ODC)": "O"}
Nabin Hait34c551d2019-07-03 10:34:31 +0530756
757 data.transMode = transport_modes.get(doc.mode_of_transport)
758
Ankush Menat494bd9e2022-03-28 18:52:46 +0530759 if doc.mode_of_transport == "Road":
Nabin Hait34c551d2019-07-03 10:34:31 +0530760 if not doc.gst_transporter_id and not doc.vehicle_no:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530761 frappe.throw(
762 _("Either GST Transporter ID or Vehicle No is required if Mode of Transport is Road")
763 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530764 if doc.vehicle_no:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530765 data.vehicleNo = doc.vehicle_no.replace(" ", "")
Nabin Hait34c551d2019-07-03 10:34:31 +0530766 if not doc.gst_vehicle_type:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530767 frappe.throw(_("Vehicle Type is required if Mode of Transport is Road"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530768 else:
769 data.vehicleType = vehicle_types.get(doc.gst_vehicle_type)
770 else:
771 if not doc.lr_no or not doc.lr_date:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530772 frappe.throw(_("Transport Receipt No and Date are mandatory for your chosen Mode of Transport"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530773
774 if doc.lr_no:
775 data.transDocNo = doc.lr_no
776
777 if doc.lr_date:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530778 data.transDocDate = frappe.utils.formatdate(doc.lr_date, "dd/mm/yyyy")
Nabin Hait34c551d2019-07-03 10:34:31 +0530779
780 if doc.gst_transporter_id:
karthikeyan5ca46bed2020-05-30 15:00:56 +0530781 if doc.gst_transporter_id[0:2] != "88":
Ankush Menat494bd9e2022-03-28 18:52:46 +0530782 validate_gstin_check_digit(doc.gst_transporter_id, label="GST Transporter ID")
karthikeyan5ca46bed2020-05-30 15:00:56 +0530783 data.transporterId = doc.gst_transporter_id
Nabin Hait34c551d2019-07-03 10:34:31 +0530784
785 return data
786
787
788def validate_pincode(pincode, address):
789 pin_not_found = "Pin Code doesn't exist for {}"
790 incorrect_pin = "Pin Code for {} is incorrecty formatted. It must be 6 digits (without spaces)"
791
792 if not pincode:
793 frappe.throw(_(pin_not_found.format(address)))
794
Ankush Menat494bd9e2022-03-28 18:52:46 +0530795 pincode = pincode.replace(" ", "")
Nabin Hait34c551d2019-07-03 10:34:31 +0530796 if not pincode.isdigit() or len(pincode) != 6:
797 frappe.throw(_(incorrect_pin.format(address)))
798 else:
799 return int(pincode)
800
Ankush Menat494bd9e2022-03-28 18:52:46 +0530801
Nabin Hait34c551d2019-07-03 10:34:31 +0530802def validate_state_code(state_code, address):
803 no_state_code = "GST State Code not found for {0}. Please set GST State in {0}"
804 if not state_code:
805 frappe.throw(_(no_state_code.format(address)))
806 else:
807 return int(state_code)
808
Ankush Menat494bd9e2022-03-28 18:52:46 +0530809
Deepesh Garg3c004ad2020-07-02 21:18:29 +0530810@frappe.whitelist()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530811def get_gst_accounts(
812 company=None, account_wise=False, only_reverse_charge=0, only_non_reverse_charge=0
813):
814 filters = {"parent": "GST Settings"}
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530815
816 if company:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530817 filters.update({"company": company})
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530818 if only_reverse_charge:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530819 filters.update({"is_reverse_charge_account": 1})
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530820 elif only_non_reverse_charge:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530821 filters.update({"is_reverse_charge_account": 0})
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530822
Nabin Hait34c551d2019-07-03 10:34:31 +0530823 gst_accounts = frappe._dict()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530824 gst_settings_accounts = frappe.get_all(
825 "GST Account",
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530826 filters=filters,
Ankush Menat494bd9e2022-03-28 18:52:46 +0530827 fields=["cgst_account", "sgst_account", "igst_account", "cess_account"],
828 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530829
Deepesh Garg44273902021-05-20 17:19:24 +0530830 if not gst_settings_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
Nabin Hait34c551d2019-07-03 10:34:31 +0530831 frappe.throw(_("Please set GST Accounts in GST Settings"))
832
833 for d in gst_settings_accounts:
834 for acc, val in d.items():
835 if not account_wise:
836 gst_accounts.setdefault(acc, []).append(val)
837 elif val:
838 gst_accounts[val] = acc
839
Nabin Hait34c551d2019-07-03 10:34:31 +0530840 return gst_accounts
Deepesh Garg24f9a802020-06-03 10:59:37 +0530841
Deepesh Garg52c319c2020-07-15 23:57:03 +0530842
Ankush Menat494bd9e2022-03-28 18:52:46 +0530843def validate_reverse_charge_transaction(doc, method):
844 country = frappe.get_cached_value("Company", doc.company, "country")
845
846 if country != "India":
Deepesh Garg52c319c2020-07-15 23:57:03 +0530847 return
848
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530849 base_gst_tax = 0
850 base_reverse_charge_booked = 0
Deepesh Garg8aed48f2020-08-19 18:30:18 +0530851
Ankush Menat494bd9e2022-03-28 18:52:46 +0530852 if doc.reverse_charge == "Y":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530853 gst_accounts = get_gst_accounts(doc.company, only_reverse_charge=1)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530854 reverse_charge_accounts = (
855 gst_accounts.get("cgst_account")
856 + gst_accounts.get("sgst_account")
857 + gst_accounts.get("igst_account")
858 )
Deepesh Garg3c004ad2020-07-02 21:18:29 +0530859
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530860 gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530861 non_reverse_charge_accounts = (
862 gst_accounts.get("cgst_account")
863 + gst_accounts.get("sgst_account")
864 + gst_accounts.get("igst_account")
865 )
Deepesh Garg24f9a802020-06-03 10:59:37 +0530866
Ankush Menat494bd9e2022-03-28 18:52:46 +0530867 for tax in doc.get("taxes"):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530868 if tax.account_head in non_reverse_charge_accounts:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530869 if tax.add_deduct_tax == "Add":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530870 base_gst_tax += tax.base_tax_amount_after_discount_amount
871 else:
872 base_gst_tax += tax.base_tax_amount_after_discount_amount
873 elif tax.account_head in reverse_charge_accounts:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530874 if tax.add_deduct_tax == "Add":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530875 base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
876 else:
877 base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
Deepesh Garg24f9a802020-06-03 10:59:37 +0530878
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530879 if base_gst_tax != base_reverse_charge_booked:
880 msg = _("Booked reverse charge is not equal to applied tax amount")
881 msg += "<br>"
Ankush Menat494bd9e2022-03-28 18:52:46 +0530882 msg += _(
883 "Please refer {gst_document_link} to learn more about how to setup and create reverse charge invoice"
884 ).format(
885 gst_document_link='<a href="https://docs.erpnext.com/docs/user/manual/en/regional/india/gst-setup">GST Documentation</a>'
886 )
Deepesh Garg24f9a802020-06-03 10:59:37 +0530887
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530888 frappe.throw(msg)
Deepesh Garg24f9a802020-06-03 10:59:37 +0530889
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530890
Ankush Menat494bd9e2022-03-28 18:52:46 +0530891def update_itc_availed_fields(doc, method):
892 country = frappe.get_cached_value("Company", doc.company, "country")
893
894 if country != "India":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530895 return
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530896
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530897 # Initialize values
898 doc.itc_integrated_tax = doc.itc_state_tax = doc.itc_central_tax = doc.itc_cess_amount = 0
899 gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530900
Ankush Menat494bd9e2022-03-28 18:52:46 +0530901 for tax in doc.get("taxes"):
902 if tax.account_head in gst_accounts.get("igst_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530903 doc.itc_integrated_tax += flt(tax.base_tax_amount_after_discount_amount)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530904 if tax.account_head in gst_accounts.get("sgst_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530905 doc.itc_state_tax += flt(tax.base_tax_amount_after_discount_amount)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530906 if tax.account_head in gst_accounts.get("cgst_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530907 doc.itc_central_tax += flt(tax.base_tax_amount_after_discount_amount)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530908 if tax.account_head in gst_accounts.get("cess_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530909 doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
Deepesh Garg004f9e62021-03-16 13:09:59 +0530910
Ankush Menat494bd9e2022-03-28 18:52:46 +0530911
Deepesh Garg8b644d82021-07-15 15:36:54 +0530912def update_place_of_supply(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530913 country = frappe.get_cached_value("Company", doc.company, "country")
914 if country != "India":
Deepesh Garg8b644d82021-07-15 15:36:54 +0530915 return
916
Ankush Menat494bd9e2022-03-28 18:52:46 +0530917 address = frappe.db.get_value(
918 "Address", doc.get("customer_address"), ["gst_state", "gst_state_number"], as_dict=1
919 )
Deepesh Garg8b644d82021-07-15 15:36:54 +0530920 if address and address.gst_state and address.gst_state_number:
921 doc.place_of_supply = cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
922
Ankush Menat494bd9e2022-03-28 18:52:46 +0530923
Deepesh Garg004f9e62021-03-16 13:09:59 +0530924@frappe.whitelist()
925def get_regional_round_off_accounts(company, account_list):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530926 country = frappe.get_cached_value("Company", company, "country")
Deepesh Garg004f9e62021-03-16 13:09:59 +0530927
Ankush Menat494bd9e2022-03-28 18:52:46 +0530928 if country != "India":
Deepesh Garg004f9e62021-03-16 13:09:59 +0530929 return
930
Ankush Menat8fe5feb2021-11-04 19:48:32 +0530931 if isinstance(account_list, str):
Deepesh Garg004f9e62021-03-16 13:09:59 +0530932 account_list = json.loads(account_list)
933
Ankush Menat494bd9e2022-03-28 18:52:46 +0530934 if not frappe.db.get_single_value("GST Settings", "round_off_gst_values"):
Deepesh Garg004f9e62021-03-16 13:09:59 +0530935 return
936
937 gst_accounts = get_gst_accounts(company)
walstanb52403c52021-03-27 10:13:27 +0530938
939 gst_account_list = []
Ankush Menat494bd9e2022-03-28 18:52:46 +0530940 for account in ["cgst_account", "sgst_account", "igst_account"]:
walstanbab673d92021-03-27 12:52:23 +0530941 if account in gst_accounts:
walstanb52403c52021-03-27 10:13:27 +0530942 gst_account_list += gst_accounts.get(account)
Deepesh Garg004f9e62021-03-16 13:09:59 +0530943
944 account_list.extend(gst_account_list)
945
946 return account_list
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530947
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530948
Ankush Menat494bd9e2022-03-28 18:52:46 +0530949def update_taxable_values(doc, method):
950 country = frappe.get_cached_value("Company", doc.company, "country")
951
952 if country != "India":
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530953 return
954
955 gst_accounts = get_gst_accounts(doc.company)
956
957 # Only considering sgst account to avoid inflating taxable value
Ankush Menat494bd9e2022-03-28 18:52:46 +0530958 gst_account_list = (
959 gst_accounts.get("sgst_account", [])
960 + gst_accounts.get("sgst_account", [])
961 + gst_accounts.get("igst_account", [])
962 )
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530963
964 additional_taxes = 0
965 total_charges = 0
966 item_count = 0
967 considered_rows = []
968
Ankush Menat494bd9e2022-03-28 18:52:46 +0530969 for tax in doc.get("taxes"):
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530970 prev_row_id = cint(tax.row_id) - 1
971 if tax.account_head in gst_account_list and prev_row_id not in considered_rows:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530972 if tax.charge_type == "On Previous Row Amount":
973 additional_taxes += doc.get("taxes")[prev_row_id].tax_amount_after_discount_amount
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530974 considered_rows.append(prev_row_id)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530975 if tax.charge_type == "On Previous Row Total":
976 additional_taxes += doc.get("taxes")[prev_row_id].base_total - doc.base_net_total
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530977 considered_rows.append(prev_row_id)
978
Ankush Menat494bd9e2022-03-28 18:52:46 +0530979 for item in doc.get("items"):
Deepesh Garg4afda3c2021-06-01 13:13:04 +0530980 proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
981 total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530982
Ankush Menat494bd9e2022-03-28 18:52:46 +0530983 applicable_charges = flt(
984 flt(
985 proportionate_value * (flt(additional_taxes) / flt(total_value)),
986 item.precision("taxable_value"),
987 )
988 )
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530989 item.taxable_value = applicable_charges + proportionate_value
990 total_charges += applicable_charges
991 item_count += 1
992
993 if total_charges != additional_taxes:
994 diff = additional_taxes - total_charges
Ankush Menat494bd9e2022-03-28 18:52:46 +0530995 doc.get("items")[item_count - 1].taxable_value += diff
996
Saqib9226cd32021-05-10 12:36:56 +0530997
998def get_depreciation_amount(asset, depreciable_value, row):
Saqib9226cd32021-05-10 12:36:56 +0530999 if row.depreciation_method in ("Straight Line", "Manual"):
GangaManoj2b93e542021-06-19 13:45:37 +05301000 # if the Depreciation Schedule is being prepared for the first time
GangaManojda8da9f2021-06-19 14:00:26 +05301001 if not asset.flags.increase_in_asset_life:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301002 depreciation_amount = (
1003 flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
1004 ) / flt(row.total_number_of_depreciations)
GangaManoj2b93e542021-06-19 13:45:37 +05301005
1006 # if the Depreciation Schedule is being modified after Asset Repair
1007 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301008 depreciation_amount = (
1009 flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
1010 ) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
Ankush Menat4551d7d2021-08-19 13:41:10 +05301011
Saqib9226cd32021-05-10 12:36:56 +05301012 else:
1013 rate_of_depreciation = row.rate_of_depreciation
1014 # if its the first depreciation
1015 if depreciable_value == asset.gross_purchase_amount:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301016 if row.finance_book and frappe.db.get_value("Finance Book", row.finance_book, "for_income_tax"):
Saqib424efd42021-09-28 18:12:02 +05301017 # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
1018 diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
1019 if diff <= 180:
1020 rate_of_depreciation = rate_of_depreciation / 2
1021 frappe.msgprint(
Ankush Menat494bd9e2022-03-28 18:52:46 +05301022 _(
1023 "As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%."
1024 )
1025 )
Saqib9226cd32021-05-10 12:36:56 +05301026
1027 depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
1028
Saqib3a504902021-08-03 15:57:11 +05301029 return depreciation_amount
1030
Ankush Menat494bd9e2022-03-28 18:52:46 +05301031
Saqib3a504902021-08-03 15:57:11 +05301032def set_item_tax_from_hsn_code(item):
Ankush Menat4551d7d2021-08-19 13:41:10 +05301033 if not item.taxes and item.gst_hsn_code:
Saqib3a504902021-08-03 15:57:11 +05301034 hsn_doc = frappe.get_doc("GST HSN Code", item.gst_hsn_code)
1035
1036 for tax in hsn_doc.taxes:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301037 item.append(
1038 "taxes",
1039 {
1040 "item_tax_template": tax.item_tax_template,
1041 "tax_category": tax.tax_category,
1042 "valid_from": tax.valid_from,
1043 },
1044 )
1045
Deepesh Garg2b2572b2021-08-20 14:40:12 +05301046
1047def delete_gst_settings_for_company(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +05301048 if doc.country != "India":
Deepesh Garg2b2572b2021-08-20 14:40:12 +05301049 return
1050
1051 gst_settings = frappe.get_doc("GST Settings")
1052 records_to_delete = []
1053
Ankush Menat494bd9e2022-03-28 18:52:46 +05301054 for d in reversed(gst_settings.get("gst_accounts")):
Deepesh Garg2b2572b2021-08-20 14:40:12 +05301055 if d.company == doc.name:
1056 records_to_delete.append(d)
1057
1058 for d in records_to_delete:
1059 gst_settings.remove(d)
1060
1061 gst_settings.save()