Merge branch 'develop' into feat-exotel-customer-link
diff --git a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
index 3a0d416..340b9dd 100644
--- a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
+++ b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py
@@ -9,6 +9,8 @@
from erpnext.stock.get_item_details import get_item_details
from frappe.test_runner import make_test_objects
+test_dependencies = ['Item']
+
def test_create_test_data():
frappe.set_user("Administrator")
# create test item
@@ -95,7 +97,6 @@
})
coupon_code.insert()
-
class TestCouponCode(unittest.TestCase):
def setUp(self):
test_create_test_data()
diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
index 8a4050c..edf8659 100644
--- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
@@ -8,6 +8,8 @@
from erpnext.stock.get_item_details import get_pos_profile
from erpnext.accounts.doctype.pos_profile.pos_profile import get_child_nodes
+test_dependencies = ['Item']
+
class TestPOSProfile(unittest.TestCase):
def test_pos_profile(self):
make_pos_profile()
@@ -88,7 +90,7 @@
"write_off_account": args.write_off_account or "_Test Write Off - _TC",
"write_off_cost_center": args.write_off_cost_center or "_Test Write Off Cost Center - _TC"
})
-
+
payments = [{
'mode_of_payment': 'Cash',
'default': 1
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index cff7d5b..aa6194c 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -1,5 +1,4 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
# For license information, please see license.txt
@@ -208,7 +207,7 @@
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
from erpnext.accounts.doctype.pricing_rule.utils import (get_pricing_rules,
- get_applied_pricing_rules, get_pricing_rule_items, get_product_discount_rule)
+ get_applied_pricing_rules, get_pricing_rule_items, get_product_discount_rule)
if isinstance(doc, string_types):
doc = json.loads(doc)
@@ -237,7 +236,7 @@
update_args_for_pricing_rule(args)
- pricing_rules = (get_applied_pricing_rules(args)
+ pricing_rules = (get_applied_pricing_rules(args.get('pricing_rules'))
if for_validate and args.get("pricing_rules") else get_pricing_rules(args, doc))
if pricing_rules:
@@ -365,8 +364,9 @@
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_pricing_rule_items
- for d in json.loads(pricing_rules):
+ from erpnext.accounts.doctype.pricing_rule.utils import (get_applied_pricing_rules,
+ get_pricing_rule_items)
+ for d in get_applied_pricing_rules(pricing_rules):
if not d or not frappe.db.exists("Pricing Rule", d): continue
pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 3fd316f..53b0cf7b 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -447,9 +447,14 @@
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
doc.set_missing_values()
-def get_applied_pricing_rules(item_row):
- return (json.loads(item_row.get("pricing_rules"))
- if item_row.get("pricing_rules") else [])
+def get_applied_pricing_rules(pricing_rules):
+ if pricing_rules:
+ if pricing_rules.startswith('['):
+ return json.loads(pricing_rules)
+ else:
+ return pricing_rules.split(',')
+
+ return []
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
free_item = pricing_rule.free_item
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 31613e5..2397b7d 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -447,7 +447,7 @@
{
"allow_on_submit": 1,
"fieldname": "po_no",
- "fieldtype": "Small Text",
+ "fieldtype": "Data",
"hide_days": 1,
"hide_seconds": 1,
"label": "Customer's Purchase Order",
@@ -1946,7 +1946,7 @@
"idx": 181,
"is_submittable": 1,
"links": [],
- "modified": "2020-08-03 23:31:12.675040",
+ "modified": "2020-08-27 01:56:28.532140",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
index f106928..2980213 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
@@ -13,7 +13,8 @@
'Auto Repeat': 'reference_document',
},
'internal_links': {
- 'Sales Order': ['items', 'sales_order']
+ 'Sales Order': ['items', 'sales_order'],
+ 'Delivery Note': ['items', 'delivery_note']
},
'transactions': [
{
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
index 53ee08a..d0904ee 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
@@ -3,6 +3,22 @@
frappe.ui.form.on('Shipping Rule', {
refresh: function(frm) {
+ frm.set_query("cost_center", function() {
+ return {
+ filters: {
+ company: frm.doc.company
+ }
+ }
+ })
+
+ frm.set_query("account", function() {
+ return {
+ filters: {
+ company: frm.doc.company
+ }
+ }
+ })
+
frm.trigger('toggle_reqd');
},
calculate_based_on: function(frm) {
@@ -12,4 +28,4 @@
frm.toggle_reqd("shipping_amount", frm.doc.calculate_based_on === 'Fixed');
frm.toggle_reqd("conditions", frm.doc.calculate_based_on !== 'Fixed');
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py
index 2cb10b1..10b32fe 100644
--- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py
+++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py
@@ -173,7 +173,7 @@
from `tabGL Entry` gle
{join}
where
- gle.docstatus < 2 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != ''
+ gle.docstatus < 2 and gle.is_cancelled = 0 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != ''
and gle.posting_date <= %(to_date)s {conditions}
order by gle.posting_date
""".format(join=join, join_field=join_field, conditions=conditions), self.filters, as_dict=True)
@@ -248,7 +248,7 @@
from
`tabGL Entry`
where
- docstatus < 2
+ docstatus < 2 and is_cancelled = 0
and (voucher_type, voucher_no) in (
select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc
where acc.name = gle.account and acc.account_type = '{income_or_expense}'
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 3091193..d61e44b 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -325,7 +325,7 @@
apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data'))
elif pricing_rule_args.get("validate_applied_rule"):
- for pricing_rule in get_applied_pricing_rules(item):
+ for pricing_rule in get_applied_pricing_rules(item.get('pricing_rules')):
pricing_rule_doc = frappe.get_cached_doc("Pricing Rule", pricing_rule)
for field in ['discount_percentage', 'discount_amount', 'rate']:
if item.get(field) < pricing_rule_doc.get(field):
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index f982700..ac567b7 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -276,6 +276,9 @@
qty_to_be_received_map = get_qty_to_be_received(purchase_orders)
for item in self.get('items'):
+ if not item.purchase_order:
+ continue
+
# reset raw_material cost
item.rm_supp_cost = 0
@@ -288,6 +291,12 @@
fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
+ if not fg_yet_to_be_received:
+ frappe.throw(_("Row #{0}: Item {1} is already fully received in Purchase Order {2}")
+ .format(item.idx, frappe.bold(item.item_code),
+ frappe.utils.get_link_to_form("Purchase Order", item.purchase_order)),
+ title=_("Limit Crossed"))
+
transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 2a14be8..92cfdb7 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -9,6 +9,7 @@
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax
from erpnext.stock.get_item_details import _get_item_tax_template
+from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
class calculate_taxes_and_totals(object):
def __init__(self, doc):
@@ -209,7 +210,7 @@
elif tax.charge_type == "On Previous Row Total":
current_tax_fraction = (tax_rate / 100.0) * \
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
-
+
elif tax.charge_type == "On Item Quantity":
inclusive_tax_amount_per_qty = flt(tax_rate)
@@ -607,7 +608,7 @@
base_rate_with_margin = 0.0
if item.price_list_rate:
if item.pricing_rules and not self.doc.ignore_pricing_rule:
- for d in json.loads(item.pricing_rules):
+ 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)\
diff --git a/erpnext/crm/doctype/social_media_post/social_media_post.js b/erpnext/crm/doctype/social_media_post/social_media_post.js
index 3a14f2d..0ce8b44 100644
--- a/erpnext/crm/doctype/social_media_post/social_media_post.js
+++ b/erpnext/crm/doctype/social_media_post/social_media_post.js
@@ -30,14 +30,14 @@
let color = frm.doc.twitter_post_id ? "green" : "red";
let status = frm.doc.twitter_post_id ? "Posted" : "Not Posted";
html += `<div class="col-xs-6">
- <span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">Twitter : ${status} </span></span>
+ <span class="indicator whitespace-nowrap ${color}"><span>Twitter : ${status} </span></span>
</div>` ;
}
if (frm.doc.linkedin){
let color = frm.doc.linkedin_post_id ? "green" : "red";
let status = frm.doc.linkedin_post_id ? "Posted" : "Not Posted";
html += `<div class="col-xs-6">
- <span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">LinkedIn : ${status} </span></span>
+ <span class="indicator whitespace-nowrap ${color}"><span>LinkedIn : ${status} </span></span>
</div>` ;
}
html = `<div class="row">${html}</div>`;
diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
index 207351f..4ee5f6b 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py
@@ -7,6 +7,8 @@
import frappe
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_clinical_procedure_template
+test_dependencies = ['Item']
+
class TestClinicalProcedure(unittest.TestCase):
def test_procedure_template_item(self):
patient, medical_department, practitioner = create_healthcare_docs()
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
index f7ed31b..2d6b645 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
@@ -226,7 +226,9 @@
primary_action_label: __('Book'),
primary_action: function() {
frm.set_value('appointment_time', selected_slot);
- frm.set_value('duration', duration);
+ if (!frm.doc.duration) {
+ frm.set_value('duration', duration);
+ }
frm.set_value('practitioner', d.get_value('practitioner'));
frm.set_value('department', d.get_value('department'));
frm.set_value('appointment_date', d.get_value('appointment_date'));
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index db1d191..1b92358 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -132,6 +132,9 @@
if filters.get('employee'):
conditions['name'] = filters.get('employee')
+ if filters.get('company'):
+ conditions['company'] = filters.get('company')
+
return conditions
def get_department_leave_approver_map(department=None):
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index c51f655..3189433 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -494,7 +494,7 @@
'image' : d.image,
'stock_uom' : d.stock_uom,
'stock_qty' : flt(d.stock_qty),
- 'rate' : flt(d.base_rate) / flt(d.conversion_factor),
+ 'rate' : flt(d.base_rate) / (flt(d.conversion_factor) or 1.0),
'include_item_in_manufacturing': d.include_item_in_manufacturing
}))
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index e6c10ad..742d18c 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -90,6 +90,7 @@
update_cost()
def replace_bom(args):
+ frappe.db.auto_commit_on_many_writes = 1
args = frappe._dict(args)
doc = frappe.get_doc("BOM Update Tool")
@@ -97,6 +98,8 @@
doc.new_bom = args.new_bom
doc.replace_bom()
+ frappe.db.auto_commit_on_many_writes = 0
+
def update_cost():
frappe.db.auto_commit_on_many_writes = 1
bom_list = get_boms_in_bottom_up_order()
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index e17e949..a8648f5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -718,6 +718,7 @@
erpnext.patches.v12_0.update_item_tax_template_company
erpnext.patches.v13_0.move_branch_code_to_bank_account
erpnext.patches.v13_0.healthcare_lab_module_rename_doctypes
+erpnext.patches.v13_0.add_standard_navbar_items #4
erpnext.patches.v13_0.stock_entry_enhancements
erpnext.patches.v12_0.update_state_code_for_daman_and_diu
erpnext.patches.v12_0.rename_lost_reason_detail
diff --git a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
index 43bd0cc..7feaffd 100644
--- a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
+++ b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py
@@ -7,6 +7,7 @@
frappe.reload_doc('accounts', 'doctype', 'allowed_to_transact_with', force=True)
frappe.reload_doc('accounts', 'doctype', 'pricing_rule_detail', force=True)
frappe.reload_doc('crm', 'doctype', 'lost_reason_detail', force=True)
+ frappe.reload_doc('setup', 'doctype', 'quotation_lost_reason_detail', force=True)
company = frappe.get_all('Company', filters = {'country': 'United States'})
if not company:
diff --git a/erpnext/patches/v12_0/rename_lost_reason_detail.py b/erpnext/patches/v12_0/rename_lost_reason_detail.py
index 044d023..d0dc356 100644
--- a/erpnext/patches/v12_0/rename_lost_reason_detail.py
+++ b/erpnext/patches/v12_0/rename_lost_reason_detail.py
@@ -3,6 +3,7 @@
def execute():
if frappe.db.exists("DocType", "Lost Reason Detail"):
+ frappe.reload_doc("crm", "doctype", "opportunity_lost_reason")
frappe.reload_doc("crm", "doctype", "opportunity_lost_reason_detail")
frappe.reload_doc("setup", "doctype", "quotation_lost_reason_detail")
@@ -10,8 +11,8 @@
frappe.db.sql("""INSERT INTO `tabQuotation Lost Reason Detail` SELECT * FROM `tabLost Reason Detail` WHERE `parenttype` = 'Quotation'""")
- frappe.db.sql("""INSERT INTO `tabQuotation Lost Reason` (`name`, `creation`, `modified`, `modified_by`, `owner`, `docstatus`, `parent`, `parentfield`, `parenttype`, `idx`, `_comments`, `_assign`, `_user_tags`, `_liked_by`, `order_lost_reason`)
- SELECT o.`name`, o.`creation`, o.`modified`, o.`modified_by`, o.`owner`, o.`docstatus`, o.`parent`, o.`parentfield`, o.`parenttype`, o.`idx`, o.`_comments`, o.`_assign`, o.`_user_tags`, o.`_liked_by`, o.`lost_reason`
+ frappe.db.sql("""INSERT INTO `tabQuotation Lost Reason` (`name`, `creation`, `modified`, `modified_by`, `owner`, `docstatus`, `parent`, `parentfield`, `parenttype`, `idx`, `_comments`, `_assign`, `_user_tags`, `_liked_by`, `order_lost_reason`)
+ SELECT o.`name`, o.`creation`, o.`modified`, o.`modified_by`, o.`owner`, o.`docstatus`, o.`parent`, o.`parentfield`, o.`parenttype`, o.`idx`, o.`_comments`, o.`_assign`, o.`_user_tags`, o.`_liked_by`, o.`lost_reason`
FROM `tabOpportunity Lost Reason` o LEFT JOIN `tabQuotation Lost Reason` q ON q.name = o.name WHERE q.name IS NULL""")
-
+
frappe.delete_doc("DocType", "Lost Reason Detail")
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/add_standard_navbar_items.py b/erpnext/patches/v13_0/add_standard_navbar_items.py
new file mode 100644
index 0000000..d05b258
--- /dev/null
+++ b/erpnext/patches/v13_0/add_standard_navbar_items.py
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+# import frappe
+from erpnext.setup.install import add_standard_navbar_items
+
+def execute():
+ # Add standard navbar items for ERPNext in Navbar Settings
+ add_standard_navbar_items()
diff --git a/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py b/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py
index 7c07b98..0f521cb 100644
--- a/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py
+++ b/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py
@@ -7,4 +7,7 @@
def execute():
frappe.reload_doc('hr', 'doctype', 'shift_assignment')
- frappe.db.sql("update `tabShift Assignment` set end_date=date, start_date=date where date IS NOT NULL and start_date IS NULL and end_date IS NULL;")
+ if frappe.db.has_column('Shift Assignment', 'date'):
+ frappe.db.sql("""update `tabShift Assignment`
+ set end_date=date, start_date=date
+ where date IS NOT NULL and start_date IS NULL and end_date IS NULL;""")
diff --git a/erpnext/portal/doctype/homepage/homepage.js b/erpnext/portal/doctype/homepage/homepage.js
index ca34d69..c7c66e0 100644
--- a/erpnext/portal/doctype/homepage/homepage.js
+++ b/erpnext/portal/doctype/homepage/homepage.js
@@ -21,34 +21,6 @@
});
frappe.ui.form.on('Homepage Featured Product', {
- item_code: function(frm, cdt, cdn) {
- var featured_product = frappe.model.get_doc(cdt, cdn);
- if (featured_product.item_code) {
- frappe.call({
- method: 'frappe.client.get_value',
- args: {
- 'doctype': 'Item',
- 'filters': {'name': featured_product.item_code},
- 'fieldname': [
- 'item_name',
- 'web_long_description',
- 'description',
- 'image',
- 'thumbnail'
- ]
- },
- callback: function(r) {
- if (!r.exc) {
- $.extend(featured_product, r.message);
- if (r.message.web_long_description) {
- featured_product.description = r.message.web_long_description;
- }
- frm.refresh_field('products');
- }
- }
- });
- }
- },
view: function(frm, cdt, cdn){
var child= locals[cdt][cdn]
diff --git a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json
index c8b4ae9..01c32ef 100644
--- a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json
+++ b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.json
@@ -1,301 +1,116 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "hash",
- "beta": 0,
- "creation": "2016-04-22 05:57:06.261401",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2016-04-22 05:57:06.261401",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "col_break1",
+ "item_name",
+ "view",
+ "section_break_5",
+ "description",
+ "column_break_7",
+ "image",
+ "thumbnail",
+ "route"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "fieldname": "item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 1,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "item_code",
- "oldfieldtype": "Link",
- "options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "150px",
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0,
+ "bold": 1,
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "label": "Item Code",
+ "oldfieldname": "item_code",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "print_width": "150px",
+ "reqd": 1,
+ "search_index": 1,
"width": "150px"
- },
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "col_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "col_break1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "item_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Item Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "item_name",
- "oldfieldtype": "Data",
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "print_width": "150",
- "read_only": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "fetch_from": "item_code.item_name",
+ "fetch_if_empty": 1,
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Item Name",
+ "oldfieldname": "item_name",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "print_width": "150",
+ "read_only": 1,
+ "reqd": 1,
"width": "150"
- },
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "view",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "View",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "view",
+ "fieldtype": "Button",
+ "in_list_view": 1,
+ "label": "View"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "label": "Description"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 1,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "Small Text",
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "300px",
- "read_only": 1,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "fetch_from": "item_code.web_long_description",
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Small Text",
+ "print_width": "300px",
"width": "300px"
- },
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "column_break_7",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "image",
- "fieldtype": "Attach Image",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Image",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fetch_from": "item_code.website_image",
+ "fetch_if_empty": 1,
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "label": "Image"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "thumbnail",
- "fieldtype": "Attach Image",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Thumbnail",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "thumbnail",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Thumbnail"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "route",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "route",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "route",
+ "fieldtype": "Small Text",
+ "label": "route",
+ "read_only": 1
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2016-08-09 06:09:34.731971",
- "modified_by": "Administrator",
- "module": "Portal",
- "name": "Homepage Featured Product",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_seen": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-08-25 15:27:49.573537",
+ "modified_by": "Administrator",
+ "module": "Portal",
+ "name": "Homepage Featured Product",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index 9870f81..2af9140 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -3,32 +3,6 @@
frappe.provide('erpnext');
-// add toolbar icon
-$(document).bind('toolbar_setup', function() {
- frappe.app.name = "ERPNext";
-
- frappe.help_feedback_link = '<p><a class="text-muted" \
- href="https://discuss.erpnext.com">Feedback</a></p>'
-
-
- $('[data-link="docs"]').attr("href", "https://erpnext.com/docs")
- $('[data-link="issues"]').attr("href", "https://github.com/frappe/erpnext/issues")
-
-
- // default documentation goes to erpnext
- // $('[data-link-type="documentation"]').attr('data-path', '/erpnext/manual/index');
-
- // additional help links for erpnext
- var $help_menu = $('.dropdown-help ul .documentation-links');
- $('<li><a data-link-type="forum" href="https://erpnext.com/docs/user/manual" \
- target="_blank">'+__('Documentation')+'</a></li>').insertBefore($help_menu);
- $('<li><a data-link-type="forum" href="https://discuss.erpnext.com" \
- target="_blank">'+__('User Forum')+'</a></li>').insertBefore($help_menu);
- $('<li><a href="https://github.com/frappe/erpnext/issues" \
- target="_blank">'+__('Report an Issue')+'</a></li>').insertBefore($help_menu);
-
-});
-
// preferred modules for breadcrumbs
$.extend(frappe.breadcrumbs.preferred, {
"Item Group": "Stock",
diff --git a/erpnext/selling/doctype/customer/customer_dashboard.py b/erpnext/selling/doctype/customer/customer_dashboard.py
index 09e474d..532c11b 100644
--- a/erpnext/selling/doctype/customer/customer_dashboard.py
+++ b/erpnext/selling/doctype/customer/customer_dashboard.py
@@ -33,7 +33,7 @@
},
{
'label': _('Support'),
- 'items': ['Issue']
+ 'items': ['Issue', 'Maintenance Visit', 'Installation Note', 'Warranty Claim']
},
{
'label': _('Projects'),
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index ab095eb..20ae19f 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -285,9 +285,17 @@
return customer
else:
raise
- except frappe.MandatoryError:
+ except frappe.MandatoryError as e:
+ mandatory_fields = e.args[0].split(':')[1].split(',')
+ mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
+
frappe.local.message_log = []
- frappe.throw(_("Please create Customer from Lead {0}").format(lead_name))
+ lead_link = frappe.utils.get_link_to_form("Lead", lead_name)
+ message = _("Could not auto create Customer due to the following missing mandatory field(s):") + "<br>"
+ message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
+ message += _("Please create Customer from Lead {0}.").format(lead_link)
+
+ frappe.throw(message, title=_("Mandatory Missing"))
else:
return customer_name
else:
diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
index 4126bc6..05a760d 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
+++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
@@ -10,6 +10,7 @@
'Payment Entry': 'reference_name',
'Payment Request': 'reference_name',
'Auto Repeat': 'reference_document',
+ 'Maintenance Visit': 'prevdoc_docname'
},
'internal_links': {
'Quotation': ['items', 'prevdoc_docname']
@@ -17,7 +18,7 @@
'transactions': [
{
'label': _('Fulfillment'),
- 'items': ['Sales Invoice', 'Pick List', 'Delivery Note']
+ 'items': ['Sales Invoice', 'Pick List', 'Delivery Note', 'Maintenance Visit']
},
{
'label': _('Purchasing'),
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index c23a6ad..eadeb8f 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -356,7 +356,7 @@
onchange: function() {
if (this.value || this.value == 0) {
const frm = me.events.get_frm();
- frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', this.value);
+ frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', flt(this.value));
me.hide_discount_control(this.value);
}
},
@@ -948,4 +948,4 @@
show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index 8ecc13b..c94831e 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -26,7 +26,8 @@
tabDocField where fieldtype='Link' and options='Company'"""):
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
"Party Account", "Employee", "Sales Taxes and Charges Template",
- "Purchase Taxes and Charges Template", "POS Profile", 'BOM'):
+ "Purchase Taxes and Charges Template", "POS Profile", "BOM",
+ "Company", "Bank Account"):
delete_for_doctype(doctype, company_name)
# reset company values
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 50f9d84..4f0f572 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -26,6 +26,7 @@
create_default_success_action()
create_default_energy_point_rules()
add_company_to_session_defaults()
+ add_standard_navbar_items()
frappe.db.commit()
@@ -104,3 +105,45 @@
"ref_doctype": "Company"
})
settings.save()
+
+def add_standard_navbar_items():
+ navbar_settings = frappe.get_single("Navbar Settings")
+
+ erpnext_navbar_items = [
+ {
+ 'item_label': 'Documentation',
+ 'item_type': 'Route',
+ 'route': 'https://erpnext.com/docs/user/manual',
+ 'is_standard': 1
+ },
+ {
+ 'item_label': 'User Forum',
+ 'item_type': 'Route',
+ 'route': 'https://discuss.erpnext.com',
+ 'is_standard': 1
+ },
+ {
+ 'item_label': 'Report an Issue',
+ 'item_type': 'Route',
+ 'route': 'https://github.com/frappe/erpnext/issues',
+ 'is_standard': 1
+ }
+ ]
+
+ current_nabvar_items = navbar_settings.help_dropdown
+ navbar_settings.set('help_dropdown', [])
+
+ for item in erpnext_navbar_items:
+ navbar_settings.append('help_dropdown', item)
+
+ for item in current_nabvar_items:
+ navbar_settings.append('help_dropdown', {
+ 'item_label': item.item_label,
+ 'item_type': item.item_type,
+ 'route': item.route,
+ 'action': item.action,
+ 'is_standard': item.is_standard,
+ 'hidden': item.hidden
+ })
+
+ navbar_settings.save()
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 4a8236d..67161aa 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import unittest
+import json
import frappe, erpnext
import frappe.defaults
from frappe.utils import cint, flt, cstr, today, random_string
@@ -152,13 +153,78 @@
qty=100, basic_rate=100, company="_Test Company with perpetual inventory")
pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=0, is_subcontracted="Yes",
company="_Test Company with perpetual inventory", warehouse='Stores - TCP1', supplier_warehouse='Work In Progress - TCP1')
-
+
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
self.assertFalse(gl_entries)
set_perpetual_inventory(0)
+ def test_subcontracting_over_receipt(self):
+ """
+ Behaviour: Raise multiple PRs against one PO that in total
+ receive more than the required qty in the PO.
+ Expected Result: Error Raised for Over Receipt against PO.
+ """
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+ from erpnext.buying.doctype.purchase_order.test_purchase_order import (update_backflush_based_on,
+ make_subcontracted_item, create_purchase_order)
+ from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt,
+ make_rm_stock_entry as make_subcontract_transfer_entry)
+
+ update_backflush_based_on("Material Transferred for Subcontract")
+ item_code = "_Test Subcontracted FG Item 1"
+ make_subcontracted_item(item_code)
+
+ po = create_purchase_order(item_code=item_code, qty=1,
+ is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
+
+ #stock raw materials in a warehouse before transfer
+ make_stock_entry(target="_Test Warehouse - _TC",
+ item_code="_Test Item Home Desktop 100", qty=1, basic_rate=100)
+ make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Test Extra Item 1", qty=1, basic_rate=100)
+ make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "_Test Item", qty=1, basic_rate=100)
+
+ rm_items = [
+ {
+ "item_code": item_code,
+ "rm_item_code": po.supplied_items[0].rm_item_code,
+ "item_name": "_Test Item",
+ "qty": po.supplied_items[0].required_qty,
+ "warehouse": "_Test Warehouse - _TC",
+ "stock_uom": "Nos"
+ },
+ {
+ "item_code": item_code,
+ "rm_item_code": po.supplied_items[1].rm_item_code,
+ "item_name": "Test Extra Item 1",
+ "qty": po.supplied_items[1].required_qty,
+ "warehouse": "_Test Warehouse - _TC",
+ "stock_uom": "Nos"
+ },
+ {
+ "item_code": item_code,
+ "rm_item_code": po.supplied_items[2].rm_item_code,
+ "item_name": "_Test Item Home Desktop 100",
+ "qty": po.supplied_items[2].required_qty,
+ "warehouse": "_Test Warehouse - _TC",
+ "stock_uom": "Nos"
+ }
+ ]
+ rm_item_string = json.dumps(rm_items)
+ se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
+ se.to_warehouse = "_Test Warehouse 1 - _TC"
+ se.save()
+ se.submit()
+
+ pr1 = make_purchase_receipt(po.name)
+ pr2 = make_purchase_receipt(po.name)
+
+ pr1.submit()
+ self.assertRaises(frappe.ValidationError, pr2.submit)
+
def test_serial_no_supplier(self):
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
self.assertEqual(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"),
diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js
index 9e15757..858564a 100644
--- a/erpnext/support/doctype/issue/issue.js
+++ b/erpnext/support/doctype/issue/issue.js
@@ -209,11 +209,11 @@
frm.dashboard.set_headline_alert(
'<div class="row">' +
- '<div class="col-xs-6">' +
- '<span class="indicator whitespace-nowrap '+ time_to_respond.indicator +'"><span class="hidden-xs">Time to Respond: '+ time_to_respond.diff_display +'</span></span> ' +
+ '<div class="col-xs-12 col-sm-6">' +
+ '<span class="indicator whitespace-nowrap '+ time_to_respond.indicator +'"><span>Time to Respond: '+ time_to_respond.diff_display +'</span></span> ' +
'</div>' +
- '<div class="col-xs-6">' +
- '<span class="indicator whitespace-nowrap '+ time_to_resolve.indicator +'"><span class="hidden-xs">Time to Resolve: '+ time_to_resolve.diff_display +'</span></span> ' +
+ '<div class="col-xs-12 col-sm-6">' +
+ '<span class="indicator whitespace-nowrap '+ time_to_resolve.indicator +'"><span>Time to Resolve: '+ time_to_resolve.diff_display +'</span></span> ' +
'</div>' +
'</div>'
);
diff --git a/erpnext/templates/generators/item/item_inquiry.js b/erpnext/templates/generators/item/item_inquiry.js
index 52ddae2..e7db3a3 100644
--- a/erpnext/templates/generators/item/item_inquiry.js
+++ b/erpnext/templates/generators/item/item_inquiry.js
@@ -22,6 +22,13 @@
},
{
fieldtype: 'Data',
+ label: __('Phone Number'),
+ fieldname: 'phone',
+ options: 'Phone',
+ reqd: 1
+ },
+ {
+ fieldtype: 'Data',
label: __('Subject'),
fieldname: 'subject',
reqd: 1