# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt import frappe, os, json from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.permissions import add_permission, update_permission_property from erpnext.regional.india import states from erpnext.accounts.utils import get_fiscal_year, FiscalYearError from frappe.utils import today def setup(company=None, patch=True): # Company independent fixtures should be called only once at the first company setup if patch or frappe.db.count("Company", {"country": "India"}) <= 1: setup_company_independent_fixtures(patch=patch) if not patch: make_fixtures(company) # TODO: for all countries def setup_company_independent_fixtures(patch=False): make_custom_fields() make_property_setters(patch=patch) add_permissions() add_custom_roles_for_reports() frappe.enqueue("erpnext.regional.india.setup.add_hsn_sac_codes", now=frappe.flags.in_test) create_gratuity_rule() add_print_formats() update_accounts_settings_for_taxes() def add_hsn_sac_codes(): if frappe.flags.in_test and frappe.flags.created_hsn_codes: return # HSN codes with open(os.path.join(os.path.dirname(__file__), "hsn_code_data.json"), "r") as f: hsn_codes = json.loads(f.read()) create_hsn_codes(hsn_codes, code_field="hsn_code") # SAC Codes with open(os.path.join(os.path.dirname(__file__), "sac_code_data.json"), "r") as f: sac_codes = json.loads(f.read()) create_hsn_codes(sac_codes, code_field="sac_code") if frappe.flags.in_test: frappe.flags.created_hsn_codes = True def create_hsn_codes(data, code_field): for d in data: hsn_code = frappe.new_doc("GST HSN Code") hsn_code.description = d["description"] hsn_code.hsn_code = d[code_field] hsn_code.name = d[code_field] hsn_code.db_insert(ignore_if_duplicate=True) def add_custom_roles_for_reports(): for report_name in ( "GST Sales Register", "GST Purchase Register", "GST Itemised Sales Register", "GST Itemised Purchase Register", "Eway Bill", "E-Invoice Summary", ): if not frappe.db.get_value("Custom Role", dict(report=report_name)): frappe.get_doc( dict( doctype="Custom Role", report=report_name, roles=[dict(role="Accounts User"), dict(role="Accounts Manager")], ) ).insert() for report_name in ("Professional Tax Deductions", "Provident Fund Deductions"): if not frappe.db.get_value("Custom Role", dict(report=report_name)): frappe.get_doc( dict( doctype="Custom Role", report=report_name, roles=[dict(role="HR User"), dict(role="HR Manager"), dict(role="Employee")], ) ).insert() for report_name in ("HSN-wise-summary of outward supplies", "GSTR-1", "GSTR-2"): if not frappe.db.get_value("Custom Role", dict(report=report_name)): frappe.get_doc( dict( doctype="Custom Role", report=report_name, roles=[dict(role="Accounts User"), dict(role="Accounts Manager"), dict(role="Auditor")], ) ).insert() def add_permissions(): for doctype in ( "GST HSN Code", "GST Settings", "GSTR 3B Report", "Lower Deduction Certificate", "E Invoice Settings", ): add_permission(doctype, "All", 0) for role in ("Accounts Manager", "Accounts User", "System Manager"): add_permission(doctype, role, 0) update_permission_property(doctype, role, 0, "write", 1) update_permission_property(doctype, role, 0, "create", 1) if doctype == "GST HSN Code": for role in ("Item Manager", "Stock Manager"): add_permission(doctype, role, 0) update_permission_property(doctype, role, 0, "write", 1) update_permission_property(doctype, role, 0, "create", 1) def add_print_formats(): frappe.reload_doc("regional", "print_format", "gst_tax_invoice") frappe.reload_doc("selling", "print_format", "gst_pos_invoice") frappe.reload_doc("accounts", "print_format", "GST E-Invoice") frappe.db.set_value("Print Format", "GST POS Invoice", "disabled", 0) frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0) frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0) def make_property_setters(patch=False): # GST rules do not allow for an invoice no. bigger than 16 characters journal_entry_types = frappe.get_meta("Journal Entry").get_options("voucher_type").split("\n") + [ "Reversal Of ITC" ] sales_invoice_series = ["SINV-.YY.-", "SRET-.YY.-", ""] + frappe.get_meta( "Sales Invoice" ).get_options("naming_series").split("\n") purchase_invoice_series = ["PINV-.YY.-", "PRET-.YY.-", ""] + frappe.get_meta( "Purchase Invoice" ).get_options("naming_series").split("\n") if not patch: make_property_setter( "Sales Invoice", "naming_series", "options", "\n".join(sales_invoice_series), "" ) make_property_setter( "Purchase Invoice", "naming_series", "options", "\n".join(purchase_invoice_series), "" ) make_property_setter( "Journal Entry", "voucher_type", "options", "\n".join(journal_entry_types), "" ) def make_custom_fields(update=True): custom_fields = get_custom_fields() create_custom_fields(custom_fields, update=update) def get_custom_fields(): hsn_sac_field = dict( fieldname="gst_hsn_code", label="HSN/SAC", fieldtype="Data", fetch_from="item_code.gst_hsn_code", insert_after="description", allow_on_submit=1, print_hide=1, fetch_if_empty=1, ) nil_rated_exempt = dict( fieldname="is_nil_exempt", label="Is Nil Rated or Exempted", fieldtype="Check", fetch_from="item_code.is_nil_exempt", insert_after="gst_hsn_code", print_hide=1, ) is_non_gst = dict( fieldname="is_non_gst", label="Is Non GST", fieldtype="Check", fetch_from="item_code.is_non_gst", insert_after="is_nil_exempt", print_hide=1, ) taxable_value = dict( fieldname="taxable_value", label="Taxable Value", fieldtype="Currency", insert_after="base_net_amount", hidden=1, options="Company:company:default_currency", print_hide=1, ) purchase_invoice_gst_category = [ dict( fieldname="gst_section", label="GST Details", fieldtype="Section Break", insert_after="language", print_hide=1, collapsible=1, ), dict( fieldname="gst_category", label="GST Category", fieldtype="Select", insert_after="gst_section", print_hide=1, options="\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nUIN Holders", fetch_from="supplier.gst_category", fetch_if_empty=1, ), dict( fieldname="export_type", label="Export Type", fieldtype="Select", insert_after="gst_category", print_hide=1, depends_on='eval:in_list(["SEZ", "Overseas"], doc.gst_category)', options="\nWith Payment of Tax\nWithout Payment of Tax", fetch_from="supplier.export_type", fetch_if_empty=1, ), ] sales_invoice_gst_category = [ dict( fieldname="gst_section", label="GST Details", fieldtype="Section Break", insert_after="language", print_hide=1, collapsible=1, ), dict( fieldname="gst_category", label="GST Category", fieldtype="Select", insert_after="gst_section", print_hide=1, options="\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders", fetch_from="customer.gst_category", fetch_if_empty=1, length=25, ), dict( fieldname="export_type", label="Export Type", fieldtype="Select", insert_after="gst_category", print_hide=1, depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', options="\nWith Payment of Tax\nWithout Payment of Tax", fetch_from="customer.export_type", fetch_if_empty=1, length=25, ), ] delivery_note_gst_category = [ dict( fieldname="gst_category", label="GST Category", fieldtype="Select", insert_after="gst_vehicle_type", print_hide=1, options="\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders", fetch_from="customer.gst_category", fetch_if_empty=1, ), ] invoice_gst_fields = [ dict( fieldname="invoice_copy", label="Invoice Copy", length=30, fieldtype="Select", insert_after="export_type", print_hide=1, allow_on_submit=1, options="Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier", ), dict( fieldname="reverse_charge", label="Reverse Charge", length=2, fieldtype="Select", insert_after="invoice_copy", print_hide=1, options="Y\nN", default="N", ), dict( fieldname="ecommerce_gstin", label="E-commerce GSTIN", length=15, fieldtype="Data", insert_after="export_type", print_hide=1, ), dict(fieldname="gst_col_break", fieldtype="Column Break", insert_after="ecommerce_gstin"), dict( fieldname="reason_for_issuing_document", label="Reason For Issuing document", fieldtype="Select", insert_after="gst_col_break", print_hide=1, depends_on="eval:doc.is_return==1", length=45, options="\n01-Sales Return\n02-Post Sale Discount\n03-Deficiency in services\n04-Correction in Invoice\n05-Change in POS\n06-Finalization of Provisional assessment\n07-Others", ), ] purchase_invoice_gst_fields = [ dict( fieldname="supplier_gstin", label="Supplier GSTIN", fieldtype="Data", insert_after="supplier_address", fetch_from="supplier_address.gstin", print_hide=1, read_only=1, ), dict( fieldname="company_gstin", label="Company GSTIN", fieldtype="Data", insert_after="shipping_address_display", fetch_from="shipping_address.gstin", print_hide=1, read_only=1, ), dict( fieldname="place_of_supply", label="Place of Supply", fieldtype="Data", insert_after="shipping_address", print_hide=1, read_only=1, ), ] purchase_invoice_itc_fields = [ dict( fieldname="eligibility_for_itc", label="Eligibility For ITC", fieldtype="Select", insert_after="reason_for_issuing_document", print_hide=1, options="Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC", default="All Other ITC", ), dict( fieldname="itc_integrated_tax", label="Availed ITC Integrated Tax", fieldtype="Currency", insert_after="eligibility_for_itc", options="Company:company:default_currency", print_hide=1, ), dict( fieldname="itc_central_tax", label="Availed ITC Central Tax", fieldtype="Currency", insert_after="itc_integrated_tax", options="Company:company:default_currency", print_hide=1, ), dict( fieldname="itc_state_tax", label="Availed ITC State/UT Tax", fieldtype="Currency", insert_after="itc_central_tax", options="Company:company:default_currency", print_hide=1, ), dict( fieldname="itc_cess_amount", label="Availed ITC Cess", fieldtype="Currency", insert_after="itc_state_tax", options="Company:company:default_currency", print_hide=1, ), ] sales_invoice_gst_fields = [ dict( fieldname="billing_address_gstin", label="Billing Address GSTIN", fieldtype="Data", insert_after="customer_address", read_only=1, fetch_from="customer_address.gstin", print_hide=1, length=15, ), dict( fieldname="customer_gstin", label="Customer GSTIN", fieldtype="Data", insert_after="shipping_address_name", fetch_from="shipping_address_name.gstin", print_hide=1, length=15, ), dict( fieldname="place_of_supply", label="Place of Supply", fieldtype="Data", insert_after="customer_gstin", print_hide=1, read_only=1, length=50, ), dict( fieldname="company_gstin", label="Company GSTIN", fieldtype="Data", insert_after="company_address", fetch_from="company_address.gstin", print_hide=1, read_only=1, length=15, ), ] sales_invoice_shipping_fields = [ dict( fieldname="port_code", label="Port Code", fieldtype="Data", insert_after="reason_for_issuing_document", print_hide=1, depends_on="eval:doc.gst_category=='Overseas' ", length=15, ), dict( fieldname="shipping_bill_number", label=" Shipping Bill Number", fieldtype="Data", insert_after="port_code", print_hide=1, depends_on="eval:doc.gst_category=='Overseas' ", length=50, ), dict( fieldname="shipping_bill_date", label="Shipping Bill Date", fieldtype="Date", insert_after="shipping_bill_number", print_hide=1, depends_on="eval:doc.gst_category=='Overseas' ", ), ] journal_entry_fields = [ dict( fieldname="reversal_type", label="Reversal Type", fieldtype="Select", insert_after="voucher_type", print_hide=1, options="As per rules 42 & 43 of CGST Rules\nOthers", depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'", ), dict( fieldname="company_address", label="Company Address", fieldtype="Link", options="Address", insert_after="reversal_type", print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'", ), dict( fieldname="company_gstin", label="Company GSTIN", fieldtype="Data", read_only=1, insert_after="company_address", print_hide=1, fetch_from="company_address.gstin", depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'", ), ] inter_state_gst_field = [ dict( fieldname="is_inter_state", label="Is Inter State", fieldtype="Check", insert_after="disabled", print_hide=1, ), dict( fieldname="is_reverse_charge", label="Is Reverse Charge", fieldtype="Check", insert_after="is_inter_state", print_hide=1, ), dict( fieldname="tax_category_column_break", fieldtype="Column Break", insert_after="is_reverse_charge", ), dict( fieldname="gst_state", label="Source State", fieldtype="Select", options="\n".join(states), insert_after="company", ), ] ewaybill_fields = [ { "fieldname": "distance", "label": "Distance (in km)", "fieldtype": "Float", "insert_after": "vehicle_no", "print_hide": 1, }, { "fieldname": "gst_transporter_id", "label": "GST Transporter ID", "fieldtype": "Data", "insert_after": "transporter", "fetch_from": "transporter.gst_transporter_id", "print_hide": 1, "translatable": 0, }, { "fieldname": "mode_of_transport", "label": "Mode of Transport", "fieldtype": "Select", "options": "\nRoad\nAir\nRail\nShip", "default": "Road", "insert_after": "transporter_name", "print_hide": 1, "translatable": 0, }, { "fieldname": "gst_vehicle_type", "label": "GST Vehicle Type", "fieldtype": "Select", "options": "Regular\nOver Dimensional Cargo (ODC)", "depends_on": 'eval:(doc.mode_of_transport === "Road")', "default": "Regular", "insert_after": "lr_date", "print_hide": 1, "translatable": 0, }, { "fieldname": "ewaybill", "label": "E-Way Bill No.", "fieldtype": "Data", "depends_on": "eval:(doc.docstatus === 1)", "allow_on_submit": 1, "insert_after": "customer_name_in_arabic", "translatable": 0, }, ] si_ewaybill_fields = [ { "fieldname": "transporter_info", "label": "Transporter Info", "fieldtype": "Section Break", "insert_after": "terms", "collapsible": 1, "collapsible_depends_on": "transporter", "print_hide": 1, }, { "fieldname": "transporter", "label": "Transporter", "fieldtype": "Link", "insert_after": "transporter_info", "options": "Supplier", "print_hide": 1, }, { "fieldname": "gst_transporter_id", "label": "GST Transporter ID", "fieldtype": "Data", "insert_after": "transporter", "fetch_from": "transporter.gst_transporter_id", "print_hide": 1, "translatable": 0, "length": 20, }, { "fieldname": "driver", "label": "Driver", "fieldtype": "Link", "insert_after": "gst_transporter_id", "options": "Driver", "print_hide": 1, }, { "fieldname": "lr_no", "label": "Transport Receipt No", "fieldtype": "Data", "insert_after": "driver", "print_hide": 1, "translatable": 0, "length": 30, }, { "fieldname": "vehicle_no", "label": "Vehicle No", "fieldtype": "Data", "insert_after": "lr_no", "print_hide": 1, "translatable": 0, "length": 10, }, { "fieldname": "distance", "label": "Distance (in km)", "fieldtype": "Float", "insert_after": "vehicle_no", "print_hide": 1, }, {"fieldname": "transporter_col_break", "fieldtype": "Column Break", "insert_after": "distance"}, { "fieldname": "transporter_name", "label": "Transporter Name", "fieldtype": "Small Text", "insert_after": "transporter_col_break", "fetch_from": "transporter.name", "read_only": 1, "print_hide": 1, "translatable": 0, }, { "fieldname": "mode_of_transport", "label": "Mode of Transport", "fieldtype": "Select", "options": "\nRoad\nAir\nRail\nShip", "insert_after": "transporter_name", "print_hide": 1, "translatable": 0, "length": 5, }, { "fieldname": "driver_name", "label": "Driver Name", "fieldtype": "Small Text", "insert_after": "mode_of_transport", "fetch_from": "driver.full_name", "print_hide": 1, "translatable": 0, }, { "fieldname": "lr_date", "label": "Transport Receipt Date", "fieldtype": "Date", "insert_after": "driver_name", "default": "Today", "print_hide": 1, }, { "fieldname": "gst_vehicle_type", "label": "GST Vehicle Type", "fieldtype": "Select", "options": "Regular\nOver Dimensional Cargo (ODC)", "depends_on": 'eval:(doc.mode_of_transport === "Road")', "default": "Regular", "insert_after": "lr_date", "print_hide": 1, "translatable": 0, "length": 30, }, { "fieldname": "ewaybill", "label": "E-Way Bill No.", "fieldtype": "Data", "depends_on": "eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)", "allow_on_submit": 1, "insert_after": "tax_id", "translatable": 0, "length": 20, }, ] payment_entry_fields = [ dict( fieldname="gst_section", label="GST Details", fieldtype="Section Break", insert_after="deductions", print_hide=1, collapsible=1, ), dict( fieldname="company_address", label="Company Address", fieldtype="Link", insert_after="gst_section", print_hide=1, options="Address", ), dict( fieldname="company_gstin", label="Company GSTIN", fieldtype="Data", insert_after="company_address", fetch_from="company_address.gstin", print_hide=1, read_only=1, ), dict( fieldname="place_of_supply", label="Place of Supply", fieldtype="Data", insert_after="company_gstin", print_hide=1, read_only=1, ), dict(fieldname="gst_column_break", fieldtype="Column Break", insert_after="place_of_supply"), dict( fieldname="customer_address", label="Customer Address", fieldtype="Link", insert_after="gst_column_break", print_hide=1, options="Address", depends_on='eval:doc.party_type == "Customer"', ), dict( fieldname="customer_gstin", label="Customer GSTIN", fieldtype="Data", insert_after="customer_address", fetch_from="customer_address.gstin", print_hide=1, read_only=1, ), ] si_einvoice_fields = [ dict( fieldname="irn", label="IRN", fieldtype="Data", read_only=1, insert_after="customer", no_copy=1, print_hide=1, depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0', ), dict( fieldname="irn_cancelled", label="IRN Cancelled", fieldtype="Check", no_copy=1, print_hide=1, depends_on="eval: doc.irn", allow_on_submit=1, insert_after="customer", ), dict( fieldname="eway_bill_validity", label="E-Way Bill Validity", fieldtype="Data", no_copy=1, print_hide=1, depends_on="ewaybill", read_only=1, allow_on_submit=1, insert_after="ewaybill", ), dict( fieldname="eway_bill_cancelled", label="E-Way Bill Cancelled", fieldtype="Check", no_copy=1, print_hide=1, depends_on="eval:(doc.eway_bill_cancelled === 1)", read_only=1, allow_on_submit=1, insert_after="customer", ), dict( fieldname="einvoice_section", label="E-Invoice Fields", fieldtype="Section Break", insert_after="gst_vehicle_type", print_hide=1, hidden=1, ), dict( fieldname="ack_no", label="Ack. No.", fieldtype="Data", read_only=1, hidden=1, insert_after="einvoice_section", no_copy=1, print_hide=1, ), dict( fieldname="ack_date", label="Ack. Date", fieldtype="Data", read_only=1, hidden=1, insert_after="ack_no", no_copy=1, print_hide=1, ), dict( fieldname="irn_cancel_date", label="Cancel Date", fieldtype="Data", read_only=1, hidden=1, insert_after="ack_date", no_copy=1, print_hide=1, ), dict( fieldname="signed_einvoice", label="Signed E-Invoice", fieldtype="Code", options="JSON", hidden=1, insert_after="irn_cancel_date", no_copy=1, print_hide=1, read_only=1, ), dict( fieldname="signed_qr_code", label="Signed QRCode", fieldtype="Code", options="JSON", hidden=1, insert_after="signed_einvoice", no_copy=1, print_hide=1, read_only=1, ), dict( fieldname="qrcode_image", label="QRCode", fieldtype="Attach Image", hidden=1, insert_after="signed_qr_code", no_copy=1, print_hide=1, read_only=1, ), dict( fieldname="einvoice_status", label="E-Invoice Status", fieldtype="Select", insert_after="qrcode_image", options="\nPending\nGenerated\nCancelled\nFailed", default=None, hidden=1, no_copy=1, print_hide=1, read_only=1, ), dict( fieldname="failure_description", label="E-Invoice Failure Description", fieldtype="Code", options="JSON", hidden=1, insert_after="einvoice_status", no_copy=1, print_hide=1, read_only=1, ), ] custom_fields = { "Address": [ dict(fieldname="gstin", label="Party GSTIN", fieldtype="Data", insert_after="fax"), dict( fieldname="gst_state", label="GST State", fieldtype="Select", options="\n".join(states), insert_after="gstin", ), dict( fieldname="gst_state_number", label="GST State Number", fieldtype="Data", insert_after="gst_state", read_only=1, ), ], "Purchase Invoice": purchase_invoice_gst_category + invoice_gst_fields + purchase_invoice_itc_fields + purchase_invoice_gst_fields, "Purchase Order": purchase_invoice_gst_fields, "Purchase Receipt": purchase_invoice_gst_fields, "Sales Invoice": sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields, "POS Invoice": sales_invoice_gst_fields, "Delivery Note": sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category, "Payment Entry": payment_entry_fields, "Journal Entry": journal_entry_fields, "Sales Order": sales_invoice_gst_fields, "Tax Category": inter_state_gst_field, "Item": [ dict( fieldname="gst_hsn_code", label="HSN/SAC", fieldtype="Link", options="GST HSN Code", insert_after="item_group", ), dict( fieldname="is_nil_exempt", label="Is Nil Rated or Exempted", fieldtype="Check", insert_after="gst_hsn_code", ), dict( fieldname="is_non_gst", label="Is Non GST ", fieldtype="Check", insert_after="is_nil_exempt" ), ], "Quotation Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Supplier Quotation Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Sales Order Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Delivery Note Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Sales Invoice Item": [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], "POS Invoice Item": [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], "Purchase Order Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Purchase Receipt Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Purchase Invoice Item": [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], "Material Request Item": [hsn_sac_field, nil_rated_exempt, is_non_gst], "Salary Component": [ dict( fieldname="component_type", label="Component Type", fieldtype="Select", insert_after="description", options="\nProvident Fund\nAdditional Provident Fund\nProvident Fund Loan\nProfessional Tax", depends_on='eval:doc.type == "Deduction"', ) ], "Employee": [ dict( fieldname="ifsc_code", label="IFSC Code", fieldtype="Data", insert_after="bank_ac_no", print_hide=1, depends_on='eval:doc.salary_mode == "Bank"', ), dict( fieldname="pan_number", label="PAN Number", fieldtype="Data", insert_after="payroll_cost_center", print_hide=1, ), dict( fieldname="micr_code", label="MICR Code", fieldtype="Data", insert_after="ifsc_code", print_hide=1, depends_on='eval:doc.salary_mode == "Bank"', ), dict( fieldname="provident_fund_account", label="Provident Fund Account", fieldtype="Data", insert_after="pan_number", ), ], "Company": [ dict( fieldname="hra_section", label="HRA Settings", fieldtype="Section Break", insert_after="asset_received_but_not_billed", collapsible=1, ), dict( fieldname="basic_component", label="Basic Component", fieldtype="Link", options="Salary Component", insert_after="hra_section", ), dict( fieldname="hra_component", label="HRA Component", fieldtype="Link", options="Salary Component", insert_after="basic_component", ), dict(fieldname="hra_column_break", fieldtype="Column Break", insert_after="hra_component"), dict( fieldname="arrear_component", label="Arrear Component", fieldtype="Link", options="Salary Component", insert_after="hra_column_break", ), ], "Employee Tax Exemption Declaration": [ dict( fieldname="hra_section", label="HRA Exemption", fieldtype="Section Break", insert_after="declarations", ), dict( fieldname="monthly_house_rent", label="Monthly House Rent", fieldtype="Currency", insert_after="hra_section", ), dict( fieldname="rented_in_metro_city", label="Rented in Metro City", fieldtype="Check", insert_after="monthly_house_rent", depends_on="monthly_house_rent", ), dict( fieldname="salary_structure_hra", label="HRA as per Salary Structure", fieldtype="Currency", insert_after="rented_in_metro_city", read_only=1, depends_on="monthly_house_rent", ), dict( fieldname="hra_column_break", fieldtype="Column Break", insert_after="salary_structure_hra", depends_on="monthly_house_rent", ), dict( fieldname="annual_hra_exemption", label="Annual HRA Exemption", fieldtype="Currency", insert_after="hra_column_break", read_only=1, depends_on="monthly_house_rent", ), dict( fieldname="monthly_hra_exemption", label="Monthly HRA Exemption", fieldtype="Currency", insert_after="annual_hra_exemption", read_only=1, depends_on="monthly_house_rent", ), ], "Employee Tax Exemption Proof Submission": [ dict( fieldname="hra_section", label="HRA Exemption", fieldtype="Section Break", insert_after="tax_exemption_proofs", ), dict( fieldname="house_rent_payment_amount", label="House Rent Payment Amount", fieldtype="Currency", insert_after="hra_section", ), dict( fieldname="rented_in_metro_city", label="Rented in Metro City", fieldtype="Check", insert_after="house_rent_payment_amount", depends_on="house_rent_payment_amount", ), dict( fieldname="rented_from_date", label="Rented From Date", fieldtype="Date", insert_after="rented_in_metro_city", depends_on="house_rent_payment_amount", ), dict( fieldname="rented_to_date", label="Rented To Date", fieldtype="Date", insert_after="rented_from_date", depends_on="house_rent_payment_amount", ), dict( fieldname="hra_column_break", fieldtype="Column Break", insert_after="rented_to_date", depends_on="house_rent_payment_amount", ), dict( fieldname="monthly_house_rent", label="Monthly House Rent", fieldtype="Currency", insert_after="hra_column_break", read_only=1, depends_on="house_rent_payment_amount", ), dict( fieldname="monthly_hra_exemption", label="Monthly Eligible Amount", fieldtype="Currency", insert_after="monthly_house_rent", read_only=1, depends_on="house_rent_payment_amount", ), dict( fieldname="total_eligible_hra_exemption", label="Total Eligible HRA Exemption", fieldtype="Currency", insert_after="monthly_hra_exemption", read_only=1, depends_on="house_rent_payment_amount", ), ], "Supplier": [ {"fieldname": "pan", "label": "PAN", "fieldtype": "Data", "insert_after": "supplier_type"}, { "fieldname": "gst_transporter_id", "label": "GST Transporter ID", "fieldtype": "Data", "insert_after": "pan", "depends_on": "eval:doc.is_transporter", }, { "fieldname": "gst_category", "label": "GST Category", "fieldtype": "Select", "insert_after": "gst_transporter_id", "options": "Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nUIN Holders", "default": "Unregistered", }, { "fieldname": "export_type", "label": "Export Type", "fieldtype": "Select", "insert_after": "gst_category", "depends_on": 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)', "options": "\nWith Payment of Tax\nWithout Payment of Tax", "mandatory_depends_on": 'eval:in_list(["SEZ", "Overseas"], doc.gst_category)', }, ], "Customer": [ {"fieldname": "pan", "label": "PAN", "fieldtype": "Data", "insert_after": "customer_type"}, { "fieldname": "gst_category", "label": "GST Category", "fieldtype": "Select", "insert_after": "pan", "options": "Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders", "default": "Unregistered", }, { "fieldname": "export_type", "label": "Export Type", "fieldtype": "Select", "insert_after": "gst_category", "depends_on": 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', "options": "\nWith Payment of Tax\nWithout Payment of Tax", "mandatory_depends_on": 'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', }, ], "Finance Book": [ { "fieldname": "for_income_tax", "label": "For Income Tax", "fieldtype": "Check", "insert_after": "finance_book_name", "description": "If the asset is put to use for less than 180 days, the first Depreciation Rate will be reduced by 50%.", } ], } return custom_fields def make_fixtures(company=None): docs = [] company = company or frappe.db.get_value("Global Defaults", None, "default_company") set_salary_components(docs) set_tds_account(docs, company) for d in docs: try: doc = frappe.get_doc(d) doc.flags.ignore_permissions = True doc.insert() except frappe.NameError: frappe.clear_messages() except frappe.DuplicateEntryError: frappe.clear_messages() # create records for Tax Withholding Category set_tax_withholding_category(company) def update_regional_tax_settings(country, company): # Will only add default GST accounts if present input_account_names = ["Input Tax CGST", "Input Tax SGST", "Input Tax IGST"] output_account_names = ["Output Tax CGST", "Output Tax SGST", "Output Tax IGST"] rcm_accounts = ["Input Tax CGST RCM", "Input Tax SGST RCM", "Input Tax IGST RCM"] gst_settings = frappe.get_single("GST Settings") existing_account_list = [] for account in gst_settings.get("gst_accounts"): for key in ["cgst_account", "sgst_account", "igst_account"]: existing_account_list.append(account.get(key)) gst_accounts = frappe._dict( frappe.get_all( "Account", { "company": company, "account_name": ("in", input_account_names + output_account_names + rcm_accounts), }, ["account_name", "name"], as_list=1, ) ) add_accounts_in_gst_settings( company, input_account_names, gst_accounts, existing_account_list, gst_settings ) add_accounts_in_gst_settings( company, output_account_names, gst_accounts, existing_account_list, gst_settings ) add_accounts_in_gst_settings( company, rcm_accounts, gst_accounts, existing_account_list, gst_settings, is_reverse_charge=1 ) gst_settings.save() def add_accounts_in_gst_settings( company, account_names, gst_accounts, existing_account_list, gst_settings, is_reverse_charge=0 ): accounts_not_added = 1 for account in account_names: # Default Account Added does not exists if not gst_accounts.get(account): accounts_not_added = 0 # Check if already added in GST Settings if gst_accounts.get(account) in existing_account_list: accounts_not_added = 0 if accounts_not_added: gst_settings.append( "gst_accounts", { "company": company, "cgst_account": gst_accounts.get(account_names[0]), "sgst_account": gst_accounts.get(account_names[1]), "igst_account": gst_accounts.get(account_names[2]), "is_reverse_charge_account": is_reverse_charge, }, ) def set_salary_components(docs): docs.extend( [ { "doctype": "Salary Component", "salary_component": "Professional Tax", "description": "Professional Tax", "type": "Deduction", "exempted_from_income_tax": 1, }, { "doctype": "Salary Component", "salary_component": "Provident Fund", "description": "Provident fund", "type": "Deduction", "is_tax_applicable": 1, }, { "doctype": "Salary Component", "salary_component": "House Rent Allowance", "description": "House Rent Allowance", "type": "Earning", "is_tax_applicable": 1, }, { "doctype": "Salary Component", "salary_component": "Basic", "description": "Basic", "type": "Earning", "is_tax_applicable": 1, }, { "doctype": "Salary Component", "salary_component": "Arrear", "description": "Arrear", "type": "Earning", "is_tax_applicable": 1, }, { "doctype": "Salary Component", "salary_component": "Leave Encashment", "description": "Leave Encashment", "type": "Earning", "is_tax_applicable": 1, }, ] ) def set_tax_withholding_category(company): accounts = [] fiscal_year_details = None abbr = frappe.get_value("Company", company, "abbr") tds_account = frappe.get_value("Account", "TDS Payable - {0}".format(abbr), "name") if company and tds_account: accounts = [dict(company=company, account=tds_account)] try: fiscal_year_details = get_fiscal_year(today(), verbose=0) except FiscalYearError: pass docs = get_tds_details(accounts, fiscal_year_details) for d in docs: if not frappe.db.exists("Tax Withholding Category", d.get("name")): doc = frappe.get_doc(d) doc.flags.ignore_validate = True doc.flags.ignore_permissions = True doc.flags.ignore_mandatory = True doc.insert() else: doc = frappe.get_doc("Tax Withholding Category", d.get("name"), for_update=True) if accounts: doc.append("accounts", accounts[0]) if fiscal_year_details: # if fiscal year don't match with any of the already entered data, append rate row fy_exist = [ k for k in doc.get("rates") if k.get("from_date") <= fiscal_year_details[1] and k.get("to_date") >= fiscal_year_details[2] ] if not fy_exist: doc.append("rates", d.get("rates")[0]) doc.flags.ignore_permissions = True doc.flags.ignore_validate = True doc.flags.ignore_mandatory = True doc.flags.ignore_links = True doc.save() def set_tds_account(docs, company): parent_account = frappe.db.get_value( "Account", filters={"account_name": "Duties and Taxes", "company": company} ) if parent_account: docs.extend( [ { "doctype": "Account", "account_name": "TDS Payable", "account_type": "Tax", "parent_account": parent_account, "company": company, } ] ) def get_tds_details(accounts, fiscal_year_details): # bootstrap default tax withholding sections return [ dict( name="TDS - 194C - Company", category_name="Payment to Contractors (Single / Aggregate)", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 2, "single_threshold": 30000, "cumulative_threshold": 100000, } ], ), dict( name="TDS - 194C - Individual", category_name="Payment to Contractors (Single / Aggregate)", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 1, "single_threshold": 30000, "cumulative_threshold": 100000, } ], ), dict( name="TDS - 194C - No PAN / Invalid PAN", category_name="Payment to Contractors (Single / Aggregate)", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 100000, } ], ), dict( name="TDS - 194D - Company", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194D - Company Assessee", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194D - Individual", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194D - No PAN / Invalid PAN", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194DA - Company", category_name="Non-exempt payments made under a life insurance policy", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194DA - Individual", category_name="Non-exempt payments made under a life insurance policy", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194DA - No PAN / Invalid PAN", category_name="Non-exempt payments made under a life insurance policy", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 100000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194H - Company", category_name="Commission / Brokerage", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194H - Individual", category_name="Commission / Brokerage", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194H - No PAN / Invalid PAN", category_name="Commission / Brokerage", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194I - Rent - Company", category_name="Rent", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194I - Rent - Individual", category_name="Rent", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194I - Rent - No PAN / Invalid PAN", category_name="Rent", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194I - Rent/Machinery - Company", category_name="Rent-Plant / Machinery", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194I - Rent/Machinery - Individual", category_name="Rent-Plant / Machinery", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194I - Rent/Machinery - No PAN / Invalid PAN", category_name="Rent-Plant / Machinery", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194J - Professional Fees - Company", category_name="Professional Fees", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194J - Professional Fees - Individual", category_name="Professional Fees", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194J - Professional Fees - No PAN / Invalid PAN", category_name="Professional Fees", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194J - Director Fees - Company", category_name="Director Fees", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194J - Director Fees - Individual", category_name="Director Fees", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194J - Director Fees - No PAN / Invalid PAN", category_name="Director Fees", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 0, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194 - Dividends - Company", category_name="Dividends", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194 - Dividends - Individual", category_name="Dividends", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0, } ], ), dict( name="TDS - 194 - Dividends - No PAN / Invalid PAN", category_name="Dividends", doctype="Tax Withholding Category", accounts=accounts, rates=[ { "from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], "tax_withholding_rate": 20, "single_threshold": 2500, "cumulative_threshold": 0, } ], ), ] def create_gratuity_rule(): # Standard Indain Gratuity Rule if not frappe.db.exists("Gratuity Rule", "Indian Standard Gratuity Rule"): rule = frappe.new_doc("Gratuity Rule") rule.name = "Indian Standard Gratuity Rule" rule.calculate_gratuity_amount_based_on = "Current Slab" rule.work_experience_calculation_method = "Round Off Work Experience" rule.minimum_year_for_gratuity = 5 fraction = 15 / 26 rule.append( "gratuity_rule_slabs", {"from_year": 0, "to_year": 0, "fraction_of_applicable_earnings": fraction}, ) rule.flags.ignore_mandatory = True rule.save() def update_accounts_settings_for_taxes(): if frappe.db.count("Company") == 1: frappe.db.set_value("Accounts Settings", None, "add_taxes_from_item_tax_template", 0)