blob: 47e6ae67f4e3fcb475e834fb85e1040b81ed28c3 [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 Garg466e5492022-01-02 17:53:15 +0530271 return party_details
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530272
Ankush Menat494bd9e2022-03-28 18:52:46 +0530273 if not party_details.place_of_supply:
274 return party_details
275 if not party_details.company_gstin:
276 return party_details
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530277
Ankush Menat494bd9e2022-03-28 18:52:46 +0530278 if (
279 doctype in ("Sales Invoice", "Delivery Note", "Sales Order")
280 and party_details.company_gstin
281 and party_details.company_gstin[:2] != party_details.place_of_supply[:2]
282 ) or (
283 doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt")
284 and party_details.supplier_gstin
285 and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2]
286 ):
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530287 default_tax = get_tax_template(master_doctype, company, 1, party_details.company_gstin[:2])
Shreya Shah4fa600a2018-06-05 11:27:53 +0530288 else:
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530289 default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
Shreya Shah4fa600a2018-06-05 11:27:53 +0530290
291 if not default_tax:
pateljannatcd05b342020-11-19 11:37:08 +0530292 return party_details
Deepesh Garg35e2bd82021-12-02 17:17:56 +0530293
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530294 party_details["taxes_and_charges"] = default_tax
295 party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
296
pateljannatcd05b342020-11-19 11:37:08 +0530297 return party_details
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530298
Ankush Menat494bd9e2022-03-28 18:52:46 +0530299
Deepesh Garga7670852020-12-04 18:07:46 +0530300def update_party_details(party_details, doctype):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530301 for address_field in [
302 "shipping_address",
303 "company_address",
304 "supplier_address",
305 "shipping_address_name",
306 "customer_address",
307 ]:
Deepesh Garga7670852020-12-04 18:07:46 +0530308 if party_details.get(address_field):
309 party_details.update(get_fetch_values(doctype, address_field, party_details.get(address_field)))
310
Ankush Menat494bd9e2022-03-28 18:52:46 +0530311
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530312def is_internal_transfer(party_details, doctype):
313 if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
314 destination_gstin = party_details.company_gstin
315 elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
316 destination_gstin = party_details.supplier_gstin
317
Deepesh Gargda47fe22021-09-30 13:28:53 +0530318 if not destination_gstin or party_details.gstin:
319 return False
320
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530321 if party_details.gstin == destination_gstin:
322 return True
323 else:
324 False
325
Ankush Menat494bd9e2022-03-28 18:52:46 +0530326
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530327def get_tax_template_based_on_category(master_doctype, company, party_details):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530328 if not party_details.get("tax_category"):
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530329 return
330
Ankush Menat494bd9e2022-03-28 18:52:46 +0530331 default_tax = frappe.db.get_value(
332 master_doctype, {"company": company, "tax_category": party_details.get("tax_category")}, "name"
333 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530334
Deepesh Garg35e2bd82021-12-02 17:17:56 +0530335 return default_tax
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530336
Ankush Menat494bd9e2022-03-28 18:52:46 +0530337
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530338def get_tax_template(master_doctype, company, is_inter_state, state_code):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530339 tax_categories = frappe.get_all(
340 "Tax Category",
341 fields=["name", "is_inter_state", "gst_state"],
342 filters={"is_inter_state": is_inter_state, "is_reverse_charge": 0},
343 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530344
Ankush Menat494bd9e2022-03-28 18:52:46 +0530345 default_tax = ""
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530346
347 for tax_category in tax_categories:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530348 if tax_category.gst_state == number_state_mapping[state_code] or (
349 not default_tax and not tax_category.gst_state
350 ):
351 default_tax = frappe.db.get_value(
352 master_doctype, {"company": company, "disabled": 0, "tax_category": tax_category.name}, "name"
353 )
Deepesh Garg6e2c13f2019-12-10 15:55:05 +0530354 return default_tax
355
Ankush Menat494bd9e2022-03-28 18:52:46 +0530356
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530357def calculate_annual_eligible_hra_exemption(doc):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530358 basic_component, hra_component = frappe.db.get_value(
359 "Company", doc.company, ["basic_component", "hra_component"]
360 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530361 if not (basic_component and hra_component):
362 frappe.throw(_("Please mention Basic and HRA component in Company"))
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530363 annual_exemption, monthly_exemption, hra_amount = 0, 0, 0
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530364 if hra_component and basic_component:
Nabin Hait04e7bf42019-04-25 18:44:10 +0530365 assignment = get_salary_assignment(doc.employee, nowdate())
Nabin Hait04e7bf42019-04-25 18:44:10 +0530366 if assignment:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530367 hra_component_exists = frappe.db.exists(
368 "Salary Detail",
369 {
370 "parent": assignment.salary_structure,
371 "salary_component": hra_component,
372 "parentfield": "earnings",
373 "parenttype": "Salary Structure",
374 },
375 )
Nabin Hait6b9d64c2019-05-16 11:23:04 +0530376
Nabin Hait04e7bf42019-04-25 18:44:10 +0530377 if hra_component_exists:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530378 basic_amount, hra_amount = get_component_amt_from_salary_slip(
379 doc.employee, assignment.salary_structure, basic_component, hra_component
380 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530381 if hra_amount:
382 if doc.monthly_house_rent:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530383 annual_exemption = calculate_hra_exemption(
384 assignment.salary_structure,
385 basic_amount,
386 hra_amount,
387 doc.monthly_house_rent,
388 doc.rented_in_metro_city,
389 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530390 if annual_exemption > 0:
391 monthly_exemption = annual_exemption / 12
392 else:
393 annual_exemption = 0
Nabin Hait6b9d64c2019-05-16 11:23:04 +0530394
Nabin Hait04e7bf42019-04-25 18:44:10 +0530395 elif doc.docstatus == 1:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530396 frappe.throw(
397 _("Salary Structure must be submitted before submission of Tax Ememption Declaration")
398 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530399
Ankush Menat494bd9e2022-03-28 18:52:46 +0530400 return frappe._dict(
401 {
402 "hra_amount": hra_amount,
403 "annual_exemption": annual_exemption,
404 "monthly_exemption": monthly_exemption,
405 }
406 )
407
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530408
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530409def get_component_amt_from_salary_slip(employee, salary_structure, basic_component, hra_component):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530410 salary_slip = make_salary_slip(
411 salary_structure, employee=employee, for_preview=1, ignore_permissions=True
412 )
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530413 basic_amt, hra_amt = 0, 0
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530414 for earning in salary_slip.earnings:
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530415 if earning.salary_component == basic_component:
416 basic_amt = earning.amount
417 elif earning.salary_component == hra_component:
418 hra_amt = earning.amount
419 if basic_amt and hra_amt:
420 return basic_amt, hra_amt
Ranjith Kurungadam14e94f82018-07-16 16:12:46 +0530421 return basic_amt, hra_amt
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530422
Ankush Menat494bd9e2022-03-28 18:52:46 +0530423
424def calculate_hra_exemption(
425 salary_structure, basic, monthly_hra, monthly_house_rent, rented_in_metro_city
426):
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530427 # TODO make this configurable
428 exemptions = []
429 frequency = frappe.get_value("Salary Structure", salary_structure, "payroll_frequency")
430 # case 1: The actual amount allotted by the employer as the HRA.
431 exemptions.append(get_annual_component_pay(frequency, monthly_hra))
Nabin Hait04e7bf42019-04-25 18:44:10 +0530432
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530433 actual_annual_rent = monthly_house_rent * 12
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530434 annual_basic = get_annual_component_pay(frequency, basic)
Nabin Hait04e7bf42019-04-25 18:44:10 +0530435
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530436 # case 2: Actual rent paid less 10% of the basic salary.
Ranjith Kurungadamb1a756c2018-07-01 16:42:38 +0530437 exemptions.append(flt(actual_annual_rent) - flt(annual_basic * 0.1))
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530438 # 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 +0530439 exemptions.append(annual_basic * 0.5 if rented_in_metro_city else annual_basic * 0.4)
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530440 # return minimum of 3 cases
441 return min(exemptions)
442
Ankush Menat494bd9e2022-03-28 18:52:46 +0530443
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530444def get_annual_component_pay(frequency, amount):
445 if frequency == "Daily":
446 return amount * 365
447 elif frequency == "Weekly":
448 return amount * 52
449 elif frequency == "Fortnightly":
450 return amount * 26
451 elif frequency == "Monthly":
452 return amount * 12
453 elif frequency == "Bimonthly":
454 return amount * 6
455
Ankush Menat494bd9e2022-03-28 18:52:46 +0530456
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530457def validate_house_rent_dates(doc):
458 if not doc.rented_to_date or not doc.rented_from_date:
459 frappe.throw(_("House rented dates required for exemption calculation"))
Nabin Hait04e7bf42019-04-25 18:44:10 +0530460
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530461 if date_diff(doc.rented_to_date, doc.rented_from_date) < 14:
462 frappe.throw(_("House rented dates should be atleast 15 days apart"))
Nabin Hait04e7bf42019-04-25 18:44:10 +0530463
Ankush Menat494bd9e2022-03-28 18:52:46 +0530464 proofs = frappe.db.sql(
465 """
Nabin Hait04e7bf42019-04-25 18:44:10 +0530466 select name
467 from `tabEmployee Tax Exemption Proof Submission`
468 where
Nabin Hait49446ba2019-04-25 19:54:20 +0530469 docstatus=1 and employee=%(employee)s and payroll_period=%(payroll_period)s
470 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 +0530471 """,
472 {
473 "employee": doc.employee,
474 "payroll_period": doc.payroll_period,
475 "from_date": doc.rented_from_date,
476 "to_date": doc.rented_to_date,
477 },
478 )
Nabin Hait04e7bf42019-04-25 18:44:10 +0530479
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530480 if proofs:
Nabin Hait49446ba2019-04-25 19:54:20 +0530481 frappe.throw(_("House rent paid days overlapping with {0}").format(proofs[0][0]))
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530482
Ankush Menat494bd9e2022-03-28 18:52:46 +0530483
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530484def calculate_hra_exemption_for_period(doc):
485 monthly_rent, eligible_hra = 0, 0
486 if doc.house_rent_payment_amount:
487 validate_house_rent_dates(doc)
488 # TODO receive rented months or validate dates are start and end of months?
489 # Calc monthly rent, round to nearest .5
Ankush Menat494bd9e2022-03-28 18:52:46 +0530490 factor = flt(date_diff(doc.rented_to_date, doc.rented_from_date) + 1) / 30
491 factor = round(factor * 2) / 2
Ranjith Kurungadama8e047a2018-06-14 17:56:16 +0530492 monthly_rent = doc.house_rent_payment_amount / factor
493 # update field used by calculate_annual_eligible_hra_exemption
494 doc.monthly_house_rent = monthly_rent
495 exemptions = calculate_annual_eligible_hra_exemption(doc)
496
497 if exemptions["monthly_exemption"]:
498 # calc total exemption amount
499 eligible_hra = exemptions["monthly_exemption"] * factor
Ranjith Kurungadam4f9744a2018-06-20 11:10:56 +0530500 exemptions["monthly_house_rent"] = monthly_rent
501 exemptions["total_eligible_hra_exemption"] = eligible_hra
502 return exemptions
Prasann Shah829172c2019-06-06 12:08:09 +0530503
Ankush Menat494bd9e2022-03-28 18:52:46 +0530504
Nabin Hait34c551d2019-07-03 10:34:31 +0530505def get_ewb_data(dt, dn):
Nabin Hait34c551d2019-07-03 10:34:31 +0530506
507 ewaybills = []
508 for doc_name in dn:
509 doc = frappe.get_doc(dt, doc_name)
510
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530511 validate_doc(doc)
Nabin Hait34c551d2019-07-03 10:34:31 +0530512
Ankush Menat494bd9e2022-03-28 18:52:46 +0530513 data = frappe._dict(
514 {
515 "transporterId": "",
516 "TotNonAdvolVal": 0,
517 }
518 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530519
520 data.userGstin = data.fromGstin = doc.company_gstin
Ankush Menat494bd9e2022-03-28 18:52:46 +0530521 data.supplyType = "O"
Nabin Hait34c551d2019-07-03 10:34:31 +0530522
Ankush Menat494bd9e2022-03-28 18:52:46 +0530523 if dt == "Delivery Note":
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530524 data.subSupplyType = 1
Ankush Menat494bd9e2022-03-28 18:52:46 +0530525 elif doc.gst_category in ["Registered Regular", "SEZ"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530526 data.subSupplyType = 1
Ankush Menat494bd9e2022-03-28 18:52:46 +0530527 elif doc.gst_category in ["Overseas", "Deemed Export"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530528 data.subSupplyType = 3
529 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530530 frappe.throw(_("Unsupported GST Category for E-Way Bill JSON generation"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530531
Ankush Menat494bd9e2022-03-28 18:52:46 +0530532 data.docType = "INV"
533 data.docDate = frappe.utils.formatdate(doc.posting_date, "dd/mm/yyyy")
Nabin Hait34c551d2019-07-03 10:34:31 +0530534
Ankush Menat494bd9e2022-03-28 18:52:46 +0530535 company_address = frappe.get_doc("Address", doc.company_address)
536 billing_address = frappe.get_doc("Address", doc.customer_address)
Nabin Hait34c551d2019-07-03 10:34:31 +0530537
Ankush Menat494bd9e2022-03-28 18:52:46 +0530538 # added dispatch address
539 dispatch_address = (
540 frappe.get_doc("Address", doc.dispatch_address_name)
541 if doc.dispatch_address_name
542 else company_address
543 )
544 shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
Nabin Hait34c551d2019-07-03 10:34:31 +0530545
Subin Tom5265ba32021-07-13 14:58:17 +0530546 data = get_address_details(data, doc, company_address, billing_address, dispatch_address)
Nabin Hait34c551d2019-07-03 10:34:31 +0530547
548 data.itemList = []
Smit Vorae2d866d2021-11-01 15:55:19 +0530549 data.totalValue = doc.net_total
Nabin Hait34c551d2019-07-03 10:34:31 +0530550
Subin Tomd49346a2021-09-17 10:39:03 +0530551 data = get_item_list(data, doc, hsn_wise=True)
Nabin Hait34c551d2019-07-03 10:34:31 +0530552
Ankush Menat494bd9e2022-03-28 18:52:46 +0530553 disable_rounded = frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
Nabin Hait34c551d2019-07-03 10:34:31 +0530554 data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total
555
556 data = get_transport_details(data, doc)
557
558 fields = {
559 "/. -": {
Ankush Menat494bd9e2022-03-28 18:52:46 +0530560 "docNo": doc.name,
561 "fromTrdName": doc.company,
562 "toTrdName": doc.customer_name,
563 "transDocNo": doc.lr_no,
Nabin Hait34c551d2019-07-03 10:34:31 +0530564 },
565 "@#/,&. -": {
Ankush Menat494bd9e2022-03-28 18:52:46 +0530566 "fromAddr1": company_address.address_line1,
567 "fromAddr2": company_address.address_line2,
568 "fromPlace": company_address.city,
569 "toAddr1": shipping_address.address_line1,
570 "toAddr2": shipping_address.address_line2,
571 "toPlace": shipping_address.city,
572 "transporterName": doc.transporter_name,
573 },
Nabin Hait34c551d2019-07-03 10:34:31 +0530574 }
575
576 for allowed_chars, field_map in fields.items():
577 for key, value in field_map.items():
578 if not value:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530579 data[key] = ""
Nabin Hait34c551d2019-07-03 10:34:31 +0530580 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530581 data[key] = re.sub(r"[^\w" + allowed_chars + "]", "", value)
Nabin Hait34c551d2019-07-03 10:34:31 +0530582
583 ewaybills.append(data)
584
Ankush Menat494bd9e2022-03-28 18:52:46 +0530585 data = {"version": "1.0.0421", "billLists": ewaybills}
Nabin Hait34c551d2019-07-03 10:34:31 +0530586
587 return data
588
Ankush Menat494bd9e2022-03-28 18:52:46 +0530589
Nabin Hait34c551d2019-07-03 10:34:31 +0530590@frappe.whitelist()
591def generate_ewb_json(dt, dn):
Deepesh Garg00ea59b2020-04-27 10:50:40 +0530592 dn = json.loads(dn)
593 return get_ewb_data(dt, dn)
Nabin Hait34c551d2019-07-03 10:34:31 +0530594
Ankush Menat494bd9e2022-03-28 18:52:46 +0530595
Deepesh Garg00ea59b2020-04-27 10:50:40 +0530596@frappe.whitelist()
597def download_ewb_json():
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530598 data = json.loads(frappe.local.form_dict.data)
599 frappe.local.response.filecontent = json.dumps(data, indent=4, sort_keys=True)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530600 frappe.local.response.type = "download"
Nabin Hait34c551d2019-07-03 10:34:31 +0530601
Ankush Menat494bd9e2022-03-28 18:52:46 +0530602 filename_prefix = "Bulk"
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530603 docname = frappe.local.form_dict.docname
604 if docname:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530605 if docname.startswith("["):
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530606 docname = json.loads(docname)
607 if len(docname) == 1:
608 docname = docname[0]
Deepesh Garg00ea59b2020-04-27 10:50:40 +0530609
Sagar Vorac9b4ba62020-07-11 17:44:20 +0530610 if not isinstance(docname, list):
611 # removes characters not allowed in a filename (https://stackoverflow.com/a/38766141/4767738)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530612 filename_prefix = re.sub(r"[^\w_.)( -]", "", docname)
Nabin Hait34c551d2019-07-03 10:34:31 +0530613
Ankush Menat494bd9e2022-03-28 18:52:46 +0530614 frappe.local.response.filename = "{0}_e-WayBill_Data_{1}.json".format(
615 filename_prefix, frappe.utils.random_string(5)
616 )
617
Nabin Hait34c551d2019-07-03 10:34:31 +0530618
Prasann Shah829172c2019-06-06 12:08:09 +0530619@frappe.whitelist()
620def get_gstins_for_company(company):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530621 company_gstins = []
Prasann Shah829172c2019-06-06 12:08:09 +0530622 if company:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530623 company_gstins = frappe.db.sql(
624 """select
Prasann Shah829172c2019-06-06 12:08:09 +0530625 distinct `tabAddress`.gstin
626 from
627 `tabAddress`, `tabDynamic Link`
628 where
629 `tabDynamic Link`.parent = `tabAddress`.name and
630 `tabDynamic Link`.parenttype = 'Address' and
631 `tabDynamic Link`.link_doctype = 'Company' and
Ankush Menat494bd9e2022-03-28 18:52:46 +0530632 `tabDynamic Link`.link_name = %(company)s""",
633 {"company": company},
634 )
Prasann Shah829172c2019-06-06 12:08:09 +0530635 return company_gstins
636
Ankush Menat494bd9e2022-03-28 18:52:46 +0530637
Subin Tom5265ba32021-07-13 14:58:17 +0530638def get_address_details(data, doc, company_address, billing_address, dispatch_address):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530639 data.fromPincode = validate_pincode(company_address.pincode, "Company Address")
640 data.fromStateCode = validate_state_code(company_address.gst_state_number, "Company Address")
641 data.actualFromStateCode = validate_state_code(
642 dispatch_address.gst_state_number, "Dispatch Address"
643 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530644
645 if not doc.billing_address_gstin or len(doc.billing_address_gstin) < 15:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530646 data.toGstin = "URP"
Nabin Hait34c551d2019-07-03 10:34:31 +0530647 set_gst_state_and_state_number(billing_address)
648 else:
649 data.toGstin = doc.billing_address_gstin
650
Ankush Menat494bd9e2022-03-28 18:52:46 +0530651 data.toPincode = validate_pincode(billing_address.pincode, "Customer Address")
652 data.toStateCode = validate_state_code(billing_address.gst_state_number, "Customer Address")
Nabin Hait34c551d2019-07-03 10:34:31 +0530653
654 if doc.customer_address != doc.shipping_address_name:
655 data.transType = 2
Ankush Menat494bd9e2022-03-28 18:52:46 +0530656 shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
Nabin Hait34c551d2019-07-03 10:34:31 +0530657 set_gst_state_and_state_number(shipping_address)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530658 data.toPincode = validate_pincode(shipping_address.pincode, "Shipping Address")
659 data.actualToStateCode = validate_state_code(
660 shipping_address.gst_state_number, "Shipping Address"
661 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530662 else:
663 data.transType = 1
664 data.actualToStateCode = data.toStateCode
665 shipping_address = billing_address
Deepesh Gargd07447a2020-11-24 08:09:17 +0530666
Ankush Menat494bd9e2022-03-28 18:52:46 +0530667 if doc.gst_category == "SEZ":
Smit Vorabbe49332020-11-18 20:58:59 +0530668 data.toStateCode = 99
Nabin Hait34c551d2019-07-03 10:34:31 +0530669
670 return data
671
Ankush Menat494bd9e2022-03-28 18:52:46 +0530672
Subin Tomd49346a2021-09-17 10:39:03 +0530673def get_item_list(data, doc, hsn_wise=False):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530674 for attr in ["cgstValue", "sgstValue", "igstValue", "cessValue", "OthValue"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530675 data[attr] = 0
676
677 gst_accounts = get_gst_accounts(doc.company, account_wise=True)
678 tax_map = {
Ankush Menat494bd9e2022-03-28 18:52:46 +0530679 "sgst_account": ["sgstRate", "sgstValue"],
680 "cgst_account": ["cgstRate", "cgstValue"],
681 "igst_account": ["igstRate", "igstValue"],
682 "cess_account": ["cessRate", "cessValue"],
Nabin Hait34c551d2019-07-03 10:34:31 +0530683 }
Ankush Menat494bd9e2022-03-28 18:52:46 +0530684 item_data_attrs = ["sgstRate", "cgstRate", "igstRate", "cessRate", "cessNonAdvol"]
685 hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(
686 doc, account_wise=True, hsn_wise=hsn_wise
687 )
Smit Vora520f33b2021-11-14 08:10:53 +0530688 for item_or_hsn, taxable_amount in hsn_taxable_amount.items():
Nabin Hait34c551d2019-07-03 10:34:31 +0530689 item_data = frappe._dict()
Smit Vora520f33b2021-11-14 08:10:53 +0530690 if not item_or_hsn:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530691 frappe.throw(_("GST HSN Code does not exist for one or more items"))
Smit Vora520f33b2021-11-14 08:10:53 +0530692 item_data.hsnCode = int(item_or_hsn) if hsn_wise else item_or_hsn
Nabin Hait34c551d2019-07-03 10:34:31 +0530693 item_data.taxableAmount = taxable_amount
694 item_data.qtyUnit = ""
695 for attr in item_data_attrs:
696 item_data[attr] = 0
697
Smit Vora520f33b2021-11-14 08:10:53 +0530698 for account, tax_detail in hsn_wise_charges.get(item_or_hsn, {}).items():
Ankush Menat494bd9e2022-03-28 18:52:46 +0530699 account_type = gst_accounts.get(account, "")
Nabin Hait34c551d2019-07-03 10:34:31 +0530700 for tax_acc, attrs in tax_map.items():
701 if account_type == tax_acc:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530702 item_data[attrs[0]] = tax_detail.get("tax_rate")
703 data[attrs[1]] += tax_detail.get("tax_amount")
Nabin Hait34c551d2019-07-03 10:34:31 +0530704 break
705 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530706 data.OthValue += tax_detail.get("tax_amount")
Nabin Hait34c551d2019-07-03 10:34:31 +0530707
708 data.itemList.append(item_data)
709
710 # Tax amounts rounded to 2 decimals to avoid exceeding max character limit
Ankush Menat494bd9e2022-03-28 18:52:46 +0530711 for attr in ["sgstValue", "cgstValue", "igstValue", "cessValue"]:
Nabin Hait34c551d2019-07-03 10:34:31 +0530712 data[attr] = flt(data[attr], 2)
713
714 return data
715
Ankush Menat494bd9e2022-03-28 18:52:46 +0530716
Deepesh Garg15ff6a52020-02-18 12:28:41 +0530717def validate_doc(doc):
Nabin Hait34c551d2019-07-03 10:34:31 +0530718 if doc.docstatus != 1:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530719 frappe.throw(_("E-Way Bill JSON can only be generated from submitted document"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530720
721 if doc.is_return:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530722 frappe.throw(_("E-Way Bill JSON cannot be generated for Sales Return as of now"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530723
724 if doc.ewaybill:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530725 frappe.throw(_("e-Way Bill already exists for this document"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530726
Ankush Menat494bd9e2022-03-28 18:52:46 +0530727 reqd_fields = [
728 "company_gstin",
729 "company_address",
730 "customer_address",
731 "shipping_address_name",
732 "mode_of_transport",
733 "distance",
734 ]
Nabin Hait34c551d2019-07-03 10:34:31 +0530735
736 for fieldname in reqd_fields:
737 if not doc.get(fieldname):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530738 frappe.throw(
739 _("{} is required to generate E-Way Bill JSON").format(doc.meta.get_label(fieldname))
740 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530741
742 if len(doc.company_gstin) < 15:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530743 frappe.throw(_("You must be a registered supplier to generate e-Way Bill"))
744
Nabin Hait34c551d2019-07-03 10:34:31 +0530745
746def get_transport_details(data, doc):
747 if doc.distance > 4000:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530748 frappe.throw(_("Distance cannot be greater than 4000 kms"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530749
750 data.transDistance = int(round(doc.distance))
751
Ankush Menat494bd9e2022-03-28 18:52:46 +0530752 transport_modes = {"Road": 1, "Rail": 2, "Air": 3, "Ship": 4}
Nabin Hait34c551d2019-07-03 10:34:31 +0530753
Ankush Menat494bd9e2022-03-28 18:52:46 +0530754 vehicle_types = {"Regular": "R", "Over Dimensional Cargo (ODC)": "O"}
Nabin Hait34c551d2019-07-03 10:34:31 +0530755
756 data.transMode = transport_modes.get(doc.mode_of_transport)
757
Ankush Menat494bd9e2022-03-28 18:52:46 +0530758 if doc.mode_of_transport == "Road":
Nabin Hait34c551d2019-07-03 10:34:31 +0530759 if not doc.gst_transporter_id and not doc.vehicle_no:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530760 frappe.throw(
761 _("Either GST Transporter ID or Vehicle No is required if Mode of Transport is Road")
762 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530763 if doc.vehicle_no:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530764 data.vehicleNo = doc.vehicle_no.replace(" ", "")
Nabin Hait34c551d2019-07-03 10:34:31 +0530765 if not doc.gst_vehicle_type:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530766 frappe.throw(_("Vehicle Type is required if Mode of Transport is Road"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530767 else:
768 data.vehicleType = vehicle_types.get(doc.gst_vehicle_type)
769 else:
770 if not doc.lr_no or not doc.lr_date:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530771 frappe.throw(_("Transport Receipt No and Date are mandatory for your chosen Mode of Transport"))
Nabin Hait34c551d2019-07-03 10:34:31 +0530772
773 if doc.lr_no:
774 data.transDocNo = doc.lr_no
775
776 if doc.lr_date:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530777 data.transDocDate = frappe.utils.formatdate(doc.lr_date, "dd/mm/yyyy")
Nabin Hait34c551d2019-07-03 10:34:31 +0530778
779 if doc.gst_transporter_id:
karthikeyan5ca46bed2020-05-30 15:00:56 +0530780 if doc.gst_transporter_id[0:2] != "88":
Ankush Menat494bd9e2022-03-28 18:52:46 +0530781 validate_gstin_check_digit(doc.gst_transporter_id, label="GST Transporter ID")
karthikeyan5ca46bed2020-05-30 15:00:56 +0530782 data.transporterId = doc.gst_transporter_id
Nabin Hait34c551d2019-07-03 10:34:31 +0530783
784 return data
785
786
787def validate_pincode(pincode, address):
788 pin_not_found = "Pin Code doesn't exist for {}"
789 incorrect_pin = "Pin Code for {} is incorrecty formatted. It must be 6 digits (without spaces)"
790
791 if not pincode:
792 frappe.throw(_(pin_not_found.format(address)))
793
Ankush Menat494bd9e2022-03-28 18:52:46 +0530794 pincode = pincode.replace(" ", "")
Nabin Hait34c551d2019-07-03 10:34:31 +0530795 if not pincode.isdigit() or len(pincode) != 6:
796 frappe.throw(_(incorrect_pin.format(address)))
797 else:
798 return int(pincode)
799
Ankush Menat494bd9e2022-03-28 18:52:46 +0530800
Nabin Hait34c551d2019-07-03 10:34:31 +0530801def validate_state_code(state_code, address):
802 no_state_code = "GST State Code not found for {0}. Please set GST State in {0}"
803 if not state_code:
804 frappe.throw(_(no_state_code.format(address)))
805 else:
806 return int(state_code)
807
Ankush Menat494bd9e2022-03-28 18:52:46 +0530808
Deepesh Garg3c004ad2020-07-02 21:18:29 +0530809@frappe.whitelist()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530810def get_gst_accounts(
811 company=None, account_wise=False, only_reverse_charge=0, only_non_reverse_charge=0
812):
813 filters = {"parent": "GST Settings"}
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530814
815 if company:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530816 filters.update({"company": company})
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530817 if only_reverse_charge:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530818 filters.update({"is_reverse_charge_account": 1})
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530819 elif only_non_reverse_charge:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530820 filters.update({"is_reverse_charge_account": 0})
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530821
Nabin Hait34c551d2019-07-03 10:34:31 +0530822 gst_accounts = frappe._dict()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530823 gst_settings_accounts = frappe.get_all(
824 "GST Account",
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530825 filters=filters,
Ankush Menat494bd9e2022-03-28 18:52:46 +0530826 fields=["cgst_account", "sgst_account", "igst_account", "cess_account"],
827 )
Nabin Hait34c551d2019-07-03 10:34:31 +0530828
Deepesh Garg44273902021-05-20 17:19:24 +0530829 if not gst_settings_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
Nabin Hait34c551d2019-07-03 10:34:31 +0530830 frappe.throw(_("Please set GST Accounts in GST Settings"))
831
832 for d in gst_settings_accounts:
833 for acc, val in d.items():
834 if not account_wise:
835 gst_accounts.setdefault(acc, []).append(val)
836 elif val:
837 gst_accounts[val] = acc
838
Nabin Hait34c551d2019-07-03 10:34:31 +0530839 return gst_accounts
Deepesh Garg24f9a802020-06-03 10:59:37 +0530840
Deepesh Garg52c319c2020-07-15 23:57:03 +0530841
Ankush Menat494bd9e2022-03-28 18:52:46 +0530842def validate_reverse_charge_transaction(doc, method):
843 country = frappe.get_cached_value("Company", doc.company, "country")
844
845 if country != "India":
Deepesh Garg52c319c2020-07-15 23:57:03 +0530846 return
847
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530848 base_gst_tax = 0
849 base_reverse_charge_booked = 0
Deepesh Garg8aed48f2020-08-19 18:30:18 +0530850
Ankush Menat494bd9e2022-03-28 18:52:46 +0530851 if doc.reverse_charge == "Y":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530852 gst_accounts = get_gst_accounts(doc.company, only_reverse_charge=1)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530853 reverse_charge_accounts = (
854 gst_accounts.get("cgst_account")
855 + gst_accounts.get("sgst_account")
856 + gst_accounts.get("igst_account")
857 )
Deepesh Garg3c004ad2020-07-02 21:18:29 +0530858
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530859 gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530860 non_reverse_charge_accounts = (
861 gst_accounts.get("cgst_account")
862 + gst_accounts.get("sgst_account")
863 + gst_accounts.get("igst_account")
864 )
Deepesh Garg24f9a802020-06-03 10:59:37 +0530865
Ankush Menat494bd9e2022-03-28 18:52:46 +0530866 for tax in doc.get("taxes"):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530867 if tax.account_head in non_reverse_charge_accounts:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530868 if tax.add_deduct_tax == "Add":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530869 base_gst_tax += tax.base_tax_amount_after_discount_amount
870 else:
871 base_gst_tax += tax.base_tax_amount_after_discount_amount
872 elif tax.account_head in reverse_charge_accounts:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530873 if tax.add_deduct_tax == "Add":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530874 base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
875 else:
876 base_reverse_charge_booked += tax.base_tax_amount_after_discount_amount
Deepesh Garg24f9a802020-06-03 10:59:37 +0530877
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530878 if base_gst_tax != base_reverse_charge_booked:
879 msg = _("Booked reverse charge is not equal to applied tax amount")
880 msg += "<br>"
Ankush Menat494bd9e2022-03-28 18:52:46 +0530881 msg += _(
882 "Please refer {gst_document_link} to learn more about how to setup and create reverse charge invoice"
883 ).format(
884 gst_document_link='<a href="https://docs.erpnext.com/docs/user/manual/en/regional/india/gst-setup">GST Documentation</a>'
885 )
Deepesh Garg24f9a802020-06-03 10:59:37 +0530886
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530887 frappe.throw(msg)
Deepesh Garg24f9a802020-06-03 10:59:37 +0530888
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530889
Ankush Menat494bd9e2022-03-28 18:52:46 +0530890def update_itc_availed_fields(doc, method):
891 country = frappe.get_cached_value("Company", doc.company, "country")
892
893 if country != "India":
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530894 return
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530895
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530896 # Initialize values
897 doc.itc_integrated_tax = doc.itc_state_tax = doc.itc_central_tax = doc.itc_cess_amount = 0
898 gst_accounts = get_gst_accounts(doc.company, only_non_reverse_charge=1)
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530899
Ankush Menat494bd9e2022-03-28 18:52:46 +0530900 for tax in doc.get("taxes"):
901 if tax.account_head in gst_accounts.get("igst_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530902 doc.itc_integrated_tax += flt(tax.base_tax_amount_after_discount_amount)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530903 if tax.account_head in gst_accounts.get("sgst_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530904 doc.itc_state_tax += flt(tax.base_tax_amount_after_discount_amount)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530905 if tax.account_head in gst_accounts.get("cgst_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530906 doc.itc_central_tax += flt(tax.base_tax_amount_after_discount_amount)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530907 if tax.account_head in gst_accounts.get("cess_account", []):
Deepesh Garg55fe85d2021-05-14 12:17:41 +0530908 doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
Deepesh Garg004f9e62021-03-16 13:09:59 +0530909
Ankush Menat494bd9e2022-03-28 18:52:46 +0530910
Deepesh Garg8b644d82021-07-15 15:36:54 +0530911def update_place_of_supply(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530912 country = frappe.get_cached_value("Company", doc.company, "country")
913 if country != "India":
Deepesh Garg8b644d82021-07-15 15:36:54 +0530914 return
915
Ankush Menat494bd9e2022-03-28 18:52:46 +0530916 address = frappe.db.get_value(
917 "Address", doc.get("customer_address"), ["gst_state", "gst_state_number"], as_dict=1
918 )
Deepesh Garg8b644d82021-07-15 15:36:54 +0530919 if address and address.gst_state and address.gst_state_number:
920 doc.place_of_supply = cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
921
Ankush Menat494bd9e2022-03-28 18:52:46 +0530922
Deepesh Garg004f9e62021-03-16 13:09:59 +0530923@frappe.whitelist()
924def get_regional_round_off_accounts(company, account_list):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530925 country = frappe.get_cached_value("Company", company, "country")
Deepesh Garg004f9e62021-03-16 13:09:59 +0530926
Ankush Menat494bd9e2022-03-28 18:52:46 +0530927 if country != "India":
Deepesh Garg004f9e62021-03-16 13:09:59 +0530928 return
929
Ankush Menat8fe5feb2021-11-04 19:48:32 +0530930 if isinstance(account_list, str):
Deepesh Garg004f9e62021-03-16 13:09:59 +0530931 account_list = json.loads(account_list)
932
Ankush Menat494bd9e2022-03-28 18:52:46 +0530933 if not frappe.db.get_single_value("GST Settings", "round_off_gst_values"):
Deepesh Garg004f9e62021-03-16 13:09:59 +0530934 return
935
936 gst_accounts = get_gst_accounts(company)
walstanb52403c52021-03-27 10:13:27 +0530937
938 gst_account_list = []
Ankush Menat494bd9e2022-03-28 18:52:46 +0530939 for account in ["cgst_account", "sgst_account", "igst_account"]:
walstanbab673d92021-03-27 12:52:23 +0530940 if account in gst_accounts:
walstanb52403c52021-03-27 10:13:27 +0530941 gst_account_list += gst_accounts.get(account)
Deepesh Garg004f9e62021-03-16 13:09:59 +0530942
943 account_list.extend(gst_account_list)
944
945 return account_list
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530946
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530947
Ankush Menat494bd9e2022-03-28 18:52:46 +0530948def update_taxable_values(doc, method):
949 country = frappe.get_cached_value("Company", doc.company, "country")
950
951 if country != "India":
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530952 return
953
954 gst_accounts = get_gst_accounts(doc.company)
955
956 # Only considering sgst account to avoid inflating taxable value
Ankush Menat494bd9e2022-03-28 18:52:46 +0530957 gst_account_list = (
958 gst_accounts.get("sgst_account", [])
959 + gst_accounts.get("sgst_account", [])
960 + gst_accounts.get("igst_account", [])
961 )
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530962
963 additional_taxes = 0
964 total_charges = 0
965 item_count = 0
966 considered_rows = []
967
Ankush Menat494bd9e2022-03-28 18:52:46 +0530968 for tax in doc.get("taxes"):
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530969 prev_row_id = cint(tax.row_id) - 1
970 if tax.account_head in gst_account_list and prev_row_id not in considered_rows:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530971 if tax.charge_type == "On Previous Row Amount":
972 additional_taxes += doc.get("taxes")[prev_row_id].tax_amount_after_discount_amount
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530973 considered_rows.append(prev_row_id)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530974 if tax.charge_type == "On Previous Row Total":
975 additional_taxes += doc.get("taxes")[prev_row_id].base_total - doc.base_net_total
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530976 considered_rows.append(prev_row_id)
977
Ankush Menat494bd9e2022-03-28 18:52:46 +0530978 for item in doc.get("items"):
Deepesh Garg4afda3c2021-06-01 13:13:04 +0530979 proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
980 total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530981
Ankush Menat494bd9e2022-03-28 18:52:46 +0530982 applicable_charges = flt(
983 flt(
984 proportionate_value * (flt(additional_taxes) / flt(total_value)),
985 item.precision("taxable_value"),
986 )
987 )
Deepesh Gargc36e48a2021-04-12 10:55:43 +0530988 item.taxable_value = applicable_charges + proportionate_value
989 total_charges += applicable_charges
990 item_count += 1
991
992 if total_charges != additional_taxes:
993 diff = additional_taxes - total_charges
Ankush Menat494bd9e2022-03-28 18:52:46 +0530994 doc.get("items")[item_count - 1].taxable_value += diff
995
Saqib9226cd32021-05-10 12:36:56 +0530996
997def get_depreciation_amount(asset, depreciable_value, row):
Saqib9226cd32021-05-10 12:36:56 +0530998 if row.depreciation_method in ("Straight Line", "Manual"):
GangaManoj2b93e542021-06-19 13:45:37 +0530999 # if the Depreciation Schedule is being prepared for the first time
GangaManojda8da9f2021-06-19 14:00:26 +05301000 if not asset.flags.increase_in_asset_life:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301001 depreciation_amount = (
1002 flt(asset.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
1003 ) / flt(row.total_number_of_depreciations)
GangaManoj2b93e542021-06-19 13:45:37 +05301004
1005 # if the Depreciation Schedule is being modified after Asset Repair
1006 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301007 depreciation_amount = (
1008 flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)
1009 ) / (date_diff(asset.to_date, asset.available_for_use_date) / 365)
Ankush Menat4551d7d2021-08-19 13:41:10 +05301010
Saqib9226cd32021-05-10 12:36:56 +05301011 else:
1012 rate_of_depreciation = row.rate_of_depreciation
1013 # if its the first depreciation
1014 if depreciable_value == asset.gross_purchase_amount:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301015 if row.finance_book and frappe.db.get_value("Finance Book", row.finance_book, "for_income_tax"):
Saqib424efd42021-09-28 18:12:02 +05301016 # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
1017 diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
1018 if diff <= 180:
1019 rate_of_depreciation = rate_of_depreciation / 2
1020 frappe.msgprint(
Ankush Menat494bd9e2022-03-28 18:52:46 +05301021 _(
1022 "As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%."
1023 )
1024 )
Saqib9226cd32021-05-10 12:36:56 +05301025
1026 depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
1027
Saqib3a504902021-08-03 15:57:11 +05301028 return depreciation_amount
1029
Ankush Menat494bd9e2022-03-28 18:52:46 +05301030
Saqib3a504902021-08-03 15:57:11 +05301031def set_item_tax_from_hsn_code(item):
Ankush Menat4551d7d2021-08-19 13:41:10 +05301032 if not item.taxes and item.gst_hsn_code:
Saqib3a504902021-08-03 15:57:11 +05301033 hsn_doc = frappe.get_doc("GST HSN Code", item.gst_hsn_code)
1034
1035 for tax in hsn_doc.taxes:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301036 item.append(
1037 "taxes",
1038 {
1039 "item_tax_template": tax.item_tax_template,
1040 "tax_category": tax.tax_category,
1041 "valid_from": tax.valid_from,
1042 },
1043 )
1044
Deepesh Garg2b2572b2021-08-20 14:40:12 +05301045
1046def delete_gst_settings_for_company(doc, method):
Ankush Menat494bd9e2022-03-28 18:52:46 +05301047 if doc.country != "India":
Deepesh Garg2b2572b2021-08-20 14:40:12 +05301048 return
1049
1050 gst_settings = frappe.get_doc("GST Settings")
1051 records_to_delete = []
1052
Ankush Menat494bd9e2022-03-28 18:52:46 +05301053 for d in reversed(gst_settings.get("gst_accounts")):
Deepesh Garg2b2572b2021-08-20 14:40:12 +05301054 if d.company == doc.name:
1055 records_to_delete.append(d)
1056
1057 for d in records_to_delete:
1058 gst_settings.remove(d)
1059
1060 gst_settings.save()