Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Extended E-Way Bill Support for Stock Entry #2594

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
30 changes: 24 additions & 6 deletions india_compliance/gst_india/client_scripts/e_waybill_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,29 @@ function get_sub_suppy_type_options(frm) {
sub_supply_type = ["Job Work", "SKD/CKD", "Others"];
}
}
} else if (frm.doctype === "Stock Entry") {
document_type = "Delivery Challan";

if (frm.doc.purpose === "Send to Subcontractor") {
supply_type = "Outward";
sub_supply_type = ["Job Work"];
} else if (["Material Transfer", "Material Issue"].includes(frm.doc.purpose)) {
const same_gstin = frm.doc.bill_from_gstin === frm.doc.bill_to_gstin;

if (frm.doc.is_return) {
supply_type = "Inward";
sub_supply_type = ["Job Work Returns"];
} else if (same_gstin) {
supply_type = "Outward";
sub_supply_type = [
"For Own Use",
"Exhibition or Fairs",
"Line Sales",
"Recipient Not Known",
"Others",
];
}
}
} else {
const key = `${frm.doctype}_${frm.doc.is_return || 0}`;
const default_supply_types = {
Expand Down Expand Up @@ -570,11 +593,6 @@ function get_sub_suppy_type_options(frm) {
sub_supply_desc: "Purchase Return",
document_type: "Delivery Challan",
},
"Stock Entry_0": {
supply_type: "Outward",
sub_supply_type: ["Job Work"],
document_type: "Delivery Challan",
},
"Subcontracting Receipt_0": {
supply_type: "Inward",
sub_supply_type: ["Job Work Returns"],
Expand All @@ -587,7 +605,7 @@ function get_sub_suppy_type_options(frm) {
},
};

return default_supply_types[key]
return default_supply_types[key];
}

return { supply_type, sub_supply_type, sub_supply_desc, document_type };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ class StockEntryEwaybill extends EwaybillApplicability {
if (
!gst_settings.enable_e_waybill ||
!gst_settings.enable_e_waybill_for_sc ||
this.frm.doc.purpose !== "Send to Subcontractor"
!["Material Transfer", "Material Issue", "Send to Subcontractor"].includes(
this.frm.doc.purpose
)
)
return false;

Expand Down Expand Up @@ -282,17 +284,32 @@ class StockEntryEwaybill extends EwaybillApplicability {
let is_ewb_generatable = this.is_e_waybill_applicable(show_message);

let message_list = [];
const same_gstin = this.frm.doc.bill_from_gstin === this.frm.doc.bill_to_gstin;

if (!this.frm.doc.bill_to_address) {
is_ewb_generatable = false;
message_list.push("Bill To address is mandatory to generate e-Waybill.");
}

if (this.frm.doc.bill_from_gstin === this.frm.doc.bill_to_gstin) {
if (
(this.frm.doc.purpose === "Send to Subcontractor" ||
(this.frm.doc.purpose === "Material Transfer" &&
this.frm.doc.is_return)) &&
same_gstin
) {
is_ewb_generatable = false;
message_list.push("Bill From GSTIN and Bill To GSTIN are same.");
}

if (
["Material Transfer", "Material Issue"].includes(this.frm.doc.purpose) &&
!this.frm.doc.is_return &&
!same_gstin
) {
is_ewb_generatable = false;
message_list.push("Bill From GSTIN and Bill To GSTIN are different.");
}

if (show_message) {
this.frm._ewb_message += message_list
.map(message => `<li>${message}</li>`)
Expand All @@ -304,7 +321,9 @@ class StockEntryEwaybill extends EwaybillApplicability {

is_e_waybill_api_enabled() {
return (
this.frm.doc.purpose == "Send to Subcontractor" &&
["Material Transfer", "Material Issue", "Send to Subcontractor"].includes(
this.frm.doc.purpose
) &&
super.is_e_waybill_api_enabled() &&
gst_settings.enable_e_waybill_for_sc
);
Expand Down
37 changes: 32 additions & 5 deletions india_compliance/gst_india/client_scripts/stock_entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ frappe.ui.form.on(DOCTYPE, {
filters: get_filters_for_relevant_stock_entries(doc),
};
});

// No event trigger are called when form is new
if (frm.is_new()) {
frm.trigger("bill_to_address");
}
},

onload(frm) {
Expand All @@ -44,8 +49,7 @@ frappe.ui.form.on(DOCTYPE, {
on_change_set_address(
frm,
"supplier_address",
"bill_to_address",
__("Bill To (same as Supplier Address)"),
...get_field_and_label(frm, "party_field"),
__("Bill To")
);
},
Expand All @@ -72,8 +76,7 @@ frappe.ui.form.on(DOCTYPE, {
on_change_set_address(
frm,
"supplier_address",
"bill_to_address",
__("Bill To (same as Supplier Address)"),
...get_field_and_label(frm, "party_field"),
__("Bill To")
);
},
Expand Down Expand Up @@ -107,7 +110,10 @@ frappe.ui.form.on(DOCTYPE, {
name: frm.doc.company,
},
callback(r) {
frm.set_value("bill_from_address", r.message);
frm.set_value(
get_field_and_label(frm, "company_field")[0],
r.message
);
},
});
}
Expand Down Expand Up @@ -190,3 +196,24 @@ function get_filters_for_relevant_stock_entries(doc) {
function get_items(doc) {
return Array.from(new Set(doc.items.map(row => row.item_code)));
}

function get_field_and_label(frm, field) {
let field_label_dict = {};

if (frm.doc.purpose === "Material Transfer" && frm.doc.is_return) {
field_label_dict = {
party_field: [
"bill_from_address",
__("Bill From (same as Supplier Address)"),
],
company_field: ["bill_to_address", __("Bill To")],
};
} else {
field_label_dict = {
party_field: ["bill_to_address", __("Bill To (same as Supplier Address)")],
company_field: ["bill_from_address", __("Bill From")],
};
}

return field_label_dict[field];
}
4 changes: 2 additions & 2 deletions india_compliance/gst_india/constants/custom_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,14 @@
"label": "Taxes",
"fieldtype": "Section Break",
"insert_after": "get_stock_and_rate",
"depends_on": "eval:doc.subcontracting_order",
"depends_on": "eval:((doc.purpose == 'Send to Subcontractor' && doc.subcontracting_order) || (in_list(['Material Transfer', 'Material Issue'], doc.purpose)))",
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
},
{
"label": "E-Waybill Info",
"fieldname": "tab_break_ewaybill",
"fieldtype": "Tab Break",
"insert_after": "address_display",
"depends_on": "eval:doc.purpose === 'Send to Subcontractor'",
"depends_on": "eval:((doc.purpose == 'Send to Subcontractor' && doc.subcontracting_order) || (in_list(['Material Transfer', 'Material Issue'], doc.purpose)))",
},
{
"label": "e-Waybill Address",
Expand Down
32 changes: 27 additions & 5 deletions india_compliance/gst_india/overrides/subcontracting_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,18 @@ def after_mapping_subcontracting_order(doc, method, source_doc):


def after_mapping_stock_entry(doc, method, source_doc):
if source_doc.doctype == "Subcontracting Order":
if not source_doc.doctype == "Subcontracting Order":
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
doc.taxes_and_charges = ""
doc.taxes = []

if not doc.purpose == "Material Transfer" or not doc.is_return:
Copy link
Contributor Author

@Ninad1306 Ninad1306 Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work standalone, as some fields in erpnext has to be updated in postprocess to correctly evaluate the conditions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference PR in ERPNext: frappe/erpnext#43061

return

doc.taxes_and_charges = ""
doc.taxes = []
doc.bill_to_address = source_doc.billing_address
doc.bill_from_address = source_doc.supplier_address
doc.bill_to_gstin = source_doc.company_gstin
doc.bill_from_gstin = source_doc.supplier_gstin
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
set_address_display(doc)


def before_mapping_subcontracting_receipt(doc, method, source_doc, table_maps):
Expand Down Expand Up @@ -165,7 +172,7 @@ def onload(doc, method=None):


def validate(doc, method=None):
if ignore_gst_validation_for_subcontracting(doc):
if ignore_based_on_purpose(doc):
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
return

field_map = (
Expand Down Expand Up @@ -287,6 +294,12 @@ def validate(self, doc, is_sales_transaction=False):
self.validate_for_charge_type()

def validate_for_same_party_gstin(self):
if (
self.doc.doctype == "Stock Entry"
and self.doc.purpose != "Send to Subcontractor"
):
return

company_gstin = self.doc.get("company_gstin") or self.doc.bill_from_gstin
party_gstin = self.doc.get("supplier_gstin") or self.doc.bill_to_gstin

Expand Down Expand Up @@ -330,7 +343,6 @@ def set_address_display(doc):
def get_relevant_references(
supplier, supplied_items, received_items, subcontracting_orders
):

if isinstance(supplied_items, str):
supplied_items = frappe.parse_json(supplied_items)
received_items = frappe.parse_json(received_items)
Expand Down Expand Up @@ -390,3 +402,13 @@ def remove_duplicates(doc):
doc.doc_references = []
for row in references:
doc.append("doc_references", dict(link_doctype=row[0], link_name=row[1]))


def ignore_based_on_purpose(doc):
if doc.doctype == "Stock Entry" and (
Ninad1306 marked this conversation as resolved.
Show resolved Hide resolved
not doc.subcontracting_order
and (doc.purpose not in ["Material Transfer", "Material Issue"])
):
return True

return ignore_gst_validations(doc)
44 changes: 30 additions & 14 deletions india_compliance/gst_india/overrides/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ def set_gst_breakup(doc):


def update_taxable_values(doc):

if doc.doctype not in DOCTYPES_WITH_GST_DETAIL:
return

Expand Down Expand Up @@ -785,9 +784,15 @@ def update_party_details(party_details, doctype, company):
def get_party_details_for_subcontracting(party_details, doctype, company):
party_details = frappe.parse_json(party_details)

party_address_field = (
"supplier_address" if doctype != "Stock Entry" else "bill_to_address"
)
if doctype == "Stock Entry":
party_address_field = (
"bill_from_address"
if party_details.get("is_inward_material_transfer")
else "bill_to_address"
)
else:
party_address_field = "supplier_address"

party_details[party_address_field] = get_default_address(
"Supplier", party_details.supplier
)
Expand Down Expand Up @@ -817,11 +822,14 @@ def get_gst_details(party_details, doctype, company, *, update_place_of_supply=F
- tax template
- taxes in the tax template
"""

is_sales_transaction = doctype in SALES_DOCTYPES or doctype == "Payment Entry"
party_details = frappe.parse_json(party_details)
gst_details = frappe._dict()

allow_same_gstin = False
if party_details.get("is_outward_material_transfer_or_issue"):
allow_same_gstin = True

# Party/Address Defaults
if is_sales_transaction:
company_gstin_field = "company_gstin"
Expand All @@ -830,10 +838,16 @@ def get_gst_details(party_details, doctype, company, *, update_place_of_supply=F
gst_category_field = "gst_category"

elif doctype == "Stock Entry":
company_gstin_field = "bill_from_gstin"
party_gstin_field = "bill_to_gstin"
party_address_field = "bill_to_address"
gst_category_field = "bill_to_gst_category"
if party_details.get("is_inward_material_transfer"):
company_gstin_field = "bill_to_gstin"
party_gstin_field = "bill_from_gstin"
party_address_field = "bill_from_address"
gst_category_field = "bill_from_gst_category"
else:
company_gstin_field = "bill_from_gstin"
party_gstin_field = "bill_to_gstin"
party_address_field = "bill_to_address"
gst_category_field = "bill_to_gst_category"

else:
company_gstin_field = "company_gstin"
Expand Down Expand Up @@ -877,10 +891,13 @@ def get_gst_details(party_details, doctype, company, *, update_place_of_supply=F
# Taxes Not Applicable
if (
(
party_details.get(company_gstin_field)
and party_details.get(company_gstin_field)
== party_details.get(party_gstin_field)
) # Internal transfer
not allow_same_gstin
and (
party_details.get(company_gstin_field)
and party_details.get(company_gstin_field)
== party_details.get(party_gstin_field)
) # Internal transfer
)
or (is_sales_transaction and is_export_without_payment_of_gst(party_details))
or (
not is_sales_transaction
Expand Down Expand Up @@ -1522,7 +1539,6 @@ def before_print(doc, method=None, print_settings=None):


def onload(doc, method=None):

if ignore_gst_validations(doc) or not doc.place_of_supply or not doc.company_gstin:
return

Expand Down
13 changes: 11 additions & 2 deletions india_compliance/gst_india/utils/e_waybill.py
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,6 @@ def get_extend_validity_data(self, values):
return extension_details

def validate_transaction(self):

super().validate_transaction()

if self.doc.ewaybill:
Expand Down Expand Up @@ -1264,7 +1263,10 @@ def validate_applicability(self):
self.validate_same_gstin()

def validate_same_gstin(self):
if self.doc.doctype == "Delivery Note":
if self.doc.doctype == "Delivery Note" or (
self.doc.get("purpose") in ["Material Transfer", "Material Issue"]
and not self.doc.is_return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibility to use subcontracting order field

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subcontracting order is not a mandatory field in Stock Entry and also is not mandatory for e-Waybill Generation.
So using it may not be a differentiating factor.

):
return

party_gstin_fieldname = (
Expand Down Expand Up @@ -1488,6 +1490,11 @@ def update_transaction_details(self):
"sub_supply_type": doc.get("_sub_supply_type", ""),
"document_type": "CHL",
},
("Stock Entry", 1): {
"supply_type": "I",
"sub_supply_type": doc.get("_sub_supply_type", ""),
"document_type": "CHL",
},
("Subcontracting Receipt", 0): {
"supply_type": "I",
"sub_supply_type": doc.get("_sub_supply_type", ""),
Expand Down Expand Up @@ -1634,6 +1641,7 @@ def get_transaction_data(self):
("Delivery Note", 0): (REGISTERED_GSTIN, OTHER_GSTIN),
("Delivery Note", 1): (OTHER_GSTIN, REGISTERED_GSTIN),
("Stock Entry", 0): (REGISTERED_GSTIN, OTHER_GSTIN),
("Stock Entry", 1): (OTHER_GSTIN, REGISTERED_GSTIN),
("Subcontracting Receipt", 0): (OTHER_GSTIN, REGISTERED_GSTIN),
("Subcontracting Receipt", 1): (REGISTERED_GSTIN, OTHER_GSTIN),
}
Expand All @@ -1643,6 +1651,7 @@ def get_transaction_data(self):
{
("Delivery Note", 0): (REGISTERED_GSTIN, REGISTERED_GSTIN),
("Delivery Note", 1): (REGISTERED_GSTIN, REGISTERED_GSTIN),
("Stock Entry", 0): (REGISTERED_GSTIN, REGISTERED_GSTIN),
}
)

Expand Down
Loading