Merge branch 'develop' into hr-separation

This commit is contained in:
Rucha Mahabal
2022-07-07 13:46:54 +05:30
192 changed files with 517 additions and 73374 deletions

View File

@@ -1,21 +0,0 @@
from __future__ import unicode_literals
import frappe
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company or not frappe.db.count("E Invoice User"):
return
frappe.reload_doc("regional", "doctype", "e_invoice_user")
for creds in frappe.db.get_all("E Invoice User", fields=["name", "gstin"]):
company_name = frappe.db.sql(
"""
select dl.link_name from `tabAddress` a, `tabDynamic Link` dl
where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
""",
(creds.get("gstin")),
)
if company_name and len(company_name) > 0:
frappe.db.set_value("E Invoice User", creds.get("name"), "company", company_name[0][0])

View File

@@ -1,160 +0,0 @@
from __future__ import unicode_literals
import json
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
# move hidden einvoice fields to a different section
custom_fields = {
"Sales Invoice": [
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,
),
]
}
create_custom_fields(custom_fields, update=True)
if frappe.db.exists("E Invoice Settings") and frappe.db.get_single_value(
"E Invoice Settings", "enable"
):
frappe.db.sql(
"""
UPDATE `tabSales Invoice` SET einvoice_status = 'Pending'
WHERE
posting_date >= '2021-04-01'
AND ifnull(irn, '') = ''
AND ifnull(`billing_address_gstin`, '') != ifnull(`company_gstin`, '')
AND ifnull(gst_category, '') in ('Registered Regular', 'SEZ', 'Overseas', 'Deemed Export')
"""
)
# set appropriate statuses
frappe.db.sql(
"""UPDATE `tabSales Invoice` SET einvoice_status = 'Generated'
WHERE ifnull(irn, '') != '' AND ifnull(irn_cancelled, 0) = 0"""
)
frappe.db.sql(
"""UPDATE `tabSales Invoice` SET einvoice_status = 'Cancelled'
WHERE ifnull(irn_cancelled, 0) = 1"""
)
# set correct acknowledgement in e-invoices
einvoices = frappe.get_all("Sales Invoice", {"irn": ["is", "set"]}, ["name", "signed_einvoice"])
if einvoices:
for inv in einvoices:
signed_einvoice = inv.get("signed_einvoice")
if signed_einvoice:
signed_einvoice = json.loads(signed_einvoice)
frappe.db.set_value(
"Sales Invoice",
inv.get("name"),
"ack_no",
signed_einvoice.get("AckNo"),
update_modified=False,
)
frappe.db.set_value(
"Sales Invoice",
inv.get("name"),
"ack_date",
signed_einvoice.get("AckDt"),
update_modified=False,
)

View File

@@ -1,20 +0,0 @@
from __future__ import unicode_literals
import frappe
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
if frappe.db.exists("Report", "E-Invoice Summary") and not frappe.db.get_value(
"Custom Role", dict(report="E-Invoice Summary")
):
frappe.get_doc(
dict(
doctype="Custom Role",
report="E-Invoice Summary",
roles=[dict(role="Accounts User"), dict(role="Accounts Manager")],
)
).insert()

View File

@@ -1,23 +0,0 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
create_custom_field(
"Delivery Note",
{
"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,
"owner": "Administrator",
},
)

View File

@@ -1,27 +0,0 @@
from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
custom_fields = {
"Sales Invoice": [
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",
)
]
}
create_custom_fields(custom_fields, update=True)

View File

@@ -1,42 +0,0 @@
import frappe
from erpnext.regional.india.setup import make_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
make_custom_fields()
frappe.reload_doctype("Tax Category")
frappe.reload_doctype("Sales Taxes and Charges Template")
frappe.reload_doctype("Purchase Taxes and Charges Template")
# Create tax category with inter state field checked
tax_category = frappe.db.get_value("Tax Category", {"name": "OUT OF STATE"}, "name")
if not tax_category:
inter_state_category = frappe.get_doc(
{"doctype": "Tax Category", "title": "OUT OF STATE", "is_inter_state": 1}
).insert()
tax_category = inter_state_category.name
for doctype in ("Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"):
if not frappe.get_meta(doctype).has_field("is_inter_state"):
continue
template = frappe.db.get_value(doctype, {"is_inter_state": 1, "disabled": 0}, ["name"])
if template:
frappe.db.set_value(doctype, template, "tax_category", tax_category)
frappe.db.sql(
"""
DELETE FROM `tabCustom Field`
WHERE fieldname = 'is_inter_state'
AND dt IN ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template')
"""
)

View File

@@ -1,25 +0,0 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
custom_fields = {
"Delivery Note": [
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,
),
]
}
create_custom_fields(custom_fields, update=True)

View File

@@ -1,19 +0,0 @@
import frappe
from erpnext.regional.india import states
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
custom_fields = ["Address-gst_state", "Tax Category-gst_state"]
# Update options in gst_state custom fields
for field in custom_fields:
if frappe.db.exists("Custom Field", field):
gst_state_field = frappe.get_doc("Custom Field", field)
gst_state_field.options = "\n".join(states)
gst_state_field.save()

View File

@@ -1,167 +0,0 @@
import frappe
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 erpnext.regional.india.utils import get_gst_accounts
def execute():
company = frappe.get_all("Company", filters={"country": "India"}, fields=["name"])
if not company:
return
frappe.reload_doc("regional", "doctype", "gst_settings")
frappe.reload_doc("accounts", "doctype", "gst_account")
journal_entry_types = frappe.get_meta("Journal Entry").get_options("voucher_type").split("\n") + [
"Reversal Of ITC"
]
make_property_setter(
"Journal Entry", "voucher_type", "options", "\n".join(journal_entry_types), ""
)
custom_fields = {
"Journal Entry": [
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'",
),
],
"Purchase Invoice": [
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",
)
],
"Purchase Invoice Item": [
dict(
fieldname="taxable_value",
label="Taxable Value",
fieldtype="Currency",
insert_after="base_net_amount",
hidden=1,
options="Company:company:default_currency",
print_hide=1,
)
],
}
create_custom_fields(custom_fields, update=True)
# Patch ITC Availed fields from Data to Currency
# Patch Availed ITC for current fiscal_year
gst_accounts = get_gst_accounts(only_non_reverse_charge=1)
frappe.db.sql(
"""
UPDATE `tabCustom Field` SET fieldtype='Currency', options='Company:company:default_currency'
WHERE dt = 'Purchase Invoice' and fieldname in ('itc_integrated_tax', 'itc_state_tax', 'itc_central_tax',
'itc_cess_amount')
"""
)
frappe.db.sql(
"""UPDATE `tabPurchase Invoice` set itc_integrated_tax = '0'
WHERE trim(coalesce(itc_integrated_tax, '')) = '' """
)
frappe.db.sql(
"""UPDATE `tabPurchase Invoice` set itc_state_tax = '0'
WHERE trim(coalesce(itc_state_tax, '')) = '' """
)
frappe.db.sql(
"""UPDATE `tabPurchase Invoice` set itc_central_tax = '0'
WHERE trim(coalesce(itc_central_tax, '')) = '' """
)
frappe.db.sql(
"""UPDATE `tabPurchase Invoice` set itc_cess_amount = '0'
WHERE trim(coalesce(itc_cess_amount, '')) = '' """
)
# Get purchase invoices
invoices = frappe.get_all(
"Purchase Invoice",
{"posting_date": (">=", "2021-04-01"), "eligibility_for_itc": ("!=", "Ineligible")},
["name"],
)
amount_map = {}
if invoices:
invoice_list = set([d.name for d in invoices])
# Get GST applied
amounts = frappe.db.sql(
"""
SELECT parent, account_head, sum(base_tax_amount_after_discount_amount) as amount
FROM `tabPurchase Taxes and Charges`
where parent in %s
GROUP BY parent, account_head
""",
(invoice_list),
as_dict=1,
)
for d in amounts:
amount_map.setdefault(
d.parent,
{"itc_integrated_tax": 0, "itc_state_tax": 0, "itc_central_tax": 0, "itc_cess_amount": 0},
)
if not gst_accounts:
continue
if d.account_head in gst_accounts.get("igst_account"):
amount_map[d.parent]["itc_integrated_tax"] += d.amount
if d.account_head in gst_accounts.get("cgst_account"):
amount_map[d.parent]["itc_central_tax"] += d.amount
if d.account_head in gst_accounts.get("sgst_account"):
amount_map[d.parent]["itc_state_tax"] += d.amount
if d.account_head in gst_accounts.get("cess_account"):
amount_map[d.parent]["itc_cess_amount"] += d.amount
for invoice, values in amount_map.items():
frappe.db.set_value(
"Purchase Invoice",
invoice,
{
"itc_integrated_tax": values.get("itc_integrated_tax"),
"itc_central_tax": values.get("itc_central_tax"),
"itc_state_tax": values["itc_state_tax"],
"itc_cess_amount": values["itc_cess_amount"],
},
)

View File

@@ -1,24 +0,0 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
custom_fields = {
"Sales Invoice Item": [
dict(
fieldname="taxable_value",
label="Taxable Value",
fieldtype="Currency",
insert_after="base_net_amount",
hidden=1,
options="Company:company:default_currency",
print_hide=1,
)
]
}
create_custom_fields(custom_fields, update=True)

View File

@@ -1,66 +0,0 @@
import frappe
from erpnext.regional.india.setup import make_custom_fields
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
frappe.reload_doc("accounts", "doctype", "Tax Category")
make_custom_fields()
for doctype in ["Sales Invoice", "Purchase Invoice"]:
has_column = frappe.db.has_column(doctype, "invoice_type")
if has_column:
update_map = {
"Regular": "Registered Regular",
"Export": "Overseas",
"SEZ": "SEZ",
"Deemed Export": "Deemed Export",
}
for old, new in update_map.items():
frappe.db.sql(
"UPDATE `tab{doctype}` SET gst_category = %s where invoice_type = %s".format(doctype=doctype),
(new, old),
) # nosec
frappe.delete_doc("Custom Field", "Sales Invoice-invoice_type")
frappe.delete_doc("Custom Field", "Purchase Invoice-invoice_type")
itc_update_map = {
"ineligible": "Ineligible",
"input service": "Input Service Distributor",
"capital goods": "Import Of Capital Goods",
"input": "All Other ITC",
}
has_gst_fields = frappe.db.has_column("Purchase Invoice", "eligibility_for_itc")
if has_gst_fields:
for old, new in itc_update_map.items():
frappe.db.sql(
"UPDATE `tabPurchase Invoice` SET eligibility_for_itc = %s where eligibility_for_itc = %s ",
(new, old),
)
for doctype in ["Customer", "Supplier"]:
frappe.db.sql(
""" UPDATE `tab{doctype}` t1, `tabAddress` t2, `tabDynamic Link` t3 SET t1.gst_category = "Registered Regular"
where t3.link_name = t1.name and t3.parent = t2.name and t2.gstin IS NOT NULL and t2.gstin != '' """.format(
doctype=doctype
)
) # nosec
frappe.db.sql(
""" UPDATE `tab{doctype}` t1, `tabAddress` t2, `tabDynamic Link` t3 SET t1.gst_category = "Overseas"
where t3.link_name = t1.name and t3.parent = t2.name and t2.country != 'India' """.format(
doctype=doctype
)
) # nosec

View File

@@ -1,134 +0,0 @@
from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.regional.india.setup import add_permissions, add_print_formats
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
frappe.reload_doc("custom", "doctype", "custom_field")
frappe.reload_doc("regional", "doctype", "e_invoice_settings")
custom_fields = {
"Sales Invoice": [
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="ack_no",
label="Ack. No.",
fieldtype="Data",
read_only=1,
hidden=1,
insert_after="irn",
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_cancelled",
label="IRN Cancelled",
fieldtype="Check",
no_copy=1,
print_hide=1,
depends_on="eval:(doc.irn_cancelled === 1)",
read_only=1,
allow_on_submit=1,
insert_after="customer",
),
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="signed_einvoice",
fieldtype="Code",
options="JSON",
hidden=1,
no_copy=1,
print_hide=1,
read_only=1,
),
dict(
fieldname="signed_qr_code",
fieldtype="Code",
options="JSON",
hidden=1,
no_copy=1,
print_hide=1,
read_only=1,
),
dict(
fieldname="qrcode_image",
label="QRCode",
fieldtype="Attach Image",
hidden=1,
no_copy=1,
print_hide=1,
read_only=1,
),
]
}
create_custom_fields(custom_fields, update=True)
add_permissions()
add_print_formats()
einvoice_cond = (
'in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category)'
)
t = {
"mode_of_transport": [{"default": None}],
"distance": [{"mandatory_depends_on": f"eval:{einvoice_cond} && doc.transporter"}],
"gst_vehicle_type": [
{"mandatory_depends_on": f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}
],
"lr_date": [
{
"mandatory_depends_on": f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'
}
],
"lr_no": [
{
"mandatory_depends_on": f'eval:{einvoice_cond} && in_list(["Air", "Ship", "Rail"], doc.mode_of_transport)'
}
],
"vehicle_no": [
{"mandatory_depends_on": f'eval:{einvoice_cond} && doc.mode_of_transport == "Road"'}
],
"ewaybill": [
{"read_only_depends_on": "eval:doc.irn && doc.ewaybill"},
{"depends_on": "eval:((doc.docstatus === 1 || doc.ewaybill) && doc.eway_bill_cancelled === 0)"},
],
}
for field, conditions in t.items():
for c in conditions:
[(prop, value)] = c.items()
frappe.db.set_value("Custom Field", {"fieldname": field}, prop, value)

View File

@@ -1,16 +0,0 @@
from __future__ import unicode_literals
import frappe
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
irn_cancelled_field = frappe.db.exists(
"Custom Field", {"dt": "Sales Invoice", "fieldname": "irn_cancelled"}
)
if irn_cancelled_field:
frappe.db.set_value("Custom Field", irn_cancelled_field, "depends_on", "eval: doc.irn")
frappe.db.set_value("Custom Field", irn_cancelled_field, "read_only", 0)

View File

@@ -1,14 +0,0 @@
# Copyright (c) 2020, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
from erpnext.regional.address_template.setup import set_up_address_templates
def execute():
if frappe.db.get_value("Company", {"country": "India"}, "name"):
address_template = frappe.db.get_value("Address Template", "India", "template")
if not address_template or "gstin" not in address_template:
set_up_address_templates(default_country="India")

View File

@@ -1,29 +0,0 @@
import frappe
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
field = frappe.db.get_value("Custom Field", {"dt": "Sales Invoice", "fieldname": "ewaybill"})
if field:
ewaybill_field = frappe.get_doc("Custom Field", field)
ewaybill_field.flags.ignore_validate = True
ewaybill_field.update(
{
"fieldname": "ewaybill",
"label": "e-Way Bill No.",
"fieldtype": "Data",
"depends_on": "eval:(doc.docstatus === 1)",
"allow_on_submit": 1,
"insert_after": "tax_id",
"translatable": 0,
}
)
ewaybill_field.save()

View File

@@ -1,23 +0,0 @@
import frappe
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
frappe.db.sql(
""" UPDATE `tabSales Invoice` set gst_category = 'Unregistered'
where gst_category = 'Registered Regular'
and ifnull(customer_gstin, '')=''
and ifnull(billing_address_gstin,'')=''
"""
)
frappe.db.sql(
""" UPDATE `tabPurchase Invoice` set gst_category = 'Unregistered'
where gst_category = 'Registered Regular'
and ifnull(supplier_gstin, '')=''
"""
)

View File

@@ -1,26 +0,0 @@
import frappe
from erpnext.regional.india import states
def execute():
company = frappe.get_all("Company", filters={"country": "India"})
if not company:
return
# Update options in gst_state custom field
gst_state = frappe.get_doc("Custom Field", "Address-gst_state")
gst_state.options = "\n".join(states)
gst_state.save()
# Update gst_state and state code in existing address
frappe.db.sql(
"""
UPDATE `tabAddress`
SET
gst_state = 'Dadra and Nagar Haveli and Daman and Diu',
gst_state_number = 26
WHERE gst_state = 'Daman and Diu'
"""
)