diff --git a/.github/stale.yml b/.github/stale.yml index 3ad0bff5d7f..dabc66eb730 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 10 +daysUntilStale: 30 # Number of days of inactivity before a stale Issue or Pull Request is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. diff --git a/erpnext/__init__.py b/erpnext/__init__.py index ff96e92ae88..92efe8e302f 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.64' +__version__ = '10.1.72' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py index 7a7d7d226c8..f5581941ba2 100644 --- a/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py +++ b/erpnext/accounts/doctype/bank_statement_transaction_entry/bank_statement_transaction_entry.py @@ -16,10 +16,11 @@ import copy class BankStatementTransactionEntry(Document): def autoname(self): self.name = self.bank_account + "-" + self.from_date + "-" + self.to_date - mapper_name = self.bank + "-Statement-Settings" - if not frappe.db.exists("Bank Statement Settings", mapper_name): - self.create_settings(self.bank) - self.bank_settings = mapper_name + if self.bank: + mapper_name = self.bank + "-Statement-Settings" + if not frappe.db.exists("Bank Statement Settings", mapper_name): + self.create_settings(self.bank) + self.bank_settings = mapper_name def create_settings(self, bank): mapper = frappe.new_doc("Bank Statement Settings") diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index b0795caf238..afb44e8f92f 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -807,15 +807,25 @@ frappe.ui.form.on('Payment Entry', { var write_off_row = $.map(frm.doc["deductions"] || [], function(t) { return t.account==r.message[account] ? t : null; }); - if (!write_off_row.length) { - var row = frm.add_child("deductions"); + var row = []; + + var difference_amount = flt(frm.doc.difference_amount, + precision("difference_amount")); + + if (!write_off_row.length && difference_amount) { + row = frm.add_child("deductions"); row.account = r.message[account]; row.cost_center = r.message["cost_center"]; } else { - var row = write_off_row[0]; + row = write_off_row[0]; + } + + if (row) { + row.amount = flt(row.amount) + difference_amount; + } else { + frappe.msgprint(__("No gain or loss in the exchange rate")) } - row.amount = flt(row.amount) + flt(frm.doc.difference_amount); refresh_field("deductions"); frm.events.set_unallocated_amount(frm); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index aec3d1b0148..f213ffa6580 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -933,7 +933,7 @@ def get_paid_amount(dt, dn, party_type, party, account, due_date): return paid_amount[0][0] if paid_amount else 0 @frappe.whitelist() -def get_party_and_account_balance(company, date, paid_from, paid_to=None, ptype=None, pty=None, cost_center=None): +def get_party_and_account_balance(company, date, paid_from=None, paid_to=None, ptype=None, pty=None, cost_center=None): return frappe._dict({ "party_balance": get_balance_on(party_type=ptype, party=pty, cost_center=cost_center), "paid_from_account_balance": get_balance_on(paid_from, date, cost_center=cost_center), diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 42f371bdddd..fe99763a351 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -201,8 +201,8 @@ def get_pricing_rule_for_item(args): "discount_percentage": 0.0 }) else: - item_details.discount_percentage = pricing_rule.discount_percentage or args.discount_percentage - + item_details.discount_percentage = (pricing_rule.get('discount_percentage', 0) + if pricing_rule else args.discount_percentage) elif args.get('pricing_rule'): item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details) @@ -393,4 +393,4 @@ def make_pricing_rule(doctype, docname): doc.selling = 1 if doctype == "Customer" else 0 doc.buying = 1 if doctype == "Supplier" else 0 - return doc \ No newline at end of file + return doc diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index f5f832d857f..995efee2c0e 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -11,11 +11,17 @@ from erpnext.stock.get_item_details import get_item_details from frappe import MandatoryError class TestPricingRule(unittest.TestCase): + def setUp(self): + frappe.db.sql("delete from `tabPricing Rule`") + + def tearDown(self): + frappe.db.sql("delete from `tabPricing Rule`") + def test_pricing_rule_for_discount(self): from erpnext.stock.get_item_details import get_item_details from frappe import MandatoryError - frappe.db.sql("delete from `tabPricing Rule`") + test_record = { "doctype": "Pricing Rule", @@ -89,14 +95,10 @@ class TestPricingRule(unittest.TestCase): details = get_item_details(args) self.assertEqual(details.get("discount_percentage"), 15) - frappe.db.sql("delete from `tabPricing Rule`") - def test_pricing_rule_for_margin(self): from erpnext.stock.get_item_details import get_item_details from frappe import MandatoryError - frappe.db.sql("delete from `tabPricing Rule`") - test_record = { "doctype": "Pricing Rule", "title": "_Test Pricing Rule", @@ -111,14 +113,14 @@ class TestPricingRule(unittest.TestCase): "company": "_Test Company" } frappe.get_doc(test_record.copy()).insert() - + item_price = frappe.get_doc({ "doctype": "Item Price", "price_list": "_Test Price List 2", "item_code": "_Test FG Item 2", "price_list_rate": 100 }) - + item_price.insert(ignore_permissions=True) args = frappe._dict({ @@ -138,14 +140,10 @@ class TestPricingRule(unittest.TestCase): self.assertEqual(details.get("margin_type"), "Percentage") self.assertEqual(details.get("margin_rate_or_amount"), 10) - frappe.db.sql("delete from `tabPricing Rule`") - def test_pricing_rule_for_variants(self): from erpnext.stock.get_item_details import get_item_details from frappe import MandatoryError - frappe.db.sql("delete from `tabPricing Rule`") - if not frappe.db.exists("Item", "Test Variant PRT"): frappe.get_doc({ "doctype": "Item", @@ -213,8 +211,6 @@ class TestPricingRule(unittest.TestCase): self.assertEqual(details.get("discount_percentage"), 17.5) def test_pricing_rule_for_stock_qty(self): - frappe.db.sql("delete from `tabPricing Rule`") - test_record = { "doctype": "Pricing Rule", "title": "_Test Pricing Rule", @@ -257,25 +253,19 @@ class TestPricingRule(unittest.TestCase): self.assertEqual(so.items[0].rate, 100) def test_pricing_rule_with_margin_and_discount(self): - frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule') - make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10) + make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10, discount_percentage=10) si = create_sales_invoice(do_not_save=True) si.items[0].price_list_rate = 1000 si.payment_schedule = [] si.insert(ignore_permissions=True) item = si.items[0] - self.assertEqual(item.rate, 1100) self.assertEqual(item.margin_rate_or_amount, 10) - - # With discount - item.discount_percentage = 10 - si.payment_schedule = [] - si.save() - item = si.items[0] - self.assertEqual(item.rate, 990) + self.assertEqual(item.rate_with_margin, 1100) self.assertEqual(item.discount_percentage, 10) - frappe.db.sql("delete from `tabPricing Rule`") + self.assertEqual(item.discount_amount, 110) + self.assertEqual(item.rate, 990) + def make_pricing_rule(**args): args = frappe._dict(args) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 3da54f0611f..263b5bb75e6 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -514,25 +514,9 @@ frappe.ui.form.on("Purchase Invoice", { me.frm.set_df_property("apply_tds", "read_only", 1); } - $.each(["warehouse", "rejected_warehouse"], function(i, field) { - frm.set_query(field, "items", function() { - return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] - ] - } - }) - }) - - frm.set_query("supplier_warehouse", function() { - return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] - ] - } - }) + erpnext.queries.setup_queries(frm, "Warehouse", function() { + return erpnext.queries.warehouse(frm.doc); + }); }, is_subcontracted: function(frm) { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 504d45f64ff..bd55c28dddb 100755 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -1485,6 +1486,207 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "update_stock", + "fieldname": "set_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Set Accepted Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "update_stock", + "description": "Warehouse where you are maintaining stock of rejected items", + "fieldname": "rejected_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Rejected Warehouse", + "length": 0, + "no_copy": 1, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break_warehouse", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "No", + "fieldname": "is_subcontracted", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Raw Materials Supplied", + "length": 0, + "no_copy": 0, + "options": "No\nYes", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.is_subcontracted==\"Yes\"", + "fieldname": "supplier_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplier Warehouse", + "length": 0, + "no_copy": 1, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "print_width": "50px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0, + "width": "50px" + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1551,6 +1753,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "scan_barcode", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scan Barcode", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 1, "allow_in_quick_entry": 0, @@ -1585,6 +1819,73 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": "supplied_items", + "columns": 0, + "depends_on": "", + "fieldname": "raw_materials_supplied", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Raw Materials Supplied", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "supplied_items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplied Items", + "length": 0, + "no_copy": 0, + "options": "Purchase Receipt Item Supplied", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -3723,140 +4024,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "raw_materials_supplied", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Raw Materials Supplied", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "No", - "fieldname": "is_subcontracted", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Raw Materials Supplied", - "length": 0, - "no_copy": 0, - "options": "No\nYes", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplier_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplier Warehouse", - "length": 0, - "no_copy": 1, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, - "width": "50px" - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplied_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplied Items", - "length": 0, - "no_copy": 0, - "options": "Purchase Receipt Item Supplied", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -4351,40 +4518,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Warehouse where you are maintaining stock of rejected items", - "fieldname": "rejected_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Rejected Warehouse", - "length": 0, - "no_copy": 1, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -4593,7 +4726,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-09-11 14:44:31.220376", + "modified": "2018-11-13 19:55:58.018816", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index b14597d3a09..1bb7c97b0de 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -61,11 +61,11 @@ class PurchaseInvoice(BuyingController): self.validate_posting_time() + super(PurchaseInvoice, self).validate() + # apply tax withholding only if checked and applicable self.set_tax_withholding() - super(PurchaseInvoice, self).validate() - if not self.is_return: self.po_required() self.pr_required() @@ -226,7 +226,7 @@ class PurchaseInvoice(BuyingController): item.expense_account = warehouse_account[item.warehouse]["account"] else: item.expense_account = stock_not_billed_account - + elif not item.expense_account and for_validate: throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) @@ -379,7 +379,7 @@ class PurchaseInvoice(BuyingController): return gl_entries def make_supplier_gl_entry(self, gl_entries): - # Checked both rounding_adjustment and rounded_total + # Checked both rounding_adjustment and rounded_total # because rounded_total had value even before introcution of posting GLE based on rounded total grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total @@ -839,6 +839,9 @@ class PurchaseInvoice(BuyingController): if not accounts or tax_withholding_details.get("account_head") not in accounts: self.append("taxes", tax_withholding_details) + # calculate totals again after applying TDS + self.calculate_taxes_and_totals() + @frappe.whitelist() def make_debit_note(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc @@ -856,7 +859,8 @@ def make_stock_entry(source_name, target_doc=None): "Purchase Invoice Item": { "doctype": "Stock Entry Detail", "field_map": { - "stock_qty": "transfer_qty" + "stock_qty": "transfer_qty", + "batch_no": "batch_no" }, } }, target_doc) diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index f2a5c16bad9..7348e1f8ece 100755 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -165,9 +165,12 @@ def get_items_list(pos_profile, company): select i.name, i.item_code, i.item_name, i.description, i.item_group, i.has_batch_no, i.has_serial_no, i.is_stock_item, i.brand, i.stock_uom, i.image, - id.expense_account, id.selling_cost_center, id.default_warehouse + id.expense_account, id.selling_cost_center, id.default_warehouse, + i.sales_uom, c.conversion_factor from - `tabItem` i LEFT JOIN `tabItem Default` id ON id.parent = i.name and id.company = %s + `tabItem` i + left join `tabItem Default` id on id.parent = i.name and id.company = %s + left join `tabUOM Conversion Detail` c on i.name = c.parent and i.sales_uom = c.uom where i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 {cond} @@ -534,6 +537,7 @@ def validate_item(doc): item_doc.item_name = item.get('item_name') item_doc.description = item.get('description') item_doc.stock_uom = item.get('stock_uom') + item_doc.uom = item.get('uom') item_doc.item_group = item.get('item_group') item_doc.append('item_defaults', { "company": doc.get("company"), diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index b8ea205d488..a4588b3dd82 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -939,7 +939,9 @@ var set_primary_action= function(frm, dialog, $results, invoice_healthcare_servi dialog.set_primary_action(__('Add'), function() { let checked_values = get_checked_values($results); if(checked_values.length > 0){ - frm.set_value("patient", dialog.fields_dict.patient.input.value); + if(invoice_healthcare_services) { + frm.set_value("patient", dialog.fields_dict.patient.input.value); + } frm.set_value("items", []); add_to_item_line(frm, checked_values, invoice_healthcare_services); dialog.hide(); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 4154d2ed989..09e952bd484 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -1585,6 +1586,71 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "update_stock", + "fieldname": "set_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Set Source Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1651,6 +1717,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "scan_barcode", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scan Barcode", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 1, "allow_in_quick_entry": 0, @@ -5546,7 +5644,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-09-07 14:24:58.854289", + "modified": "2018-11-12 20:01:21.289303", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 607051e50a5..6387003f018 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -662,9 +662,6 @@ class SalesInvoice(SellingController): def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company) - if not self.grand_total: - return - if not gl_entries: gl_entries = self.get_gl_entries() @@ -747,9 +744,11 @@ class SalesInvoice(SellingController): self.get_gl_dict({ "account": tax.account_head, "against": self.customer, - "credit": flt(tax.base_tax_amount_after_discount_amount), - "credit_in_account_currency": flt(tax.base_tax_amount_after_discount_amount) \ - if account_currency==self.company_currency else flt(tax.tax_amount_after_discount_amount), + "credit": flt(tax.base_tax_amount_after_discount_amount, + tax.precision("tax_amount_after_discount_amount")), + "credit_in_account_currency": (flt(tax.base_tax_amount_after_discount_amount, + tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else + flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount_after_discount_amount"))), "cost_center": tax.cost_center }, account_currency) ) @@ -757,7 +756,7 @@ class SalesInvoice(SellingController): def make_item_gl_entries(self, gl_entries): # income account gl entries for item in self.get("items"): - if flt(item.base_net_amount): + if flt(item.base_net_amount, item.precision("base_net_amount")): if item.is_fixed_asset: asset = frappe.get_doc("Asset", item.asset) @@ -774,9 +773,10 @@ class SalesInvoice(SellingController): self.get_gl_dict({ "account": item.income_account if not item.enable_deferred_revenue else item.deferred_revenue_account, "against": self.customer, - "credit": item.base_net_amount, - "credit_in_account_currency": item.base_net_amount \ - if account_currency==self.company_currency else item.net_amount, + "credit": flt(item.base_net_amount, item.precision("base_net_amount")), + "credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount")) + if account_currency==self.company_currency + else flt(item.net_amount, item.precision("net_amount"))), "cost_center": item.cost_center }, account_currency) ) @@ -875,7 +875,7 @@ class SalesInvoice(SellingController): def make_write_off_gl_entry(self, gl_entries): # write off entries, applicable if only pos - if self.write_off_account and self.write_off_amount: + if self.write_off_account and flt(self.write_off_amount, self.precision("write_off_amount")): write_off_account_currency = get_account_currency(self.write_off_account) default_cost_center = frappe.get_cached_value('Company', self.company, 'cost_center') @@ -885,10 +885,11 @@ class SalesInvoice(SellingController): "party_type": "Customer", "party": self.customer, "against": self.write_off_account, - "credit": self.base_write_off_amount, - "credit_in_account_currency": self.base_write_off_amount \ - if self.party_account_currency==self.company_currency else self.write_off_amount, - "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, + "credit": flt(self.base_write_off_amount, self.precision("base_write_off_amount")), + "credit_in_account_currency": (flt(self.base_write_off_amount, + self.precision("base_write_off_amount")) if self.party_account_currency==self.company_currency + else flt(self.write_off_amount, self.precision("write_off_amount"))), + "against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher_type": self.doctype, "cost_center": self.cost_center }, self.party_account_currency) @@ -897,15 +898,16 @@ class SalesInvoice(SellingController): self.get_gl_dict({ "account": self.write_off_account, "against": self.customer, - "debit": self.base_write_off_amount, - "debit_in_account_currency": self.base_write_off_amount \ - if write_off_account_currency==self.company_currency else self.write_off_amount, + "debit": flt(self.base_write_off_amount, self.precision("base_write_off_amount")), + "debit_in_account_currency": (flt(self.base_write_off_amount, + self.precision("base_write_off_amount")) if write_off_account_currency==self.company_currency + else flt(self.write_off_amount, self.precision("write_off_amount"))), "cost_center": self.cost_center or self.write_off_cost_center or default_cost_center }, write_off_account_currency) ) def make_gle_for_rounding_adjustment(self, gl_entries): - if self.rounding_adjustment: + if flt(self.rounding_adjustment, self.precision("rounding_adjustment")): round_off_account, round_off_cost_center = \ get_round_off_account_and_cost_center(self.company) @@ -913,8 +915,10 @@ class SalesInvoice(SellingController): self.get_gl_dict({ "account": round_off_account, "against": self.customer, - "credit_in_account_currency": self.base_rounding_adjustment, - "credit": self.base_rounding_adjustment, + "credit_in_account_currency": flt(self.rounding_adjustment, + self.precision("rounding_adjustment")), + "credit": flt(self.base_rounding_adjustment, + self.precision("base_rounding_adjustment")), "cost_center": self.cost_center or round_off_cost_center, } )) diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.py b/erpnext/accounts/doctype/share_transfer/share_transfer.py index 50ce9f2bfd8..1a1f036278d 100644 --- a/erpnext/accounts/doctype/share_transfer/share_transfer.py +++ b/erpnext/accounts/doctype/share_transfer/share_transfer.py @@ -189,7 +189,7 @@ class ShareTransfer(Document): if (shareholder == 'from_shareholder') else self.to_folio_no; doc.save() else: - if doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no): + if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no): frappe.throw(_('The folio numbers are not matching')) def autoname_folio(self, shareholder, is_company=False): diff --git a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py index 44ab09999b5..f1cf31b8205 100644 --- a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py +++ b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py @@ -79,7 +79,8 @@ class TestShareTransfer(unittest.TestCase): } ] for d in share_transfers: - frappe.get_doc(d).submit() + st = frappe.get_doc(d) + st.submit() def test_invalid_share_transfer(self): doc = frappe.get_doc({ diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 528e3d3f9cd..91f3711f8d9 100755 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -1407,6 +1407,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.child.item_code = this.items[0].item_code; this.child.item_name = this.items[0].item_name; this.child.stock_uom = this.items[0].stock_uom; + this.child.uom = this.items[0].sales_uom || this.items[0].stock_uom; + this.child.conversion_factor = this.items[0].conversion_factor || 1; this.child.brand = this.items[0].brand; this.child.description = this.items[0].description || this.items[0].item_name; this.child.discount_percentage = 0.0; @@ -1416,8 +1418,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.child.income_account = this.pos_profile_data['income_account'] || this.items[0].income_account; this.child.warehouse = (this.item_serial_no[this.child.item_code] ? this.item_serial_no[this.child.item_code][1] : (this.pos_profile_data['warehouse'] || this.items[0].default_warehouse)); - this.child.price_list_rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9); - this.child.rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9); + this.child.price_list_rate = flt(this.price_list_data[this.child.item_code] * this.child.conversion_factor, 9) / flt(this.frm.doc.conversion_rate, 9); + this.child.rate = flt(this.price_list_data[this.child.item_code] * this.child.conversion_factor, 9) / flt(this.frm.doc.conversion_rate, 9); this.child.actual_qty = me.get_actual_qty(this.items[0]); this.child.amount = flt(this.child.qty) * flt(this.child.rate); this.child.batch_no = this.item_batch_no[this.child.item_code]; @@ -1573,15 +1575,16 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ style="margin-right: 5px;">${__('Print')} ${__('New')}`); - $('.print_doc').click(function () { - var html = frappe.render(me.print_template_data, me.frm.doc) - me.print_document(html) + this.msgprint.msg_area.find('.print_doc').on('click', function() { + var html = frappe.render(me.print_template_data, me.frm.doc); + me.print_document(html); }) - $('.new_doc').click(function () { - me.msgprint.hide() - me.make_new_cart() + this.msgprint.msg_area.find('.new_doc').on('click', function() { + me.msgprint.hide(); + me.make_new_cart(); }) + }, print_document: function (html) { diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html index 2284fcd69e0..dfcf64c7972 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html @@ -75,7 +75,7 @@ {%= format_currency(balance_row[range3]) %} {%= format_currency(balance_row[range4]) %} - {%= format_currency(flt(balance_row[__("Outstanding Amount")]), data[data.length-1]["currency"]) %} + {%= format_currency(flt(balance_row[("outstanding_amount")]), data[data.length-1]["currency"]) %} {%= __("PDC/LC") %} @@ -84,7 +84,7 @@ - {%= format_currency(flt(balance_row[__("PDC/LC Amount")]), data[data.length-1]["currency"]) %} + {%= format_currency(flt(balance_row[("pdc/lc_amount")]), data[data.length-1]["currency"]) %} {%= __("Cheques Required") %} @@ -93,7 +93,7 @@ - {%= format_currency(flt(balance_row[__("Outstanding Amount")]-balance_row[__("PDC/LC Amount")]), data[data.length-1]["currency"]) %} + {%= format_currency(flt(balance_row[("outstanding_amount")]-balance_row[("pdc/lc_amount")]), data[data.length-1]["currency"]) %} @@ -177,10 +177,10 @@ {%= data[i]["po_no"] %} {% } %} - {%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %} - {%= data[i][__("PDC/LC Ref")] %} - {%= format_currency(data[i][__("PDC/LC Amount")], data[i]["currency"]) %} - {%= format_currency(data[i][__("Remaining Balance")], data[i]["currency"]) %} + {%= frappe.datetime.str_to_user(data[i][("pdc/lc_date")]) %} + {%= data[i][("pdc/lc_ref")] %} + {%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %} + {%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %} {% } %} {% } else { %} @@ -205,9 +205,9 @@ {%= data[i][__("Customer LPO")] %} {% } %} {%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %} - {%= data[i][__("PDC/LC Ref")] %} - {%= format_currency(data[i][__("PDC/LC Amount")], data[i]["currency"]) %} - {%= format_currency(data[i][__("Remaining Balance")], data[i]["currency"]) %} + {%= data[i][("pdc/lc_ref")] %} + {%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %} + {%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %} {% } %} {% } %} {% } else { %} @@ -228,10 +228,10 @@ {% } else { %} {%= __("Total") %} {% } %} - {%= format_currency(data[i][__("Total Invoiced Amt")], data[i]["currency"]) %} - {%= format_currency(data[i][__("Total Paid Amt")], data[i]["currency"]) %} - {%= report.report_name === "Accounts Receivable Summary" ? format_currency(data[i][__("Credit Note Amt")], data[i]["currency"]) : format_currency(data[i][__("Debit Note Amt")], data[i]["currency"]) %} - {%= format_currency(data[i][__("Total Outstanding Amt")], data[i]["currency"]) %} + {%= format_currency(data[i][("total_invoiced_amt")], data[i]["currency"]) %} + {%= format_currency(data[i][("total_paid_amt")], data[i]["currency"]) %} + {%= report.report_name === "Accounts Receivable Summary" ? format_currency(data[i][__("credit_note_amt")], data[i]["currency"]) : format_currency(data[i][__("debit_note_amt")], data[i]["currency"]) %} + {%= format_currency(data[i][("total_outstanding_amt")], data[i]["currency"]) %} {% } %} {% } %} diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 6bdafd7abf6..572f81dc35e 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -89,20 +89,40 @@ class ReceivablePayableReport(object): "width": 120 }) - columns.append({ + columns += [ + { "fieldname": "currency", "label": _("Currency"), "fieldtype": "Link", "options": "Currency", "width": 100 - }) - - columns += [ - _("PDC/LC Date") + ":Date:110", - _("PDC/LC Ref") + ":Data:110", - _("PDC/LC Amount") + ":Currency/currency:130", - _("Remaining Balance") + ":Currency/currency:130" - ] + }, + { + "fieldname": "pdc/lc_date", + "label": _("PDC/LC Date"), + "fieldtype": "Date", + "width": 110 + }, + { + "fieldname": "pdc/lc_ref", + "label": _("PDC/LC Ref"), + "fieldtype": "Data", + "width": 110 + }, + { + "fieldname": "pdc/lc_amount", + "label": _("PDC/LC Amount"), + "fieldtype": "Currency", + "options": "Currency", + "width": 130 + }, + { + "fieldname": "remaining_balance", + "label": _("Remaining Balance"), + "fieldtype": "Currency", + "options": "Currency", + "width": 130 + }] if args.get('party_type') == 'Customer': columns.append({ @@ -140,7 +160,6 @@ class ReceivablePayableReport(object): data = [] pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date) - gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type")) if gl_entries_data: @@ -464,7 +483,6 @@ def get_pdc_details(party_type, report_date): and pent.party_type = %s group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1): pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc) - if scrub(party_type): amount_field = ("jea.debit_in_account_currency" if party_type == 'Supplier' else "jea.credit_in_account_currency") diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index c56ae0d9ff5..7b0072cd152 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe import _ +from frappe import _, scrub from frappe.utils import flt from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport @@ -21,24 +21,92 @@ class AccountsReceivableSummary(ReceivablePayableReport): if party_naming_by == "Naming Series": columns += [ args.get("party_type") + " Name::140"] - credit_debit_label = _("Credit Note Amt") if args.get('party_type') == 'Customer' else _("Debit Note Amt") + credit_debit_label = "Credit Note Amt" if args.get('party_type') == 'Customer' else "Debit Note Amt" + + columns += [{ + "label": _("Total Invoiced Amt"), + "fieldname": "total_invoiced_amt", + "fieldtype": "Currency", + "options": "currency", + "width": 100 + }, + { + "label": _("Total Paid Amt"), + "fieldname": "total_paid_amt", + "fieldtype": "Currency", + "options": "currency", + "width": 100 + }] + columns += [ - _("Total Invoiced Amt") + ":Currency/currency:140", - _("Total Paid Amt") + ":Currency/currency:140", - credit_debit_label + ":Currency/currency:140", - _("Total Outstanding Amt") + ":Currency/currency:160", - "0-" + str(self.filters.range1) + ":Currency/currency:100", - str(self.filters.range1) + "-" + str(self.filters.range2) + ":Currency/currency:100", - str(self.filters.range2) + "-" + str(self.filters.range3) + ":Currency/currency:100", - str(self.filters.range3) + _("-Above") + ":Currency/currency:100"] + { + "label": _(credit_debit_label), + "fieldname": scrub(credit_debit_label), + "fieldtype": "Currency", + "options": "currency", + "width": 140 + }, + { + "label": _("Total Outstanding Amt"), + "fieldname": "total_outstanding_amt", + "fieldtype": "Currency", + "options": "currency", + "width": 160 + }, + { + "label": _("0-" + str(self.filters.range1)), + "fieldname": scrub("0-" + str(self.filters.range1)), + "fieldtype": "Currency", + "options": "currency", + "width": 160 + }, + { + "label": _(str(self.filters.range1) + "-" + str(self.filters.range2)), + "fieldname": scrub(str(self.filters.range1) + "-" + str(self.filters.range2)), + "fieldtype": "Currency", + "options": "currency", + "width": 160 + }, + { + "label": _(str(self.filters.range2) + "-" + str(self.filters.range3)), + "fieldname": scrub(str(self.filters.range2) + "-" + str(self.filters.range3)), + "fieldtype": "Currency", + "options": "currency", + "width": 160 + }, + { + "label": _(str(self.filters.range3) + _("-Above")), + "fieldname": scrub(str(self.filters.range3) + _("-Above")), + "fieldtype": "Currency", + "options": "currency", + "width": 160 + } + ] if args.get("party_type") == "Customer": - columns += [ - _("Territory") + ":Link/Territory:80", - _("Customer Group") + ":Link/Customer Group:120" - ] + columns += [{ + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Link", + "options": "Territory", + "width": 80 + }, + { + "label": _("Customer Group"), + "fieldname": "customer_group", + "fieldtype": "Link", + "options": "Customer Group", + "width": 80 + }] + if args.get("party_type") == "Supplier": - columns += [_("Supplier Group") + ":Link/Supplier Group:80"] + columns += [{ + "label": _("Supplier Group"), + "fieldname": "supplier_group", + "fieldtype": "Link", + "options": "Supplier Group", + "width": 80 + }] columns.append({ "fieldname": "currency", diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js index 91a06f4a406..7b373f0d9ae 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js @@ -42,6 +42,13 @@ frappe.query_reports["Consolidated Financial Statement"] = { "default": "Balance Sheet", "reqd": 1 }, + { + "fieldname": "presentation_currency", + "label": __("Currency"), + "fieldtype": "Select", + "options": erpnext.get_presentation_currency_list(), + "default": frappe.defaults.get_user_default("Currency") + }, { "fieldname":"accumulated_in_group_company", "label": __("Accumulated Values in Group Company"), diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index 2d134694f27..b9aebd83f93 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe, erpnext from frappe import _ from frappe.utils import flt, cint +from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss, check_opening_balance, get_chart_data) @@ -48,7 +49,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): data.extend(liability or []) data.extend(equity or []) - company_currency = frappe.db.get_value("Company", filters.company, "default_currency") + company_currency = get_company_currency(filters) provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity, companies, filters.get('company'), company_currency, True) @@ -59,7 +60,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): "account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'", "account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'", "warn_if_negative": True, - "currency": frappe.get_cached_value('Company', filters.company, "default_currency") + "currency": company_currency } for company in companies: unclosed[company] = opening_balance @@ -92,7 +93,7 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters): return data, None, chart def get_income_expense_data(companies, fiscal_year, filters): - company_currency = frappe.get_cached_value('Company', filters.company, "default_currency") + company_currency = get_company_currency(filters) income = get_data(companies, "Income", "Credit", fiscal_year, filters, True) expense = get_data(companies, "Expense", "Debit", fiscal_year, filters, True) @@ -107,7 +108,7 @@ def get_cash_flow_data(fiscal_year, companies, filters): income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) data = [] - company_currency = frappe.get_cached_value('Company', filters.company, "default_currency") + company_currency = get_company_currency(filters) for cash_flow_account in cash_flow_accounts: section_data = [] @@ -185,6 +186,7 @@ def get_columns(companies): "fieldname": company, "label": company, "fieldtype": "Currency", + "options": "currency", "width": 150 }) @@ -216,7 +218,8 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i return out def get_company_currency(filters=None): - return frappe.get_cached_value('Company', filters.get('company'), "default_currency") + return (filters.get('presentation_currency') + or frappe.get_cached_value('Company', filters.company, "default_currency")) def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters): for entries in gl_entries_by_account.values(): @@ -328,28 +331,42 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g filters.get('company'), ["lft", "rgt"]) additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters) - - gl_entries = frappe.db.sql("""select gl.posting_date, gl.account, gl.debit, gl.credit, gl.is_opening, gl.company, - gl.fiscal_year, gl.debit_in_account_currency, gl.credit_in_account_currency, gl.account_currency, - acc.account_name, acc.account_number - from `tabGL Entry` gl, `tabAccount` acc where acc.name = gl.account and gl.company in - (select name from `tabCompany` where lft >= %(company_lft)s and rgt <= %(company_rgt)s) - {additional_conditions} and gl.posting_date <= %(to_date)s and acc.lft >= %(lft)s and acc.rgt <= %(rgt)s - order by gl.account, gl.posting_date""".format(additional_conditions=additional_conditions), - { - "from_date": from_date, - "to_date": to_date, - "lft": root_lft, - "rgt": root_rgt, + companies = frappe.db.sql(""" select name, default_currency from `tabCompany` + where lft >= %(company_lft)s and rgt <= %(company_rgt)s""", { "company_lft": company_lft, "company_rgt": company_rgt, - }, - as_dict=True) + }, as_dict=1) - for entry in gl_entries: - key = entry.account_number or entry.account_name - validate_entries(key, entry, accounts_by_name) - gl_entries_by_account.setdefault(key, []).append(entry) + currency_info = frappe._dict({ + 'report_date': to_date, + 'presentation_currency': filters.get('presentation_currency') + }) + + for d in companies: + gl_entries = frappe.db.sql("""select gl.posting_date, gl.account, gl.debit, gl.credit, gl.is_opening, gl.company, + gl.fiscal_year, gl.debit_in_account_currency, gl.credit_in_account_currency, gl.account_currency, + acc.account_name, acc.account_number + from `tabGL Entry` gl, `tabAccount` acc where acc.name = gl.account and gl.company = %(company)s + {additional_conditions} and gl.posting_date <= %(to_date)s and acc.lft >= %(lft)s and acc.rgt <= %(rgt)s + order by gl.account, gl.posting_date""".format(additional_conditions=additional_conditions), + { + "from_date": from_date, + "to_date": to_date, + "lft": root_lft, + "rgt": root_rgt, + "company": d.name + }, + as_dict=True) + + if filters and filters.get('presentation_currency') != d.default_currency: + currency_info['company'] = d.name + currency_info['company_currency'] = d.default_currency + convert_to_presentation_currency(gl_entries, currency_info) + + for entry in gl_entries: + key = entry.account_number or entry.account_name + validate_entries(key, entry, accounts_by_name) + gl_entries_by_account.setdefault(key, []).append(entry) return gl_entries_by_account diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 937911f4836..db733dd1e10 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -1,7 +1,9 @@ +# -*- coding: utf-8 -*- + # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt - +from __future__ import unicode_literals import re from past.builtins import cmp @@ -379,8 +381,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters): if filters: if filters.get("project"): if not isinstance(filters.get("project"), list): - projects = str(filters.get("project")).strip() - filters.project = [d.strip() for d in projects.split(',') if d] + projects = frappe.safe_encode(filters.get("project")) + filters.project = [d.strip() for d in projects.strip().split(',') if d] additional_conditions.append("project in %(project)s") if filters.get("cost_center"): @@ -400,7 +402,7 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters): def get_cost_centers_with_children(cost_centers): if not isinstance(cost_centers, list): - cost_centers = [d.strip() for d in str(cost_centers).strip().split(',') if d] + cost_centers = [d.strip() for d in cost_centers.strip().split(',') if d] all_cost_centers = [] for d in cost_centers: diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index 602e671ba62..2826760dd89 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -196,8 +196,9 @@ frappe.query_reports["General Ledger"] = { "fieldname":"group_by", "label": __("Group by"), "fieldtype": "Select", - "options": ["", "Group by Voucher", "Group by Account", "Group by Party"], - "default": "Group by Voucher" + "options": ["", __("Group by Voucher"), __("Group by Voucher (Consolidated)"), + __("Group by Account"), __("Group by Party")], + "default": __("Group by Voucher (Consolidated)") }, { "fieldname":"tax_id", diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 56663d37c4b..7e50d9be61d 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -48,11 +48,12 @@ def validate_filters(filters, account_details): if filters.get("account") and not account_details.get(filters.account): frappe.throw(_("Account {0} does not exists").format(filters.account)) - if (filters.get("account") and filters.get("group_by") == 'Group by Account' + if (filters.get("account") and filters.get("group_by") == _('Group by Account') and account_details[filters.account].is_group == 0): frappe.throw(_("Can not filter based on Account, if grouped by Account")) - if (filters.get("voucher_no") and filters.get("group_by") == 'Group by Voucher'): + if (filters.get("voucher_no") + and filters.get("group_by") in [_('Group by Voucher'), _('Group by Voucher (Consolidated)')]): frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher")) if filters.from_date > filters.to_date: @@ -114,30 +115,37 @@ def get_result(filters, account_details): return result - def get_gl_entries(filters): currency_map = get_currency(filters) - select_fields = """, debit_in_account_currency, - credit_in_account_currency""" \ + select_fields = """, debit, credit, debit_in_account_currency, + credit_in_account_currency """ - order_by_fields = "posting_date, account" - if filters.get("group_by") == "Group by Voucher": - order_by_fields = "posting_date, voucher_type, voucher_no" + group_by_statement = '' + order_by_statement = "order by posting_date, account" + + if filters.get("group_by") == _("Group by Voucher"): + order_by_statement = "order by posting_date, voucher_type, voucher_no" + + if filters.get("group_by") == _("Group by Voucher (Consolidated)"): + group_by_statement = "group by voucher_type, voucher_no, account, cost_center" + select_fields = """, sum(debit) as debit, sum(credit) as credit, + sum(debit_in_account_currency) as debit_in_account_currency, + sum(credit_in_account_currency) as credit_in_account_currency""" gl_entries = frappe.db.sql( """ select posting_date, account, party_type, party, - debit, credit, voucher_type, voucher_no, cost_center, project, against_voucher_type, against_voucher, account_currency, remarks, against, is_opening {select_fields} from `tabGL Entry` - where company=%(company)s {conditions} - order by {order_by_fields} + where company=%(company)s {conditions} {group_by_statement} + {order_by_statement} """.format( select_fields=select_fields, conditions=get_conditions(filters), - order_by_fields=order_by_fields + group_by_statement=group_by_statement, + order_by_statement=order_by_statement ), filters, as_dict=1) @@ -204,13 +212,13 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): # Opening for filtered account data.append(totals.opening) - if filters.get("group_by"): + if filters.get("group_by") != _('Group by Voucher (Consolidated)'): for acc, acc_dict in iteritems(gle_map): # acc if acc_dict.entries: # opening data.append({}) - if filters.get("group_by") != "Group by Voucher": + if filters.get("group_by") != _("Group by Voucher"): data.append(acc_dict.totals.opening) data += acc_dict.entries @@ -219,10 +227,9 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): data.append(acc_dict.totals.total) # closing - if filters.get("group_by") != "Group by Voucher": + if filters.get("group_by") != _("Group by Voucher"): data.append(acc_dict.totals.closing) data.append({}) - else: data += entries @@ -234,7 +241,6 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): return data - def get_totals_dict(): def _get_debit_credit_dict(label): return _dict( @@ -251,12 +257,12 @@ def get_totals_dict(): ) def group_by_field(group_by): - if group_by == 'Group by Party': + if group_by == _('Group by Party'): return 'party' - elif group_by == 'Group by Voucher': - return 'voucher_no' - else: + elif group_by in [_('Group by Voucher (Consolidated)'), _('Group by Account')]: return 'account' + else: + return 'voucher_no' def initialize_gle_map(gl_entries, filters): gle_map = frappe._dict() @@ -291,7 +297,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map): elif gle.posting_date <= to_date: update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle) update_value_in_dict(totals, 'total', gle) - if filters.get("group_by"): + if filters.get("group_by") != _('Group by Voucher (Consolidated)'): gle_map[gle.get(group_by)].entries.append(gle) else: entries.append(gle) @@ -301,7 +307,6 @@ def get_accountwise_gle(filters, gl_entries, gle_map): return totals, entries - def get_result_as_list(data, filters): balance, balance_in_account_currency = 0, 0 inv_details = get_supplier_invoice_details() diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 19075d35ae7..2ed664c9bf7 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -236,7 +236,7 @@ class GrossProfitGenerator(object): previous_stock_value = len(my_sle) > i+1 and \ flt(my_sle[i+1].stock_value) or 0.0 if previous_stock_value: - return previous_stock_value - flt(sle.stock_value) + return (previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty)) else: return flt(row.qty) * self.get_average_buying_rate(row, item_code) else: diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index c95c8df1c01..88c612e7f6c 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -55,7 +55,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum ] row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \ - if d.stock_uom != d.uom else [d.base_net_rate, d.base_net_amount] + if d.stock_uom != d.uom and d.stock_qty != 0 else [d.base_net_rate, d.base_net_amount] total_tax = 0 for tax in tax_columns: diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 0a3f56ab8ec..07dcd4e7a94 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -231,6 +231,13 @@ def get_columns(): "options": "Account", "width": 300 }, + { + "fieldname": "currency", + "label": _("Currency"), + "fieldtype": "Link", + "options": "Currency", + "hidden": 1 + }, { "fieldname": "opening_debit", "label": _("Opening (Dr)"), @@ -272,13 +279,6 @@ def get_columns(): "fieldtype": "Currency", "options": "currency", "width": 120 - }, - { - "fieldname": "currency", - "label": _("Currency"), - "fieldtype": "Link", - "options": "Currency", - "hidden": 1 } ] diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py index 2508a1f4c2a..bd2c34b3b4c 100644 --- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py +++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py @@ -21,6 +21,8 @@ def get_data(filters, show_party_name): party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type'))) if filters.get('party_type') == 'Student': party_name_field = 'first_name' + elif filters.get('party_type') == 'Shareholder': + party_name_field = 'title' party_filters = {"name": filters.get("party")} if filters.get("party") else {} parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field], diff --git a/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.json b/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.json index 26d5e9ca673..bb5e4d9108b 100644 --- a/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.json +++ b/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "unique": 0 + "translatable": 0, + "unique": 1 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -102,6 +108,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -115,7 +122,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-25 22:26:28.797375", + "modified": "2018-11-04 03:27:36.678832", "modified_by": "Administrator", "module": "Agriculture", "name": "Agriculture Analysis Criteria", @@ -124,7 +131,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -144,7 +150,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -166,10 +171,12 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "title_field": "", "track_changes": 1, - "track_seen": 0 -} + "track_seen": 0, + "track_views": 0 +} \ No newline at end of file diff --git a/erpnext/agriculture/doctype/agriculture_task/agriculture_task.json b/erpnext/agriculture/doctype/agriculture_task/agriculture_task.json index c06c085c734..d943d771676 100644 --- a/erpnext/agriculture/doctype/agriculture_task/agriculture_task.json +++ b/erpnext/agriculture/doctype/agriculture_task/agriculture_task.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -191,7 +192,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-21 16:15:48.528845", + "modified": "2018-11-04 03:28:08.679157", "modified_by": "Administrator", "module": "Agriculture", "name": "Agriculture Task", @@ -201,6 +202,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/agriculture/doctype/crop/crop.json b/erpnext/agriculture/doctype/crop/crop.json index 8e6807f6fbb..e357abb98b1 100644 --- a/erpnext/agriculture/doctype/crop/crop.json +++ b/erpnext/agriculture/doctype/crop/crop.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 0 + "translatable": 0, + "unique": 1 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -70,10 +74,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -100,10 +106,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -129,10 +137,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -159,10 +169,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -190,10 +202,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -221,10 +235,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -252,10 +268,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -281,10 +299,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -311,10 +331,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -342,10 +364,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -371,10 +395,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -401,10 +427,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -432,10 +460,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -461,10 +491,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -492,10 +524,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -521,10 +555,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -551,10 +587,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -580,10 +618,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -611,10 +651,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -640,10 +682,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -671,10 +715,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -701,10 +747,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -730,10 +778,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -761,10 +811,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -790,10 +842,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -820,10 +874,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -851,10 +907,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -881,10 +939,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -912,10 +972,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -942,10 +1004,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -973,6 +1037,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -986,7 +1051,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-06 11:00:06.333894", + "modified": "2018-11-04 03:27:10.651075", "modified_by": "Administrator", "module": "Agriculture", "name": "Crop", @@ -995,7 +1060,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1015,7 +1079,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -1037,9 +1100,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json index 18a3b8c6bb6..a0767189195 100644 --- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json +++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -844,7 +845,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-06-20 04:41:36.148829", + "modified": "2018-11-04 03:31:47.602312", "modified_by": "Administrator", "module": "Agriculture", "name": "Crop Cycle", @@ -893,9 +894,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/detected_disease/detected_disease.json b/erpnext/agriculture/doctype/detected_disease/detected_disease.json index bfed9a755c7..f670cd31b80 100644 --- a/erpnext/agriculture/doctype/detected_disease/detected_disease.json +++ b/erpnext/agriculture/doctype/detected_disease/detected_disease.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -121,7 +122,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-06-06 02:24:52.131482", + "modified": "2018-11-04 03:27:47.463994", "modified_by": "Administrator", "module": "Agriculture", "name": "Detected Disease", @@ -131,9 +132,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/disease/disease.json b/erpnext/agriculture/doctype/disease/disease.json index 9294cc75543..16b735a6607 100644 --- a/erpnext/agriculture/doctype/disease/disease.json +++ b/erpnext/agriculture/doctype/disease/disease.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 0 + "translatable": 0, + "unique": 1 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -100,10 +106,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,10 +139,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -161,10 +171,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -191,10 +203,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -221,6 +235,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -234,7 +249,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-07 16:24:22.923154", + "modified": "2018-11-04 03:27:25.076490", "modified_by": "Administrator", "module": "Agriculture", "name": "Disease", @@ -243,7 +258,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -263,7 +277,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -285,9 +298,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/fertilizer/fertilizer.json b/erpnext/agriculture/doctype/fertilizer/fertilizer.json index b2a1b81294d..6a1877344b4 100644 --- a/erpnext/agriculture/doctype/fertilizer/fertilizer.json +++ b/erpnext/agriculture/doctype/fertilizer/fertilizer.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 0 + "translatable": 0, + "unique": 1 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,10 +76,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,10 +139,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -160,10 +170,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -190,10 +202,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -220,6 +234,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -233,7 +248,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-05 19:13:42.471667", + "modified": "2018-11-04 03:26:29.211792", "modified_by": "Administrator", "module": "Agriculture", "name": "Fertilizer", @@ -242,7 +257,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -262,7 +276,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -284,9 +297,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/linked_location/linked_location.json b/erpnext/agriculture/doctype/linked_location/linked_location.json index 56a29d52003..a14ae3d5c4e 100644 --- a/erpnext/agriculture/doctype/linked_location/linked_location.json +++ b/erpnext/agriculture/doctype/linked_location/linked_location.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -56,7 +57,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-06-20 04:35:51.675244", + "modified": "2018-11-04 03:27:58.120962", "modified_by": "Administrator", "module": "Agriculture", "name": "Linked Location", @@ -66,9 +67,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.json b/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.json index e136d611359..57d2aab7b29 100644 --- a/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.json +++ b/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,6 +43,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -54,7 +57,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-04 13:25:30.437597", + "modified": "2018-11-04 03:25:15.359130", "modified_by": "Administrator", "module": "Agriculture", "name": "Linked Plant Analysis", @@ -64,9 +67,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.json b/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.json index a248ed0218d..38e5030d854 100644 --- a/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.json +++ b/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,6 +43,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -54,7 +57,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-04 13:26:18.682109", + "modified": "2018-11-04 03:25:27.670079", "modified_by": "Administrator", "module": "Agriculture", "name": "Linked Soil Analysis", @@ -64,9 +67,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.json b/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.json index 5df18129ef4..80682b07a5b 100644 --- a/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.json +++ b/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,6 +43,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -54,7 +57,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-04 13:26:07.773314", + "modified": "2018-11-04 03:26:17.877616", "modified_by": "Administrator", "module": "Agriculture", "name": "Linked Soil Texture", @@ -64,9 +67,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/plant_analysis/plant_analysis.json b/erpnext/agriculture/doctype/plant_analysis/plant_analysis.json index 4f97dc0c7bd..ceb1a5ba5f1 100644 --- a/erpnext/agriculture/doctype/plant_analysis/plant_analysis.json +++ b/erpnext/agriculture/doctype/plant_analysis/plant_analysis.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -312,7 +313,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:40.027967", + "modified": "2018-11-04 03:28:48.087828", "modified_by": "Administrator", "module": "Agriculture", "name": "Plant Analysis", @@ -361,6 +362,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.json b/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.json index 9b07a8a1f1b..eefc5ee1abb 100644 --- a/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.json +++ b/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +139,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -144,7 +153,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-05 19:37:02.289320", + "modified": "2018-11-04 03:25:43.714882", "modified_by": "Administrator", "module": "Agriculture", "name": "Plant Analysis Criteria", @@ -154,9 +163,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/soil_analysis/soil_analysis.json b/erpnext/agriculture/doctype/soil_analysis/soil_analysis.json index 7497c13ba7d..59680fab99f 100644 --- a/erpnext/agriculture/doctype/soil_analysis/soil_analysis.json +++ b/erpnext/agriculture/doctype/soil_analysis/soil_analysis.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -533,7 +534,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:56.754373", + "modified": "2018-11-04 03:28:58.403760", "modified_by": "Administrator", "module": "Agriculture", "name": "Soil Analysis", @@ -582,6 +583,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.json b/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.json index d2627e42452..860e48aa50f 100644 --- a/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.json +++ b/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +139,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -144,7 +153,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-05 23:35:34.569482", + "modified": "2018-11-04 03:25:54.359008", "modified_by": "Administrator", "module": "Agriculture", "name": "Soil Analysis Criteria", @@ -154,9 +163,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/soil_texture/soil_texture.json b/erpnext/agriculture/doctype/soil_texture/soil_texture.json index 52727c719ff..f78c262be49 100644 --- a/erpnext/agriculture/doctype/soil_texture/soil_texture.json +++ b/erpnext/agriculture/doctype/soil_texture/soil_texture.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -473,7 +474,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:41.823722", + "modified": "2018-11-04 03:29:18.221173", "modified_by": "Administrator", "module": "Agriculture", "name": "Soil Texture", @@ -522,6 +523,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.json b/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.json index e48a34b35bf..0cd72b0f6ec 100644 --- a/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.json +++ b/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +139,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -144,7 +153,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-05 23:45:17.419610", + "modified": "2018-11-04 03:26:46.178377", "modified_by": "Administrator", "module": "Agriculture", "name": "Soil Texture Criteria", @@ -154,9 +163,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/water_analysis/water_analysis.json b/erpnext/agriculture/doctype/water_analysis/water_analysis.json index 5983601ced3..f990fef997a 100644 --- a/erpnext/agriculture/doctype/water_analysis/water_analysis.json +++ b/erpnext/agriculture/doctype/water_analysis/water_analysis.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -534,7 +535,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:52.416815", + "modified": "2018-11-04 03:29:08.325644", "modified_by": "Administrator", "module": "Agriculture", "name": "Water Analysis", @@ -583,6 +584,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.json b/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.json index 395669a2b0b..be9f1beffee 100644 --- a/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.json +++ b/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +139,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -144,7 +153,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-05 23:36:45.836858", + "modified": "2018-11-04 03:26:07.026834", "modified_by": "Administrator", "module": "Agriculture", "name": "Water Analysis Criteria", @@ -154,9 +163,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/weather/weather.json b/erpnext/agriculture/doctype/weather/weather.json index 8f54957cec0..ebab78ad720 100644 --- a/erpnext/agriculture/doctype/weather/weather.json +++ b/erpnext/agriculture/doctype/weather/weather.json @@ -1,9 +1,10 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, - "autoname": "field:date", + "autoname": "format:WEA-{date}-{location}", "beta": 0, "creation": "2017-10-17 19:01:05.095598", "custom": 0, @@ -15,12 +16,13 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "source", - "fieldtype": "Data", + "fieldname": "location", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -28,9 +30,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Source", + "label": "Location", "length": 0, "no_copy": 0, + "options": "Location", "permlevel": 0, "precision": "", "print_hide": 0, @@ -41,10 +44,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -70,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -100,10 +107,44 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "source", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Source", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -129,10 +170,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -159,10 +202,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -189,6 +234,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -202,7 +248,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-06 11:04:36.977755", + "modified": "2018-11-04 03:31:36.839743", "modified_by": "Administrator", "module": "Agriculture", "name": "Weather", @@ -211,7 +257,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -231,7 +276,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -253,9 +297,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/agriculture/doctype/weather_parameter/weather_parameter.json b/erpnext/agriculture/doctype/weather_parameter/weather_parameter.json index 724ead95700..45c4cfc4f5f 100644 --- a/erpnext/agriculture/doctype/weather_parameter/weather_parameter.json +++ b/erpnext/agriculture/doctype/weather_parameter/weather_parameter.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +139,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -144,7 +153,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-06 00:26:48.887975", + "modified": "2018-11-04 03:26:58.794373", "modified_by": "Administrator", "module": "Agriculture", "name": "Weather Parameter", @@ -154,9 +163,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Agriculture", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 69977767017..a38b40bc60b 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -85,8 +85,17 @@ class Asset(AccountsController): elif not self.finance_books: frappe.throw(_("Enter depreciation details")) - if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(nowdate()): - frappe.throw(_("Available-for-use Date is entered as past date")) + if self.is_existing_asset: + return + + date = nowdate() + docname = self.purchase_receipt or self.purchase_invoice + if docname: + doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' + date = frappe.db.get_value(doctype, docname, 'posting_date') + + if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(date): + frappe.throw(_("Available-for-use Date should be after purchase date")) def make_depreciation_schedule(self): if self.depreciation_method != 'Manual': diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js index 29909f8bb94..a6e6974c48d 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js @@ -13,7 +13,11 @@ frappe.ui.form.on('Asset Value Adjustment', { } }); }, - + onload: function(frm) { + if(frm.is_new() && frm.doc.asset) { + frm.trigger("set_current_asset_value"); + } + }, asset: function(frm) { frm.trigger("set_current_asset_value"); }, diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 601af690928..c6f4fcc50c5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -180,39 +181,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "No", - "fieldname": "is_subcontracted", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Supply Raw Materials", - "length": 0, - "no_copy": 0, - "options": "No\nYes", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -246,40 +214,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_subcontracted==\"Yes\"", - "fieldname": "supplier_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplier Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1353,6 +1287,168 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "set_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Set Target Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break_warehouse", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "No", + "fieldname": "is_subcontracted", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Supply Raw Materials", + "length": 0, + "no_copy": 0, + "options": "No\nYes", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.is_subcontracted==\"Yes\"", + "fieldname": "supplier_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplier Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1386,6 +1482,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "scan_barcode", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scan Barcode", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 1, "allow_in_quick_entry": 0, @@ -1420,6 +1548,74 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": "supplied_items", + "columns": 0, + "fieldname": "raw_material_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Raw Materials Supplied", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "supplied_items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplied Items", + "length": 0, + "no_copy": 0, + "oldfieldname": "po_raw_material_details", + "oldfieldtype": "Table", + "options": "Purchase Order Item Supplied", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -3428,107 +3624,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "collapsible_depends_on": "supplied_items", - "columns": 0, - "fieldname": "raw_material_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Raw Materials Supplied", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_subcontracted", - "fieldname": "supplied_items_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplied Items", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "supplied_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplied Items", - "length": 0, - "no_copy": 0, - "oldfieldname": "po_raw_material_details", - "oldfieldtype": "Table", - "options": "Purchase Order Item Supplied", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -3736,8 +3831,8 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-29 12:16:12.886021", - "modified_by": "nabinhait@gmail.com", + "modified": "2018-11-12 19:59:49.211145", + "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", "owner": "Administrator", diff --git a/erpnext/buying/report/purchase_analytics/__init__.py b/erpnext/buying/report/purchase_analytics/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.js b/erpnext/buying/report/purchase_analytics/purchase_analytics.js new file mode 100644 index 00000000000..297ec51cb13 --- /dev/null +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.js @@ -0,0 +1,128 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Purchase Analytics"] = { + "filters": [ + { + fieldname: "tree_type", + label: __("Tree Type"), + fieldtype: "Select", + options: ["Supplier Group","Supplier","Item Group","Item"], + default: "Supplier", + reqd: 1 + }, + { + fieldname: "doc_type", + label: __("based_on"), + fieldtype: "Select", + options: ["Purchase Order","Purchase Receipt","Purchase Invoice"], + default: "Purchase Invoice", + reqd: 1 + }, + { + fieldname: "value_quantity", + label: __("Value Or Qty"), + fieldtype: "Select", + options: [ + { "value": "Value", "label": __("Value") }, + { "value": "Quantity", "label": __("Quantity") }, + ], + default: "Value", + reqd: 1 + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + default: frappe.defaults.get_user_default("year_start_date"), + reqd: 1 + }, + { + fieldname:"to_date", + label: __("To Date"), + fieldtype: "Date", + default: frappe.defaults.get_user_default("year_end_date"), + reqd: 1 + }, + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company"), + reqd: 1 + }, + { + fieldname: "range", + label: __("Range"), + fieldtype: "Select", + options: [ + { "value": "Weekly", "label": __("Weekly") }, + { "value": "Monthly", "label": __("Monthly") }, + { "value": "Quarterly", "label": __("Quarterly") }, + { "value": "Yearly", "label": __("Yearly") } + ], + default: "Monthly", + reqd: 1 + } + + ], + "formatter": function(value, row, column, data) { + if(!value){ + value = 0 + } + return value; + }, + get_datatable_options(options) { + return Object.assign(options, { + checkboxColumn: true, + events: { + onCheckRow: function(data) { + row_name = data[2].content; + row_values = data.slice(5).map(function (column) { + return column.content; + }) + + entry = { + 'name':row_name, + 'values':row_values + } + + let raw_data = frappe.query_report.chart.data; + let new_datasets = raw_data.datasets; + + var found = false; + + for(var i=0; i < new_datasets.length;i++){ + if(new_datasets[i].name == row_name){ + found = true; + new_datasets.splice(i,1); + break; + } + } + + if(!found){ + new_datasets.push(entry); + } + + let new_data = { + labels: raw_data.labels, + datasets: new_datasets + } + + setTimeout(() => { + frappe.query_report.chart.update(new_data) + },200) + + + setTimeout(() => { + frappe.query_report.chart.draw(true); + }, 800) + + frappe.query_report.raw_chart_data = new_data; + }, + } + }) + }, +} diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.json b/erpnext/buying/report/purchase_analytics/purchase_analytics.json new file mode 100644 index 00000000000..996e3eef457 --- /dev/null +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.json @@ -0,0 +1,26 @@ +{ + "add_total_row": 0, + "creation": "2018-10-05 16:08:24.156448", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2018-10-05 16:08:33.272201", + "modified_by": "Administrator", + "module": "Buying", + "name": "Purchase Analytics", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Purchase Order", + "report_name": "Purchase Analytics", + "report_type": "Script Report", + "roles": [ + { + "role": "Purchase Manager" + }, + { + "role": "Purchase User" + } + ] +} \ No newline at end of file diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.py b/erpnext/buying/report/purchase_analytics/purchase_analytics.py new file mode 100644 index 00000000000..0f949477b1c --- /dev/null +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.py @@ -0,0 +1,8 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from erpnext.selling.report.sales_analytics.sales_analytics import Analytics + +def execute(filters=None): + return Analytics(filters).run() diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py index 270519e4e8c..e99b1d88aa5 100644 --- a/erpnext/config/buying.py +++ b/erpnext/config/buying.py @@ -122,10 +122,10 @@ def get_data(): "icon": "fa fa-table", "items": [ { - "type": "page", - "name": "purchase-analytics", - "label": _("Purchase Analytics"), - "icon": "fa fa-bar-chart", + "type": "report", + "is_query_report": True, + "name": "Purchase Analytics", + "doctype": "Purchase Order" }, { "type": "report", diff --git a/erpnext/config/manufacturing.py b/erpnext/config/manufacturing.py index 16ca9145b4a..621c2dc4e29 100644 --- a/erpnext/config/manufacturing.py +++ b/erpnext/config/manufacturing.py @@ -112,11 +112,12 @@ def get_data(): "is_query_report": True, "name": "Completed Work Orders", "doctype": "Work Order" - },{ - "type": "page", - "name": "production-analytics", - "label": _("Production Analytics"), - "icon": "fa fa-bar-chart", + }, + { + "type": "report", + "is_query_report": True, + "name": "Production Analytics", + "doctype": "Work Order" }, { "type": "report", diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py index 029fdac2842..94f31028311 100644 --- a/erpnext/config/selling.py +++ b/erpnext/config/selling.py @@ -185,10 +185,10 @@ def get_data(): "icon": "fa fa-table", "items": [ { - "type": "page", - "name": "sales-analytics", - "label": _("Sales Analytics"), - "icon": "fa fa-bar-chart", + "type": "report", + "is_query_report": True, + "name": "Sales Analytics", + "doctype": "Sales Order" }, { "type": "page", diff --git a/erpnext/config/setup.py b/erpnext/config/setup.py index e38b30d5e09..1a119e80e06 100644 --- a/erpnext/config/setup.py +++ b/erpnext/config/setup.py @@ -64,7 +64,7 @@ def get_data(): { "type": "help", "label": _("Users and Permissions"), - "youtube_id": "fnBoRhBrwR4" + "youtube_id": "8Slw1hsTmUI" }, { "type": "help", diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py index abdca0d7d7d..60eee71dfa0 100644 --- a/erpnext/config/stock.py +++ b/erpnext/config/stock.py @@ -218,10 +218,10 @@ def get_data(): "doctype": "Item Price", }, { - "type": "page", - "name": "stock-analytics", - "label": _("Stock Analytics"), - "icon": "fa fa-bar-chart" + "type": "report", + "is_query_report": True, + "name": "Stock Analytics", + "doctype": "Stock Entry" }, { "type": "report", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index e277602f0a3..51747f67aec 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -117,6 +117,13 @@ class AccountsController(TransactionBase): if self.get("group_same_items"): self.group_similar_items() + df = self.meta.get_field("discount_amount") + if self.get("discount_amount") and hasattr(self, "taxes") and not len(self.taxes): + df.set("print_hide", 0) + self.discount_amount = -self.discount_amount + else: + df.set("print_hide", 1) + def validate_paid_amount(self): if hasattr(self, "is_pos") or hasattr(self, "is_paid"): is_paid = self.get("is_pos") or self.get("is_paid") diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 57c6556a036..7739592cedb 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -41,6 +41,7 @@ class SellingController(StockController): self.validate_selling_price() self.set_qty_as_per_stock_uom() self.set_po_nos() + self.set_gross_profit() set_default_income_account_for_item(self) def set_missing_values(self, for_validate=False): @@ -345,7 +346,14 @@ class SellingController(StockController): sales_orders = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)])) if sales_orders: po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)}) - self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no]))) + if po_nos and po_nos[0].get('po_no'): + self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no]))) + + def set_gross_profit(self): + if self.doctype == "Sales Order": + for item in self.items: + item.gross_profit = flt(((item.base_rate - item.valuation_rate) * item.stock_qty), self.precision("amount", item)) + def validate_items(self): # validate items to see if they have is_sales_item enabled diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 6985c80bc1d..a4410256f61 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -65,12 +65,13 @@ class calculate_taxes_and_totals(object): if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item']: item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item) - - item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))\ - if item.rate_with_margin > 0 else item.rate + if flt(item.rate_with_margin) > 0: + item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate")) + item.discount_amount = item.rate_with_margin - item.rate + elif flt(item.price_list_rate) > 0: + item.discount_amount = item.price_list_rate - item.rate item.net_rate = item.rate - item.discount_amount = item.price_list_rate - item.rate item.amount = flt(item.rate * item.qty, item.precision("amount")) item.net_amount = item.amount diff --git a/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.json b/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.json index e9a5c12f7f2..f644dc21fb8 100644 --- a/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.json +++ b/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,10 +76,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -102,6 +108,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -115,7 +122,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 19:09:02.326827", + "modified": "2018-11-04 03:37:57.763134", "modified_by": "Administrator", "module": "Education", "name": "Fee Schedule Program", @@ -125,9 +132,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.json b/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.json index aed1ae51b24..d4e0acbce06 100644 --- a/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.json +++ b/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,6 +75,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -84,7 +89,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 19:09:19.498184", + "modified": "2018-11-04 03:38:06.535706", "modified_by": "Administrator", "module": "Education", "name": "Fee Schedule Student Group", @@ -94,9 +99,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/fees/fees.json b/erpnext/education/doctype/fees/fees.json index ac327177214..2413967442f 100644 --- a/erpnext/education/doctype/fees/fees.json +++ b/erpnext/education/doctype/fees/fees.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -991,39 +992,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "paid_amount", - "fieldtype": "Currency", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Paid Amount", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1360,7 +1328,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-08-21 14:44:48.968839", + "modified": "2018-11-26 20:42:14.467284", "modified_by": "Administrator", "module": "Education", "name": "Fees", diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py index bfe6af4bdbb..aa616e6206a 100644 --- a/erpnext/education/doctype/fees/fees.py +++ b/erpnext/education/doctype/fees/fees.py @@ -112,7 +112,10 @@ def get_fee_list(doctype, txt, filters, limit_start, limit_page_length=20, order user = frappe.session.user student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) if student: - return frappe. db.sql('''select name, program, due_date, paid_amount, outstanding_amount, grand_total from `tabFees` + return frappe. db.sql(''' + select name, program, due_date, grand_total - outstanding_amount as paid_amount, + outstanding_amount, grand_total, currency + from `tabFees` where student= %s and docstatus=1 order by due_date asc limit {0} , {1}''' .format(limit_start, limit_page_length), student, as_dict = True) diff --git a/erpnext/education/doctype/instructor_log/instructor_log.json b/erpnext/education/doctype/instructor_log/instructor_log.json index 631bfc0f3b6..dc9380f2c12 100644 --- a/erpnext/education/doctype/instructor_log/instructor_log.json +++ b/erpnext/education/doctype/instructor_log/instructor_log.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,10 +76,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -103,10 +109,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -132,10 +140,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -163,10 +173,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -194,10 +206,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -225,10 +239,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -254,10 +270,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -284,6 +302,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -297,7 +316,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-27 10:05:22.307860", + "modified": "2018-11-04 03:38:30.902942", "modified_by": "Administrator", "module": "Education", "name": "Instructor Log", @@ -307,9 +326,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_admission_program/student_admission_program.json b/erpnext/education/doctype/student_admission_program/student_admission_program.json index 46c5fabdb79..97b1bba4217 100644 --- a/erpnext/education/doctype/student_admission_program/student_admission_program.json +++ b/erpnext/education/doctype/student_admission_program/student_admission_program.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -42,10 +44,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,10 +76,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -102,10 +108,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,10 +139,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -161,10 +171,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -191,6 +203,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -204,7 +217,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 18:57:21.174604", + "modified": "2018-11-04 03:37:17.408427", "modified_by": "Administrator", "module": "Education", "name": "Student Admission Program", @@ -214,9 +227,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json b/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json index ac768d7d351..9f691a1cb0a 100644 --- a/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json +++ b/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,11 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -73,11 +76,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -105,11 +109,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -135,11 +140,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -166,16 +172,17 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fetch_from": "course.course_name", + "fetch_from": "course.course_name", "fieldname": "course_code", "fieldtype": "Read Only", "hidden": 0, @@ -199,11 +206,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -230,7 +238,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 } ], @@ -244,7 +252,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-16 22:42:54.254306", + "modified": "2018-11-04 03:38:52.525155", "modified_by": "Administrator", "module": "Education", "name": "Student Group Creation Tool Course", @@ -254,9 +262,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_group_instructor/student_group_instructor.json b/erpnext/education/doctype/student_group_instructor/student_group_instructor.json index 549b548842b..cb4e52756bb 100644 --- a/erpnext/education/doctype/student_group_instructor/student_group_instructor.json +++ b/erpnext/education/doctype/student_group_instructor/student_group_instructor.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,11 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,16 +74,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fetch_from": "instructor.instructor_name", + "fetch_from": "instructor.instructor_name", "fieldname": "instructor_name", "fieldtype": "Read Only", "hidden": 0, @@ -104,7 +108,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 } ], @@ -118,7 +122,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-16 22:43:13.173633", + "modified": "2018-11-04 03:39:02.413082", "modified_by": "Administrator", "module": "Education", "name": "Student Group Instructor", @@ -128,9 +132,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_group_student/student_group_student.json b/erpnext/education/doctype/student_group_student/student_group_student.json index 3ff339ffb22..d55db344eb0 100644 --- a/erpnext/education/doctype/student_group_student/student_group_student.json +++ b/erpnext/education/doctype/student_group_student/student_group_student.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -13,6 +14,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,10 +42,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -70,10 +74,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -99,10 +105,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -129,10 +137,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -160,6 +170,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -173,7 +184,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 19:11:39.735521", + "modified": "2018-11-04 03:38:22.896203", "modified_by": "Administrator", "module": "Education", "name": "Student Group Student", @@ -183,9 +194,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_guardian/student_guardian.json b/erpnext/education/doctype/student_guardian/student_guardian.json index b4844fd6fb9..3f03a3d1a2e 100644 --- a/erpnext/education/doctype/student_guardian/student_guardian.json +++ b/erpnext/education/doctype/student_guardian/student_guardian.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -13,6 +14,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,10 +42,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -70,10 +74,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,6 +107,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -114,7 +121,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 19:10:57.680471", + "modified": "2018-11-04 03:38:14.211238", "modified_by": "Administrator", "module": "Education", "name": "Student Guardian", @@ -124,9 +131,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_language/student_language.json b/erpnext/education/doctype/student_language/student_language.json index 43e6dbdbcb1..fc53cd13c66 100644 --- a/erpnext/education/doctype/student_language/student_language.json +++ b/erpnext/education/doctype/student_language/student_language.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,7 +43,8 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 0 + "translatable": 0, + "unique": 1 } ], "has_web_view": 0, @@ -54,7 +57,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-11-10 19:05:37.035846", + "modified": "2018-11-04 03:37:34.712397", "modified_by": "Administrator", "module": "Education", "name": "Student Language", @@ -63,7 +66,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -85,10 +87,12 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "title_field": "", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.json b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.json index 88c59c2bdb6..a3282990d00 100644 --- a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.json +++ b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -102,10 +108,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -133,10 +141,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -163,10 +173,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -193,10 +205,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -224,10 +238,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -253,10 +269,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -284,10 +302,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -315,10 +335,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -346,10 +368,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -378,10 +402,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -408,10 +434,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -438,10 +466,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -469,10 +499,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -500,10 +532,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -530,6 +564,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -543,7 +578,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2018-03-20 17:57:53.936119", + "modified": "2018-11-04 03:38:42.970869", "modified_by": "Administrator", "module": "Education", "name": "Student Report Generation Tool", @@ -552,7 +587,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 0, @@ -574,9 +608,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_sibling/student_sibling.json b/erpnext/education/doctype/student_sibling/student_sibling.json index 22b71824a98..f67fe79d98c 100644 --- a/erpnext/education/doctype/student_sibling/student_sibling.json +++ b/erpnext/education/doctype/student_sibling/student_sibling.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -13,6 +14,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,10 +42,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -103,10 +109,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -132,10 +140,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -164,10 +174,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -195,10 +207,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -225,10 +239,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -256,6 +272,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -269,7 +286,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 19:05:24.999063", + "modified": "2018-11-04 03:37:25.881487", "modified_by": "Administrator", "module": "Education", "name": "Student Sibling", @@ -279,9 +296,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/student_siblings/student_siblings.json b/erpnext/education/doctype/student_siblings/student_siblings.json index 0fdc2fd70a2..9d91ad2e2cb 100644 --- a/erpnext/education/doctype/student_siblings/student_siblings.json +++ b/erpnext/education/doctype/student_siblings/student_siblings.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -13,6 +14,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,10 +42,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -71,10 +75,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,6 +107,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -114,7 +121,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-10 19:05:46.408887", + "modified": "2018-11-04 03:37:46.485218", "modified_by": "Administrator", "module": "Education", "name": "Student Siblings", @@ -124,9 +131,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Education", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py index 0c7baa848fa..3f1d5b371b8 100644 --- a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py +++ b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py @@ -73,6 +73,7 @@ def get_attendance_list(from_date, to_date, student_group, students_list): return att_map def get_students_with_leave_application(from_date, to_date, students_list): + if not students_list: return leave_applications = frappe.db.sql(""" select student, from_date, to_date from `tabStudent Leave Application` diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json index a974f2143d1..75151b1d3f5 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json +++ b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -410,7 +411,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-07-26 17:05:29.402908", + "modified": "2018-11-04 03:33:16.833884", "modified_by": "Administrator", "module": "Healthcare", "name": "Clinical Procedure Item", @@ -420,6 +421,7 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Healthcare", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json index 62dc198309f..818f125e773 100644 --- a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json +++ b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -185,7 +186,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-06 16:46:54.699133", + "modified": "2018-11-04 03:33:26.958713", "modified_by": "Administrator", "module": "Healthcare", "name": "Inpatient Occupancy", @@ -195,6 +196,7 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Healthcare", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/healthcare/doctype/patient/patient.js b/erpnext/healthcare/doctype/patient/patient.js index d0ab94c7929..de5bce0aa65 100644 --- a/erpnext/healthcare/doctype/patient/patient.js +++ b/erpnext/healthcare/doctype/patient/patient.js @@ -120,3 +120,16 @@ var btn_invoice_registration = function (frm) { } }); }; + +frappe.ui.form.on('Patient Relation', { + patient_relation_add: function(frm){ + frm.fields_dict['patient_relation'].grid.get_field('patient').get_query = function(frm){ + var patient_list = []; + if(!frm.doc.__islocal) patient_list.push(frm.doc.name); + $.each(frm.doc.patient_relation, function(idx, val){ + if (val.patient) patient_list.push(val.patient); + }); + return { filters: [['Patient', 'name', 'not in', patient_list]] }; + }; + } +}); \ No newline at end of file diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json index f4a80ab0658..4c283aaf1e4 100644 --- a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json +++ b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -89,7 +90,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-06-29 15:14:18.647514", + "modified": "2018-11-04 03:33:07.936958", "modified_by": "Administrator", "module": "Healthcare", "name": "Practitioner Service Unit Schedule", @@ -99,9 +100,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Healthcare", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json index d67da9711d2..236c2b84023 100644 --- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json +++ b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json @@ -1,5 +1,6 @@ { "allow_copy": 1, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -317,7 +318,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-06 16:53:36.440428", + "modified": "2018-11-04 03:33:35.939816", "modified_by": "Administrator", "module": "Healthcare", "name": "Procedure Prescription", @@ -327,6 +328,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Healthcare", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/healthcare/page/medical_record/medical_record.css b/erpnext/healthcare/page/medical_record/medical_record.css index 70014da1c07..977625bbd17 100644 --- a/erpnext/healthcare/page/medical_record/medical_record.css +++ b/erpnext/healthcare/page/medical_record/medical_record.css @@ -14,10 +14,6 @@ margin-bottom: -4px; } -.medical_record-row > * { - z-index: -999; -} - .date-indicator { background:none; font-size:12px; diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 6c1575c54eb..43afa2ae28d 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -11,8 +11,8 @@ app_email = "info@erpnext.com" app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" -develop_version = '11.x.x-develop' -staging_version = '11.0.3-beta.15' +develop_version = '12.x.x-develop' +staging_version = '11.0.3-beta.24' error_report_email = "support@erpnext.com" diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json index 92bd98050dd..1e529325cd7 100644 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,10 +42,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -70,10 +74,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +139,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -144,7 +153,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-08 12:52:01.743866", + "modified": "2018-11-04 03:34:02.551811", "modified_by": "Administrator", "module": "Hotels", "name": "Hotel Room Pricing Package", @@ -154,9 +163,11 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Hospitality", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index 6f550bcee85..1c8b5f96626 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -13,7 +13,7 @@ class EmployeeAdvanceOverPayment(frappe.ValidationError): class EmployeeAdvance(Document): def onload(self): - self.get("__onload").make_payment_via_journal_entry = frappe.db.get_single_value('Accounts Settings', + self.get("__onload").make_payment_via_journal_entry = frappe.db.get_single_value('Accounts Settings', 'make_payment_via_journal_entry') def validate(self): @@ -47,7 +47,7 @@ class EmployeeAdvance(Document): paid_amount = frappe.db.sql(""" select ifnull(sum(debit_in_account_currency), 0) as paid_amount from `tabGL Entry` - where against_voucher_type = 'Employee Advance' + where against_voucher_type = 'Employee Advance' and against_voucher = %s and party_type = 'Employee' and party = %s @@ -67,9 +67,10 @@ class EmployeeAdvance(Document): select sum(ifnull(allocated_amount, 0)) from `tabExpense Claim Advance` where employee_advance = %s and docstatus=1 and allocated_amount > 0 - """, self.name)[0][0] + """, self.name)[0][0] or 0 - frappe.db.set_value("Employee Advance", self.name, "claimed_amount", claimed_amount) + if claimed_amount: + frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount)) @frappe.whitelist() def get_due_advance_amount(employee, posting_date): @@ -109,4 +110,4 @@ def make_bank_entry(dt, dn): "account_type": payment_account.account_type }) - return je.as_dict() \ No newline at end of file + return je.as_dict() diff --git a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py index 75247a45855..9a0c5f77a87 100644 --- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py +++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py @@ -36,10 +36,13 @@ class EmployeeBenefitClaim(Document): frappe.throw(_("Maximum benefit amount of employee {0} exceeds {1}").format(self.employee, max_benefits)) def validate_max_benefit_for_component(self, payroll_period): - claimed_amount = self.claimed_amount - claimed_amount += get_previous_claimed_amount(self.employee, payroll_period, component = self.earning_component) - if claimed_amount > self.max_amount_eligible: - frappe.throw(_("Maximum amount eligible for the component {0} exceeds {1}").format(self.earning_component, self.max_amount_eligible)) + if self.max_amount_eligible: + claimed_amount = self.claimed_amount + claimed_amount += get_previous_claimed_amount(self.employee, + payroll_period, component = self.earning_component) + if claimed_amount > self.max_amount_eligible: + frappe.throw(_("Maximum amount eligible for the component {0} exceeds {1}") + .format(self.earning_component, self.max_amount_eligible)) def validate_non_pro_rata_benefit_claim(self, max_benefits, payroll_period): claimed_amount = self.claimed_amount diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.js b/erpnext/hr/doctype/holiday_list/holiday_list.js index b4c56da6491..462bd8bb671 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.js +++ b/erpnext/hr/doctype/holiday_list/holiday_list.js @@ -3,7 +3,9 @@ frappe.ui.form.on('Holiday List', { refresh: function(frm) { - frm.set_value('total_holidays', frm.doc.holidays.length); + if (frm.doc.holidays) { + frm.set_value('total_holidays', frm.doc.holidays.length); + } }, from_date: function(frm) { if (frm.doc.from_date && !frm.doc.to_date) { diff --git a/erpnext/hr/doctype/job_offer/job_offer.js b/erpnext/hr/doctype/job_offer/job_offer.js index 367ce383186..4217a782a81 100755 --- a/erpnext/hr/doctype/job_offer/job_offer.js +++ b/erpnext/hr/doctype/job_offer/job_offer.js @@ -14,7 +14,7 @@ frappe.ui.form.on("Job Offer", { refresh: function (frm) { if ((!frm.doc.__islocal) && (frm.doc.status == 'Accepted') - && (frm.doc.docstatus === 1) && (!frm.doc.__onload.employee)) { + && (frm.doc.docstatus === 1) && (!frm.doc.__onload || !frm.doc.__onload.employee)) { frm.add_custom_button(__('Make Employee'), function () { erpnext.job_offer.make_employee(frm); @@ -22,7 +22,7 @@ frappe.ui.form.on("Job Offer", { ); } - if(frm.doc.__onload.employee) { + if(frm.doc.__onload && frm.doc.__onload.employee) { frm.add_custom_button(__('Show Employee'), function () { frappe.set_route("Form", "Employee", frm.doc.__onload.employee); diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index 73ab67dd6f8..208a7339fa3 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -26,6 +26,7 @@ class TestSalarySlip(unittest.TestCase): self.make_holiday_list() frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List") + frappe.db.set_value("HR Settings", None, "email_salary_slip_to_employee", 0) def tearDown(self): frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js index 4a111e7d4b4..033938de361 100755 --- a/erpnext/hr/doctype/salary_structure/salary_structure.js +++ b/erpnext/hr/doctype/salary_structure/salary_structure.js @@ -58,6 +58,9 @@ frappe.ui.form.on('Salary Structure', { doc.company = frm.doc.company; frappe.set_route('Form', 'Salary Structure Assignment', doc.name); }); + frm.add_custom_button(__("Assign to Employees"),function () { + frm.trigger('assign_to_employees') + }) } let fields_read_only = ["is_tax_applicable", "is_flexible_benefit", "variable_based_on_taxable_salary"]; fields_read_only.forEach(function(field) { @@ -65,6 +68,43 @@ frappe.ui.form.on('Salary Structure', { }); }, + assign_to_employees:function (frm) { + var d = new frappe.ui.Dialog({ + title: __("Assign to Employees"), + fields: [ + {fieldname: "sec_break", fieldtype: "Section Break", label: __("Filter Employees By (Optional)")}, + {fieldname: "grade", fieldtype: "Link", options: "Employee Grade", label: __("Employee Grade")}, + {fieldname:'department', fieldtype:'Link', options: 'Department', label: __('Department')}, + {fieldname:'designation', fieldtype:'Link', options: 'Designation', label: __('Designation')}, + {fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")}, + {fieldname:'base_variable', fieldtype:'Section Break'}, + {fieldname:'from_date', fieldtype:'Date', label: __('From Date'), "reqd": 1}, + {fieldname:'base_col_br', fieldtype:'Column Break'}, + {fieldname:'base', fieldtype:'Currency', label: __('Base')}, + {fieldname:'variable', fieldtype:'Currency', label: __('Variable')} + ], + primary_action: function() { + var data = d.get_values(); + + frappe.call({ + doc: frm.doc, + method: "assign_salary_structure", + args: data, + callback: function(r) { + if(!r.exc) { + d.hide(); + frm.reload_doc(); + } + } + }); + }, + primary_action_label: __('Assign') + }); + + + d.show(); + }, + salary_slip_based_on_timesheet: function(frm) { frm.trigger("toggle_fields") }, diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py index a36d820f2c8..7ead14030f2 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.py +++ b/erpnext/hr/doctype/salary_structure/salary_structure.py @@ -65,6 +65,76 @@ class SalaryStructure(Document): if not have_a_flexi and flt(self.max_benefits) > 0: frappe.throw(_("Salary Structure should have flexible benefit component(s) to dispense benefit amount")) + def get_employees(self, **kwargs): + conditions, values = [], [] + for field, value in kwargs.items(): + if value: + conditions.append("{0}=%s".format(field)) + values.append(value) + + condition_str = " and " + " and ".join(conditions) if conditions else "" + + employees = frappe.db.sql_list("select name from tabEmployee where status='Active' {condition}" + .format(condition=condition_str), tuple(values)) + + return employees + + @frappe.whitelist() + def assign_salary_structure(self, grade=None, department=None, designation=None,employee=None, + from_date=None, base=None,variable=None): + employees = self.get_employees(grade= grade,department= department,designation= designation,name=employee) + + if employees: + if len(employees) > 20: + frappe.enqueue(assign_salary_structure_for_employees, timeout=600, + employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable) + else: + assign_salary_structure_for_employees(employees, self,from_date=from_date, base=base,variable=variable) + else: + frappe.msgprint(_("No Employee Found")) + + + +def assign_salary_structure_for_employees(employees, salary_structure,from_date=None, base=None,variable=None): + salary_structures_assignments = [] + existing_assignments_for = get_existing_assignments(employees, salary_structure.name,from_date) + count=0 + for employee in employees: + if employee in existing_assignments_for: + continue + count +=1 + + salary_structures_assignment = create_salary_structures_assignment(employee, salary_structure, from_date, base, variable) + salary_structures_assignments.append(salary_structures_assignment) + frappe.publish_progress(count*100/len(set(employees) - set(existing_assignments_for)), title = _("Assigning Structures...")) + + if salary_structures_assignments: + frappe.msgprint(_("Structures have been assigned successfully")) + + +def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable): + assignment = frappe.new_doc("Salary Structure Assignment") + assignment.employee = employee + assignment.salary_structure = salary_structure.name + assignment.from_date = from_date + assignment.base = base + assignment.variable = variable + assignment.save(ignore_permissions = True) + assignment.submit() + return assignment.name + + +def get_existing_assignments(employees, salary_structure,from_date): + salary_structures_assignments = frappe.db.sql_list(""" + select distinct employee from `tabSalary Structure Assignment` + where salary_structure=%s and employee in (%s) + and from_date=%s and docstatus=1 + """ % ('%s', ', '.join(['%s']*len(employees)),'%s'), [salary_structure] + employees+[from_date]) + if salary_structures_assignments: + frappe.msgprint(_("Skipping Salary Structure Assignment for the following employees, as Salary Structure Assignment records already exists against them. {0}") + .format("\n".join(salary_structures_assignments))) + return salary_structures_assignments + @frappe.whitelist() def make_salary_slip(source_name, target_doc = None, employee = None, as_print = False, print_format = None): def postprocess(source, target): diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py index 1a16db74a58..1a660d90ecd 100644 --- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py @@ -71,6 +71,19 @@ class TestSalaryStructure(unittest.TestCase): for row in salary_structure.deductions: self.assertFalse(("\n" in row.formula) or ("\n" in row.condition)) + def test_salary_structures_assignment(self): + salary_structure = make_salary_structure("Salary Structure Sample", "Monthly") + employee = "test_assign_stucture@salary.com" + employee_doc_name = make_employee(employee) + # clear the already assigned stuctures + frappe.db.sql('''delete from `tabSalary Structure Assignment` where employee=%s and salary_structure=%s ''', + ("test_assign_stucture@salary.com",salary_structure.name)) + #test structure_assignment + salary_structure.assign_salary_structure(employee=employee_doc_name,from_date='2013-01-01',base=5000,variable=200) + salary_structure_assignment = frappe.get_doc("Salary Structure Assignment",{'employee':employee_doc_name, 'from_date':'2013-01-01'}) + self.assertEqual(salary_structure_assignment.docstatus, 1) + self.assertEqual(salary_structure_assignment.base, 5000) + self.assertEqual(salary_structure_assignment.variable, 200) def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None, test_tax=False): if test_tax: diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 281b7fcb5d4..f35eb5919e9 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -178,7 +178,8 @@ def validate_overlap(doc, from_date, to_date, company = None): }, as_dict = 1) if overlap_doc: - exists_for = doc.employee + if doc.get("employee"): + exists_for = doc.employee if company: exists_for = company throw_overlap_error(doc, exists_for, overlap_doc[0].name, from_date, to_date) diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py index 23564010e7d..c236822490d 100644 --- a/erpnext/hub_node/api.py +++ b/erpnext/hub_node/api.py @@ -10,7 +10,6 @@ import requests from frappe import _ from frappe.frappeclient import FrappeClient from frappe.desk.form.load import get_attachments -from frappe.utils.file_manager import get_file_path from six import string_types current_user = frappe.session.user diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json index a55c3c57780..8c5f2af96a8 100644 --- a/erpnext/manufacturing/doctype/bom/bom.json +++ b/erpnext/manufacturing/doctype/bom/bom.json @@ -54,7 +54,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:!doc.__islocal", + "depends_on": "", "fieldname": "item_name", "fieldtype": "Data", "hidden": 0, @@ -1976,7 +1976,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-10-11 11:52:39.047935", + "modified": "2018-10-24 02:07:21.618275", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 0eab9826c32..d72f00af8f0 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -108,7 +108,8 @@ class BOM(WebsiteGenerator): "item_code": item.item_code, "item_name": item.item_name, "bom_no": item.bom_no, - "stock_qty": item.stock_qty + "stock_qty": item.stock_qty, + "allow_transfer_for_manufacture": item.allow_transfer_for_manufacture }) for r in ret: if not item.get(r): @@ -127,6 +128,8 @@ class BOM(WebsiteGenerator): self.validate_rm_item(item) args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or '' + args['transfer_for_manufacture'] = (cstr(args.get('allow_transfer_for_manufacture', '')) or + item and item[0].allow_transfer_for_manufacture or 0) args.update(item[0]) rate = self.get_rm_rate(args) @@ -142,7 +145,7 @@ class BOM(WebsiteGenerator): 'qty' : args.get("qty") or args.get("stock_qty") or 1, 'stock_qty' : args.get("qty") or args.get("stock_qty") or 1, 'base_rate' : rate, - 'allow_transfer_for_manufacture': item and args['allow_transfer_for_manufacture'] or 0 + 'allow_transfer_for_manufacture': cint(args['transfer_for_manufacture']) or 0 } return ret_item diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json index cc9564276a6..1a7e594e87c 100644 --- a/erpnext/manufacturing/doctype/bom/test_records.json +++ b/erpnext/manufacturing/doctype/bom/test_records.json @@ -10,7 +10,8 @@ "rate": 5000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 }, { "amount": 2000.0, @@ -21,7 +22,8 @@ "rate": 1000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 } ], "docstatus": 1, @@ -54,7 +56,8 @@ "rate": 5000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 }, { "amount": 2000.0, @@ -65,7 +68,8 @@ "rate": 1000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 } ], "docstatus": 1, @@ -97,7 +101,8 @@ "rate": 5000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 }, { "amount": 3000.0, @@ -109,7 +114,8 @@ "rate": 1000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 } ], "docstatus": 1, @@ -143,7 +149,8 @@ "rate": 3000.0, "uom": "_Test UOM", "stock_uom": "_Test UOM", - "source_warehouse": "_Test Warehouse - _TC" + "source_warehouse": "_Test Warehouse - _TC", + "allow_transfer_for_manufacture": 1 } ], "docstatus": 1, diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json index de079751a73..cc69471eba2 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.json +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json @@ -1,1051 +1,1053 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-02-22 01:27:49", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2013-02-22 01:27:49", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 3, + "fieldname": "item_code", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Item Code", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "item_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 3, + "fieldname": "item_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "bom_no", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "BOM No", - "length": 0, - "no_copy": 0, - "oldfieldname": "bom_no", - "oldfieldtype": "Link", - "options": "BOM", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "150px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "bom_no", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "BOM No", + "length": 0, + "no_copy": 0, + "oldfieldname": "bom_no", + "oldfieldtype": "Link", + "options": "BOM", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "150px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0, "width": "150px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "source_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Source Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "source_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Source Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "section_break_5", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Description", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "250px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item Description", + "length": 0, + "no_copy": 0, + "oldfieldname": "description", + "oldfieldtype": "Text", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "250px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0, "width": "250px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image", - "fieldtype": "Attach", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "image", + "fieldtype": "Attach", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Image", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image_view", - "fieldtype": "Image", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image View", - "length": 0, - "no_copy": 0, - "options": "image", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "image_view", + "fieldtype": "Image", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Image View", + "length": 0, + "no_copy": 0, + "options": "image", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "quantity_and_rate", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Quantity and Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "quantity_and_rate", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Quantity and Rate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fieldname": "qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "qty", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 2, + "fieldname": "qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Qty", + "length": 0, + "no_copy": 0, + "oldfieldname": "qty", + "oldfieldtype": "Currency", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 1, - "fieldname": "uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 1, + "fieldname": "uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "UOM", + "length": 0, + "no_copy": 0, + "options": "UOM", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break2", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "stock_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Stock Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "stock_qty", - "oldfieldtype": "Currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "stock_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Stock Qty", + "length": 0, + "no_copy": 0, + "oldfieldname": "stock_qty", + "oldfieldtype": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "stock_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Stock UOM", - "length": 0, - "no_copy": 0, - "oldfieldname": "stock_uom", - "oldfieldtype": "Data", - "options": "UOM", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "stock_uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Stock UOM", + "length": 0, + "no_copy": 0, + "oldfieldname": "stock_uom", + "oldfieldtype": "Data", + "options": "UOM", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "conversion_factor", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Conversion Factor", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "conversion_factor", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Conversion Factor", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "rate_amount_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Rate & Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rate_amount_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Rate & Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "rate", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Rate", - "length": 0, - "no_copy": 0, - "options": "currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Rate", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "base_rate", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Basic Rate (Company Currency)", - "length": 0, - "no_copy": 0, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "base_rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Basic Rate (Company Currency)", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_21", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Amount", - "length": 0, - "no_copy": 0, - "oldfieldname": "amount_as_per_mar", - "oldfieldtype": "Currency", - "options": "currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "150px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Amount", + "length": 0, + "no_copy": 0, + "oldfieldname": "amount_as_per_mar", + "oldfieldtype": "Currency", + "options": "currency", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "150px", + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0, "width": "150px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "base_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amount (Company Currency)", - "length": 0, - "no_copy": 0, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "base_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amount (Company Currency)", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_18", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_18", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 1, - "fieldname": "scrap", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Scrap %", - "length": 0, - "no_copy": 0, - "oldfieldname": "scrap", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 1, + "fieldname": "scrap", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scrap %", + "length": 0, + "no_copy": 0, + "oldfieldname": "scrap", + "oldfieldtype": "Currency", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "qty_consumed_per_unit", - "fieldtype": "Float", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Qty Consumed Per Unit", - "length": 0, - "no_copy": 0, - "oldfieldname": "qty_consumed_per_unit", - "oldfieldtype": "Float", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "qty_consumed_per_unit", + "fieldtype": "Float", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Qty Consumed Per Unit", + "length": 0, + "no_copy": 0, + "oldfieldname": "qty_consumed_per_unit", + "oldfieldtype": "Float", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_27", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_27", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "allow_alternative_item", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Alternative Item", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "allow_alternative_item", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Allow Alternative Item", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "allow_transfer_for_manufacture", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Transfer for Manufacture", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "item_code.allow_transfer_for_manufacture", + "fieldname": "allow_transfer_for_manufacture", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Allow Transfer for Manufacture", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "original_item", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Original Item", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "original_item", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Original Item", + "length": 0, + "no_copy": 0, + "options": "Item", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "operation", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item operation", - "length": 0, - "no_copy": 0, - "options": "Operation", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "operation", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item operation", + "length": 0, + "no_copy": 0, + "options": "Operation", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-09-16 19:59:36.636884", - "modified_by": "clarkejjm@gmail.com", - "module": "Manufacturing", - "name": "BOM Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 1, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2018-11-22 15:04:55.187136", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "BOM Item", + "owner": "Administrator", + "permissions": [], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 0, + "track_seen": 0, "track_views": 0 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index e74a3755577..dbbf3d33f7c 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -104,13 +104,26 @@ frappe.ui.form.on('Production Plan', { } }); }, - + get_items_for_mr: function(frm) { frappe.call({ - method: "get_items_for_material_requests", + method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests", freeze: true, - doc: frm.doc, - callback: function() { + args: {doc: frm.doc}, + callback: function(r) { + if(r.message) { + frm.set_value('mr_items', []); + $.each(r.message, function(i, d) { + var item = frm.add_child('mr_items'); + item.actual_qty = d.actual_qty; + item.item_code = d.item_code; + item.item_name = d.item_name; + item.min_order_qty = d.min_order_qty; + item.quantity = d.quantity; + item.sales_order = d.sales_order; + item.warehouse = d.warehouse; + }); + } refresh_field('mr_items'); } }); diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 12f2f04e38a..7d11ae4993c 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -10,6 +10,7 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and, now_datetime from erpnext.manufacturing.doctype.work_order.work_order import get_item_details from six import string_types +from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults class ProductionPlan(Document): def validate(self): @@ -209,9 +210,10 @@ class ProductionPlan(Document): def set_status(self): self.status = { - '0': 'Draft', - '1': 'Submitted' - }[cstr(self.docstatus or 0)] + 0: 'Draft', + 1: 'Submitted', + 2: 'Cancelled' + }.get(self.docstatus) if self.total_produced_qty > 0: self.status = "In Process" @@ -281,102 +283,6 @@ class ProductionPlan(Document): return item_dict - def get_items_for_material_requests(self): - self.mr_items = [] - - for data in self.po_items: - bom_wise_item_details = {} - if not data.planned_qty: - frappe.throw(_("For row {0}: Enter planned qty").format(data.idx)) - - if data.include_exploded_items and data.bom_no and self.include_subcontracted_items: - for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom, - ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name, - bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse, - item.default_material_request_type, item.min_order_qty, item_default.default_warehouse - from - `tabBOM Explosion Item` bei - JOIN `tabBOM` bom ON bom.name = bei.parent - JOIN `tabItem` item ON item.name = bei.item_code - LEFT JOIN `tabItem Default` item_default - ON item_default.parent = item.name and item_default.company=%s - where - bei.docstatus < 2 - and bom.name=%s and item.is_stock_item in (1, {0}) - group by bei.item_code, bei.stock_uom""".format(0 if self.include_non_stock_items else 1), - (self.company, data.bom_no), as_dict=1): - bom_wise_item_details.setdefault(d.item_code, d) - else: - bom_wise_item_details = self.get_subitems(data, bom_wise_item_details, data.bom_no, 1) - - for item, item_details in bom_wise_item_details.items(): - if item_details.qty > 0: - self.add_item_in_material_request_items(item, item_details, data) - - def get_subitems(self, data, bom_wise_item_details, bom_no, parent_qty): - items = frappe.db.sql(""" - SELECT - bom_item.item_code, default_material_request_type, item.item_name, - ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, - item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse, - item.default_bom as default_bom, bom_item.description as description, - bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, - item_default.default_warehouse - FROM - `tabBOM Item` bom_item - JOIN `tabBOM` bom ON bom.name = bom_item.parent - JOIN tabItem item ON bom_item.item_code = item.name - LEFT JOIN `tabItem Default` item_default - ON item.name = item_default.parent and item_default.company = %(company)s - where - bom.name = %(bom)s - and bom_item.docstatus < 2 - and item.is_stock_item in (1, {0}) - group by bom_item.item_code""".format(0 if self.include_non_stock_items else 1),{ - 'bom': bom_no, - 'parent_qty': parent_qty, - 'company': self.company - }, as_dict=1) - - for d in items: - if not data.include_exploded_items or not d.default_bom: - if d.item_code in bom_wise_item_details: - bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty - else: - bom_wise_item_details[d.item_code] = d - - if data.include_exploded_items and d.default_bom: - if ((d.default_material_request_type in ["Manufacture", "Purchase"] and - not d.is_sub_contracted) or (d.is_sub_contracted and self.include_subcontracted_items)): - if d.qty > 0: - self.get_subitems(data, bom_wise_item_details, d.default_bom, d.qty) - - return bom_wise_item_details - - def add_item_in_material_request_items(self, item, row, data): - total_qty = row.qty * data.planned_qty - projected_qty, actual_qty = get_bin_details(row) - - requested_qty = 0 - if self.ignore_existing_ordered_qty: - requested_qty = total_qty - else: - requested_qty = total_qty - projected_qty - - if requested_qty > 0 and requested_qty < row.min_order_qty: - requested_qty = row.min_order_qty - - if requested_qty > 0: - self.append('mr_items', { - 'item_code': item, - 'item_name': row.item_name, - 'quantity': requested_qty, - 'warehouse': row.source_warehouse or row.default_warehouse, - 'actual_qty': actual_qty, - 'min_order_qty': row.min_order_qty, - 'sales_order': data.sales_order - }) - def make_work_order(self): wo_list = [] self.validate_data() @@ -466,6 +372,87 @@ class ProductionPlan(Document): else : msgprint(_("No material request created")) +def get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items): + for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom, + ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name, + bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse, + item.default_material_request_type, item.min_order_qty, item_default.default_warehouse + from + `tabBOM Explosion Item` bei + JOIN `tabBOM` bom ON bom.name = bei.parent + JOIN `tabItem` item ON item.name = bei.item_code + LEFT JOIN `tabItem Default` item_default + ON item_default.parent = item.name and item_default.company=%s + where + bei.docstatus < 2 + and bom.name=%s and item.is_stock_item in (1, {0}) + group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1), + (company, bom_no), as_dict=1): + bom_wise_item_details.setdefault(d.get('item_code'), d) + return bom_wise_item_details + +def get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, parent_qty): + items = frappe.db.sql(""" + SELECT + bom_item.item_code, default_material_request_type, item.item_name, + ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, + item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse, + item.default_bom as default_bom, bom_item.description as description, + bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, + item_default.default_warehouse + FROM + `tabBOM Item` bom_item + JOIN `tabBOM` bom ON bom.name = bom_item.parent + JOIN tabItem item ON bom_item.item_code = item.name + LEFT JOIN `tabItem Default` item_default + ON item.name = item_default.parent and item_default.company = %(company)s + where + bom.name = %(bom)s + and bom_item.docstatus < 2 + and item.is_stock_item in (1, {0}) + group by bom_item.item_code""".format(0 if include_non_stock_items else 1),{ + 'bom': bom_no, + 'parent_qty': parent_qty, + 'company': company + }, as_dict=1) + + for d in items: + if not data.get('include_exploded_items') or not d.default_bom: + if d.item_code in bom_wise_item_details: + bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty + else: + bom_wise_item_details[d.item_code] = d + + if data.get('include_exploded_items') and d.default_bom: + if ((d.default_material_request_type in ["Manufacture", "Purchase"] and + not d.is_sub_contracted) or (d.is_sub_contracted and include_subcontracted_items)): + if d.qty > 0: + get_subitems(doc, data, bom_wise_item_details, d.default_bom, company, include_non_stock_items, include_subcontracted_items, d.qty) + return bom_wise_item_details + +def add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, row, data, warehouse, company): + total_qty = row.qty * planned_qty + projected_qty, actual_qty = get_bin_details(row) + + requested_qty = 0 + if ignore_existing_ordered_qty: + requested_qty = total_qty + else: + requested_qty = total_qty - projected_qty + if requested_qty > 0 and requested_qty < row.min_order_qty: + requested_qty = row.min_order_qty + item_group_defaults = get_item_group_defaults(item, company) + if requested_qty > 0: + doc.setdefault('mr_items', []).append({ + 'item_code': item, + 'item_name': row.item_name, + 'quantity': requested_qty, + 'warehouse': warehouse or row.source_warehouse or row.default_warehouse or item_group_defaults.get("default_warehouse"), + 'actual_qty': actual_qty, + 'min_order_qty': row.min_order_qty, + 'sales_order': data.get('sales_order') + }) + def get_sales_orders(self): so_filter = item_filter = "" if self.from_date: @@ -520,3 +507,46 @@ def get_bin_details(row): """.format(conditions=conditions), { "item_code": row.item_code }, as_list=1) return item_projected_qty and item_projected_qty[0] or (0,0) + +@frappe.whitelist() +def get_items_for_material_requests(doc, company=None): + if isinstance(doc, string_types): + doc = frappe._dict(json.loads(doc)) + + doc['mr_items'] = [] + po_items = doc['po_items'] if doc.get('po_items') else doc['items'] + + for data in po_items: + warehouse = None + bom_wise_item_details = {} + + if data.get('required_qty'): + planned_qty = data.get('required_qty') + bom_no = data.get('bom') + ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') + include_non_stock_items = 1 + warehouse = data.get('for_warehouse') + if data.get('include_exploded_items'): + include_subcontracted_items = 1 + else: + include_subcontracted_items = 0 + else: + planned_qty = data.get('planned_qty') + bom_no = data.get('bom_no') + include_subcontracted_items = doc['include_subcontracted_items'] + company = doc['company'] + include_non_stock_items = doc['include_non_stock_items'] + ignore_existing_ordered_qty = doc['ignore_existing_ordered_qty'] + if not planned_qty: + frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx'))) + + if data.get('include_exploded_items') and bom_no and include_subcontracted_items: + # fetch exploded items from BOM + bom_wise_item_details = get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items) + else: + bom_wise_item_details = get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1) + for item, item_details in bom_wise_item_details.items(): + if item_details.qty > 0: + add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, item_details, data, warehouse, company) + + return doc['mr_items'] diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 7cf426858d1..8eade98ecb7 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -10,6 +10,7 @@ from erpnext.stock.doctype.item.test_item import create_item from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order +from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests class TestProductionPlan(unittest.TestCase): def setUp(self): @@ -47,7 +48,7 @@ class TestProductionPlan(unittest.TestCase): filters = {'production_plan': pln.name}, as_list=1) self.assertTrue(len(work_orders), len(pln.po_items)) - + for name in material_requests: mr = frappe.get_doc('Material Request', name[0]) mr.cancel() @@ -160,8 +161,10 @@ def create_production_plan(**args): 'planned_start_date': args.planned_start_date or now_datetime() }] }) - pln.get_items_for_material_requests() - + mr_items = get_items_for_material_requests(pln.as_dict()) + for d in mr_items: + pln.append('mr_items', d) + if not args.do_not_save: pln.insert() if not args.do_not_submit: @@ -179,7 +182,7 @@ def make_bom(**args): 'quantity': args.quantity or 1, 'company': args.company or '_Test Company' }) - + for item in args.raw_materials: item_doc = frappe.get_doc('Item', item) @@ -188,8 +191,8 @@ def make_bom(**args): 'qty': 1, 'uom': item_doc.stock_uom, 'stock_uom': item_doc.stock_uom, - 'rate': item_doc.valuation_rate or args.rate + 'rate': item_doc.valuation_rate or args.rate, }) - + bom.insert(ignore_permissions=True) bom.submit() \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index fb8fd262068..431ad325587 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -292,6 +292,7 @@ class TestWorkOrder(unittest.TestCase): make_bom(item=fg_item, rate=1000, raw_materials = ['_Test FG Item', '_Test FG Non Stock Item']) wo = make_wo_order_test_record(production_item = fg_item) + se = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", 1)) se.insert() se.submit() diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 1d465d57ae3..e73328f10e1 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -448,7 +448,9 @@ class WorkOrder(Document): if item_dict.get(d.item_code): d.required_qty = item_dict.get(d.item_code).get("qty") else: - for item in sorted(item_dict.values(), key=lambda d: d['idx']): + # Attribute a big number (999) to idx for sorting putpose in case idx is NULL + # For instance in BOM Explosion Item child table, the items coming from sub assembly items + for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999): self.append('required_items', { 'operation': item.operation, 'item_code': item.item_code, diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js index 049a822ec0d..2ac6fa073bf 100644 --- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js +++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js @@ -16,6 +16,22 @@ frappe.query_reports["BOM Stock Report"] = { "fieldname": "show_exploded_view", "label": __("Show exploded view"), "fieldtype": "Check" + }, { + "fieldname": "qty_to_produce", + "label": __("Quantity to Produce"), + "fieldtype": "Int", + "default": "1" + }, + ], + "formatter": function(value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + if (column.id == "Item"){ + if (data["Enough Parts to Build"] > 0){ + value = `${data['Item']}` + } else { + value = `${data['Item']}` + } } - ] + return value + } } diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py index 32368395c0d..ec3672025b6 100644 --- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py +++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py @@ -7,6 +7,7 @@ from frappe import _ def execute(filters=None): if not filters: filters = {} + columns = get_columns() data = get_bom_stock(filters) @@ -18,6 +19,7 @@ def get_columns(): columns = [ _("Item") + ":Link/Item:150", _("Description") + "::500", + _("Qty per BOM Line") + ":Float:100", _("Required Qty") + ":Float:100", _("In Stock Qty") + ":Float:100", _("Enough Parts to Build") + ":Float:200", @@ -32,6 +34,10 @@ def get_bom_stock(filters): table = "`tabBOM Item`" qty_field = "qty" + qty_to_produce = filters.get("qty_to_produce", 1) + if int(qty_to_produce) <= 0: + frappe.throw(_("Quantity to Produce can not be less than Zero")) + if filters.get("show_exploded_view"): table = "`tabBOM Explosion Item`" qty_field = "stock_qty" @@ -50,11 +56,12 @@ def get_bom_stock(filters): return frappe.db.sql(""" SELECT - bom_item.item_code , + bom_item.item_code, bom_item.description , bom_item.{qty_field}, + bom_item.{qty_field} * {qty_to_produce}, sum(ledger.actual_qty) as actual_qty, - sum(FLOOR(ledger.actual_qty / bom_item.{qty_field}))as to_build + sum(FLOOR(ledger.actual_qty / (bom_item.{qty_field} * {qty_to_produce}))) FROM {table} AS bom_item LEFT JOIN `tabBin` AS ledger @@ -63,4 +70,10 @@ def get_bom_stock(filters): WHERE bom_item.parent = '{bom}' and bom_item.parenttype='BOM' - GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom)) + GROUP BY bom_item.item_code""".format( + qty_field=qty_field, + table=table, + conditions=conditions, + bom=bom, + qty_to_produce=qty_to_produce or 1) + ) diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.py b/erpnext/manufacturing/report/production_analytics/production_analytics.py index 1dc821c6e10..7447a1f6705 100644 --- a/erpnext/manufacturing/report/production_analytics/production_analytics.py +++ b/erpnext/manufacturing/report/production_analytics/production_analytics.py @@ -3,17 +3,16 @@ from __future__ import unicode_literals import frappe -from frappe import _ +from frappe import _, scrub from frappe.utils import getdate -from erpnext.selling.report.sales_analytics.sales_analytics import (get_period_date_ranges,get_period) +from erpnext.stock.report.stock_analytics.stock_analytics import (get_period_date_ranges, get_period) def execute(filters=None): columns = get_columns(filters) - data, chart = get_data(filters,columns) - return columns, data,None ,chart + data, chart = get_data(filters, columns) + return columns, data, None , chart def get_columns(filters): - columns =[ { "label": _("Status"), @@ -22,122 +21,113 @@ def get_columns(filters): "width": 140 }] - ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"]) + ranges = get_period_date_ranges(filters) for dummy, end_date in ranges: - label = field_name = get_period(end_date,filters["range"]) + period = get_period(end_date, filters) - columns.append( - { - "label": _(label), - "field_name":field_name, + columns.append({ + "label": _(period), + "fieldname": scrub(period), "fieldtype": "Float", "width": 120 - }, - ) + }) return columns -def get_data_list(filters,entry): - - data_list = { - "All Work Orders" : {}, - "Not Started" : {}, - "Overdue" : {}, - "Pending" : {}, - "Completed" : {} +def get_periodic_data(filters, entry): + periodic_data = { + "All Work Orders": {}, + "Not Started": {}, + "Overdue": {}, + "Pending": {}, + "Completed": {} } - ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"]) + ranges = get_period_date_ranges(filters) - for from_date,end_date in ranges: - period = get_period(end_date,filters["range"]) + for from_date, end_date in ranges: + period = get_period(end_date, filters) for d in entry: if getdate(d.creation) <= getdate(from_date) or getdate(d.creation) <= getdate(end_date) : - data_list = update_data_list(data_list,"All Work Orders",period) - + periodic_data = update_periodic_data(periodic_data, "All Work Orders", period) if d.status == 'Completed': if getdate(d.actual_end_date) < getdate(from_date) or getdate(d.modified) < getdate(from_date): - data_list = update_data_list(data_list, "Completed",period) + periodic_data = update_periodic_data(periodic_data, "Completed", period) elif getdate(d.actual_start_date) < getdate(from_date) : - data_list = update_data_list(data_list, "Pending", period) + periodic_data = update_periodic_data(periodic_data, "Pending", period) elif getdate(d.planned_start_date) < getdate(from_date) : - data_list = update_data_list(data_list, "Overdue", period) + periodic_data = update_periodic_data(periodic_data, "Overdue", period) else: - data_list = update_data_list(data_list, "Not Started", period) + periodic_data = update_periodic_data(periodic_data, "Not Started", period) elif d.status == 'In Process': if getdate(d.actual_start_date) < getdate(from_date) : - data_list = update_data_list(data_list, "Pending", period) + periodic_data = update_periodic_data(periodic_data, "Pending", period) elif getdate(d.planned_start_date) < getdate(from_date) : - data_list = update_data_list(data_list, "Overdue", period) + periodic_data = update_periodic_data(periodic_data, "Overdue", period) else: - data_list = update_data_list(data_list, "Not Started", period) + periodic_data = update_periodic_data(periodic_data, "Not Started", period) elif d.status == 'Not Started': if getdate(d.planned_start_date) < getdate(from_date) : - data_list = update_data_list(data_list, "Overdue", period) + periodic_data = update_periodic_data(periodic_data, "Overdue", period) else: - data_list = update_data_list(data_list, "Not Started", period) - return data_list + periodic_data = update_periodic_data(periodic_data, "Not Started", period) + return periodic_data -def update_data_list(data_list, status, period): - if data_list.get(status).get(period): - data_list[status][period] += 1 +def update_periodic_data(periodic_data, status, period): + if periodic_data.get(status).get(period): + periodic_data[status][period] += 1 else: - data_list[status][period] = 1 + periodic_data[status][period] = 1 - return data_list - -def get_data(filters,columns): + return periodic_data +def get_data(filters, columns): data = [] - entry = frappe.get_all("Work Order", fields=["creation", "modified", "actual_start_date", "actual_end_date", "planned_start_date", "planned_end_date", "status"], - filters={"docstatus" : 1, "company" : filters["company"] }) + filters={"docstatus": 1, "company": filters["company"] }) - data_list = get_data_list(filters,entry) + periodic_data = get_periodic_data(filters,entry) labels = ["All Work Orders", "Not Started", "Overdue", "Pending", "Completed"] - - chart_data = get_chart_data(data_list,columns) - - ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"]) + chart_data = get_chart_data(periodic_data,columns) + ranges = get_period_date_ranges(filters) for label in labels: work = {} work["Status"] = label for dummy,end_date in ranges: - period = get_period(end_date,filters["range"]) - if data_list.get(label).get(period): - work[period] = data_list.get(label).get(period) + period = get_period(end_date, filters) + if periodic_data.get(label).get(period): + work[scrub(period)] = periodic_data.get(label).get(period) else: - work[period] = 0.0 + work[scrub(period)] = 0.0 data.append(work) return data, chart_data -def get_chart_data(data_list,columns): - +def get_chart_data(periodic_data, columns): labels = [d.get("label") for d in columns[1:]] all_data, not_start, overdue, pending, completed = [], [], [] , [], [] datasets = [] for d in labels: - all_data.append(data_list.get("All Work Orders").get(d)) - not_start.append(data_list.get("Not Started").get(d)) - overdue.append(data_list.get("Overdue").get(d)) - pending.append(data_list.get("Pending").get(d)) - completed.append(data_list.get("Completed").get(d)) + all_data.append(periodic_data.get("All Work Orders").get(d)) + not_start.append(periodic_data.get("Not Started").get(d)) + overdue.append(periodic_data.get("Overdue").get(d)) + pending.append(periodic_data.get("Pending").get(d)) + completed.append(periodic_data.get("Completed").get(d)) datasets.append({'name':'All Work Orders', 'values': all_data}) datasets.append({'name':'Not Started', 'values': not_start}) @@ -148,10 +138,9 @@ def get_chart_data(data_list,columns): chart = { "data": { 'labels': labels, - 'datasets':datasets + 'datasets': datasets } } - chart["type"] = "line" return chart diff --git a/erpnext/non_profit/doctype/certification_application/certification_application.json b/erpnext/non_profit/doctype/certification_application/certification_application.json index 49d5aac91c7..f562fa67343 100644 --- a/erpnext/non_profit/doctype/certification_application/certification_application.json +++ b/erpnext/non_profit/doctype/certification_application/certification_application.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -14,261 +15,261 @@ "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "name_of_applicant", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Name of Applicant", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "name_of_applicant", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Name of Applicant", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Email", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "email", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Email", + "length": 0, + "no_copy": 0, + "options": "User", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "certification_status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Certification Status", - "length": 0, - "no_copy": 0, - "options": "Yet to appear\nCertified\nNot Certified", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "certification_status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Certification Status", + "length": 0, + "no_copy": 0, + "options": "Yet to appear\nCertified\nNot Certified", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "payment_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Payment Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "payment_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Payment Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "paid", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Paid", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "paid", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Paid", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "currency", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Currency", - "length": 0, - "no_copy": 0, - "options": "USD\nINR", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "currency", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Currency", + "length": 0, + "no_copy": 0, + "options": "USD\nINR", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amount", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amount", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -282,7 +283,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:34.417984", + "modified": "2018-11-04 03:36:35.337403", "modified_by": "Administrator", "module": "Non Profit", "name": "Certification Application", @@ -290,28 +291,29 @@ "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } ], "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Non Profit", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json index 430811b0c22..d77f1b25694 100644 --- a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json +++ b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -664,7 +665,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 16:15:52.082520", + "modified": "2018-11-04 03:36:47.386618", "modified_by": "Administrator", "module": "Non Profit", "name": "Certified Consultant", @@ -713,6 +714,7 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Non Profit", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/non_profit/doctype/membership/membership.py b/erpnext/non_profit/doctype/membership/membership.py index db679050b16..98bee56979f 100644 --- a/erpnext/non_profit/doctype/membership/membership.py +++ b/erpnext/non_profit/doctype/membership/membership.py @@ -12,20 +12,21 @@ import erpnext class Membership(Document): def validate(self): - member_name = frappe.get_value('Member', dict(email=frappe.session.user)) + if not self.member or not frappe.db.exists("Member", self.member): + member_name = frappe.get_value('Member', dict(email=frappe.session.user)) - if not member_name: - user = frappe.get_doc('User', frappe.session.user) - member = frappe.get_doc(dict( - doctype='Member', - email=frappe.session.user, - membership_type=self.membership_type, - member_name=user.get_fullname() - )).insert(ignore_permissions=True) - member_name = member.name + if not member_name: + user = frappe.get_doc('User', frappe.session.user) + member = frappe.get_doc(dict( + doctype='Member', + email=frappe.session.user, + membership_type=self.membership_type, + member_name=user.get_fullname() + )).insert(ignore_permissions=True) + member_name = member.name - if self.get("__islocal"): - self.member = member_name + if self.get("__islocal"): + self.member = member_name # get last membership (if active) last_membership = erpnext.get_last_membership() diff --git a/erpnext/non_profit/doctype/volunteer/volunteer.json b/erpnext/non_profit/doctype/volunteer/volunteer.json index ef827e60b46..052b288089a 100644 --- a/erpnext/non_profit/doctype/volunteer/volunteer.json +++ b/erpnext/non_profit/doctype/volunteer/volunteer.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 1, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -41,10 +43,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -70,10 +74,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,10 +107,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,10 +139,12 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 0 + "translatable": 0, + "unique": 1 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -161,10 +171,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -192,10 +204,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -222,10 +236,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -251,10 +267,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -281,10 +299,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -311,10 +331,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -342,10 +364,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -373,10 +397,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -402,10 +428,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -433,10 +461,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -462,10 +492,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -492,6 +524,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -506,7 +539,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-01-22 15:53:46.480182", + "modified": "2018-11-04 03:36:25.776211", "modified_by": "Administrator", "module": "Non Profit", "name": "Volunteer", @@ -515,7 +548,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -537,10 +569,12 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, + "restrict_to_domain": "Non Profit", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "title_field": "volunteer_name", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/patches.txt b/erpnext/patches.txt old mode 100644 new mode 100755 index 9c569488c96..dc4c94c8d14 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -568,7 +568,14 @@ erpnext.patches.v11_0.remove_land_unit_icon erpnext.patches.v11_0.add_default_dispatch_notification_template erpnext.patches.v11_0.add_market_segments erpnext.patches.v11_0.add_sales_stages -erpnext.patches.v11_0.ewaybill_fields_gst_india +execute:frappe.delete_doc("Page", "sales-analytics") +execute:frappe.delete_doc("Page", "purchase-analytics") +execute:frappe.delete_doc("Page", "stock-analytics") +execute:frappe.delete_doc("Page", "production-analytics") +erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 erpnext.patches.v11_0.drop_column_max_days_allowed erpnext.patches.v11_0.change_healthcare_desktop_icons erpnext.patches.v10_0.update_user_image_in_employee +erpnext.patches.v11_0.update_delivery_trip_status +erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items +erpnext.patches.v11_0.set_missing_gst_hsn_code diff --git a/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py b/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py new file mode 100644 index 00000000000..68c06ef62b2 --- /dev/null +++ b/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py @@ -0,0 +1,32 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe, erpnext + +def execute(): + for company in frappe.get_all("Company"): + if not erpnext.is_perpetual_inventory_enabled(company.name): + continue + + acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto") or "1900-01-01" + pr_with_rejected_warehouse = frappe.db.sql(""" + select pr.name + from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item + where pr.name = pr_item.parent + and pr.posting_date > %s + and pr.docstatus=1 + and pr.company = %s + and pr_item.rejected_qty > 0 + """, (acc_frozen_upto, company.name), as_dict=1) + + for d in pr_with_rejected_warehouse: + doc = frappe.get_doc("Purchase Receipt", d.name) + + doc.docstatus = 2 + doc.make_gl_entries_on_cancel(repost_future_gle=False) + + + # update gl entries for submit state of PR + doc.docstatus = 1 + doc.make_gl_entries(repost_future_gle=False) diff --git a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py new file mode 100644 index 00000000000..3c2cea22306 --- /dev/null +++ b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py @@ -0,0 +1,43 @@ +import frappe +from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html + +def execute(): + company = frappe.db.sql_list("select name from tabCompany where country = 'India'") + if not company: + return + + doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", + "Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"] + + for dt in doctypes: + date_field = "posting_date" + if dt in ["Quotation", "Sales Order", "Supplier Quotation", "Purchase Order"]: + date_field = "transaction_date" + + transactions = frappe.db.sql(""" + select dt.name, dt_item.name as child_name + from `tab{dt}` dt, `tab{dt} Item` dt_item + where dt.name = dt_item.parent + and dt.`{date_field}` > '2018-06-01' + and dt.docstatus = 1 + and ifnull(dt_item.gst_hsn_code, '') = '' + and ifnull(dt_item.item_code, '') != '' + and dt.company in ({company}) + """.format(dt=dt, date_field=date_field, company=", ".join(['%s']*len(company))), tuple(company), as_dict=1) + + if not transactions: + continue + + transaction_rows_name = [d.child_name for d in transactions] + + frappe.db.sql(""" + update `tab{dt} Item` dt_item + set dt_item.gst_hsn_code = (select gst_hsn_code from tabItem where name=dt_item.item_code) + where dt_item.name in ({rows_name}) + """.format(dt=dt, rows_name=", ".join(['%s']*len(transaction_rows_name))), tuple(transaction_rows_name)) + + parent = set([d.name for d in transactions]) + for t in list(parent): + trans_doc = frappe.get_doc(dt, t) + hsnwise_tax = get_itemised_tax_breakup_html(trans_doc) + frappe.db.set_value(dt, t, "other_charges_calculation", hsnwise_tax, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v11_0/update_delivery_trip_status.py b/erpnext/patches/v11_0/update_delivery_trip_status.py new file mode 100755 index 00000000000..64b3063bac1 --- /dev/null +++ b/erpnext/patches/v11_0/update_delivery_trip_status.py @@ -0,0 +1,27 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('stock', 'doctype', 'delivery_trip') + frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True) + + for trip in frappe.get_all("Delivery Trip"): + trip_doc = frappe.get_doc("Delivery Trip", trip.name) + + status = { + 0: "Draft", + 1: "Scheduled", + 2: "Cancelled" + }[trip_doc.docstatus] + + if trip_doc.docstatus == 1: + visited_stops = [stop.visited for stop in trip_doc.delivery_stops] + if all(visited_stops): + status = "Completed" + elif any(visited_stops): + status = "In Transit" + + frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False) diff --git a/erpnext/patches/v11_0/update_department_lft_rgt.py b/erpnext/patches/v11_0/update_department_lft_rgt.py index 5a8837ee2c3..b2f407b18ef 100644 --- a/erpnext/patches/v11_0/update_department_lft_rgt.py +++ b/erpnext/patches/v11_0/update_department_lft_rgt.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import frappe from frappe import _ from frappe.utils.nestedset import rebuild_tree diff --git a/erpnext/patches/v11_0/update_total_qty_field.py b/erpnext/patches/v11_0/update_total_qty_field.py index 5c7663d5aa2..8f086992b63 100644 --- a/erpnext/patches/v11_0/update_total_qty_field.py +++ b/erpnext/patches/v11_0/update_total_qty_field.py @@ -9,12 +9,12 @@ def execute(): frappe.reload_doc('stock', 'doctype', 'purchase_receipt') frappe.reload_doc('accounts', 'doctype', 'sales_invoice') frappe.reload_doc('accounts', 'doctype', 'purchase_invoice') - + doctypes = ["Sales Order", "Sales Invoice", "Delivery Note",\ "Purchase Order", "Purchase Invoice", "Purchase Receipt", "Quotation", "Supplier Quotation"] for doctype in doctypes: - total_qty = frappe.db.sql(''' + total_qty = frappe.db.sql(''' SELECT parent, SUM(qty) as qty FROM @@ -22,14 +22,25 @@ def execute(): GROUP BY parent ''' % (doctype), as_dict = True) - when_then = [] - for d in total_qty: - when_then.append(""" - when dt.name = '{0}' then {1} - """.format(frappe.db.escape(d.get("parent")), d.get("qty"))) + # Query to update total_qty might become too big, Update in batches + # batch_size is chosen arbitrarily, Don't try too hard to reason about it + batch_size = 100000 + for i in range(0, len(total_qty), batch_size): + batch_transactions = total_qty[i:i + batch_size] - if when_then: - frappe.db.sql(''' - UPDATE - `tab%s` dt SET dt.total_qty = CASE %s ELSE 0.0 END - ''' % (doctype, " ".join(when_then))) \ No newline at end of file + # UPDATE with CASE for some reason cannot use PRIMARY INDEX, + # causing all rows to be examined, leading to a very slow update + + # UPDATE with WHERE clause uses PRIMARY INDEX, but will lead to too many queries + + # INSERT with ON DUPLICATE KEY UPDATE uses PRIMARY INDEX + # and can perform multiple updates per query + # This is probably never used anywhere else as of now, but should be + values = [] + for d in batch_transactions: + values.append("('{}', {})".format(d.parent, d.qty)) + conditions = ",".join(values) + frappe.db.sql(""" + INSERT INTO `tab{}` (name, total_qty) VALUES {} + ON DUPLICATE KEY UPDATE name = VALUES(name), total_qty = VALUES(total_qty) + """.format(doctype, conditions)) diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 9f1c58601d9..8c84c11ae9c 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -128,6 +128,50 @@ class TestTimesheet(unittest.TestCase): settings.ignore_employee_time_overlap = initial_setting settings.save() + def test_timesheet_std_working_hours(self): + company = frappe.get_doc('Company', "_Test Company") + company.standard_working_hours = 8 + company.save() + + timesheet = frappe.new_doc("Timesheet") + timesheet.employee = "_T-Employee-00001" + timesheet.company = '_Test Company' + timesheet.append( + 'time_logs', + { + "activity_type": "_Test Activity Type", + "from_time": now_datetime(), + "to_time": now_datetime() + datetime.timedelta(days= 4) + } + ) + timesheet.save() + + ts = frappe.get_doc('Timesheet', timesheet.name) + self.assertEqual(ts.total_hours, 32) + ts.submit() + ts.cancel() + + company = frappe.get_doc('Company', "_Test Company") + company.standard_working_hours = 0 + company.save() + + timesheet = frappe.new_doc("Timesheet") + timesheet.employee = "_T-Employee-00001" + timesheet.company = '_Test Company' + timesheet.append( + 'time_logs', + { + "activity_type": "_Test Activity Type", + "from_time": now_datetime(), + "to_time": now_datetime() + datetime.timedelta(days= 4) + } + ) + timesheet.save() + + ts = frappe.get_doc('Timesheet', timesheet.name) + self.assertEqual(ts.total_hours, 96) + ts.submit() + ts.cancel() def make_salary_structure_for_timesheet(employee): salary_structure_name = "Timesheet Salary Structure Test" diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 5234df67ffb..e890befd1a2 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -90,6 +90,13 @@ frappe.ui.form.on("Timesheet", { } }, + company: function(frm) { + frappe.db.get_value('Company', { 'company_name' : frm.doc.company }, 'standard_working_hours') + .then(({ message }) => { + (frappe.working_hours = message.standard_working_hours || 0); + }); + }, + make_invoice: function(frm) { let dialog = new frappe.ui.Dialog({ title: __("Select Item (optional)"), @@ -142,11 +149,21 @@ frappe.ui.form.on("Timesheet Detail", { to_time: function(frm, cdt, cdn) { var child = locals[cdt][cdn]; + var time_diff = (moment(child.to_time).diff(moment(child.from_time),"seconds")) / ( 60 * 60 * 24); + var std_working_hours = 0; if(frm._setting_hours) return; - frappe.model.set_value(cdt, cdn, "hours", moment(child.to_time).diff(moment(child.from_time), - "seconds") / 3600); + + var hours = moment(child.to_time).diff(moment(child.from_time), "seconds") / 3600; + std_working_hours = time_diff * frappe.working_hours; + + if (std_working_hours < hours && std_working_hours > 0) { + frappe.model.set_value(cdt, cdn, "hours", std_working_hours); + } else { + frappe.model.set_value(cdt, cdn, "hours", hours); + } }, + time_logs_add: function(frm) { var $trigger_again = $('.form-grid').find('.grid-row').find('.btn-open-row'); $trigger_again.on('click', () => { @@ -209,17 +226,23 @@ var calculate_end_time = function(frm, cdt, cdn) { let d = moment(child.from_time); if(child.hours) { - d.add(child.hours, "hours"); - frm._setting_hours = true; - frappe.model.set_value(cdt, cdn, "to_time", - d.format(frappe.defaultDatetimeFormat)).then(() => { - frm._setting_hours = false; - }); - } + var time_diff = (moment(child.to_time).diff(moment(child.from_time),"seconds")) / (60 * 60 * 24); + var std_working_hours = 0; + var hours = moment(child.to_time).diff(moment(child.from_time), "seconds") / 3600; + std_working_hours = time_diff * frappe.working_hours; - if((frm.doc.__islocal || frm.doc.__onload.maintain_bill_work_hours_same) && child.hours){ - frappe.model.set_value(cdt, cdn, "billing_hours", child.hours); + if (std_working_hours < hours && std_working_hours > 0) { + frappe.model.set_value(cdt, cdn, "hours", std_working_hours); + frappe.model.set_value(cdt, cdn, "to_time", d.add(hours, "hours").format(frappe.defaultDatetimeFormat)); + } else { + d.add(child.hours, "hours"); + frm._setting_hours = true; + frappe.model.set_value(cdt, cdn, "to_time", + d.format(frappe.defaultDatetimeFormat)).then(() => { + frm._setting_hours = false; + }); + } } } diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index e5198dea639..0be147bfb1c 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -444,39 +445,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "start_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "User", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1032,7 +1000,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-28 14:44:32.912004", + "modified": "2018-11-15 07:58:42.629845", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index f48c0c634bd..4b466d26301 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -9,7 +9,7 @@ from frappe import _ import json from datetime import timedelta from erpnext.controllers.queries import get_match_cond -from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint +from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, date_diff, add_to_date from frappe.model.document import Document from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours, WorkstationHolidayError) @@ -27,6 +27,7 @@ class Timesheet(Document): self.set_status() self.validate_dates() self.validate_time_logs() + self.calculate_std_hours() self.update_cost() self.calculate_total_amounts() self.calculate_percentage_billed() @@ -93,6 +94,17 @@ class Timesheet(Document): self.start_date = getdate(start_date) self.end_date = getdate(end_date) + def calculate_std_hours(self): + std_working_hours = frappe.get_value("Company", self.company, 'standard_working_hours') + + for time in self.time_logs: + if time.from_time and time.to_time: + if flt(std_working_hours) > 0: + time.hours = flt(std_working_hours) * date_diff(time.to_time, time.from_time) + else: + if not time.hours: + time.hours = time_diff_in_hours(time.to_time, time.from_time) + def before_cancel(self): self.set_status() diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 21e02b7c80b..a2d44c3ae24 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -13,8 +13,8 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ + flt(effective_item_rate) * ( flt(item.margin_rate_or_amount) / 100); } else { item.rate_with_margin = flt(effective_item_rate) + flt(item.margin_rate_or_amount); - item.base_rate_with_margin = flt(item.rate_with_margin) * flt(this.frm.doc.conversion_rate); } + item.base_rate_with_margin = flt(item.rate_with_margin) * flt(this.frm.doc.conversion_rate); item.rate = flt(item.rate_with_margin , precision("rate", item)); diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 3e27d5638d0..035c58d6d2a 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -33,6 +33,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ item.margin_rate_or_amount = 0; item.rate_with_margin = 0; } + item.base_rate_with_margin = item.rate_with_margin * flt(frm.doc.conversion_rate); cur_frm.cscript.set_gross_profit(item); cur_frm.cscript.calculate_taxes_and_totals(); @@ -98,6 +99,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ frm.cscript.calculate_taxes_and_totals(); }); + frappe.ui.form.on(this.frm.doctype + " Item", { + items_add: function(frm, cdt, cdn) { + var item = frappe.get_doc(cdt, cdn); + if(!item.warehouse && frm.doc.set_warehouse) { + item.warehouse = frm.doc.set_warehouse; + } + } + }); + var me = this; if(this.frm.fields_dict["items"].grid.get_field('batch_no')) { this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) { @@ -175,6 +185,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }, + is_return: function() { + if(!this.frm.doc.is_return && this.frm.doc.return_against) { + this.frm.set_value('return_against', ''); + } + }, + setup_quality_inspection: function() { if(!in_list(["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype)) { return; @@ -253,6 +269,62 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ this.set_dynamic_labels(); this.setup_sms(); this.setup_quality_inspection(); + this.frm.fields_dict["scan_barcode"] && this.frm.fields_dict["scan_barcode"].set_value(""); + this.frm.fields_dict["scan_barcode"] && this.frm.fields_dict["scan_barcode"].set_new_description(""); + }, + + scan_barcode: function() { + let scan_barcode_field = this.frm.fields_dict["scan_barcode"]; + + let show_description = function(idx, item_code, exist=null) { + if(exist) { + scan_barcode_field.set_new_description(__('Row : ') + idx + ' ' + + item_code + __(' Qty increased by 1')); + } else { + scan_barcode_field.set_new_description(__('New row : ') + idx + ' ' + + item_code + __(' Created')); + } + } + + if(this.frm.doc.scan_barcode) { + frappe.call({ + method: "erpnext.selling.page.point_of_sale.point_of_sale.search_serial_or_batch_or_barcode_number", + args: { search_value: this.frm.doc.scan_barcode } + }).then(r => { + + if(r && r.message && r.message.item_code) { + let child = ""; + let add_row_index = -1; + let cur_grid= this.frm.fields_dict["items"].grid; + + this.frm.doc.items.map(d => { + if(d.item_code==r.message.item_code){ + add_row_index = d.idx; + return; + } else if(!d.item_code && add_row_index==-1) { + add_row_index = d.idx; + } + }); + + if(add_row_index == -1) { + child = frappe.model.add_child(this.frm.doc, cur_grid.doctype, "items", add_row_index); + } else { + child = cur_grid.get_grid_row(add_row_index-1).doc; + } + show_description(child.idx, r.message.item_code, child.item_code); + + frappe.model.set_value(child.doctype, child.name, { + "item_code": r.message.item_code, + "qty": (child.qty || 0) + 1 + }); + } + else{ + scan_barcode_field.set_new_description(this.frm.doc.scan_barcode +__(' does not exist!')); + } + }); + scan_barcode_field.set_value(""); + } + return false; }, apply_default_taxes: function() { @@ -1407,6 +1479,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }) } + }, + + set_warehouse: function() { + var me = this; + if(this.frm.doc.set_warehouse) { + $.each(this.frm.doc.items || [], function(i, item) { + frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse); + }); + } } }); diff --git a/erpnext/public/js/hub/PageContainer.vue b/erpnext/public/js/hub/PageContainer.vue index 5ec92d581b7..a101eaf4d38 100644 --- a/erpnext/public/js/hub/PageContainer.vue +++ b/erpnext/public/js/hub/PageContainer.vue @@ -1,6 +1,6 @@ @@ -100,10 +100,16 @@ export default { } if (!route) { - return NotFound; + return { + key: 'not-found', + component: NotFound + }; } - return route_map[route]; + return { + key: curr_route, + component: route_map[route] + } } } } diff --git a/erpnext/public/js/hub/components/ReviewArea.vue b/erpnext/public/js/hub/components/ReviewArea.vue index 51b9ab15024..5e4e439f3d0 100644 --- a/erpnext/public/js/hub/components/ReviewArea.vue +++ b/erpnext/public/js/hub/components/ReviewArea.vue @@ -113,6 +113,10 @@ export default { content: this.review_content.get_value() }); + if (!hub.is_seller_registered()) { + frappe.throw(__('You need to login as a Marketplace User before you can add any reviews.')); + } + hub.call('add_item_review', { hub_item_name: this.hub_item_name, review: JSON.stringify(review) diff --git a/erpnext/public/js/hub/event_emitter.js b/erpnext/public/js/hub/event_emitter.js deleted file mode 100644 index 1e7288191d0..00000000000 --- a/erpnext/public/js/hub/event_emitter.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Simple EventEmitter which uses jQuery's event system - */ -class EventEmitter { - init() { - this.jq = jQuery(this); - } - - trigger(evt, data) { - !this.jq && this.init(); - this.jq.trigger(evt, data); - } - - once(evt, handler) { - !this.jq && this.init(); - this.jq.one(evt, (e, data) => handler(data)); - } - - on(evt, handler) { - !this.jq && this.init(); - this.jq.bind(evt, (e, data) => handler(data)); - } - - off(evt, handler) { - !this.jq && this.init(); - this.jq.unbind(evt, (e, data) => handler(data)); - } -} - - -export default EventEmitter; \ No newline at end of file diff --git a/erpnext/public/js/hub/marketplace.js b/erpnext/public/js/hub/marketplace.js index 7ef87c4eb69..a1596e0043b 100644 --- a/erpnext/public/js/hub/marketplace.js +++ b/erpnext/public/js/hub/marketplace.js @@ -8,14 +8,13 @@ import { ProfileDialog } from './components/profile_dialog'; // helpers import './hub_call'; -import EventEmitter from './event_emitter'; frappe.provide('hub'); frappe.provide('erpnext.hub'); frappe.provide('frappe.route'); -$.extend(erpnext.hub, EventEmitter.prototype); -$.extend(frappe.route, EventEmitter.prototype); +frappe.utils.make_event_emitter(frappe.route); +frappe.utils.make_event_emitter(erpnext.hub); erpnext.hub.Marketplace = class Marketplace { constructor({ parent }) { diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue index 651533eae36..7735aa23376 100644 --- a/erpnext/public/js/hub/pages/Item.vue +++ b/erpnext/public/js/hub/pages/Item.vue @@ -265,6 +265,9 @@ export default { }, report_item() { + if (!hub.is_seller_registered()) { + frappe.throw(__('Please login as a Marketplace User to report this item.')); + } this.report_item_dialog.show(); }, diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less index e962e912111..b746cc138f6 100644 --- a/erpnext/public/less/erpnext.less +++ b/erpnext/public/less/erpnext.less @@ -426,6 +426,12 @@ body[data-route="pos"] { .collapse-btn { cursor: pointer; } + + @media (max-width: @screen-xs) { + .page-actions { + max-width: 110px; + } + } } .price-info { diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index c7541212990..5fc06eabb7f 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -85,7 +85,7 @@ def add_print_formats(): def make_custom_fields(update=True): hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', - fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description', + fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description', allow_on_submit=1, print_hide=1) invoice_gst_fields = [ dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break', @@ -350,12 +350,17 @@ def set_tax_withholding_category(company): def set_tds_account(docs, company): abbr = frappe.get_value("Company", company, "abbr") - docs.extend([ - { - "doctype": "Account", "account_name": "TDS Payable", "account_type": "Tax", - "parent_account": "Duties and Taxes - {0}".format(abbr), "company": company - } - ]) + parent_account = frappe.db.get_value("Account", filters = {"account_name": "Duties and Taxes", "company": company}) + if parent_account: + docs.extend([ + { + "doctype": "Account", + "account_name": "TDS Payable", + "account_type": "Tax", + "parent_account": parent_account, + "company": company + } + ]) def get_tds_details(accounts, fiscal_year): # bootstrap default tax withholding sections diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 5275e2e2963..54d7654c2dd 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -150,6 +150,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( && flt(doc.per_delivered, 6) < 100) { this.frm.add_custom_button(__('Material Request'), function() { me.make_material_request() }, __("Make")); + this.frm.add_custom_button(__('Request for Raw Materials'), + function() { me.make_raw_material_request() }, __("Make")); } // make purchase order @@ -313,6 +315,86 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }) }, + make_raw_material_request: function() { + var me = this; + this.frm.call({ + doc: this.frm.doc, + method: 'get_work_order_items', + args: { + for_raw_material_request: 1 + }, + callback: function(r) { + if(!r.message) { + frappe.msgprint({ + message: __('No Items with Bill of Materials.'), + indicator: 'orange' + }); + return; + } + else { + me.make_raw_material_request_dialog(r); + } + } + }); + }, + + make_raw_material_request_dialog: function(r) { + var fields = [ + {fieldtype:'Check', fieldname:'include_exploded_items', + label: __('Include Exploded Items')}, + {fieldtype:'Check', fieldname:'ignore_existing_ordered_qty', + label: __('Ignore Existing Ordered Qty')}, + { + fieldtype:'Table', fieldname: 'items', + description: __('Select BOM, Qty and For Warehouse'), + fields: [ + {fieldtype:'Read Only', fieldname:'item_code', + label: __('Item Code'), in_list_view:1}, + {fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1, + label: __('BOM'), in_list_view:1, get_query: function(doc) { + return {filters: {item: doc.item_code}}; + } + }, + {fieldtype:'Float', fieldname:'required_qty', reqd: 1, + label: __('Qty'), in_list_view:1}, + {fieldtype:'Link', fieldname:'for_warehouse', options: 'Warehouse', + label: __('For Warehouse')} + ], + data: r.message, + get_data: function() { + return r.message + } + } + ] + var d = new frappe.ui.Dialog({ + title: __("Select from Items having BOM"), + fields: fields, + primary_action: function() { + var data = d.get_values(); + me.frm.call({ + method: 'erpnext.selling.doctype.sales_order.sales_order.make_raw_material_request', + args: { + items: data, + company: me.frm.doc.company, + sales_order: me.frm.docname, + project: me.frm.project + }, + freeze: true, + callback: function(r) { + if(r.message) { + frappe.msgprint(__('Material Request {0} submitted.', + ['' + r.message.name+ ''])); + } + d.hide(); + me.frm.reload_doc(); + } + }); + }, + primary_action_label: __('Make') + }); + d.show(); + }, + make_delivery_note_based_on_delivery_date: function() { var me = this; @@ -423,7 +505,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( filters: {'parent': me.frm.doc.name} } }}, - + {"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order", "cssClass": "btn-primary"}, ] }); diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 22e574167c2..0f3b6776ca1 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -1171,6 +1172,70 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "set_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Set Source Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1204,6 +1269,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "scan_barcode", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scan Barcode", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 1, "allow_in_quick_entry": 0, @@ -3918,7 +4015,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-21 14:44:44.011356", + "modified": "2018-11-12 20:00:35.272747", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index db39545c57a..5f435ced745 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -5,8 +5,9 @@ from __future__ import unicode_literals import frappe import json import frappe.utils -from frappe.utils import cstr, flt, getdate, comma_and, cint +from frappe.utils import cstr, flt, getdate, comma_and, cint, nowdate, add_days from frappe import _ +from six import string_types from frappe.model.utils import get_fetch_values from frappe.model.mapper import get_mapped_doc from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty @@ -17,6 +18,7 @@ from frappe.desk.doctype.auto_repeat.auto_repeat import get_next_schedule_date from erpnext.selling.doctype.customer.customer import check_credit_limit from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults +from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -346,7 +348,15 @@ class SalesOrder(SellingController): def set_indicator(self): """Set indicator for portal""" - if self.per_billed < 100 and self.per_delivered < 100: + if self.status == 'Closed': + self.indicator_color = "green" + self.indicator_title = _("Closed") + + elif self.per_delivered < 100 and getdate(self.delivery_date) < getdate(nowdate()): + self.indicator_color = "red" + self.indicator_title = _("Overdue") + + elif self.per_billed < 100 and self.per_delivered < 100: self.indicator_color = "orange" self.indicator_title = _("Not Paid and Not Delivered") @@ -358,7 +368,7 @@ class SalesOrder(SellingController): self.indicator_color = "green" self.indicator_title = _("Paid") - def get_work_order_items(self): + def get_work_order_items(self, for_raw_material_request=0): '''Returns items with BOM that already do not have a linked work order''' items = [] @@ -367,8 +377,13 @@ class SalesOrder(SellingController): bom = get_default_bom_item(i.item_code) if bom: stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty - pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabWork Order` + if not for_raw_material_request: + total_work_order_qty = flt(frappe.db.sql('''select sum(qty) from `tabWork Order` where production_item=%s and sales_order=%s and sales_order_item = %s and docstatus<2''', (i.item_code, self.name, i.name))[0][0]) + pending_qty = stock_qty - total_work_order_qty + else: + pending_qty = stock_qty + if pending_qty: items.append(dict( name= i.name, @@ -376,6 +391,7 @@ class SalesOrder(SellingController): bom = bom, warehouse = i.warehouse, pending_qty = pending_qty, + required_qty = pending_qty if for_raw_material_request else 0, sales_order_item = i.name )) return items @@ -838,7 +854,7 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters): or supplier_name like %(txt)s) and name in (select supplier from `tabSales Order Item` where parent = %(parent)s) and name not in (select supplier from `tabPurchase Order` po inner join `tabPurchase Order Item` poi - on po.name=poi.parent where po.docstatus<2 and poi.sales_order=%(parent)s) + on po.name=poi.parent where po.docstatus<2 and poi.sales_order=%(parent)s) order by if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999), @@ -894,3 +910,44 @@ def get_default_bom_item(item_code): bom = bom[0].name if bom else None return bom + +@frappe.whitelist() +def make_raw_material_request(items, company, sales_order, project=None): + if not frappe.has_permission("Sales Order", "write"): + frappe.throw(_("Not permitted"), frappe.PermissionError) + + if isinstance(items, string_types): + items = frappe._dict(json.loads(items)) + + for item in items.get('items'): + item["include_exploded_items"] = items.get('include_exploded_items') + item["ignore_existing_ordered_qty"] = items.get('ignore_existing_ordered_qty') + + raw_materials = get_items_for_material_requests(items, company) + if not raw_materials: + frappe.msgprint(_("Material Request not created, as quantity for Raw Materials already available.")) + + material_request = frappe.new_doc('Material Request') + material_request.update(dict( + doctype = 'Material Request', + transaction_date = nowdate(), + company = company, + requested_by = frappe.session.user, + material_request_type = 'Purchase' + )) + for item in raw_materials: + item_doc = frappe.get_cached_doc('Item', item.get('item_code')) + schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days)) + material_request.append('items', { + 'item_code': item.get('item_code'), + 'qty': item.get('quantity'), + 'schedule_date': schedule_date, + 'warehouse': item.get('warehouse'), + 'sales_order': sales_order, + 'project': project + }) + material_request.insert() + material_request.flags.ignore_permissions = 1 + material_request.run_method("set_missing_values") + material_request.submit() + return material_request \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 538ea557370..65e91bc2476 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -11,8 +11,7 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.selling.doctype.sales_order.sales_order import make_work_orders from erpnext.controllers.accounts_controller import update_child_qty_rate import json - - +from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request class TestSalesOrder(unittest.TestCase): def tearDown(self): frappe.set_user("Administrator") @@ -327,9 +326,8 @@ class TestSalesOrder(unittest.TestCase): self.assertRaises(frappe.CancelledLinkError, dn.submit) def test_service_type_product_bundle(self): - from erpnext.stock.doctype.item.test_item import make_item from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle - + from erpnext.stock.doctype.item.test_item import make_item make_item("_Test Service Product Bundle", {"is_stock_item": 0}) make_item("_Test Service Product Bundle Item 1", {"is_stock_item": 0}) make_item("_Test Service Product Bundle Item 2", {"is_stock_item": 0}) @@ -343,9 +341,8 @@ class TestSalesOrder(unittest.TestCase): self.assertTrue("_Test Service Product Bundle Item 2" in [d.item_code for d in so.packed_items]) def test_mix_type_product_bundle(self): - from erpnext.stock.doctype.item.test_item import make_item from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle - + from erpnext.stock.doctype.item.test_item import make_item make_item("_Test Mix Product Bundle", {"is_stock_item": 0}) make_item("_Test Mix Product Bundle Item 1", {"is_stock_item": 1}) make_item("_Test Mix Product Bundle Item 2", {"is_stock_item": 0}) @@ -388,11 +385,10 @@ class TestSalesOrder(unittest.TestCase): def test_drop_shipping(self): from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment - from erpnext.stock.doctype.item.test_item import make_item from erpnext.buying.doctype.purchase_order.purchase_order import update_status make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100) - + from erpnext.stock.doctype.item.test_item import make_item po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "delivered_by_supplier": 1}) dn_item = make_item("_Test Regular Item", {"is_stock_item": 1}) @@ -585,8 +581,8 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(wo_qty[0][0], so_item_name.get(item)) def test_serial_no_based_delivery(self): - from erpnext.stock.doctype.item.test_item import make_item frappe.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1) + from erpnext.stock.doctype.item.test_item import make_item item = make_item("_Reserved_Serialized_Item", {"is_stock_item": 1, "maintain_stock": 1, "has_serial_no": 1, @@ -685,12 +681,62 @@ class TestSalesOrder(unittest.TestCase): se.cancel() self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name})) + def test_request_for_raw_materials(self): + from erpnext.stock.doctype.item.test_item import make_item + item = make_item("_Test Finished Item", {"is_stock_item": 1, + "maintain_stock": 1, + "valuation_rate": 500, + "item_defaults": [ + { + "default_warehouse": "_Test Warehouse - _TC", + "company": "_Test Company" + }] + }) + make_item("_Test Raw Item A", {"maintain_stock": 1, + "valuation_rate": 100, + "item_defaults": [ + { + "default_warehouse": "_Test Warehouse - _TC", + "company": "_Test Company" + }] + }) + make_item("_Test Raw Item B", {"maintain_stock": 1, + "valuation_rate": 200, + "item_defaults": [ + { + "default_warehouse": "_Test Warehouse - _TC", + "company": "_Test Company" + }] + }) + from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom + make_bom(item=item.item_code, rate=1000, + raw_materials = ['_Test Raw Item A', '_Test Raw Item B']) + + so = make_sales_order(**{ + "item_list": [{ + "item_code": item.item_code, + "qty": 1, + "rate":1000 + }] + }) + so.submit() + mr_dict = frappe._dict() + items = so.get_work_order_items(1) + mr_dict['items'] = items + mr_dict['include_exploded_items'] = 0 + mr_dict['ignore_existing_ordered_qty'] = 1 + make_raw_material_request(mr_dict, so.company, so.name) + mr = frappe.db.sql("""select name from `tabMaterial Request` ORDER BY creation DESC LIMIT 1""", as_dict=1)[0] + mr_doc = frappe.get_doc('Material Request',mr.get('name')) + self.assertEqual(mr_doc.items[0].sales_order, so.name) + def make_sales_order(**args): so = frappe.new_doc("Sales Order") args = frappe._dict(args) if args.transaction_date: so.transaction_date = args.transaction_date + so.set_warehouse = "" # no need to test set_warehouse permission since it only affects the client so.company = args.company or "_Test Company" so.customer = args.customer or "_Test Customer" so.currency = args.currency or "INR" @@ -714,7 +760,7 @@ def make_sales_order(**args): }) so.delivery_date = add_days(so.transaction_date, 10) - + if not args.do_not_save: so.insert() if not args.do_not_submit: diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py index f3674ae373a..bb6ba1ffce4 100644 --- a/erpnext/selling/doctype/sms_center/sms_center.py +++ b/erpnext/selling/doctype/sms_center/sms_center.py @@ -15,19 +15,24 @@ class SMSCenter(Document): def create_receiver_list(self): rec, where_clause = '', '' if self.send_to == 'All Customer Contact': - where_clause = self.customer and " and customer = '%s'" % \ - self.customer.replace("'", "\'") or " and ifnull(customer, '') != ''" + where_clause = " and dl.link_doctype = 'Customer'" + if self.customer: + where_clause += " and dl.link_name = '%s'" % \ + self.customer.replace("'", "\'") or " and ifnull(dl.link_name, '') != ''" if self.send_to == 'All Supplier Contact': - where_clause = self.supplier and " and supplier = '%s'" % \ - self.supplier.replace("'", "\'") or " and ifnull(supplier, '') != ''" + where_clause = " and dl.link_doctype = 'Supplier'" + if self.supplier: + where_clause += " and dl.link_name = '%s'" % \ + self.supplier.replace("'", "\'") or " and ifnull(dl.link_name, '') != ''" if self.send_to == 'All Sales Partner Contact': - where_clause = self.sales_partner and " and sales_partner = '%s'" % \ - self.sales_partner.replace("'", "\'") or " and ifnull(sales_partner, '') != ''" - + where_clause = " and dl.link_doctype = 'Sales Partner'" + if self.sales_partner: + where_clause += "and dl.link_name = '%s'" % \ + self.sales_partner.replace("'", "\'") or " and ifnull(dl.link_name, '') != ''" if self.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']: - rec = frappe.db.sql("""select CONCAT(ifnull(first_name,''), ' ', ifnull(last_name,'')), - mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and - docstatus != 2 %s""" % where_clause) + rec = frappe.db.sql("""select CONCAT(ifnull(c.first_name,''), ' ', ifnull(c.last_name,'')), + c.mobile_no from `tabContact` c, `tabDynamic Link` dl where ifnull(c.mobile_no,'')!='' and + c.docstatus != 2 and dl.parent = c.name%s""" % where_clause) elif self.send_to == 'All Lead (Open)': rec = frappe.db.sql("""select lead_name, mobile_no from `tabLead` where @@ -50,7 +55,6 @@ class SMSCenter(Document): where ifnull(tabEmployee.cell_number,'')!=''""") rec_list = '' - for d in rec: rec_list += d[0] + ' - ' + d[1] + '\n' self.receiver_list = rec_list diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index ed28204f10b..daec5b5a218 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -11,12 +11,9 @@ from six import string_types @frappe.whitelist() def get_items(start, page_length, price_list, item_group, search_value="", pos_profile=None): - serial_no = "" - batch_no = "" - barcode = "" + data = dict() warehouse = "" display_items_in_stock = 0 - item_code = search_value if pos_profile: warehouse, display_items_in_stock = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'display_items_in_stock']) @@ -25,20 +22,12 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p item_group = get_root_of('Item Group') if search_value: - # search serial no - serial_no_data = frappe.db.get_value('Serial No', search_value, ['name', 'item_code']) - if serial_no_data: - serial_no, item_code = serial_no_data + data = search_serial_or_batch_or_barcode_number(search_value) - if not serial_no: - batch_no_data = frappe.db.get_value('Batch', search_value, ['name', 'item']) - if batch_no_data: - batch_no, item_code = batch_no_data - - if not serial_no and not batch_no: - barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['parent', 'barcode']) - if barcode_data: - item_code, barcode = barcode_data + item_code = data.get("item_code") if data.get("item_code") else search_value + serial_no = data.get("serial_no") if data.get("serial_no") else "" + batch_no = data.get("batch_no") if data.get("batch_no") else "" + barcode = data.get("barcode") if data.get("barcode") else "" item_code, condition = get_conditions(item_code, serial_no, batch_no, barcode) @@ -119,6 +108,23 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p return res +@frappe.whitelist() +def search_serial_or_batch_or_barcode_number(search_value): + # search barcode no + barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['barcode', 'parent as item_code'], as_dict=True) + if barcode_data: + return barcode_data + + # search serial no + serial_no_data = frappe.db.get_value('Serial No', search_value, ['name as serial_no', 'item_code'], as_dict=True) + if serial_no_data: + return serial_no_data + + # search batch no + batch_no_data = frappe.db.get_value('Batch', search_value, ['name as batch_no', 'item as item_code'], as_dict=True) + if batch_no_data: + return batch_no_data + def get_conditions(item_code, serial_no, batch_no, barcode): if serial_no or batch_no or barcode: return frappe.db.escape(item_code), "i.name = %(item_code)s" diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.json b/erpnext/selling/report/address_and_contacts/address_and_contacts.json index da38babbdc1..876c39c0cf6 100644 --- a/erpnext/selling/report/address_and_contacts/address_and_contacts.json +++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.json @@ -6,8 +6,7 @@ "docstatus": 0, "doctype": "Report", "idx": 0, - "is_standard": "Yes", - "letter_head": "Test", + "is_standard": "Yes", "modified": "2018-06-01 09:39:39.604944", "modified_by": "Administrator", "module": "Selling", @@ -30,4 +29,4 @@ "role": "Accounts User" } ] -} \ No newline at end of file +} diff --git a/erpnext/selling/report/sales_analytics/__init__.py b/erpnext/selling/report/sales_analytics/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js new file mode 100644 index 00000000000..7dc7c754bcd --- /dev/null +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -0,0 +1,123 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Sales Analytics"] = { + "filters": [ + { + fieldname: "tree_type", + label: __("Tree Type"), + fieldtype: "Select", + options: ["Customer Group","Customer","Item Group","Item","Territory"], + default: "Customer", + reqd: 1 + }, + { + fieldname: "doc_type", + label: __("based_on"), + fieldtype: "Select", + options: ["Sales Order","Delivery Note","Sales Invoice"], + default: "Sales Invoice", + reqd: 1 + }, + { + fieldname: "value_quantity", + label: __("Value Or Qty"), + fieldtype: "Select", + options: [ + { "value": "Value", "label": __("Value") }, + { "value": "Quantity", "label": __("Quantity") }, + ], + default: "Value", + reqd: 1 + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + default: frappe.defaults.get_user_default("year_start_date"), + reqd: 1 + }, + { + fieldname:"to_date", + label: __("To Date"), + fieldtype: "Date", + default: frappe.defaults.get_user_default("year_end_date"), + reqd: 1 + }, + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company"), + reqd: 1 + }, + { + fieldname: "range", + label: __("Range"), + fieldtype: "Select", + options: [ + { "value": "Weekly", "label": __("Weekly") }, + { "value": "Monthly", "label": __("Monthly") }, + { "value": "Quarterly", "label": __("Quarterly") }, + { "value": "Yearly", "label": __("Yearly") } + ], + default: "Monthly", + reqd: 1 + } + ], + get_datatable_options(options) { + return Object.assign(options, { + checkboxColumn: true, + events: { + onCheckRow: function(data) { + row_name = data[2].content; + length = data.length + row_values = data.slice(4,length-1).map(function (column) { + return column.content; + }) + entry = { + 'name':row_name, + 'values':row_values + } + + let raw_data = frappe.query_report.chart.data; + let new_datasets = raw_data.datasets; + + var found = false; + + for(var i=0; i < new_datasets.length;i++){ + if(new_datasets[i].name == row_name){ + found = true; + new_datasets.splice(i,1); + break; + } + } + + if(!found){ + new_datasets.push(entry); + } + + let new_data = { + labels: raw_data.labels, + datasets: new_datasets + } + + setTimeout(() => { + frappe.query_report.chart.update(new_data) + },200) + + + setTimeout(() => { + frappe.query_report.chart.draw(true); + }, 800) + + frappe.query_report.raw_chart_data = new_data; + }, + } + }) + }, +} + + diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.json b/erpnext/selling/report/sales_analytics/sales_analytics.json new file mode 100644 index 00000000000..5c95f284101 --- /dev/null +++ b/erpnext/selling/report/sales_analytics/sales_analytics.json @@ -0,0 +1,32 @@ +{ + "add_total_row": 0, + "creation": "2018-09-21 12:46:29.451048", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2018-09-21 12:46:29.451048", + "modified_by": "Administrator", + "module": "Selling", + "name": "Sales Analytics", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Order", + "report_name": "Sales Analytics", + "report_type": "Script Report", + "roles": [ + { + "role": "Stock User" + }, + { + "role": "Maintenance User" + }, + { + "role": "Accounts User" + }, + { + "role": "Sales Manager" + } + ] +} \ No newline at end of file diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py new file mode 100644 index 00000000000..8d99a9b7897 --- /dev/null +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -0,0 +1,287 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _, scrub +from frappe.utils import getdate, flt +from six import iteritems +from erpnext.accounts.utils import get_fiscal_year + +def execute(filters=None): + return Analytics(filters).run() + +class Analytics(object): + def __init__(self, filters=None): + self.filters = frappe._dict(filters or {}) + self.date_field = 'transaction_date' \ + if self.filters.doc_type in ['Sales Order', 'Purchase Order'] else 'posting_date' + self.months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + self.get_period_date_ranges() + + def run(self): + self.get_columns() + self.get_data() + self.get_chart_data() + return self.columns, self.data , None, self.chart + + def get_columns(self): + self.columns =[{ + "label": _(self.filters.tree_type + " ID"), + "options": self.filters.tree_type, + "fieldname": "entity", + "fieldtype": "Link", + "width": 140 + }] + if self.filters.tree_type in ["Customer", "Supplier", "Item"]: + self.columns.append({ + "label": _(self.filters.tree_type + " Name"), + "fieldname": "entity_name", + "fieldtype": "Data", + "width": 140 + }) + for dummy, end_date in self.periodic_daterange: + period = self.get_period(end_date) + self.columns.append({ + "label": _(period), + "fieldname": scrub(period), + "fieldtype": "Float", + "width": 120 + }) + + self.columns.append({ + "label": _("Total"), + "fieldname": "total", + "fieldtype": "Float", + "width": 120 + }) + + def get_data(self): + if self.filters.tree_type in ["Customer", "Supplier"]: + self.get_sales_transactions_based_on_customers_or_suppliers() + self.get_rows() + + elif self.filters.tree_type == 'Item': + self.get_sales_transactions_based_on_items() + self.get_rows() + + elif self.filters.tree_type in ["Customer Group", "Supplier Group", "Territory"]: + self.get_sales_transactions_based_on_customer_or_territory_group() + self.get_rows_by_group() + + elif self.filters.tree_type == 'Item Group': + self.get_sales_transactions_based_on_item_group() + self.get_rows_by_group() + + def get_sales_transactions_based_on_customers_or_suppliers(self): + if self.filters["value_quantity"] == 'Value': + value_field = "base_net_total as value_field" + else: + value_field = "total_qty as value_field" + + if self.filters.tree_type == 'Customer': + entity = "customer as entity" + entity_name = "customer_name as entity_name" + else: + entity = "supplier as entity" + entity_name = "supplier_name as entity_name" + + self.entries = frappe.get_all(self.filters.doc_type, + fields=[entity, entity_name, value_field, self.date_field], + filters = { + "docstatus": 1, + "company": self.filters.company, + self.date_field: ('between', [self.filters.from_date, self.filters.to_date]) + } + ) + + self.entity_names = {} + for d in self.entries: + self.entity_names.setdefault(d.entity, d.entity_name) + + def get_sales_transactions_based_on_items(self): + + if self.filters["value_quantity"] == 'Value': + value_field = 'base_amount' + else: + value_field = 'qty' + + self.entries = frappe.db.sql(""" + select i.item_code as entity, i.item_name as entity_name, i.{value_field} as value_field, s.{date_field} + from `tab{doctype} Item` i , `tab{doctype}` s + where s.name = i.parent and i.docstatus = 1 and s.company = %s + and s.{date_field} between %s and %s + """ + .format(date_field=self.date_field, value_field = value_field, doctype=self.filters.doc_type), + (self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1) + + self.entity_names = {} + for d in self.entries: + self.entity_names.setdefault(d.entity, d.entity_name) + + def get_sales_transactions_based_on_customer_or_territory_group(self): + if self.filters["value_quantity"] == 'Value': + value_field = "base_net_total as value_field" + else: + value_field = "total_qty as value_field" + + if self.filters.tree_type == 'Customer Group': + entity_field = 'customer_group as entity' + elif self.filters.tree_type == 'Supplier Group': + entity_field = "supplier as entity" + self.get_supplier_parent_child_map() + else: + entity_field = "territory as entity" + + self.entries = frappe.get_all(self.filters.doc_type, + fields=[entity_field, value_field, self.date_field], + filters = { + "docstatus": 1, + "company": self.filters.company, + self.date_field: ('between', [self.filters.from_date, self.filters.to_date]) + } + ) + self.get_groups() + + def get_sales_transactions_based_on_item_group(self): + if self.filters["value_quantity"] == 'Value': + value_field = "base_amount" + else: + value_field = "qty" + + self.entries = frappe.db.sql(""" + select i.item_group as entity, i.{value_field} as value_field, s.{date_field} + from `tab{doctype} Item` i , `tab{doctype}` s + where s.name = i.parent and i.docstatus = 1 and s.company = %s + and s.{date_field} between %s and %s + """.format(date_field=self.date_field, value_field = value_field, doctype=self.filters.doc_type), + (self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1) + + self.get_groups() + + def get_rows(self): + self.data=[] + self.get_periodic_data() + + for entity, period_data in iteritems(self.entity_periodic_data): + row = { + "entity": entity, + "entity_name": self.entity_names.get(entity) + } + total = 0 + for dummy, end_date in self.periodic_daterange: + period = self.get_period(end_date) + amount = flt(period_data.get(period, 0.0)) + row[scrub(period)] = amount + total += amount + + row["total"] = total + self.data.append(row) + + def get_rows_by_group(self): + self.get_periodic_data() + out = [] + + for d in reversed(self.group_entries): + row = { + "entity": d.name, + "indent": self.depth_map.get(d.name) + } + total = 0 + for dummy, end_date in self.periodic_daterange: + period = self.get_period(end_date) + amount = flt(self.entity_periodic_data.get(d.name, {}).get(period, 0.0)) + row[scrub(period)] = amount + if d.parent: + self.entity_periodic_data.setdefault(d.parent, frappe._dict()).setdefault(period, 0.0) + self.entity_periodic_data[d.parent][period] += amount + total += amount + row["total"] = total + out = [row] + out + self.data = out + + def get_periodic_data(self): + self.entity_periodic_data = frappe._dict() + + for d in self.entries: + if self.filters.tree_type == "Supplier Group": + d.entity = self.parent_child_map.get(d.entity) + period = self.get_period(d.get(self.date_field)) + self.entity_periodic_data.setdefault(d.entity, frappe._dict()).setdefault(period, 0.0) + self.entity_periodic_data[d.entity][period] += flt(d.value_field) + + def get_period(self, posting_date): + if self.filters.range == 'Weekly': + period = "Week " + str(posting_date.isocalendar()[1]) + elif self.filters.range == 'Monthly': + period = self.months[posting_date.month - 1] + elif self.filters.range == 'Quarterly': + period = "Quarter " + str(((posting_date.month-1)//3)+1) + else: + year = get_fiscal_year(posting_date, company=self.filters.company) + period = str(year[2]) + + return period + + def get_period_date_ranges(self): + from dateutil.relativedelta import relativedelta + from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date) + + increment = { + "Monthly": 1, + "Quarterly": 3, + "Half-Yearly": 6, + "Yearly": 12 + }.get(self.filters.range, 1) + + self.periodic_daterange = [] + for dummy in range(1, 53, increment): + if self.filters.range == "Weekly": + period_end_date = from_date + relativedelta(days=6) + else: + period_end_date = from_date + relativedelta(months=increment, days=-1) + + if period_end_date > to_date: + period_end_date = to_date + self.periodic_daterange.append([from_date, period_end_date]) + + from_date = period_end_date + relativedelta(days=1) + if period_end_date == to_date: + break + + def get_groups(self): + if self.filters.tree_type == "Territory": + parent = 'parent_territory' + if self.filters.tree_type == "Customer Group": + parent = 'parent_customer_group' + if self.filters.tree_type == "Item Group": + parent = 'parent_item_group' + if self.filters.tree_type == "Supplier Group": + parent = 'parent_supplier_group' + + self.depth_map = frappe._dict() + + self.group_entries = frappe.db.sql("""select name, lft, rgt , {parent} as parent + from `tab{tree}` order by lft""" + .format(tree=self.filters.tree_type, parent=parent), as_dict=1) + + for d in self.group_entries: + if d.parent: + self.depth_map.setdefault(d.name, self.depth_map.get(d.parent) + 1) + else: + self.depth_map.setdefault(d.name, 0) + + def get_supplier_parent_child_map(self): + self.parent_child_map = frappe._dict(frappe.db.sql(""" select name, supplier_group from `tabSupplier`""")) + + def get_chart_data(self): + length = len(self.columns) + labels = [d.get("label") for d in self.columns[2:length-1]] + self.chart = { + "data": { + 'labels': labels, + 'datasets':[ + ] + }, + "type": "line" + } \ No newline at end of file diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py new file mode 100644 index 00000000000..f59fff46f77 --- /dev/null +++ b/erpnext/selling/report/sales_analytics/test_analytics.py @@ -0,0 +1,228 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import frappe +import frappe.defaults +import unittest +from erpnext.selling.report.sales_analytics.sales_analytics import execute +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + +class TestAnalytics(unittest.TestCase): + def test_sales_analytics(self): + frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'") + + create_sales_orders() + + self.compare_result_for_customer() + self.compare_result_for_customer_group() + self.compare_result_for_customer_based_on_quantity() + + + def compare_result_for_customer(self): + filters = { + 'doc_type': 'Sales Order', + 'range': 'Monthly', + 'to_date': '2018-03-31', + 'tree_type': 'Customer', + 'company': '_Test Company 2', + 'from_date': '2017-04-01', + 'value_quantity': 'Value' + } + + report = execute(filters) + + expected_data = [ + { + "entity": "_Test Customer 1", + "entity_name": "_Test Customer 1", + "apr": 0.0, + "may": 0.0, + "jun": 0.0, + "jul": 0.0, + "aug": 0.0, + "sep": 0.0, + "oct": 0.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 2000.0, + "mar": 0.0, + "total":2000.0 + }, + { + "entity": "_Test Customer 2", + "entity_name": "_Test Customer 2", + "apr": 0.0, + "may": 0.0, + "jun": 0.0, + "jul": 0.0, + "aug": 0.0, + "sep": 1500.0, + "oct": 1000.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 0.0, + "mar": 0.0, + "total":2500.0 + }, + { + "entity": "_Test Customer 3", + "entity_name": "_Test Customer 3", + "apr": 0.0, + "may": 0.0, + "jun": 2000.0, + "jul": 1000.0, + "aug": 0.0, + "sep": 0.0, + "oct": 0.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 0.0, + "mar": 0.0, + "total": 3000.0 + } + ] + result = sorted(report[1], key=lambda k: k['entity']) + self.assertEqual(expected_data, result) + + def compare_result_for_customer_group(self): + filters = { + 'doc_type': 'Sales Order', + 'range': 'Monthly', + 'to_date': '2018-03-31', + 'tree_type': 'Customer Group', + 'company': '_Test Company 2', + 'from_date': '2017-04-01', + 'value_quantity': 'Value' + } + + report = execute(filters) + + expected_first_row = { + "entity": "All Customer Groups", + "indent": 0, + "apr": 0.0, + "may": 0.0, + "jun": 2000.0, + "jul": 1000.0, + "aug": 0.0, + "sep": 1500.0, + "oct": 1000.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 2000.0, + "mar": 0.0, + "total":7500.0 + } + self.assertEqual(expected_first_row, report[1][0]) + + def compare_result_for_customer_based_on_quantity(self): + filters = { + 'doc_type': 'Sales Order', + 'range': 'Monthly', + 'to_date': '2018-03-31', + 'tree_type': 'Customer', + 'company': '_Test Company 2', + 'from_date': '2017-04-01', + 'value_quantity': 'Quantity' + } + + report = execute(filters) + + expected_data = [ + { + "entity": "_Test Customer 1", + "entity_name": "_Test Customer 1", + "apr": 0.0, + "may": 0.0, + "jun": 0.0, + "jul": 0.0, + "aug": 0.0, + "sep": 0.0, + "oct": 0.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 20.0, + "mar": 0.0, + "total":20.0 + }, + { + "entity": "_Test Customer 2", + "entity_name": "_Test Customer 2", + "apr": 0.0, + "may": 0.0, + "jun": 0.0, + "jul": 0.0, + "aug": 0.0, + "sep": 15.0, + "oct": 10.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 0.0, + "mar": 0.0, + "total":25.0 + }, + { + "entity": "_Test Customer 3", + "entity_name": "_Test Customer 3", + "apr": 0.0, + "may": 0.0, + "jun": 20.0, + "jul": 10.0, + "aug": 0.0, + "sep": 0.0, + "oct": 0.0, + "nov": 0.0, + "dec": 0.0, + "jan": 0.0, + "feb": 0.0, + "mar": 0.0, + "total": 30.0 + } + ] + result = sorted(report[1], key=lambda k: k['entity']) + self.assertEqual(expected_data, result) + +def create_sales_orders(): + frappe.set_user("Administrator") + + make_sales_order(company="_Test Company 2", qty=10, + customer = "_Test Customer 1", + transaction_date = '2018-02-10', + warehouse = 'Finished Goods - _TC2', + currency = 'EUR') + + make_sales_order(company="_Test Company 2", + qty=10, customer = "_Test Customer 1", + transaction_date = '2018-02-15', + warehouse = 'Finished Goods - _TC2', + currency = 'EUR') + + make_sales_order(company = "_Test Company 2", + qty=10, customer = "_Test Customer 2", + transaction_date = '2017-10-10', + warehouse='Finished Goods - _TC2', + currency = 'EUR') + + make_sales_order(company="_Test Company 2", + qty=15, customer = "_Test Customer 2", + transaction_date='2017-09-23', + warehouse='Finished Goods - _TC2', + currency = 'EUR') + + make_sales_order(company="_Test Company 2", + qty=20, customer = "_Test Customer 3", + transaction_date='2017-06-15', + warehouse='Finished Goods - _TC2', + currency = 'EUR') + + make_sales_order(company="_Test Company 2", + qty=10, customer = "_Test Customer 3", + transaction_date='2017-07-10', + warehouse='Finished Goods - _TC2', + currency = 'EUR') diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 9377cad1431..01f8956a826 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, @@ -723,6 +724,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "standard_working_hours", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Standard Working Hours", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -837,7 +870,7 @@ "label": "Create Chart Of Accounts Based On", "length": 0, "no_copy": 0, - "options": "\nStandard Template\nExisting Company", + "options": "\nStandard Template\nExisting Company", "permlevel": 0, "precision": "", "print_hide": 0, @@ -871,7 +904,7 @@ "label": "Chart Of Accounts Template", "length": 0, "no_copy": 1, - "options": "", + "options": "", "permlevel": 0, "precision": "", "print_hide": 0, @@ -1158,39 +1191,39 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "round_off_cost_center", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Round Off Cost Center", - "length": 0, - "no_copy": 0, - "options": "Cost Center", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "fieldname": "round_off_cost_center", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Round Off Cost Center", + "length": 0, + "no_copy": 0, + "options": "Cost Center", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "write_off_account", "fieldtype": "Link", "hidden": 0, @@ -1491,7 +1524,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fieldname": "default_deferred_expense_account", + "fieldname": "default_deferred_expense_account", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 1, @@ -1500,7 +1533,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Default Deferred Expense Account", + "label": "Default Deferred Expense Account", "length": 0, "no_copy": 1, "options": "Account", @@ -1525,7 +1558,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", - "fieldname": "default_payroll_payable_account", + "fieldname": "default_payroll_payable_account", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 1, @@ -1534,7 +1567,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Default Payroll Payable Account", + "label": "Default Payroll Payable Account", "length": 0, "no_copy": 1, "options": "Account", @@ -1558,20 +1591,20 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:!doc.__islocal", - "fieldname": "default_expense_claim_payable_account", + "depends_on": "eval:!doc.__islocal", + "fieldname": "default_expense_claim_payable_account", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 1, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Default Expense Claim Payable Account", + "label": "Default Expense Claim Payable Account", "length": 0, - "no_copy": 1, - "options": "Account", + "no_copy": 1, + "options": "Account", "permlevel": 0, "precision": "", "print_hide": 0, @@ -2870,8 +2903,8 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-09-13 10:00:47.915706", - "modified_by": "Administrator", + "modified": "2018-10-24 12:57:46.776452", + "modified_by": "Administrator", "module": "Setup", "name": "Company", "owner": "Administrator", diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 0c58fb26796..40bbc2c15fb 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -363,7 +363,8 @@ def replace_abbr(company, old, new): for d in doc: _rename_record(d) - for dt in ["Warehouse", "Account", "Cost Center"]: + for dt in ["Warehouse", "Account", "Cost Center", "Department", "Location", + "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]: _rename_records(dt) frappe.db.commit() diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py index 868284a75bf..61332267e7a 100644 --- a/erpnext/setup/doctype/company/company_dashboard.py +++ b/erpnext/setup/doctype/company/company_dashboard.py @@ -13,7 +13,7 @@ def get_data(): 'goal_doctype_link': 'company', 'goal_field': 'base_grand_total', 'date_field': 'posting_date', - 'filter_str': 'status != "Draft"', + 'filter_str': 'docstatus = 1', 'aggregation': 'sum' }, diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.js b/erpnext/setup/doctype/global_defaults/global_defaults.js index a78461d9bc5..58b8c512287 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.js +++ b/erpnext/setup/doctype/global_defaults/global_defaults.js @@ -1,10 +1,35 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt $.extend(cur_frm.cscript, { - validate: function(doc, cdt, cdn) { - return $c_obj(doc, 'get_defaults', '', function(r, rt){ + onload: function (doc, cdt, cdn) { + cur_frm.trigger("get_distance_uoms"); + }, + + validate: function (doc, cdt, cdn) { + return $c_obj(doc, 'get_defaults', '', function (r, rt) { frappe.sys_defaults = r.message; }); + }, + + get_distance_uoms: function (frm) { + let units = []; + + frappe.call({ + method: "frappe.client.get_list", + args: { + doctype: "UOM Conversion Factor", + filters: { "category": "Length" }, + fields: ["to_uom"], + limit_page_length: 500 + }, + callback: function (r) { + r.message.forEach(row => units.push(row.to_uom)); + } + }); + + cur_frm.set_query("default_distance_unit", function (doc) { + return { filters: { "name": ["IN", units] } }; + }) } }); diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json index a6c59649e81..bafb97a5d80 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.json +++ b/erpnext/setup/doctype/global_defaults/global_defaults.json @@ -1,122 +1,183 @@ { "allow_copy": 1, - "allow_email": 0, + "allow_guest_to_view": 0, "allow_import": 0, - "allow_print": 0, "allow_rename": 0, - "allow_trash": 0, + "beta": 0, "creation": "2013-05-02 17:53:24", "custom": 0, "docstatus": 0, "doctype": "DocType", + "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "default_company", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Default Company", "length": 0, - "no_column": 0, "no_copy": 0, "options": "Company", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "current_fiscal_year", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Current Fiscal Year", "length": 0, - "no_column": 0, "no_copy": 0, "options": "Fiscal Year", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "country", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Country", "length": 0, - "no_column": 0, "no_copy": 0, "options": "Country", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "default_distance_unit", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Distance Unit", + "length": 0, + "no_copy": 0, + "options": "UOM", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "column_break_8", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, - "no_column": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "INR", "fieldname": "default_currency", "fieldtype": "Link", @@ -124,26 +185,32 @@ "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Default Currency", "length": 0, - "no_column": 0, "no_copy": 0, "options": "Currency", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "description": "Do not show any symbol like $ etc next to currencies.", "fieldname": "hide_currency_symbol", "fieldtype": "Select", @@ -151,26 +218,32 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Hide Currency Symbol", "length": 0, - "no_column": 0, "no_copy": 0, "options": "\nNo\nYes", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "description": "If disable, 'Rounded Total' field will not be visible in any transaction", "fieldname": "disable_rounded_total", "fieldtype": "Check", @@ -178,25 +251,31 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Disable Rounded Total", "length": 0, - "no_column": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "description": "If disable, 'In Words' field will not be visible in any transaction", "fieldname": "disable_in_words", "fieldtype": "Check", @@ -204,7 +283,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Disable In Words", "length": 0, "no_copy": 0, @@ -213,26 +294,28 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-cog", "idx": 1, + "image_view": 0, "in_create": 1, - "is_submittable": 0, - "is_transaction_doc": 0, "issingle": 1, "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-03-03 16:14:41.260467", + "modified": "2018-10-15 03:08:19.886212", "modified_by": "Administrator", "module": "Setup", "name": "Global Defaults", @@ -240,7 +323,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 0, @@ -252,7 +334,6 @@ "print": 0, "read": 1, "report": 0, - "restrict": 0, "role": "System Manager", "set_user_permissions": 0, "share": 1, @@ -260,10 +341,12 @@ "write": 1 } ], + "quick_entry": 0, "read_only": 1, "read_only_onload": 0, - "show_in_menu": 0, + "show_name_in_global_search": 0, "sort_order": "DESC", - "use_template": 0, - "version": 0 + "track_changes": 0, + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.js b/erpnext/setup/doctype/global_defaults/test_global_defaults.js new file mode 100644 index 00000000000..33634eb0f88 --- /dev/null +++ b/erpnext/setup/doctype/global_defaults/test_global_defaults.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Global Defaults", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Global Defaults + () => frappe.tests.make('Global Defaults', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.py b/erpnext/setup/doctype/global_defaults/test_global_defaults.py new file mode 100644 index 00000000000..0495af7b414 --- /dev/null +++ b/erpnext/setup/doctype/global_defaults/test_global_defaults.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestGlobalDefaults(unittest.TestCase): + pass diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index 309866bbcc7..0216c3ba69a 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -98,7 +98,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=No if not value: import requests - api_url = "https://frankfurter.erpnext.org/{0}".format(transaction_date) + api_url = "https://frankfurter.app/{0}".format(transaction_date) response = requests.get(api_url, params={ "base": from_currency, "symbols": to_currency diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js index 9620b313ed2..9a154846e5f 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note.js @@ -21,6 +21,9 @@ frappe.ui.form.on("Delivery Note", { return (doc.docstatus==1 || doc.qty<=doc.actual_qty) ? "green" : "orange" }) + erpnext.queries.setup_queries(frm, "Warehouse", function() { + return erpnext.queries.warehouse(frm.doc); + }); erpnext.queries.setup_warehouse_query(frm); frm.set_query('project', function(doc) { diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index 765033a31bf..8c96be5e88a 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -1333,6 +1334,169 @@ "set_only_once": 0, "translatable": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "set_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Set Source Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break_warehouse", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Required only for sample item.", + "fieldname": "to_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "To Warehouse", + "length": 0, + "no_copy": 1, + "oldfieldname": "to_warehouse", + "oldfieldtype": "Link", + "options": "Warehouse", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "items_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-shopping-cart", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 }, { "allow_bulk_edit": 0, @@ -1341,8 +1505,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "items_section", - "fieldtype": "Section Break", + "fieldname": "scan_barcode", + "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -1350,12 +1514,11 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "", + "label": "Scan Barcode", "length": 0, "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", "permlevel": 0, + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -3751,73 +3914,38 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Required only for sample item.", - "fieldname": "to_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "To Warehouse", - "length": 0, - "no_copy": 1, - "oldfieldname": "to_warehouse", - "oldfieldtype": "Link", - "options": "Warehouse", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "excise_page", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Excise Page Number", - "length": 0, - "no_copy": 0, - "oldfieldname": "excise_page", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "excise_page", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Excise Page Number", + "length": 0, + "no_copy": 0, + "oldfieldname": "excise_page", + "oldfieldtype": "Data", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -4168,7 +4296,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-10-06 14:25:15.326772", + "modified": "2018-11-12 20:01:34.432403", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", @@ -4282,4 +4410,4 @@ "track_changes": 1, "track_seen": 1, "track_views": 0 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js index 9ec2a387ec6..9631264f204 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js @@ -10,5 +10,47 @@ frappe.listview_settings['Delivery Note'] = { } else if (doc.grand_total === 0 || flt(doc.per_billed, 2) == 100) { return [__("Completed"), "green", "per_billed,=,100"]; } + }, + onload: function (doclist) { + const action = () => { + const selected_docs = doclist.get_checked_items(); + const docnames = doclist.get_checked_items(true); + + if (selected_docs.length > 0) { + for (let doc of selected_docs) { + if (!doc.docstatus) { + frappe.throw(__("Cannot create a Delivery Trip from Draft documents.")); + } + }; + + frappe.new_doc("Delivery Trip") + .then(() => { + // Empty out the child table before inserting new ones + cur_frm.set_value("delivery_stops", []); + + // We don't want to use `map_current_doc` since it brings up + // the dialog to select more items. We just want the mapper + // function to be called. + frappe.call({ + type: "POST", + method: "frappe.model.mapper.map_docs", + args: { + "method": "erpnext.stock.doctype.delivery_note.delivery_note.make_delivery_trip", + "source_names": docnames, + "target_doc": cur_frm.doc + }, + callback: function (r) { + if (!r.exc) { + frappe.model.sync(r.message); + cur_frm.dirty(); + cur_frm.refresh(); + } + } + }); + }) + }; + }; + + doclist.page.add_actions_menu_item(__('Create Delivery Trip'), action, false); } }; diff --git a/erpnext/stock/doctype/delivery_settings/delivery_settings.json b/erpnext/stock/doctype/delivery_settings/delivery_settings.json index b70d74d1a6f..963403b8f2f 100644 --- a/erpnext/stock/doctype/delivery_settings/delivery_settings.json +++ b/erpnext/stock/doctype/delivery_settings/delivery_settings.json @@ -143,6 +143,70 @@ "set_only_once": 0, "translatable": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cb_delivery", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "In minutes", + "fieldname": "stop_delay", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Delay between Delivery Stops", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 } ], "has_web_view": 0, @@ -155,7 +219,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2018-09-05 00:16:23.569855", + "modified": "2018-09-09 23:51:34.279941", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Settings", diff --git a/erpnext/stock/doctype/delivery_stop/delivery_stop.json b/erpnext/stock/doctype/delivery_stop/delivery_stop.json index 023e34de085..5610a8108ab 100644 --- a/erpnext/stock/doctype/delivery_stop/delivery_stop.json +++ b/erpnext/stock/doctype/delivery_stop/delivery_stop.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -173,6 +174,39 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.docstatus==1", + "fieldname": "visited", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Visited", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -493,6 +527,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "distance", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Distance", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "2", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -525,6 +591,168 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "lat", + "fieldtype": "Float", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Latitude", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_19", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "depends_on": "eval:doc.distance", + "fieldname": "uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "UOM", + "length": 0, + "no_copy": 0, + "options": "UOM", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "lng", + "fieldtype": "Float", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Longitude", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "more_information_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "More Information", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -568,7 +796,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-09-05 00:51:55.275009", + "modified": "2018-10-16 05:23:25.661542", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Stop", diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js index 9c31e05f474..a9e2f888fbc 100755 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js @@ -3,6 +3,8 @@ frappe.ui.form.on('Delivery Trip', { setup: function (frm) { + frm.set_indicator_formatter('customer', (stop) => (stop.visited) ? "green" : "orange"); + frm.set_query("driver", function () { return { filters: { @@ -65,31 +67,43 @@ frappe.ui.form.on('Delivery Trip', { }, calculate_arrival_time: function (frm) { - frappe.call({ - method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.get_arrival_times', - freeze: true, - freeze_message: __("Updating estimated arrival times."), - args: { - name: frm.doc.name, - }, - callback: function (r) { - frm.reload_doc(); + frappe.db.get_value("Google Maps Settings", { name: "Google Maps Settings" }, "enabled", (r) => { + if (r.enabled == 0) { + frappe.throw(__("Please enable Google Maps Settings to estimate and optimize routes")); + } else { + frappe.call({ + method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.get_arrival_times', + freeze: true, + freeze_message: __("Updating estimated arrival times."), + args: { + delivery_trip: frm.doc.name, + }, + callback: function (r) { + frm.reload_doc(); + } + }); } - }); + }) }, optimize_route: function (frm) { - frappe.call({ - method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.optimize_route', - freeze: true, - freeze_message: __("Optimizing routes."), - args: { - name: frm.doc.name, - }, - callback: function (r) { - frm.reload_doc(); + frappe.db.get_value("Google Maps Settings", {name: "Google Maps Settings"}, "enabled", (r) => { + if (r.enabled == 0) { + frappe.throw(__("Please enable Google Maps Settings to estimate and optimize routes")); + } else { + frappe.call({ + method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.optimize_route', + freeze: true, + freeze_message: __("Optimizing routes."), + args: { + delivery_trip: frm.doc.name, + }, + callback: function (r) { + frm.reload_doc(); + } + }); } - }); + }) }, notify_customers: function (frm) { diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.json b/erpnext/stock/doctype/delivery_trip/delivery_trip.json index 3cb19af0f29..1d32ecd12f9 100644 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip.json +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -159,101 +160,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "departure_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Departure Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, + "label": "Delivery Details", "length": 0, "no_copy": 0, "permlevel": 0, @@ -336,6 +243,104 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_distance", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Total Estimated Distance", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "2", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "depends_on": "eval:doc.total_distance", + "fieldname": "uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Distance UOM", + "length": 0, + "no_copy": 0, + "options": "UOM", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -369,6 +374,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "departure_time", + "fieldtype": "Datetime", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Departure Time", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -441,7 +478,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:!cur_frm.is_new()", + "depends_on": "eval:!doc.__islocal", "fieldname": "calculate_arrival_time", "fieldtype": "Button", "hidden": 0, @@ -474,6 +511,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:!doc.__islocal", "fieldname": "optimize_route", "fieldtype": "Button", "hidden": 0, @@ -503,7 +541,7 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, @@ -531,6 +569,70 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Status", + "length": 0, + "no_copy": 1, + "options": "Draft\nScheduled\nIn Transit\nCompleted\nCancelled", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cb_more_info", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -574,7 +676,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-09-05 01:20:34.165834", + "modified": "2018-10-22 08:25:42.323147", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Trip", @@ -626,6 +728,8 @@ "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", + "title_field": "driver_name", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py index 427bc2496d4..01b4734bf58 100644 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py @@ -10,17 +10,64 @@ import frappe from frappe import _ from frappe.contacts.doctype.address.address import get_address_display from frappe.model.document import Document -from frappe.utils import get_datetime, get_link_to_form, cstr +from frappe.utils import cint, get_datetime, get_link_to_form class DeliveryTrip(Document): + def __init__(self, *args, **kwargs): + super(DeliveryTrip, self).__init__(*args, **kwargs) + + # Google Maps returns distances in meters by default + self.default_distance_uom = frappe.db.get_single_value("Global Defaults", "default_distance_unit") or "Meter" + self.uom_conversion_factor = frappe.db.get_value("UOM Conversion Factor", + {"from_uom": "Meter", "to_uom": self.default_distance_uom}, + "value") + + def validate(self): + self.validate_stop_addresses() + def on_submit(self): + self.update_status() self.update_delivery_notes() + def on_update_after_submit(self): + self.update_status() + def on_cancel(self): + self.update_status() self.update_delivery_notes(delete=True) + def validate_stop_addresses(self): + for stop in self.delivery_stops: + if not stop.customer_address: + stop.customer_address = get_address_display(frappe.get_doc("Address", stop.address).as_dict()) + + def update_status(self): + status = { + 0: "Draft", + 1: "Scheduled", + 2: "Cancelled" + }[self.docstatus] + + if self.docstatus == 1: + visited_stops = [stop.visited for stop in self.delivery_stops] + if all(visited_stops): + status = "Completed" + elif any(visited_stops): + status = "In Transit" + + self.db_set("status", status) + def update_delivery_notes(self, delete=False): + """ + Update all connected Delivery Notes with Delivery Trip details + (Driver, Vehicle, etc.). If `delete` is `True`, then details + are removed. + + Args: + delete (bool, optional): Defaults to `False`. `True` if driver details need to be emptied, else `False`. + """ + delivery_notes = list(set([stop.delivery_note for stop in self.delivery_stops if stop.delivery_note])) update_fields = { @@ -28,7 +75,7 @@ class DeliveryTrip(Document): "driver_name": self.driver_name, "vehicle_no": self.vehicle, "lr_no": self.name, - "lr_date": self.date + "lr_date": self.departure_time } for delivery_note in delivery_notes: @@ -44,58 +91,175 @@ class DeliveryTrip(Document): delivery_notes = [get_link_to_form("Delivery Note", note) for note in delivery_notes] frappe.msgprint(_("Delivery Notes {0} updated".format(", ".join(delivery_notes)))) + def process_route(self, optimize): + """ + Estimate the arrival times for each stop in the Delivery Trip. + If `optimize` is True, the stops will be re-arranged, based + on the optimized order, before estimating the arrival times. + + Args: + optimize (bool): True if route needs to be optimized, else False + """ + + if not frappe.db.get_single_value("Google Maps Settings", "enabled"): + frappe.throw(_("Cannot process route, since Google Maps Settings is disabled.")) + + departure_datetime = get_datetime(self.departure_time) + route_list = self.form_route_list(optimize) + + # For locks, maintain idx count while looping through route list + idx = 0 + for route in route_list: + directions = get_directions(route, optimize) + + if directions: + if optimize and len(directions.get("waypoint_order")) > 1: + self.rearrange_stops(directions.get("waypoint_order"), start=idx) + + # Avoid estimating last leg back to the home address + legs = directions.get("legs")[:-1] if route == route_list[-1] else directions.get("legs") + + # Google Maps returns the legs in the optimized order + for leg in legs: + delivery_stop = self.delivery_stops[idx] + + delivery_stop.lat, delivery_stop.lng = leg.get("end_location", {}).values() + delivery_stop.uom = self.default_distance_uom + distance = leg.get("distance", {}).get("value", 0.0) # in meters + delivery_stop.distance = distance * self.uom_conversion_factor + + duration = leg.get("duration", {}).get("value", 0) + estimated_arrival = departure_datetime + datetime.timedelta(seconds=duration) + delivery_stop.estimated_arrival = estimated_arrival + + stop_delay = frappe.db.get_single_value("Delivery Settings", "stop_delay") + departure_datetime = estimated_arrival + datetime.timedelta(minutes=cint(stop_delay)) + idx += 1 + + # Include last leg in the final distance calculation + self.uom = self.default_distance_uom + total_distance = sum([leg.get("distance", {}).get("value", 0.0) + for leg in directions.get("legs")]) # in meters + self.total_distance = total_distance * self.uom_conversion_factor + else: + idx += len(route) - 1 + + self.save() + + def form_route_list(self, optimize): + """ + Form a list of address routes based on the delivery stops. If locks + are present, and the routes need to be optimized, then they will be + split into sublists at the specified lock position(s). + + Args: + optimize (bool): `True` if route needs to be optimized, else `False` + + Returns: + (list of list of str): List of address routes split at locks, if optimize is `True` + """ + + settings = frappe.get_single("Google Maps Settings") + home_address = get_address_display(frappe.get_doc("Address", settings.home_address).as_dict()) + + route_list = [] + # Initialize first leg with origin as the home address + leg = [home_address] + + for stop in self.delivery_stops: + leg.append(stop.customer_address) + + if optimize and stop.lock: + route_list.append(leg) + leg = [stop.customer_address] + + # For last leg, append home address as the destination + # only if lock isn't on the final stop + if len(leg) > 1: + leg.append(home_address) + route_list.append(leg) + + route_list = [[sanitize_address(address) for address in route] for route in route_list] + + return route_list + + def rearrange_stops(self, optimized_order, start): + """ + Re-arrange delivery stops based on order optimized + for vehicle routing problems. + + Args: + optimized_order (list of int): The index-based optimized order of the route + start (int): The index at which to start the rearrangement + """ + + stops_order = [] + + # Child table idx starts at 1 + for new_idx, old_idx in enumerate(optimized_order, 1): + new_idx = start + new_idx + old_idx = start + old_idx + + self.delivery_stops[old_idx].idx = new_idx + stops_order.append(self.delivery_stops[old_idx]) + + self.delivery_stops[start:start + len(stops_order)] = stops_order + + +@frappe.whitelist() +def get_contact_and_address(name): + out = frappe._dict() + + get_default_contact(out, name) + get_default_address(out, name) + + return out def get_default_contact(out, name): contact_persons = frappe.db.sql( """ - select parent, - (select is_primary_contact from tabContact c where c.name = dl.parent) - as is_primary_contact - from + SELECT parent, + (SELECT is_primary_contact FROM tabContact c WHERE c.name = dl.parent) AS is_primary_contact + FROM `tabDynamic Link` dl - where - dl.link_doctype="Customer" and - dl.link_name=%s and - dl.parenttype = 'Contact' + WHERE + dl.link_doctype="Customer" + AND dl.link_name=%s + AND dl.parenttype = "Contact" """, (name), as_dict=1) if contact_persons: for out.contact_person in contact_persons: if out.contact_person.is_primary_contact: return out.contact_person + out.contact_person = contact_persons[0] + return out.contact_person - else: - return None + def get_default_address(out, name): shipping_addresses = frappe.db.sql( """ - select parent, - (select is_shipping_address from tabAddress a where a.name=dl.parent) as is_shipping_address - from `tabDynamic Link` dl - where link_doctype="Customer" - and link_name=%s - and parenttype = 'Address' + SELECT parent, + (SELECT is_shipping_address FROM tabAddress a WHERE a.name=dl.parent) AS is_shipping_address + FROM + `tabDynamic Link` dl + WHERE + dl.link_doctype="Customer" + AND dl.link_name=%s + AND dl.parenttype = "Address" """, (name), as_dict=1) if shipping_addresses: for out.shipping_address in shipping_addresses: if out.shipping_address.is_shipping_address: return out.shipping_address + out.shipping_address = shipping_addresses[0] + return out.shipping_address - else: - return None - - -@frappe.whitelist() -def get_contact_and_address(name): - out = frappe._dict() - get_default_contact(out, name) - get_default_address(out, name) - return out @frappe.whitelist() @@ -103,67 +267,83 @@ def get_contact_display(contact): contact_info = frappe.db.get_value( "Contact", contact, ["first_name", "last_name", "phone", "mobile_no"], - as_dict=1) + as_dict=1) + contact_info.html = """ %(first_name)s %(last_name)s
%(phone)s
%(mobile_no)s""" % { "first_name": contact_info.first_name, "last_name": contact_info.last_name or "", "phone": contact_info.phone or "", - "mobile_no": contact_info.mobile_no or "", + "mobile_no": contact_info.mobile_no or "" } + return contact_info.html -def process_route(name, optimize): - doc = frappe.get_doc("Delivery Trip", name) - settings = frappe.get_single("Google Maps Settings") - gmaps_client = settings.get_client() +@frappe.whitelist() +def optimize_route(delivery_trip): + delivery_trip = frappe.get_doc("Delivery Trip", delivery_trip) + delivery_trip.process_route(optimize=True) - if not settings.enabled: - frappe.throw(_("Google Maps integration is not enabled")) - home_address = get_address_display(frappe.get_doc("Address", settings.home_address).as_dict()) - address_list = [] +@frappe.whitelist() +def get_arrival_times(delivery_trip): + delivery_trip = frappe.get_doc("Delivery Trip", delivery_trip) + delivery_trip.process_route(optimize=False) - for stop in doc.delivery_stops: - address_list.append(stop.customer_address) - # Cannot add datetime.date to datetime.timedelta - departure_datetime = get_datetime(doc.date) + doc.departure_time +def sanitize_address(address): + """ + Remove HTML breaks in a given address - try: - directions = gmaps_client.directions(origin=home_address, - destination=home_address, waypoints=address_list, - optimize_waypoints=optimize, departure_time=departure_datetime) - except Exception as e: - frappe.throw((e.message)) + Args: + address (str): Address to be sanitized - if not directions: + Returns: + (str): Sanitized address + """ + + if not address: return - directions = directions[0] - duration = 0 + address = address.split('
') - # Google Maps returns the optimized order of the waypoints that were sent - for idx, order in enumerate(directions.get("waypoint_order")): - # We accordingly rearrange the rows - doc.delivery_stops[order].idx = idx + 1 - # Google Maps returns the "legs" in the optimized order, so we loop through it - duration += directions.get("legs")[idx].get("duration").get("value") - arrival_datetime = departure_datetime + datetime.timedelta(seconds=duration) - doc.delivery_stops[order].estimated_arrival = arrival_datetime - - doc.save() - frappe.db.commit() + # Only get the first 3 blocks of the address + return ', '.join(address[:3]) -@frappe.whitelist() -def optimize_route(name): - process_route(name, optimize=True) +def get_directions(route, optimize): + """ + Retrieve map directions for a given route and departure time. + If optimize is `True`, Google Maps will return an optimized + order for the intermediate waypoints. + NOTE: Google's API does take an additional `departure_time` key, + but it only works for routes without any waypoints. -@frappe.whitelist() -def get_arrival_times(name): - process_route(name, optimize=False) + Args: + route (list of str): Route addresses (origin -> waypoint(s), if any -> destination) + optimize (bool): `True` if route needs to be optimized, else `False` + + Returns: + (dict): Route legs and, if `optimize` is `True`, optimized waypoint order + """ + + settings = frappe.get_single("Google Maps Settings") + maps_client = settings.get_client() + + directions_data = { + "origin": route[0], + "destination": route[-1], + "waypoints": route[1: -1], + "optimize_waypoints": optimize + } + + try: + directions = maps_client.directions(**directions_data) + except Exception as e: + frappe.throw(_(e.message)) + + return directions[0] if directions else False @frappe.whitelist() @@ -171,10 +351,6 @@ def notify_customers(delivery_trip): delivery_trip = frappe.get_doc("Delivery Trip", delivery_trip) context = delivery_trip.as_dict() - context.update({ - "departure_time": cstr(context.get("departure_time")), - "estimated_arrival": cstr(context.get("estimated_arrival")) - }) if delivery_trip.driver: context.update(frappe.db.get_value("Driver", delivery_trip.driver, "cell_number", as_dict=1)) diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js b/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js new file mode 100644 index 00000000000..1d198b733fb --- /dev/null +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js @@ -0,0 +1,12 @@ +frappe.listview_settings['Delivery Trip'] = { + add_fields: ["status"], + get_indicator: function (doc) { + if (in_list(["Cancelled", "Draft"], doc.status)) { + return [__(doc.status), "red", "status,=," + doc.status]; + } else if (in_list(["In Transit", "Scheduled"], doc.status)) { + return [__(doc.status), "orange", "status,=," + doc.status]; + } else if (doc.status === "Completed") { + return [__(doc.status), "green", "status,=," + doc.status]; + } + } +}; diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py index fae03f8d9f9..76b6fcda83d 100644 --- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py +++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py @@ -9,7 +9,7 @@ import erpnext import frappe from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers from erpnext.tests.utils import create_test_contact_and_address -from frappe.utils import add_days, now_datetime, nowdate +from frappe.utils import add_days, flt, now_datetime, nowdate class TestDeliveryTrip(unittest.TestCase): @@ -19,28 +19,85 @@ class TestDeliveryTrip(unittest.TestCase): create_delivery_notification() create_test_contact_and_address() - def test_delivery_trip(self): - contact = get_contact_and_address("_Test Customer") + settings = frappe.get_single("Google Maps Settings") + settings.home_address = frappe.get_last_doc("Address").name + settings.save() - if not frappe.db.exists("Delivery Trip", "TOUR-00000"): - delivery_trip = frappe.get_doc({ - "doctype": "Delivery Trip", - "company": erpnext.get_default_company(), - "date": add_days(nowdate(), 5), - "departure_time": add_days(now_datetime(), 5), - "driver": frappe.db.get_value('Driver', {"full_name": "Newton Scmander"}), - "vehicle": "JB 007", - "delivery_stops": [{ - "customer": "_Test Customer", - "address": contact.shipping_address.parent, - "contact": contact.contact_person.parent - }] - }) - delivery_trip.insert() + self.delivery_trip = create_delivery_trip() - notify_customers(delivery_trip=delivery_trip.name) - delivery_trip.load_from_db() - self.assertEqual(delivery_trip.email_notification_sent, 1) + def tearDown(self): + frappe.db.sql("delete from `tabDriver`") + frappe.db.sql("delete from `tabVehicle`") + frappe.db.sql("delete from `tabEmail Template`") + frappe.db.sql("delete from `tabDelivery Trip`") + + def test_delivery_trip_notify_customers(self): + notify_customers(delivery_trip=self.delivery_trip.name) + self.delivery_trip.load_from_db() + self.assertEqual(self.delivery_trip.email_notification_sent, 1) + + def test_unoptimized_route_list_without_locks(self): + route_list = self.delivery_trip.form_route_list(optimize=False) + + # Return a single list of destinations, from home address and back + self.assertEqual(len(route_list), 1) + self.assertEqual(len(route_list[0]), 4) + + def test_unoptimized_route_list_with_locks(self): + self.delivery_trip.delivery_stops[0].lock = 1 + self.delivery_trip.save() + route_list = self.delivery_trip.form_route_list(optimize=False) + + # Return a single list of destinations, from home address and back, + # since the stops don't need to optimized and simple time + # estimation is enough + self.assertEqual(len(route_list), 1) + self.assertEqual(len(route_list[0]), 4) + + def test_optimized_route_list_without_locks(self): + route_list = self.delivery_trip.form_route_list(optimize=True) + + # Return a single list of destinations, from home address and back, + # since the route doesn't have any locks to be optimized against + self.assertEqual(len(route_list), 1) + self.assertEqual(len(route_list[0]), 4) + + def test_optimized_route_list_with_locks(self): + self.delivery_trip.delivery_stops[0].lock = 1 + self.delivery_trip.save() + route_list = self.delivery_trip.form_route_list(optimize=True) + + # Return multiple route lists, taking the home address as start and end + self.assertEqual(len(route_list), 2) + self.assertEqual(len(route_list[0]), 2) # [home_address, locked_stop] + self.assertEqual(len(route_list[1]), 3) # [locked_stop, second_stop, home_address] + + def test_delivery_trip_status_draft(self): + self.assertEqual(self.delivery_trip.status, "Draft") + + def test_delivery_trip_status_scheduled(self): + self.delivery_trip.submit() + self.assertEqual(self.delivery_trip.status, "Scheduled") + + def test_delivery_trip_status_cancelled(self): + self.delivery_trip.submit() + self.delivery_trip.cancel() + self.assertEqual(self.delivery_trip.status, "Cancelled") + + def test_delivery_trip_status_in_transit(self): + self.delivery_trip.submit() + self.delivery_trip.delivery_stops[0].visited = 1 + self.delivery_trip.save() + self.assertEqual(self.delivery_trip.status, "In Transit") + + def test_delivery_trip_status_completed(self): + self.delivery_trip.submit() + + for stop in self.delivery_trip.delivery_stops: + stop.visited = 1 + + self.delivery_trip.save() + self.assertEqual(self.delivery_trip.status, "Completed") def create_driver(): @@ -67,6 +124,7 @@ def create_delivery_notification(): delivery_settings = frappe.get_single("Delivery Settings") delivery_settings.dispatch_template = 'Delivery Notification' + delivery_settings.save() def create_vehicle(): @@ -77,10 +135,37 @@ def create_vehicle(): "make": "Maruti", "model": "PCM", "last_odometer": 5000, - "acquisition_date": frappe.utils.nowdate(), + "acquisition_date": nowdate(), "location": "Mumbai", "chassis_no": "1234ABCD", "uom": "Litre", - "vehicle_value": frappe.utils.flt(500000) + "vehicle_value": flt(500000) }) vehicle.insert() + + +def create_delivery_trip(contact=None): + if not contact: + contact = get_contact_and_address("_Test Customer") + + delivery_trip = frappe.new_doc("Delivery Trip") + delivery_trip.update({ + "doctype": "Delivery Trip", + "company": erpnext.get_default_company(), + "departure_time": add_days(now_datetime(), 5), + "driver": frappe.db.get_value('Driver', {"full_name": "Newton Scmander"}), + "vehicle": "JB 007", + "delivery_stops": [{ + "customer": "_Test Customer", + "address": contact.shipping_address.parent, + "contact": contact.contact_person.parent + }, + { + "customer": "_Test Customer", + "address": contact.shipping_address.parent, + "contact": contact.contact_person.parent + }] + }) + delivery_trip.insert() + + return delivery_trip diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json index dbb9b592541..18e2910126d 100644 --- a/erpnext/stock/doctype/item/test_records.json +++ b/erpnext/stock/doctype/item/test_records.json @@ -57,6 +57,7 @@ "stock_uom": "_Test UOM", "show_in_website": 1, "website_warehouse": "_Test Warehouse - _TC", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -78,6 +79,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Item Home Desktop 100", "valuation_rate": 100, + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -107,6 +109,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Item Home Desktop 200", "stock_uom": "_Test UOM 1", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -128,6 +131,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Product Bundle Item", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -149,6 +153,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test FG Item", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -170,6 +175,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Non Stock Item", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -191,6 +197,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Serialized Item", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -213,6 +220,7 @@ "item_name": "_Test Serialized Item With Series", "serial_no_series": "ABCD.#####", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -234,6 +242,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Item Home Desktop Manufactured", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -255,6 +264,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test FG Item 2", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC", @@ -276,6 +286,7 @@ "item_group": "_Test Item Group Desktops", "item_name": "_Test Variant Item", "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", "has_variants": 1, "item_defaults": [{ "company": "_Test Company", @@ -312,6 +323,7 @@ "item_group": "_Test Item Group", "item_name": "_Test Item Warehouse Group Wise Reorder", "apply_warehouse_wise_reorder_level": 1, + "gst_hsn_code": "999800", "item_defaults": [{ "company": "_Test Company", "default_warehouse": "_Test Warehouse Group-C1 - _TC", diff --git a/erpnext/stock/doctype/item_barcode/item_barcode.json b/erpnext/stock/doctype/item_barcode/item_barcode.json index c8a3a897b32..d89ca55a4f3 100644 --- a/erpnext/stock/doctype/item_barcode/item_barcode.json +++ b/erpnext/stock/doctype/item_barcode/item_barcode.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -15,6 +16,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -38,13 +40,15 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 1 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,6 +76,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -85,7 +90,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-10 20:55:23.814039", + "modified": "2018-11-13 06:03:09.814357", "modified_by": "Administrator", "module": "Stock", "name": "Item Barcode", @@ -99,5 +104,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json index c0285cbe14f..8a53a273142 100644 --- a/erpnext/stock/doctype/material_request/material_request.json +++ b/erpnext/stock/doctype/material_request/material_request.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -312,6 +313,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "scan_barcode", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scan Barcode", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 1, "allow_in_quick_entry": 0, @@ -826,7 +859,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-09-05 07:28:01.070112", + "modified": "2018-10-18 04:41:56.818108", "modified_by": "Administrator", "module": "Stock", "name": "Material Request", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js index 736ba8bb8d7..1d9eb9965bf 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js @@ -21,26 +21,9 @@ frappe.ui.form.on("Purchase Receipt", { }) }, onload: function(frm) { - $.each(["warehouse", "rejected_warehouse"], function(i, field) { - frm.set_query(field, "items", function() { - return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] - ] - } - }) - }) - - frm.set_query("supplier_warehouse", function() { - return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] - ] - } + erpnext.queries.setup_queries(frm, "Warehouse", function() { + return erpnext.queries.warehouse(frm.doc); }); - }, onload_post_render: function(frm) { diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index f2da856d42c..3e9ff4997d5 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -1071,6 +1072,211 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sec_warehouse", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "set_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Set Accepted Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Warehouse where you are maintaining stock of rejected items", + "fieldname": "rejected_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Rejected Warehouse", + "length": 0, + "no_copy": 1, + "oldfieldname": "rejected_warehouse", + "oldfieldtype": "Link", + "options": "Warehouse", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "col_break_warehouse", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "No", + "description": "", + "fieldname": "is_subcontracted", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Raw Materials Supplied", + "length": 0, + "no_copy": 0, + "oldfieldname": "is_subcontracted", + "oldfieldtype": "Select", + "options": "No\nYes", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.is_subcontracted==\"Yes\"", + "description": "", + "fieldname": "supplier_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplier Warehouse", + "length": 0, + "no_copy": 1, + "oldfieldname": "supplier_warehouse", + "oldfieldtype": "Link", + "options": "Warehouse", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "print_width": "50px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0, + "width": "50px" + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1171,6 +1377,75 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "supplied_items", + "columns": 0, + "description": "", + "fieldname": "raw_material_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Raw Materials Supplied", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-table", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "supplied_items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplied Items", + "length": 0, + "no_copy": 1, + "oldfieldname": "pr_raw_material_details", + "oldfieldtype": "Table", + "options": "Purchase Receipt Item Supplied", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2623,148 +2898,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "supplied_items", - "columns": 0, - "description": "", - "fieldname": "raw_material_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Raw Materials Supplied", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-table", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "No", - "description": "", - "fieldname": "is_subcontracted", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Raw Materials Supplied", - "length": 0, - "no_copy": 0, - "oldfieldname": "is_subcontracted", - "oldfieldtype": "Select", - "options": "No\nYes", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "supplier_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplier Warehouse", - "length": 0, - "no_copy": 1, - "oldfieldname": "supplier_warehouse", - "oldfieldtype": "Link", - "options": "Warehouse", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, - "width": "50px" - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplied_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplied Items", - "length": 0, - "no_copy": 1, - "oldfieldname": "pr_raw_material_details", - "oldfieldtype": "Table", - "options": "Purchase Receipt Item Supplied", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2901,41 +3034,6 @@ "unique": 0, "width": "150px" }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Warehouse where you are maintaining stock of rejected items", - "fieldname": "rejected_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Rejected Warehouse", - "length": 0, - "no_copy": 1, - "oldfieldname": "rejected_warehouse", - "oldfieldtype": "Link", - "options": "Warehouse", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -3610,7 +3708,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-08-21 14:44:34.419727", + "modified": "2018-11-02 19:59:01.423485", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index e482f58da36..f006d00176e 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -185,7 +185,8 @@ class PurchaseReceipt(BuyingController): if warehouse_account.get(d.warehouse): stock_value_diff = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt", "voucher_no": self.name, - "voucher_detail_no": d.name}, "stock_value_difference") + "voucher_detail_no": d.name, "warehouse": d.warehouse}, "stock_value_difference") + if not stock_value_diff: continue gl_entries.append(self.get_gl_dict({ diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 598504af494..2039a2699b9 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -85,9 +85,9 @@ class SerialNo(StockController): self.purchase_date = purchase_sle.posting_date self.purchase_time = purchase_sle.posting_time self.purchase_rate = purchase_sle.incoming_rate - if purchase_sle.voucher_type == "Purchase Receipt": + if purchase_sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"): self.supplier, self.supplier_name = \ - frappe.db.get_value("Purchase Receipt", purchase_sle.voucher_no, + frappe.db.get_value(purchase_sle.voucher_type, purchase_sle.voucher_no, ["supplier", "supplier_name"]) # If sales return entry @@ -304,8 +304,8 @@ def has_duplicate_serial_no(sn, sle): status = False if sn.purchase_document_no: - if sle.voucher_type in ['Purchase Receipt', 'Stock Entry'] and \ - sn.delivery_document_type not in ['Purchase Receipt', 'Stock Entry']: + if sle.voucher_type in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"] and \ + sn.delivery_document_type not in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"]: status = True if status and sle.voucher_type == 'Stock Entry' and \ diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 0356b0e14fa..a26992a5ae1 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -594,6 +594,11 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ erpnext.utils.add_item(this.frm); }, + scan_barcode: function() { + let transaction_controller= new erpnext.TransactionController({frm:this.frm}); + transaction_controller.scan_barcode(); + }, + on_submit: function() { this.clean_up(); }, diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json index 35f8c273444..6a925adef13 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.json +++ b/erpnext/stock/doctype/stock_entry/stock_entry.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -1044,6 +1045,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "scan_barcode", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Scan Barcode", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1965,7 +1998,7 @@ "report_hide": 0, "reqd": 0, "search_index": 0, - "set_only_once": 0, + "set_only_once": 0, "translatable": 0, "unique": 0 }, @@ -2048,7 +2081,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-09-05 06:27:59.630826", + "modified": "2018-10-18 04:42:41.452572", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index d4e7b9574fb..d8e46563f6f 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -634,19 +634,19 @@ class StockEntry(StockController): ret = frappe._dict({ 'uom' : item.stock_uom, - 'stock_uom' : item.stock_uom, + 'stock_uom' : item.stock_uom, 'description' : item.description, - 'image' : item.image, + 'image' : item.image, 'item_name' : item.item_name, 'expense_account' : args.get("expense_account"), 'cost_center' : get_default_cost_center(args, item, item_group_defaults), - 'qty' : 0, - 'transfer_qty' : 0, + 'qty' : args.get("qty"), + 'transfer_qty' : args.get('qty'), 'conversion_factor' : 1, - 'batch_no' : '', + 'batch_no' : '', 'actual_qty' : 0, 'basic_rate' : 0, - 'serial_no' : '', + 'serial_no' : '', 'has_serial_no' : item.has_serial_no, 'has_batch_no' : item.has_batch_no, 'sample_quantity' : item.sample_quantity diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index 97d24c6c94c..65de2e58d3a 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -26,8 +26,9 @@ class StockSettings(Document): frappe.msgprint (_("`Freeze Stocks Older Than` should be smaller than %d days.") %stock_frozen_limit) # show/hide barcode field - frappe.make_property_setter({'fieldname': 'barcodes', 'property': 'hidden', - 'value': 0 if self.show_barcode_field else 1}) + for name in ["barcode", "barcodes", "scan_barcode"]: + frappe.make_property_setter({'fieldname': name, 'property': 'hidden', + 'value': 0 if self.show_barcode_field else 1}) self.cant_change_valuation_method() self.validate_clean_description_html() diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index d90db56e2c7..01ee9db1ca1 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -594,22 +594,21 @@ def get_pos_profile(company, pos_profile=None, user=None): if not user: user = frappe.session['user'] - pos_profile = frappe.db.sql("""select pf.* - from - `tabPOS Profile` pf, `tabPOS Profile User` pfu - where - pfu.parent = pf.name and pfu.user = %s and pf.company = %s - and pf.disabled = 0 and pfu.default=1""", (user, company), as_dict=1) - - if not pos_profile: - pos_profile = frappe.db.sql("""select pf.* - from - `tabPOS Profile` pf left join `tabPOS Profile User` pfu - on + pos_profile = frappe.db.sql("""SELECT pf.* + FROM + `tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu + ON pf.name = pfu.parent - where - ifnull(pfu.user, '') = '' and pf.company = %s - and pf.disabled = 0""", (company), as_dict=1) + WHERE + ( + (pfu.user = %(user)s AND pf.company = %(company)s AND pfu.default=1) + OR (pfu.user = %(user)s AND pfu.default=1) + OR (ifnull(pfu.user, '') = '' AND pf.company = %(company)s) + ) AND pf.disabled = 0 + """, { + 'user': user, + 'company': company + }, as_dict=1) return pos_profile and pos_profile[0] or None diff --git a/erpnext/stock/report/stock_analytics/__init__.py b/erpnext/stock/report/stock_analytics/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.js b/erpnext/stock/report/stock_analytics/stock_analytics.js new file mode 100644 index 00000000000..bebc84e057f --- /dev/null +++ b/erpnext/stock/report/stock_analytics/stock_analytics.js @@ -0,0 +1,135 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Stock Analytics"] = { + "filters": [ + { + fieldname: "item_group", + label: __("Item Group"), + fieldtype: "Link", + options:"Item Group", + default: "", + }, + { + fieldname: "item_code", + label: __("Item"), + fieldtype: "Link", + options:"Item", + default: "", + }, + { + fieldname: "value_quantity", + label: __("Value Or Qty"), + fieldtype: "Select", + options: [ + { "value": "Value", "label": __("Value") }, + { "value": "Quantity", "label": __("Quantity") } + ], + default: "Value", + reqd: 1 + }, + { + fieldname: "brand", + label: __("Brand"), + fieldtype: "Link", + options:"Brand", + default: "", + }, + { + fieldname: "warehouse", + label: __("Warehouse"), + fieldtype: "Link", + options:"Warehouse", + default: "", + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + default: frappe.defaults.get_global_default("year_start_date"), + reqd: 1 + }, + { + fieldname:"to_date", + label: __("To Date"), + fieldtype: "Date", + default: frappe.defaults.get_global_default("year_end_date"), + reqd: 1 + }, + { + fieldname: "range", + label: __("Range"), + fieldtype: "Select", + options: [ + { "value": "Weekly", "label": __("Weekly") }, + { "value": "Monthly", "label": __("Monthly") }, + { "value": "Quarterly", "label": __("Quarterly") }, + { "value": "Yearly", "label": __("Yearly") } + ], + default: "Monthly", + reqd: 1 + } + ], + "formatter": function(value, row, column, data) { + if(!value && (column.fieldname == 'brand' || column.fieldname == 'uom')){ + value = "" + } + + if(Number(value)){ + value = value.toFixed(2) + } + + return value; + }, + get_datatable_options(options) { + return Object.assign(options, { + checkboxColumn: true, + events: { + onCheckRow: function(data) { + row_name = data[2].content; + row_values = data.slice(7).map(function (column) { + return column.content; + }) + entry = { + 'name':row_name, + 'values':row_values + } + + let raw_data = frappe.query_report.chart.data; + let new_datasets = raw_data.datasets; + + var found = false; + + for(var i=0; i < new_datasets.length;i++){ + if(new_datasets[i].name == row_name){ + found = true; + new_datasets.splice(i,1); + break; + } + } + + if(!found){ + new_datasets.push(entry); + } + + let new_data = { + labels: raw_data.labels, + datasets: new_datasets + } + + setTimeout(() => { + frappe.query_report.chart.update(new_data) + },200) + + + setTimeout(() => { + frappe.query_report.chart.draw(true); + }, 800) + + frappe.query_report.raw_chart_data = new_data; + }, + } + }) + }, +} diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.json b/erpnext/stock/report/stock_analytics/stock_analytics.json new file mode 100644 index 00000000000..efd5e99cbcc --- /dev/null +++ b/erpnext/stock/report/stock_analytics/stock_analytics.json @@ -0,0 +1,32 @@ +{ + "add_total_row": 0, + "creation": "2018-10-08 12:11:32.133020", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2018-10-08 12:18:42.834270", + "modified_by": "Administrator", + "module": "Stock", + "name": "Stock Analytics", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Stock Entry", + "report_name": "Stock Analytics", + "report_type": "Script Report", + "roles": [ + { + "role": "Manufacturing Manager" + }, + { + "role": "Stock Manager" + }, + { + "role": "Stock User" + }, + { + "role": "Manufacturing User" + } + ] +} \ No newline at end of file diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py new file mode 100644 index 00000000000..dad8be1b8cb --- /dev/null +++ b/erpnext/stock/report/stock_analytics/stock_analytics.py @@ -0,0 +1,183 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _, scrub +from frappe.utils import getdate, flt +from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details) +from erpnext.accounts.utils import get_fiscal_year +from six import iteritems + +def execute(filters=None): + filters = frappe._dict(filters or {}) + columns = get_columns(filters) + data = get_data(filters) + chart = get_chart_data(columns) + + return columns, data, None, chart + +def get_columns(filters): + columns = [ + { + "label": _("Item"), + "options":"Item", + "fieldname": "name", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Item Name"), + "options":"Item", + "fieldname": "item_name", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Item Group"), + "options":"Item Group", + "fieldname": "item_group", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Brand"), + "fieldname": "brand", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("UOM"), + "fieldname": "uom", + "fieldtype": "Data", + "width": 120 + }] + + ranges = get_period_date_ranges(filters) + + for dummy, end_date in ranges: + period = get_period(end_date, filters) + + columns.append({ + "label": _(period), + "fieldname":scrub(period), + "fieldtype": "Float", + "width": 120 + }) + + return columns + +def get_period_date_ranges(filters): + from dateutil.relativedelta import relativedelta + from_date, to_date = getdate(filters.from_date), getdate(filters.to_date) + + increment = { + "Monthly": 1, + "Quarterly": 3, + "Half-Yearly": 6, + "Yearly": 12 + }.get(filters.range,1) + + periodic_daterange = [] + for dummy in range(1, 53, increment): + if filters.range == "Weekly": + period_end_date = from_date + relativedelta(days=6) + else: + period_end_date = from_date + relativedelta(months=increment, days=-1) + + if period_end_date > to_date: + period_end_date = to_date + periodic_daterange.append([from_date, period_end_date]) + + from_date = period_end_date + relativedelta(days=1) + if period_end_date == to_date: + break + + return periodic_daterange + +def get_period(posting_date, filters): + months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + + if filters.range == 'Weekly': + period = "Week " + str(posting_date.isocalendar()[1]) + elif filters.range == 'Monthly': + period = months[posting_date.month - 1] + elif filters.range == 'Quarterly': + period = "Quarter " + str(((posting_date.month-1)//3)+1) + else: + year = get_fiscal_year(posting_date, company=filters.company) + period = str(year[2]) + + return period + + +def get_periodic_data(entry, filters): + periodic_data = {} + for d in entry: + period = get_period(d.posting_date, filters) + bal_qty = 0 + + if d.voucher_type == "Stock Reconciliation": + if periodic_data.get(d.item_code): + bal_qty = periodic_data[d.item_code]["balance"] + + qty_diff = d.qty_after_transaction - bal_qty + else: + qty_diff = d.actual_qty + + if filters["value_quantity"] == 'Quantity': + value = qty_diff + else: + value = d.stock_value_difference + + periodic_data.setdefault(d.item_code, {}).setdefault(period, 0.0) + periodic_data.setdefault(d.item_code, {}).setdefault("balance", 0.0) + + periodic_data[d.item_code]["balance"] += value + periodic_data[d.item_code][period] = periodic_data[d.item_code]["balance"] + + + return periodic_data + +def get_data(filters): + data = [] + items = get_items(filters) + sle = get_stock_ledger_entries(filters, items) + item_details = get_item_details(items, sle, filters) + periodic_data = get_periodic_data(sle, filters) + ranges = get_period_date_ranges(filters) + + for dummy, item_data in iteritems(item_details): + row = { + "name": item_data.name, + "item_name": item_data.item_name, + "item_group": item_data.item_group, + "uom": item_data.stock_uom, + "brand": item_data.brand, + } + total = 0 + for dummy, end_date in ranges: + period = get_period(end_date, filters) + amount = flt(periodic_data.get(item_data.name, {}).get(period)) + row[scrub(period)] = amount + total += amount + row["total"] = total + data.append(row) + + return data + +def get_chart_data(columns): + labels = [d.get("label") for d in columns[5:]] + chart = { + "data": { + 'labels': labels, + 'datasets':[] + } + } + chart["type"] = "line" + + return chart + + + + diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js index 6589688d1a9..babc6dc9602 100644 --- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js +++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.js @@ -7,7 +7,8 @@ frappe.query_reports["Stock Projected Qty"] = { "fieldname":"company", "label": __("Company"), "fieldtype": "Link", - "options": "Company" + "options": "Company", + "default": frappe.defaults.get_user_default("Company") }, { "fieldname":"warehouse", diff --git a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py index 917a3342514..2a02b469fb0 100644 --- a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py +++ b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py @@ -85,6 +85,14 @@ def get_suppliers_details(filters): is_stock_item=1 and name=pri.item_code)""", as_dict=1): item_supplier_map.setdefault(d.item_code, []).append(d.supplier) + for d in frappe.db.sql("""select pr.supplier, pri.item_code from + `tabPurchase Invoice` pr, `tabPurchase Invoice Item` pri + where pr.name=pri.parent and pr.docstatus=1 and + ifnull(pr.update_stock, 0) = 1 and pri.item_code=(select name from `tabItem` + where is_stock_item=1 and name=pri.item_code)""", as_dict=1): + if d.item_code not in item_supplier_map: + item_supplier_map.setdefault(d.item_code, []).append(d.supplier) + if supplier: for item_code, suppliers in iteritems(item_supplier_map): if supplier not in suppliers: diff --git a/erpnext/templates/includes/fee/fee_row.html b/erpnext/templates/includes/fee/fee_row.html index ac2b1006ada..d5fd6822366 100644 --- a/erpnext/templates/includes/fee/fee_row.html +++ b/erpnext/templates/includes/fee/fee_row.html @@ -5,13 +5,13 @@ {{ doc.program }}
- {{ doc.get_formatted("total_amount") }} + {{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}
- {{ doc.get_formatted("paid_amount") }} + {{ frappe.utils.fmt_money(doc.paid_amount, currency=doc.currency) }}
- {{ doc.get_formatted("outstanding_amount") }} + {{ frappe.utils.fmt_money(doc.outstanding_amount, currency=doc.currency) }}
diff --git a/erpnext/utilities/product.py b/erpnext/utilities/product.py index 6f984a501b8..a2867c8806a 100644 --- a/erpnext/utilities/product.py +++ b/erpnext/utilities/product.py @@ -108,8 +108,8 @@ def get_price(item_code, price_list, customer_group, company, qty=1): uom_conversion_factor = frappe.db.sql("""select C.conversion_factor from `tabUOM Conversion Detail` C - inner join `tabItem` I on C.uom = I.sales_uom - where C.parent = %s""", item_code) + inner join `tabItem` I on C.parent = I.name and C.uom = I.sales_uom + where I.name = %s""", item_code) uom_conversion_factor = uom_conversion_factor[0][0] if uom_conversion_factor else 1 price_obj["formatted_price_sales_uom"] = fmt_money(price_obj["price_list_rate"] * uom_conversion_factor, currency=price_obj["currency"])