Merge pull request #23808 from nabinhait/web-page-bank-statement-section-pre-release
fix: Added link of bank reconciliation and clearance in accounting desk page
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 61c48c7..0f115f9 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -158,8 +158,11 @@
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
+ month = now_datetime().month
+ if month > 10:
+ month = 10
- for i in range(now_datetime().month):
+ for i in range(month):
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
@@ -177,8 +180,11 @@
set_total_expense_zero(nowdate(), "project")
budget = make_budget(budget_against="Project")
+ month = now_datetime().month
+ if month > 10:
+ month = 10
- for i in range(now_datetime().month):
+ for i in range(month):
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index c681c89..cc8ed4b 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -504,10 +504,10 @@
},
{
"default": "0",
- "depends_on": "eval:in_list(['Discount Percentage', 'Discount Amount'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
+ "depends_on": "eval:in_list(['Discount Percentage'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
"fieldname": "apply_discount_on_rate",
"fieldtype": "Check",
- "label": "Apply Discount on Rate"
+ "label": "Apply Discount on Discounted Rate"
},
{
"default": "0",
@@ -563,7 +563,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
- "modified": "2020-08-26 12:24:44.740734",
+ "modified": "2020-10-28 16:53:14.416172",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 454776e..149c476 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -60,6 +60,15 @@
if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
+ if self.apply_discount_on_rate:
+ if not self.priority:
+ throw(_("As the field {0} is enabled, the field {1} is mandatory.")
+ .format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")))
+
+ if self.priority and cint(self.priority) == 1:
+ throw(_("As the field {0} is enabled, the value of the field {1} should be more than 1.")
+ .format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")))
+
def validate_applicable_for_selling_or_buying(self):
if not self.selling and not self.buying:
throw(_("Atleast one of the Selling or Buying must be selected"))
@@ -226,12 +235,11 @@
item_details = frappe._dict({
"doctype": args.doctype,
+ "has_margin": False,
"name": args.name,
"parent": args.parent,
"parenttype": args.parenttype,
- "child_docname": args.get('child_docname'),
- "discount_percentage_on_rate": [],
- "discount_amount_on_rate": []
+ "child_docname": args.get('child_docname')
})
if args.ignore_pricing_rule or not args.item_code:
@@ -279,6 +287,10 @@
else:
get_product_discount_rule(pricing_rule, item_details, args, doc)
+ if not item_details.get("has_margin"):
+ item_details.margin_type = None
+ item_details.margin_rate_or_amount = 0.0
+
item_details.has_pricing_rule = 1
item_details.pricing_rules = frappe.as_json([d.pricing_rule for d in rules])
@@ -330,13 +342,11 @@
def apply_price_discount_rule(pricing_rule, item_details, args):
item_details.pricing_rule_for = pricing_rule.rate_or_discount
- if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
+ if ((pricing_rule.margin_type in ['Amount', 'Percentage'] and pricing_rule.currency == args.currency)
or (pricing_rule.margin_type == 'Percentage')):
item_details.margin_type = pricing_rule.margin_type
item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
- else:
- item_details.margin_type = None
- item_details.margin_rate_or_amount = 0.0
+ item_details.has_margin = True
if pricing_rule.rate_or_discount == 'Rate':
pricing_rule_rate = 0.0
@@ -351,9 +361,9 @@
if pricing_rule.rate_or_discount != apply_on: continue
field = frappe.scrub(apply_on)
- if pricing_rule.apply_discount_on_rate:
- discount_field = "{0}_on_rate".format(field)
- item_details[discount_field].append(pricing_rule.get(field, 0))
+ if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"):
+ # Apply discount on discounted rate
+ item_details[field] += ((100 - item_details[field]) * (pricing_rule.get(field, 0) / 100))
else:
if field not in item_details:
item_details.setdefault(field, 0)
@@ -361,14 +371,6 @@
item_details[field] += (pricing_rule.get(field, 0)
if pricing_rule else args.get(field, 0))
-def set_discount_amount(rate, item_details):
- for field in ['discount_percentage_on_rate', 'discount_amount_on_rate']:
- for d in item_details.get(field):
- dis_amount = (rate * d / 100
- if field == 'discount_percentage_on_rate' else d)
- rate -= dis_amount
- item_details.rate = rate
-
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
from erpnext.accounts.doctype.pricing_rule.utils import (get_applied_pricing_rules,
get_pricing_rule_items)
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 3555ca8..22a031c 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -385,7 +385,7 @@
so.load_from_db()
self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item 2")
-
+
def test_cumulative_pricing_rule(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Cumulative Pricing Rule')
test_record = {
@@ -429,34 +429,61 @@
details = get_item_details(args)
self.assertTrue(details)
-
+
def test_pricing_rule_for_condition(self):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
-
+
make_pricing_rule(selling=1, margin_type="Percentage", \
condition="customer=='_Test Customer 1' and is_return==0", discount_percentage=10)
-
+
# Incorrect Customer and Correct is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 2", is_return=0)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
self.assertEquals(item.rate, 100)
-
+
# Correct Customer and Incorrect is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
self.assertEquals(item.rate, 100)
-
+
# Correct Customer and correct is_return value
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
si.items[0].price_list_rate = 1000
si.submit()
item = si.items[0]
self.assertEquals(item.rate, 900)
-
+
+ def test_multiple_pricing_rules(self):
+ make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
+ title="_Test Pricing Rule 1")
+ make_pricing_rule(discount_percentage=10, selling=1, title="_Test Pricing Rule 2", priority=2,
+ apply_multiple_pricing_rules=1)
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
+ self.assertEqual(si.items[0].discount_percentage, 30)
+ si.delete()
+
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
+
+ def test_multiple_pricing_rules_with_apply_discount_on_discounted_rate(self):
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
+
+ make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
+ title="_Test Pricing Rule 1")
+ make_pricing_rule(discount_percentage=10, selling=1, priority=2,
+ apply_discount_on_rate=1, title="_Test Pricing Rule 2", apply_multiple_pricing_rules=1)
+
+ si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
+ self.assertEqual(si.items[0].discount_percentage, 28)
+ si.delete()
+
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
+ frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
+
def make_pricing_rule(**args):
args = frappe._dict(args)
@@ -468,6 +495,7 @@
"applicable_for": args.applicable_for,
"selling": args.selling or 0,
"currency": "USD",
+ "apply_discount_on_rate": args.apply_discount_on_rate or 0,
"buying": args.buying or 0,
"min_qty": args.min_qty or 0.0,
"max_qty": args.max_qty or 0.0,
@@ -476,9 +504,13 @@
"rate": args.rate or 0.0,
"margin_type": args.margin_type,
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
- "condition": args.condition or ''
+ "condition": args.condition or '',
+ "apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
})
+ if args.get("priority"):
+ doc.priority = args.get("priority")
+
apply_on = doc.apply_on.replace(' ', '_').lower()
child_table = {'Item Code': 'items', 'Item Group': 'item_groups', 'Brand': 'brands'}
doc.append(child_table.get(doc.apply_on), {
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 25840d4..b003328 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -14,9 +14,8 @@
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
from erpnext.stock.get_item_details import get_conversion_factor
-from frappe import _, throw
-from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
-
+from frappe import _, bold
+from frappe.utils import cint, flt, get_link_to_form, getdate, today, fmt_money
class MultiplePricingRuleConflict(frappe.ValidationError): pass
@@ -42,6 +41,7 @@
if not pricing_rules: return []
if apply_multiple_pricing_rules(pricing_rules):
+ pricing_rules = sorted_by_priority(pricing_rules)
for pricing_rule in pricing_rules:
pricing_rule = filter_pricing_rules(args, pricing_rule, doc)
if pricing_rule:
@@ -53,6 +53,20 @@
return rules
+def sorted_by_priority(pricing_rules):
+ # If more than one pricing rules, then sort by priority
+ pricing_rules_list = []
+ pricing_rule_dict = {}
+ for pricing_rule in pricing_rules:
+ if not pricing_rule.get("priority"): continue
+
+ pricing_rule_dict.setdefault(cint(pricing_rule.get("priority")), []).append(pricing_rule)
+
+ for key in sorted(pricing_rule_dict):
+ pricing_rules_list.append(pricing_rule_dict.get(key))
+
+ return pricing_rules_list or pricing_rules
+
def filter_pricing_rule_based_on_condition(pricing_rules, doc=None):
filtered_pricing_rules = []
if doc:
@@ -284,12 +298,13 @@
fieldname = field
if fieldname:
- msg = _("""If you {0} {1} quantities of the item <b>{2}</b>, the scheme <b>{3}</b>
- will be applied on the item.""").format(type_of_transaction, args.get(fieldname), item_code, args.rule_description)
+ msg = (_("If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.")
+ .format(type_of_transaction, args.get(fieldname), bold(item_code), bold(args.rule_description)))
if fieldname in ['min_amt', 'max_amt']:
- msg = _("""If you {0} {1} worth item <b>{2}</b>, the scheme <b>{3}</b> will be applied on the item.
- """).format(frappe.fmt_money(type_of_transaction, args.get(fieldname)), item_code, args.rule_description)
+ msg = (_("If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.")
+ .format(type_of_transaction, fmt_money(args.get(fieldname), currency=args.get("currency")),
+ bold(item_code), bold(args.rule_description)))
frappe.msgprint(msg)
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js
index 7425132..6dc4643 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js
@@ -92,7 +92,7 @@
frm.refresh_field('customers');
}
else{
- frappe.msgprint('No Customers found with selected options.');
+ frappe.throw('No Customers found with selected options.');
}
}
}
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index d50e4a8..43fbb06 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -126,9 +126,11 @@
sales_person_records = frappe._dict()
for d in records:
sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
- customers = frappe.get_list('Customer', fields=['name', 'email_id'], \
+ if sales_person_records.get('Customer'):
+ return frappe.get_list('Customer', fields=['name', 'email_id'], \
filters=[['name', 'in', list(sales_person_records['Customer'])]])
- return customers
+ else:
+ return []
def get_recipients_and_cc(customer, doc):
recipients = []
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
index d422876..d9b7b69 100644
--- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -50,13 +50,11 @@
"reqd": 1
},
{
- "depends_on": "eval:parent.doctype == 'Asset'",
"fieldname": "depreciation_start_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Depreciation Posting Date",
- "mandatory_depends_on": "eval:parent.doctype == 'Asset'",
- "reqd": 1
+ "mandatory_depends_on": "eval:parent.doctype == 'Asset'"
},
{
"default": "0",
@@ -87,7 +85,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-10-30 15:22:29.119868",
+ "modified": "2020-11-05 16:30:09.213479",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index f56c9b4..cf30e30 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -304,7 +304,7 @@
{
"fieldtype": "Select", "label": __("Get Suppliers By"),
"fieldname": "search_type",
- "options": ["Tag","Supplier Group"],
+ "options": ["Supplier Group", "Tag"],
"reqd": 1,
onchange() {
if(dialog.get_value('search_type') == 'Tag'){
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
index 4e09a7e..3af6cf8 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
@@ -21,9 +21,9 @@
"link_to_mrs",
"supplier_response_section",
"salutation",
- "email_template",
- "col_break_email_1",
"subject",
+ "col_break_email_1",
+ "email_template",
"preview",
"sec_break_email_2",
"message_for_supplier",
@@ -260,7 +260,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-10-16 17:49:09.561929",
+ "modified": "2020-11-04 22:04:29.017134",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation",
diff --git a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json
index 96d7e2d..534cd90 100644
--- a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json
+++ b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json
@@ -5,14 +5,14 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "send_email",
- "email_sent",
"supplier",
"contact",
"quote_status",
"column_break_3",
"supplier_name",
- "email_id"
+ "email_id",
+ "send_email",
+ "email_sent"
],
"fields": [
{
@@ -87,7 +87,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-10-16 12:23:41.769820",
+ "modified": "2020-11-04 22:01:43.832942",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation Supplier",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 983cfa8..6108a61 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -263,6 +263,7 @@
if self.doctype == "Quotation" and self.quotation_to == "Customer" and parent_dict.get("party_name"):
parent_dict.update({"customer": parent_dict.get("party_name")})
+ self.pricing_rules = []
for item in self.get("items"):
if item.get("item_code"):
args = parent_dict.copy()
@@ -301,6 +302,7 @@
if ret.get("pricing_rules"):
self.apply_pricing_rule_on_items(item, ret)
+ self.set_pricing_rule_details(item, ret)
if self.doctype == "Purchase Invoice":
self.set_expense_account(for_validate)
@@ -322,6 +324,9 @@
if item.get('discount_amount'):
item.rate = item.price_list_rate - item.discount_amount
+ if item.get("apply_discount_on_discounted_rate") and pricing_rule_args.get("rate"):
+ item.rate = pricing_rule_args.get("rate")
+
elif pricing_rule_args.get('free_item_data'):
apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data'))
@@ -335,6 +340,18 @@
frappe.msgprint(_("Row {0}: user has not applied the rule {1} on the item {2}")
.format(item.idx, frappe.bold(title), frappe.bold(item.item_code)))
+ def set_pricing_rule_details(self, item_row, args):
+ pricing_rules = get_applied_pricing_rules(args.get("pricing_rules"))
+ if not pricing_rules: return
+
+ for pricing_rule in pricing_rules:
+ self.append("pricing_rules", {
+ "pricing_rule": pricing_rule,
+ "item_code": item_row.item_code,
+ "child_docname": item_row.name,
+ "rule_applied": True
+ })
+
def set_taxes(self):
if not self.meta.get_field("taxes"):
return
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 92cfdb7..81d07c1 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -608,16 +608,19 @@
base_rate_with_margin = 0.0
if item.price_list_rate:
if item.pricing_rules and not self.doc.ignore_pricing_rule:
+ has_margin = False
for d in get_applied_pricing_rules(item.pricing_rules):
pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
- if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\
+ if (pricing_rule.margin_type in ['Amount', 'Percentage'] and pricing_rule.currency == self.doc.currency)\
or (pricing_rule.margin_type == 'Percentage'):
item.margin_type = pricing_rule.margin_type
item.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
- else:
- item.margin_type = None
- item.margin_rate_or_amount = 0.0
+ has_margin = True
+
+ if not has_margin:
+ item.margin_type = None
+ item.margin_rate_or_amount = 0.0
if item.margin_type and item.margin_rate_or_amount:
margin_value = item.margin_rate_or_amount if item.margin_type == 'Amount' else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
diff --git a/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json b/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json
index 8dcc77d..ea3b129 100644
--- a/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json
+++ b/erpnext/erpnext_integrations/desk_page/erpnext_integrations/erpnext_integrations.json
@@ -8,7 +8,7 @@
{
"hidden": 0,
"label": "Payments",
- "links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }\n]"
+ "links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }, {\n \"description\": \"M-Pesa payment gateway settings\",\n \"label\": \"M-Pesa Settings\",\n \"name\": \"Mpesa Settings\",\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
@@ -29,7 +29,7 @@
"idx": 0,
"is_standard": 1,
"label": "ERPNext Integrations",
- "modified": "2020-08-23 16:30:51.494655",
+ "modified": "2020-10-29 19:54:46.228222",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "ERPNext Integrations",
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js
index 636aa99..45d2986 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js
@@ -13,7 +13,7 @@
},
get_account_balance: function(frm) {
- if (!frm.initiator_name && !frm.security_credentials) {
+ if (!frm.doc.initiator_name && !frm.doc.security_credential) {
frappe.throw(__("Please set the initiator name and the security credential"));
}
frappe.call({
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
index dea4d81..1cad84d 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py
@@ -147,7 +147,7 @@
return response
except Exception:
frappe.log_error(title=_("Account Balance Processing Error"))
- frappe.throw(title=_("Error"), message=_("Please check your configuration and try again"))
+ frappe.throw(_("Please check your configuration and try again"), title=_("Error"))
@frappe.whitelist(allow_guest=True)
def process_balance_info(**kwargs):
@@ -173,7 +173,8 @@
ref_doc.db_set("account_balance", balance_info)
request.handle_success(account_balance_response)
- frappe.publish_realtime("refresh_mpesa_dashboard")
+ frappe.publish_realtime("refresh_mpesa_dashboard", doctype="Mpesa Settings",
+ docname=transaction_data.reference_docname, user=transaction_data.owner)
except Exception:
request.handle_failure(account_balance_response)
frappe.log_error(title=_("Mpesa Account Balance Processing Error"), message=account_balance_response)
diff --git a/erpnext/healthcare/doctype/exercise/exercise.json b/erpnext/healthcare/doctype/exercise/exercise.json
index 2486a5d..683cc6d 100644
--- a/erpnext/healthcare/doctype/exercise/exercise.json
+++ b/erpnext/healthcare/doctype/exercise/exercise.json
@@ -37,7 +37,8 @@
"depends_on": "eval:doc.parenttype==\"Therapy\";",
"fieldname": "counts_completed",
"fieldtype": "Int",
- "label": "Counts Completed"
+ "label": "Counts Completed",
+ "no_copy": 1
},
{
"fieldname": "assistance_level",
@@ -48,7 +49,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-04-10 13:41:06.662351",
+ "modified": "2020-11-04 18:20:25.583491",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Exercise",
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
index 490d458..d1f72d6 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
@@ -13,43 +13,42 @@
refresh: function(frm) {
if (!frm.doc.__islocal) {
frm.trigger('show_progress_for_therapies');
- }
-
- if (!frm.doc.__islocal && frm.doc.status != 'Completed') {
- let therapy_types = (frm.doc.therapy_plan_details || []).map(function(d){ return d.therapy_type });
- const fields = [{
- fieldtype: 'Link',
- label: __('Therapy Type'),
- fieldname: 'therapy_type',
- options: 'Therapy Type',
- reqd: 1,
- get_query: function() {
- return {
- filters: { 'therapy_type': ['in', therapy_types]}
+ if (frm.doc.status != 'Completed') {
+ let therapy_types = (frm.doc.therapy_plan_details || []).map(function(d){ return d.therapy_type; });
+ const fields = [{
+ fieldtype: 'Link',
+ label: __('Therapy Type'),
+ fieldname: 'therapy_type',
+ options: 'Therapy Type',
+ reqd: 1,
+ get_query: function() {
+ return {
+ filters: { 'therapy_type': ['in', therapy_types]}
+ };
}
- }
- }];
+ }];
- frm.add_custom_button(__('Therapy Session'), function() {
- frappe.prompt(fields, data => {
- frappe.call({
- method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_therapy_session',
- args: {
- therapy_plan: frm.doc.name,
- patient: frm.doc.patient,
- therapy_type: data.therapy_type,
- company: frm.doc.company
- },
- freeze: true,
- callback: function(r) {
- if (r.message) {
- frappe.model.sync(r.message);
- frappe.set_route('Form', r.message.doctype, r.message.name);
+ frm.add_custom_button(__('Therapy Session'), function() {
+ frappe.prompt(fields, data => {
+ frappe.call({
+ method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_therapy_session',
+ args: {
+ therapy_plan: frm.doc.name,
+ patient: frm.doc.patient,
+ therapy_type: data.therapy_type,
+ company: frm.doc.company
+ },
+ freeze: true,
+ callback: function(r) {
+ if (r.message) {
+ frappe.model.sync(r.message);
+ frappe.set_route('Form', r.message.doctype, r.message.name);
+ }
}
- }
- });
- }, __('Select Therapy Type'), __('Create'));
- }, __('Create'));
+ });
+ }, __('Select Therapy Type'), __('Create'));
+ }, __('Create'));
+ }
if (frm.doc.therapy_plan_template && !frm.doc.invoiced) {
frm.add_custom_button(__('Sales Invoice'), function() {
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
index ccb316e..c03e9de 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
@@ -115,7 +115,8 @@
"fieldname": "therapy_plan_template",
"fieldtype": "Link",
"label": "Therapy Plan Template",
- "options": "Therapy Plan Template"
+ "options": "Therapy Plan Template",
+ "set_only_once": 1
},
{
"default": "0",
@@ -128,7 +129,7 @@
}
],
"links": [],
- "modified": "2020-10-23 01:27:42.128855",
+ "modified": "2020-11-04 18:13:13.564999",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Plan",
diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
index 555587e..77f08af 100644
--- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
+++ b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
@@ -30,12 +30,13 @@
"fieldname": "sessions_completed",
"fieldtype": "Int",
"label": "Sessions Completed",
+ "no_copy": 1,
"read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2020-10-08 01:17:34.778028",
+ "modified": "2020-11-04 18:15:52.173450",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Plan Detail",
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
index 65d4cc4..a2b01c9 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
@@ -22,6 +22,10 @@
},
refresh: function(frm) {
+ if (frm.doc.therapy_plan) {
+ frm.trigger('filter_therapy_types');
+ }
+
if (!frm.doc.__islocal) {
frm.dashboard.add_indicator(__('Counts Targeted: {0}', [frm.doc.total_counts_targeted]), 'blue');
frm.dashboard.add_indicator(__('Counts Completed: {0}', [frm.doc.total_counts_completed]),
@@ -36,15 +40,43 @@
})
}, 'Create');
- frm.add_custom_button(__('Sales Invoice'), function() {
- frappe.model.open_mapped_doc({
- method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
- frm: frm,
- })
- }, 'Create');
+ frappe.db.get_value('Therapy Plan', {'name': frm.doc.therapy_plan}, 'therapy_plan_template', (r) => {
+ if (r && !r.therapy_plan_template) {
+ frm.add_custom_button(__('Sales Invoice'), function() {
+ frappe.model.open_mapped_doc({
+ method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
+ frm: frm,
+ });
+ }, 'Create');
+ }
+ });
}
},
+ therapy_plan: function(frm) {
+ if (frm.doc.therapy_plan) {
+ frm.trigger('filter_therapy_types');
+ }
+ },
+
+ filter_therapy_types: function(frm) {
+ frappe.call({
+ 'method': 'frappe.client.get',
+ args: {
+ doctype: 'Therapy Plan',
+ name: frm.doc.therapy_plan
+ },
+ callback: function(data) {
+ let therapy_types = (data.message.therapy_plan_details || []).map(function(d){ return d.therapy_type; });
+ frm.set_query('therapy_type', function() {
+ return {
+ filters: { 'therapy_type': ['in', therapy_types]}
+ };
+ });
+ }
+ });
+ },
+
patient: function(frm) {
if (frm.doc.patient) {
frappe.call({
@@ -98,19 +130,6 @@
frm.set_value(values);
}
});
- } else {
- let values = {
- 'patient': '',
- 'therapy_type': '',
- 'therapy_plan': '',
- 'practitioner': '',
- 'department': '',
- 'start_date': '',
- 'start_time': '',
- 'service_unit': '',
- 'duration': ''
- };
- frm.set_value(values);
}
},
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
index 1f877cc..0bb2b0e 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
@@ -194,6 +194,7 @@
"fieldname": "total_counts_completed",
"fieldtype": "Int",
"label": "Total Counts Completed",
+ "no_copy": 1,
"read_only": 1
},
{
@@ -222,7 +223,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-10-22 23:10:21.178644",
+ "modified": "2020-11-04 18:14:25.999939",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Session",
diff --git a/erpnext/manufacturing/doctype/routing/routing.js b/erpnext/manufacturing/doctype/routing/routing.js
index 741a3f0..9b1a8ca 100644
--- a/erpnext/manufacturing/doctype/routing/routing.js
+++ b/erpnext/manufacturing/doctype/routing/routing.js
@@ -2,7 +2,15 @@
// For license information, please see license.txt
frappe.ui.form.on('Routing', {
- setup: function(frm) {
+ refresh: function(frm) {
+ frm.trigger("display_sequence_id_column");
+ },
+
+ onload: function(frm) {
+ frm.trigger("display_sequence_id_column");
+ },
+
+ display_sequence_id_column: function(frm) {
frappe.meta.get_docfield("BOM Operation", "sequence_id",
frm.doc.name).in_list_view = true;
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 8b34eaa..268410e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -732,3 +732,4 @@
erpnext.patches.v13_0.print_uom_after_quantity_patch
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
+execute:frappe.delete_doc("Report", "Quoted Item Comparison")
\ No newline at end of file
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index ea2093e..891bbe5 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -539,7 +539,7 @@
fieldtype: "Table",
label: "Items",
cannot_add_rows: cannot_add_row,
- in_place_edit: true,
+ in_place_edit: false,
reqd: 1,
data: this.data,
get_data: () => {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 989bd33..f162291 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -573,12 +573,6 @@
"default": 0
},
{
- "fieldtype": "Section Break",
- "label": "",
- "fieldname": "sec_break_dialog",
- "hide_border": 1
- },
- {
fieldname: 'items_for_po', fieldtype: 'Table', label: 'Select Items',
fields: [
{
@@ -616,16 +610,13 @@
read_only:1,
in_list_view:1
},
- ],
- data: me.frm.doc.items.map((item) =>{
- item.pending_qty = (flt(item.stock_qty) - flt(item.ordered_qty)) / flt(item.conversion_factor);
- return item;
- }).filter((item) => {return item.pending_qty > 0;})
+ ]
}
],
primary_action_label: 'Create Purchase Order',
primary_action (args) {
if (!args) return;
+
let selected_items = dialog.fields_dict.items_for_po.grid.get_selected_children();
if(selected_items.length == 0) {
frappe.throw({message: 'Please select Items from the Table', title: __('Items Required'), indicator:'blue'})
@@ -635,8 +626,9 @@
var method = args.against_default_supplier ? "make_purchase_order_for_default_supplier" : "make_purchase_order"
return frappe.call({
- type: "GET",
method: "erpnext.selling.doctype.sales_order.sales_order." + method,
+ freeze: true,
+ freeze_message: __("Creating Purchase Order ..."),
args: {
"source_name": me.frm.doc.name,
"selected_items": selected_items
@@ -660,8 +652,9 @@
}
});
- dialog.fields_dict["against_default_supplier"].df.onchange = () => {
- console.log("yo");
+ dialog.fields_dict["against_default_supplier"].df.onchange = () => set_po_items_data(dialog);
+
+ function set_po_items_data (dialog) {
var against_default_supplier = dialog.get_value("against_default_supplier");
var items_for_po = dialog.get_value("items_for_po");
@@ -671,16 +664,28 @@
dialog.fields_dict["items_for_po"].df.data = items_with_supplier;
dialog.get_field("items_for_po").refresh();
} else {
- let pending_items = me.frm.doc.items.map((item) =>{
- item.pending_qty = (flt(item.stock_qty) - flt(item.ordered_qty)) / flt(item.conversion_factor);
- return item;
- }).filter((item) => {return item.pending_qty > 0;});
+ let po_items = [];
+ me.frm.doc.items.forEach(d => {
+ let pending_qty = (flt(d.stock_qty) - flt(d.ordered_qty)) / flt(d.conversion_factor);
+ if (pending_qty > 0) {
+ po_items.push({
+ "doctype": "Sales Order Item",
+ "name": d.name,
+ "item_name": d.item_name,
+ "item_code": d.item_code,
+ "pending_qty": pending_qty,
+ "uom": d.uom,
+ "supplier": d.supplier
+ });
+ }
+ });
- dialog.fields_dict["items_for_po"].df.data = pending_items;
+ dialog.fields_dict["items_for_po"].df.data = po_items;
dialog.get_field("items_for_po").refresh();
}
}
+ set_po_items_data(dialog);
dialog.get_field("items_for_po").grid.only_sortable();
dialog.get_field("items_for_po").refresh();
dialog.wrapper.find('.grid-heading-row .grid-row-check').click();
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index ae227e0..ec1c823 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -779,7 +779,9 @@
return data
@frappe.whitelist()
-def make_purchase_order_for_default_supplier(source_name, selected_items=[], target_doc=None):
+def make_purchase_order_for_default_supplier(source_name, selected_items=None, target_doc=None):
+ if not selected_items: return
+
if isinstance(selected_items, string_types):
selected_items = json.loads(selected_items)
@@ -878,7 +880,9 @@
frappe.msgprint(_("Purchase Order already created for all Sales Order items"))
@frappe.whitelist()
-def make_purchase_order(source_name, selected_items=[], target_doc=None):
+def make_purchase_order(source_name, selected_items=None, target_doc=None):
+ if not selected_items: return
+
if isinstance(selected_items, string_types):
selected_items = json.loads(selected_items)