Merge pull request #24408 from rohitwaghchaure/custom-user-type-feat
feat: Employee Self Service
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 248cb9a..630a1dc 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -13,6 +13,8 @@
"po_required",
"pr_required",
"maintain_same_rate",
+ "maintain_same_rate_action",
+ "role_to_override_stop_action",
"allow_multiple_items",
"subcontract",
"backflush_raw_materials_of_subcontract_based_on",
@@ -89,6 +91,23 @@
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "Stop",
+ "depends_on": "maintain_same_rate",
+ "description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
+ "fieldname": "maintain_same_rate_action",
+ "fieldtype": "Select",
+ "label": "Action If Same Rate is Not Maintained",
+ "mandatory_depends_on": "maintain_same_rate",
+ "options": "Stop\nWarn"
+ },
+ {
+ "depends_on": "eval:doc.maintain_same_rate_action == 'Stop'",
+ "fieldname": "role_to_override_stop_action",
+ "fieldtype": "Link",
+ "label": "Role Allowed to Override Stop Action",
+ "options": "Role"
}
],
"icon": "fa fa-cog",
@@ -96,7 +115,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-03-02 17:34:04.190677",
+ "modified": "2021-04-04 20:01:44.087066",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 81f0ad3..c0c1315 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -325,7 +325,7 @@
and status not in ("Stopped", "Closed") %(fcond)s
and (
(`tabDelivery Note`.is_return = 0 and `tabDelivery Note`.per_billed < 100)
- or `tabDelivery Note`.grand_total = 0
+ or (`tabDelivery Note`.grand_total = 0 and `tabDelivery Note`.per_billed < 100)
or (
`tabDelivery Note`.is_return = 1
and return_against in (select name from `tabDelivery Note` where per_billed < 100)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 1ae7310..9fae494 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -291,10 +291,13 @@
# set precision in the last item iteration
if n == len(self.doc.get("items")) - 1:
self.round_off_totals(tax)
+ self._set_in_company_currency(tax,
+ ["tax_amount", "tax_amount_after_discount_amount"])
+
+ self.round_off_base_values(tax)
self.set_cumulative_total(i, tax)
- self._set_in_company_currency(tax,
- ["total", "tax_amount", "tax_amount_after_discount_amount"])
+ self._set_in_company_currency(tax, ["total"])
# adjust Discount Amount loss in last tax iteration
if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
@@ -341,20 +344,11 @@
elif tax.charge_type == "On Item Quantity":
current_tax_amount = tax_rate * item.qty
- current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
-
if not self.doc.get("is_consolidated"):
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
return current_tax_amount
- def get_final_current_tax_amount(self, tax, current_tax_amount):
- # Some countries need individual tax components to be rounded
- # Handeled via regional doctypess
- if tax.account_head in frappe.flags.round_off_applicable_accounts:
- current_tax_amount = round(current_tax_amount, 0)
- return current_tax_amount
-
def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount):
# store tax breakup for each item
key = item.item_code or item.item_name
@@ -365,10 +359,20 @@
tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount)]
def round_off_totals(self, tax):
+ if tax.account_head in frappe.flags.round_off_applicable_accounts:
+ tax.tax_amount = round(tax.tax_amount, 0)
+ tax.tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount, 0)
+
tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount"))
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount,
tax.precision("tax_amount"))
+ def round_off_base_values(self, tax):
+ # Round off to nearest integer based on regional settings
+ if tax.account_head in frappe.flags.round_off_applicable_accounts:
+ tax.base_tax_amount = round(tax.base_tax_amount, 0)
+ tax.base_tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount, 0)
+
def manipulate_grand_total_for_inclusive_tax(self):
# if fully inclusive taxes and diff
if self.doc.get("taxes") and any([cint(t.included_in_print_rate) for t in self.doc.get("taxes")]):
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 3a3ee38..2e133be 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -323,12 +323,15 @@
// set precision in the last item iteration
if (n == me.frm.doc["items"].length - 1) {
me.round_off_totals(tax);
+ me.set_in_company_currency(tax,
+ ["tax_amount", "tax_amount_after_discount_amount"]);
+
+ me.round_off_base_values(tax);
// in tax.total, accumulate grand total for each item
me.set_cumulative_total(i, tax);
- me.set_in_company_currency(tax,
- ["total", "tax_amount", "tax_amount_after_discount_amount"]);
+ me.set_in_company_currency(tax, ["total"]);
// adjust Discount Amount loss in last tax iteration
if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied
@@ -393,20 +396,11 @@
current_tax_amount = tax_rate * item.qty;
}
- current_tax_amount = this.get_final_tax_amount(tax, current_tax_amount);
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
return current_tax_amount;
},
- get_final_tax_amount: function(tax, current_tax_amount) {
- if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
- current_tax_amount = Math.round(current_tax_amount);
- }
-
- return current_tax_amount;
- },
-
set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item
let tax_detail = tax.item_wise_tax_detail;
@@ -420,10 +414,22 @@
},
round_off_totals: function(tax) {
+ if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
+ tax.tax_amount= Math.round(tax.tax_amount);
+ tax.tax_amount_after_discount_amount = Math.round(tax.tax_amount_after_discount_amount);
+ }
+
tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, precision("tax_amount", tax));
},
+ round_off_base_values: function(tax) {
+ if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
+ tax.base_tax_amount= Math.round(tax.base_tax_amount);
+ tax.base_tax_amount_after_discount_amount = Math.round(tax.base_tax_amount_after_discount_amount);
+ }
+ },
+
manipulate_grand_total_for_inclusive_tax: function() {
var me = this;
// if fully inclusive taxes and diff
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index 2104c01..f01934b 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -18,6 +18,8 @@
"dn_required",
"sales_update_frequency",
"maintain_same_sales_rate",
+ "maintain_same_rate_action",
+ "role_to_override_stop_action",
"editable_price_list_rate",
"allow_multiple_items",
"allow_against_multiple_purchase_orders",
@@ -133,6 +135,23 @@
"fieldname": "hide_tax_id",
"fieldtype": "Check",
"label": "Hide Customer's Tax ID from Sales Transactions"
+ },
+ {
+ "default": "Stop",
+ "depends_on": "maintain_same_sales_rate",
+ "description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
+ "fieldname": "maintain_same_rate_action",
+ "fieldtype": "Select",
+ "label": "Action If Same Rate is Not Maintained",
+ "mandatory_depends_on": "maintain_same_sales_rate",
+ "options": "Stop\nWarn"
+ },
+ {
+ "depends_on": "eval: doc.maintain_same_rate_action == 'Stop'",
+ "fieldname": "role_to_override_stop_action",
+ "fieldtype": "Link",
+ "label": "Role Allowed to Override Stop Action",
+ "options": "Role"
}
],
"icon": "fa fa-cog",
@@ -140,7 +159,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-03-02 17:35:53.603607",
+ "modified": "2021-04-04 20:18:12.814624",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index b575855..f99da58 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -120,11 +120,11 @@
buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
if self.doctype in buying_doctypes:
- to_disable = "Maintain same rate throughout Purchase cycle"
- settings_page = "Buying Settings"
+ action = frappe.db.get_single_value("Buying Settings", "maintain_same_rate_action")
+ settings_doc = "Buying Settings"
else:
- to_disable = "Maintain same rate throughout Sales cycle"
- settings_page = "Selling Settings"
+ action = frappe.db.get_single_value("Selling Settings", "maintain_same_rate_action")
+ settings_doc = "Selling Settings"
for ref_dt, ref_dn_field, ref_link_field in ref_details:
for d in self.get("items"):
@@ -132,11 +132,16 @@
ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
- frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
- .format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
- frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.")
- .format(frappe.bold(_(to_disable)),
- get_link_to_form(settings_page, settings_page, frappe.bold(settings_page))))
+ if action == "Stop":
+ role_allowed_to_override = frappe.db.get_single_value(settings_doc, 'role_to_override_stop_action')
+
+ if role_allowed_to_override not in frappe.get_roles():
+ frappe.throw(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
+ d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
+ else:
+ frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
+ d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate), title=_("Warning"), indicator="orange")
+
def get_link_filters(self, for_doctype):
if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype):