From 9757a603fa99c3d05151c7b94d2eddffb04a6ddb Mon Sep 17 00:00:00 2001 From: Jay Parikh Date: Wed, 6 Mar 2019 12:44:41 +0000 Subject: [PATCH 01/34] Fix Company Default to Total Stock Summary Report --- .../stock/report/total_stock_summary/total_stock_summary.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.js b/erpnext/stock/report/total_stock_summary/total_stock_summary.js index 223a603004c..b7461c485f6 100644 --- a/erpnext/stock/report/total_stock_summary/total_stock_summary.js +++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.js @@ -18,7 +18,9 @@ frappe.query_reports["Total Stock Summary"] = { "label": __("Company"), "fieldtype": "Link", "width": "80", - "options": "Company" + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 }, ] } From 783331c64573cf56635bbe1cdb8e59c8f32db018 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 Mar 2019 18:44:04 +0530 Subject: [PATCH 02/34] sales_order to work_order item desc fix --- erpnext/selling/doctype/sales_order/sales_order.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b589cdeaa43..2345762233f 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -388,6 +388,7 @@ class SalesOrder(SellingController): items.append(dict( name= i.name, item_code= i.item_code, + description= i.description, bom = bom, warehouse = i.warehouse, pending_qty = pending_qty, @@ -398,6 +399,7 @@ class SalesOrder(SellingController): items.append(dict( name= i.name, item_code= i.item_code, + description= i.description, bom = '', warehouse = i.warehouse, pending_qty = pending_qty, @@ -901,7 +903,8 @@ def make_work_orders(items, sales_order, company, project=None): sales_order=sales_order, sales_order_item=i['sales_order_item'], project=project, - fg_warehouse=i['warehouse'] + fg_warehouse=i['warehouse'], + description=i['description'] )).insert() work_order.set_work_order_operations() work_order.save() From 4f1737c2dd248850f8d086736e170b44b66d1a2f Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 Mar 2019 22:19:15 +0530 Subject: [PATCH 03/34] fix sales order test for creating work order from sales order --- erpnext/selling/doctype/sales_order/test_sales_order.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 0eb19e3417c..f270938ad3a 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -573,7 +573,8 @@ class TestSalesOrder(unittest.TestCase): "item_code": item.get("item_code"), "pending_qty": item.get("pending_qty"), "sales_order_item": item.get("sales_order_item"), - "bom": item.get("bom") + "bom": item.get("bom"), + "description": item.get("description") }) so_item_name[item.get("sales_order_item")]= item.get("pending_qty") make_work_orders(json.dumps({"items":po_items}), so.name, so.company) From 59699bf46e2288ef89208ed7a602016455754aef Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 Mar 2019 23:33:03 +0530 Subject: [PATCH 04/34] [debug] locally tests passed but travis failed --- erpnext/selling/doctype/sales_order/sales_order.py | 1 + erpnext/selling/doctype/sales_order/test_sales_order.py | 1 + 2 files changed, 2 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 2345762233f..a84fa1430bb 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -886,6 +886,7 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters): def make_work_orders(items, sales_order, company, project=None): '''Make Work Orders against the given Sales Order for the given `items`''' items = json.loads(items).get('items') + print(items) out = [] for i in items: diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index f270938ad3a..584b5b99c66 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -577,6 +577,7 @@ class TestSalesOrder(unittest.TestCase): "description": item.get("description") }) so_item_name[item.get("sales_order_item")]= item.get("pending_qty") + print(po_items) make_work_orders(json.dumps({"items":po_items}), so.name, so.company) # Check if Work Orders were raised From 7ab961f79881c4861dd2c7664aaceb165ebc3bc7 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 Mar 2019 23:53:38 +0530 Subject: [PATCH 05/34] remove debug code --- erpnext/selling/doctype/sales_order/sales_order.py | 1 - erpnext/selling/doctype/sales_order/test_sales_order.py | 1 - 2 files changed, 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index a84fa1430bb..2345762233f 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -886,7 +886,6 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters): def make_work_orders(items, sales_order, company, project=None): '''Make Work Orders against the given Sales Order for the given `items`''' items = json.loads(items).get('items') - print(items) out = [] for i in items: diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 584b5b99c66..f270938ad3a 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -577,7 +577,6 @@ class TestSalesOrder(unittest.TestCase): "description": item.get("description") }) so_item_name[item.get("sales_order_item")]= item.get("pending_qty") - print(po_items) make_work_orders(json.dumps({"items":po_items}), so.name, so.company) # Check if Work Orders were raised From 78a32ae172063a9456c51185ccb348d97db1c58a Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 7 Mar 2019 20:00:07 +0530 Subject: [PATCH 06/34] fix: Remove validation for relieving date from additional salary --- erpnext/hr/doctype/additional_salary/additional_salary.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/hr/doctype/additional_salary/additional_salary.py b/erpnext/hr/doctype/additional_salary/additional_salary.py index e25e69e75f2..968a1c4571c 100644 --- a/erpnext/hr/doctype/additional_salary/additional_salary.py +++ b/erpnext/hr/doctype/additional_salary/additional_salary.py @@ -19,8 +19,6 @@ class AdditionalSalary(Document): ["date_of_joining", "relieving_date"]) if date_of_joining and getdate(self.payroll_date) < getdate(date_of_joining): frappe.throw(_("Payroll date can not be less than employee's joining date")) - elif relieving_date and getdate(self.payroll_date) > getdate(relieving_date): - frappe.throw(_("To date can not greater than employee's relieving date")) def get_amount(self, sal_start_date, sal_end_date): start_date = getdate(sal_start_date) From 821a002125cfed5b71559b7281c3f8cd7c634bae Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 7 Mar 2019 19:27:54 +0530 Subject: [PATCH 07/34] feat: added provision to disable CWIP accounting in asset settings --- .../purchase_invoice/purchase_invoice.py | 18 +++++-- erpnext/assets/doctype/asset/asset.py | 23 ++++++--- .../asset_settings/asset_settings.json | 50 +++++++++++++++++-- .../purchase_receipt/purchase_receipt.py | 5 +- 4 files changed, 78 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index c0d0d837fe7..bc44bc80f4e 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -8,6 +8,7 @@ from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate from frappe import _, throw import frappe.defaults +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.controllers.buying_controller import BuyingController from erpnext.accounts.party import get_party_account, get_due_date from erpnext.accounts.utils import get_account_currency, get_fiscal_year @@ -17,7 +18,7 @@ from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entri from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt from erpnext.buying.utils import check_for_closed_status from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center -from erpnext.assets.doctype.asset.asset import get_asset_account +from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled from frappe.model.mapper import get_mapped_doc from six import iteritems from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\ @@ -238,6 +239,13 @@ class PurchaseInvoice(BuyingController): item.expense_account = warehouse_account[item.warehouse]["account"] else: item.expense_account = stock_not_billed_account + elif item.is_fixed_asset and is_cwip_accounting_disabled(): + if not item.asset: + frappe.throw(_("Row {0}: asset is required for item {1}") + .format(item.idx, item.item_code)) + + item.expense_account = get_asset_category_account(item.asset, 'fixed_asset_account', + company = self.company) elif item.is_fixed_asset and item.pr_detail: item.expense_account = asset_received_but_not_billed elif not item.expense_account and for_validate: @@ -383,7 +391,9 @@ class PurchaseInvoice(BuyingController): self.make_supplier_gl_entry(gl_entries) self.make_item_gl_entries(gl_entries) - self.get_asset_gl_entry(gl_entries) + if not is_cwip_accounting_disabled(): + self.get_asset_gl_entry(gl_entries) + self.make_tax_gl_entries(gl_entries) gl_entries = merge_similar_entries(gl_entries) @@ -475,7 +485,7 @@ class PurchaseInvoice(BuyingController): "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(item.rm_supp_cost) }, warehouse_account[self.supplier_warehouse]["account_currency"])) - elif not item.is_fixed_asset: + elif not item.is_fixed_asset or (item.is_fixed_asset and is_cwip_accounting_disabled()): gl_entries.append( self.get_gl_dict({ "account": item.expense_account if not item.enable_deferred_expense else item.deferred_expense_account, @@ -520,7 +530,7 @@ class PurchaseInvoice(BuyingController): base_asset_amount = flt(item.base_net_amount + item.item_tax_amount) if (not item.expense_account or frappe.db.get_value('Account', - item.expense_account, 'account_type') != 'Asset Received But Not Billed'): + item.expense_account, 'account_type') not in ['Asset Received But Not Billed', 'Fixed Asset']): arbnb_account = self.get_company_default("asset_received_but_not_billed") item.expense_account = arbnb_account diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index a38b40bc60b..6b145956f37 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -33,7 +33,7 @@ class Asset(AccountsController): self.validate_in_use_date() self.set_status() self.update_stock_movement() - if not self.booked_fixed_asset: + if not self.booked_fixed_asset and not is_cwip_accounting_disabled(): self.make_gl_entries() def on_cancel(self): @@ -71,14 +71,15 @@ class Asset(AccountsController): if not flt(self.gross_purchase_amount): frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError) - if not self.is_existing_asset and not (self.purchase_receipt or self.purchase_invoice): - frappe.throw(_("Please create purchase receipt or purchase invoice for the item {0}"). - format(self.item_code)) + if not is_cwip_accounting_disabled(): + if not self.is_existing_asset and not (self.purchase_receipt or self.purchase_invoice): + frappe.throw(_("Please create purchase receipt or purchase invoice for the item {0}"). + format(self.item_code)) - if (not self.purchase_receipt and self.purchase_invoice - and not frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')): - frappe.throw(_("Update stock must be enable for the purchase invoice {0}"). - format(self.purchase_invoice)) + if (not self.purchase_receipt and self.purchase_invoice + and not frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')): + frappe.throw(_("Update stock must be enable for the purchase invoice {0}"). + format(self.purchase_invoice)) if not self.calculate_depreciation: return @@ -404,6 +405,9 @@ def update_maintenance_status(): asset.set_status('Out of Order') def make_post_gl_entry(): + if is_cwip_accounting_disabled(): + return + assets = frappe.db.sql_list(""" select name from `tabAsset` where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate()) @@ -551,3 +555,6 @@ def make_journal_entry(asset_name): }) return je + +def is_cwip_accounting_disabled(): + return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting")) \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_settings/asset_settings.json b/erpnext/assets/doctype/asset_settings/asset_settings.json index d6ddd33c302..a3fee96f4ee 100644 --- a/erpnext/assets/doctype/asset_settings/asset_settings.json +++ b/erpnext/assets/doctype/asset_settings/asset_settings.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,10 +15,12 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "depreciation_options", "fieldtype": "Section Break", "hidden": 0, @@ -40,14 +43,17 @@ "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, + "fetch_if_empty": 0, "fieldname": "schedule_based_on_fiscal_year", "fieldtype": "Check", "hidden": 0, @@ -70,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, @@ -81,6 +89,7 @@ "default": "360", "depends_on": "eval:doc.schedule_based_on_fiscal_year", "description": "This value is used for pro-rata temporis calculation", + "fetch_if_empty": 0, "fieldname": "number_of_days_in_fiscal_year", "fieldtype": "Data", "hidden": 0, @@ -103,6 +112,40 @@ "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, + "fetch_if_empty": 0, + "fieldname": "disable_cwip_accounting", + "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": "Disable CWIP Accounting", + "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 } ], @@ -116,7 +159,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2018-01-05 10:10:39.803255", + "modified": "2019-03-08 10:44:41.924547", "modified_by": "Administrator", "module": "Assets", "name": "Asset Settings", @@ -125,7 +168,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -145,7 +187,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -171,5 +212,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/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index cb51e220b83..ed7f2ca4323 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -13,7 +13,7 @@ from erpnext.controllers.buying_controller import BuyingController from erpnext.accounts.utils import get_account_currency from frappe.desk.notifications import clear_doctype_notifications from erpnext.buying.utils import check_for_closed_status -from erpnext.assets.doctype.asset.asset import get_asset_account +from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled from six import iteritems form_grid_templates = { @@ -258,7 +258,8 @@ class PurchaseReceipt(BuyingController): d.rejected_warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(d.warehouse) - self.get_asset_gl_entry(gl_entries) + if not is_cwip_accounting_disabled(): + self.get_asset_gl_entry(gl_entries) # Cost center-wise amount breakup for other charges included for valuation valuation_tax = {} for tax in self.get("taxes"): From 1692fbaf1c6a1a2f839ad0b1806c1153c40ba92c Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Fri, 8 Mar 2019 18:37:34 +0530 Subject: [PATCH 08/34] fetch from fix --- erpnext/regional/united_arab_emirates/setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py index 3c8328b1074..250659e54da 100644 --- a/erpnext/regional/united_arab_emirates/setup.py +++ b/erpnext/regional/united_arab_emirates/setup.py @@ -28,24 +28,24 @@ def make_custom_fields(): purchase_invoice_fields = [ dict(fieldname='company_trn', label='Company TRN', fieldtype='Read Only', insert_after='shipping_address', - options='company.tax_id', print_hide=1), + fetch_from='company.tax_id', print_hide=1), dict(fieldname='supplier_name_in_arabic', label='Supplier Name in Arabic', fieldtype='Read Only', insert_after='supplier_name', - options='supplier.supplier_name_in_arabic', print_hide=1) + fetch_from='supplier.supplier_name_in_arabic', print_hide=1) ] sales_invoice_fields = [ dict(fieldname='company_trn', label='Company TRN', fieldtype='Read Only', insert_after='company_address', - options='company.tax_id', print_hide=1), + fetch_from='company.tax_id', print_hide=1), dict(fieldname='customer_name_in_arabic', label='Customer Name in Arabic', fieldtype='Read Only', insert_after='customer_name', - options='customer.customer_name_in_arabic', print_hide=1), + fetch_from='customer.customer_name_in_arabic', print_hide=1), ] invoice_item_fields = [ dict(fieldname='tax_code', label='Tax Code', - fieldtype='Read Only', options='item_code.tax_code', insert_after='description', + fieldtype='Read Only', fetch_from='item_code.tax_code', insert_after='description', allow_on_submit=1, print_hide=1), dict(fieldname='tax_rate', label='Tax Rate', fieldtype='Float', insert_after='tax_code', From 52729bf36934711d2d748f99b73be35fb4651da1 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sun, 10 Mar 2019 14:26:30 +0530 Subject: [PATCH 09/34] feat: child table to add multiple time logs in job card --- .../doctype/job_card/job_card.js | 29 ++- .../doctype/job_card/job_card.json | 205 +++++++++++++---- .../doctype/job_card/job_card.py | 109 +++++---- .../doctype/job_card_time_log/__init__.py | 0 .../job_card_time_log/job_card_time_log.json | 208 ++++++++++++++++++ .../job_card_time_log/job_card_time_log.py | 9 + .../doctype/work_order/test_work_order.py | 15 +- erpnext/patches.txt | 1 + .../patches/v11_1/make_job_card_time_logs.py | 29 +++ 9 files changed, 513 insertions(+), 92 deletions(-) create mode 100644 erpnext/manufacturing/doctype/job_card_time_log/__init__.py create mode 100644 erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json create mode 100644 erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py create mode 100644 erpnext/patches/v11_1/make_job_card_time_logs.py diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 3fe9b8af30d..95549d5a248 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -18,20 +18,27 @@ frappe.ui.form.on('Job Card', { } if (frm.doc.docstatus == 0) { - if (!frm.doc.actual_start_date || !frm.doc.actual_end_date) { - frm.trigger("make_dashboard"); - } + frm.trigger("make_dashboard"); - if (!frm.doc.actual_start_date) { + if (!frm.doc.job_started) { frm.add_custom_button(__("Start Job"), () => { - frm.set_value('actual_start_date', frappe.datetime.now_datetime()); + let row = frappe.model.add_child(frm.doc, 'Job Card Time Log', 'time_logs'); + row.from_time = frappe.datetime.now_datetime(); + frm.set_value('job_started', 1); + frm.set_value('started_time' , row.from_time); frm.save(); }); - } else if (!frm.doc.actual_end_date) { + } else { frm.add_custom_button(__("Complete Job"), () => { - frm.set_value('actual_end_date', frappe.datetime.now_datetime()); - frm.save(); - frm.savesubmit(); + let completed_time = frappe.datetime.now_datetime(); + frm.doc.time_logs.forEach(d => { + if (d.from_time && !d.to_time) { + d.to_time = completed_time; + frm.set_value('started_time' , ''); + frm.set_value('job_started', 0); + frm.save(); + } + }) }); } } @@ -53,8 +60,8 @@ frappe.ui.form.on('Job Card', { var section = frm.dashboard.add_section(timer); - if (frm.doc.actual_start_date) { - let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.actual_start_date),"seconds"); + if (frm.doc.started_time) { + let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds"); initialiseTimer(); function initialiseTimer() { diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index b020c89053c..39c5cce313b 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -21,6 +21,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "work_order", "fieldtype": "Link", "hidden": 0, @@ -54,6 +55,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "bom_no", "fieldtype": "Link", "hidden": 0, @@ -87,6 +89,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "workstation", "fieldtype": "Link", "hidden": 0, @@ -120,6 +123,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "operation", "fieldtype": "Link", "hidden": 0, @@ -153,6 +157,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_4", "fieldtype": "Column Break", "hidden": 0, @@ -185,6 +190,7 @@ "collapsible": 0, "columns": 0, "default": "Today", + "fetch_if_empty": 0, "fieldname": "posting_date", "fieldtype": "Date", "hidden": 0, @@ -217,6 +223,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "company", "fieldtype": "Link", "hidden": 0, @@ -250,6 +257,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "for_quantity", "fieldtype": "Float", "hidden": 0, @@ -282,6 +290,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "wip_warehouse", "fieldtype": "Link", "hidden": 0, @@ -315,6 +324,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "timing_detail", "fieldtype": "Section Break", "hidden": 0, @@ -347,6 +357,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "employee", "fieldtype": "Link", "hidden": 0, @@ -380,7 +391,74 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "time_in_mins", + "fetch_if_empty": 0, + "fieldname": "time_logs", + "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": "Time Logs", + "length": 0, + "no_copy": 0, + "options": "Job Card Time Log", + "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, + "fetch_if_empty": 0, + "fieldname": "section_break_13", + "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, + "fetch_if_empty": 0, + "fieldname": "total_completed_qty", "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, @@ -389,7 +467,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Time In Mins", + "label": "Total Completed Qty", "length": 0, "no_copy": 0, "permlevel": 0, @@ -412,7 +490,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_13", + "fetch_if_empty": 0, + "fieldname": "column_break_15", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, @@ -443,8 +522,9 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "actual_start_date", - "fieldtype": "Datetime", + "fetch_if_empty": 0, + "fieldname": "total_time_in_mins", + "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -452,46 +532,14 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Actual Start Date", + "label": "Total Time in Mins", "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": "actual_end_date", - "fieldtype": "Datetime", - "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": "Actual End Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -507,6 +555,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "section_break_8", "fieldtype": "Section Break", "hidden": 0, @@ -539,6 +588,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "items", "fieldtype": "Table", "hidden": 0, @@ -572,6 +622,7 @@ "bold": 0, "collapsible": 1, "columns": 0, + "fetch_if_empty": 0, "fieldname": "more_information", "fieldtype": "Section Break", "hidden": 0, @@ -604,6 +655,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "operation_id", "fieldtype": "Data", "hidden": 1, @@ -637,6 +689,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "fetch_if_empty": 0, "fieldname": "transferred_qty", "fieldtype": "Float", "hidden": 0, @@ -670,6 +723,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "fetch_if_empty": 0, "fieldname": "requested_qty", "fieldtype": "Float", "hidden": 0, @@ -702,6 +756,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "project", "fieldtype": "Link", "hidden": 0, @@ -735,6 +790,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "remarks", "fieldtype": "Small Text", "hidden": 0, @@ -767,6 +823,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_20", "fieldtype": "Column Break", "hidden": 0, @@ -799,6 +856,7 @@ "collapsible": 0, "columns": 0, "default": "Open", + "fetch_if_empty": 0, "fieldname": "status", "fieldtype": "Select", "hidden": 0, @@ -832,6 +890,73 @@ "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, + "fieldname": "job_started", + "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": "Job Started", + "length": 0, + "no_copy": 1, + "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, + "fetch_if_empty": 0, + "fieldname": "started_time", + "fieldtype": "Datetime", + "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": "Started Time", + "length": 0, + "no_copy": 1, + "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, + "fetch_if_empty": 0, "fieldname": "amended_from", "fieldtype": "Link", "hidden": 0, @@ -868,7 +993,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-12-13 17:23:57.986381", + "modified": "2019-03-10 17:38:37.499871", "modified_by": "Administrator", "module": "Manufacturing", "name": "Job Card", diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index ea9f714fc84..23a4e5105c0 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -11,44 +11,56 @@ from frappe.model.document import Document class JobCard(Document): def validate(self): - self.validate_actual_dates() - self.set_time_in_mins() + self.validate_time_logs() self.set_status() - def validate_actual_dates(self): - if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date): - frappe.throw(_("Actual start date must be less than actual end date")) + def validate_time_logs(self): + self.total_completed_qty = 0.0 + self.total_time_in_mins = 0.0 - if not (self.employee and self.actual_start_date and self.actual_end_date): - return + for d in self.get('time_logs'): + if get_datetime(d.from_time) > get_datetime(d.to_time): + frappe.throw(_("Row {0}: From time must be less than to time").format(d.idx)) - data = frappe.db.sql(""" select name from `tabJob Card` - where - ((%(actual_start_date)s > actual_start_date and %(actual_start_date)s < actual_end_date) or - (%(actual_end_date)s > actual_start_date and %(actual_end_date)s < actual_end_date) or - (%(actual_start_date)s <= actual_start_date and %(actual_end_date)s >= actual_end_date)) and - name != %(name)s and employee = %(employee)s and docstatus =1 - """, { - 'actual_start_date': self.actual_start_date, - 'actual_end_date': self.actual_end_date, - 'employee': self.employee, - 'name': self.name - }, as_dict=1) + data = self.get_overlap_for(d) + if data: + frappe.throw(_("Row {0}: From Time and To Time of {1} is overlapping with {2}") + .format(d.idx, self.name, data.name)) - if data: - frappe.throw(_("Start date and end date is overlapping with the job card {1}") - .format(data[0].name, data[0].name)) + if d.from_time and d.to_time: + d.time_in_mins = time_diff_in_hours(d.to_time, d.from_time) * 60 + self.total_time_in_mins += d.time_in_mins - def set_time_in_mins(self): - if self.actual_start_date and self.actual_end_date: - self.time_in_mins = time_diff_in_hours(self.actual_end_date, self.actual_start_date) * 60 + if d.completed_qty: + self.total_completed_qty += d.completed_qty + + def get_overlap_for(self, args): + existing = frappe.db.sql("""select jc.name as name from + `tabJob Card Time Log` jctl, `tabJob Card` jc where jctl.parent = jc.name and + ( + (%(from_time)s > jctl.from_time and %(from_time)s < jctl.to_time) or + (%(to_time)s > jctl.from_time and %(to_time)s < jctl.to_time) or + (%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time)) + and jctl.name!=%(name)s + and jc.name!=%(parent)s + and jc.docstatus < 2 + and jc.employee = %(employee)s """, + { + "from_time": args.from_time, + "to_time": args.to_time, + "name": args.name or "No Name", + "parent": args.parent or "No Name", + "employee": self.employee + }, as_dict=True) + + return existing[0] if existing else None def get_required_items(self): if not self.get('work_order'): return doc = frappe.get_doc('Work Order', self.get('work_order')) - if doc.transfer_material_against == 'Work Order' and doc.skip_transfer: + if doc.transfer_material_against == 'Work Order' or doc.skip_transfer: return for d in doc.required_items: @@ -67,36 +79,51 @@ class JobCard(Document): }) def on_submit(self): - self.validate_dates() + self.validate_job_card() self.update_work_order() self.set_transferred_qty() - def validate_dates(self): - if not self.actual_start_date and not self.actual_end_date: - frappe.throw(_("Actual start date and actual end date is mandatory")) - def on_cancel(self): self.update_work_order() self.set_transferred_qty() + def validate_job_card(self): + if not self.time_logs: + frappe.throw(_("Time logs are required for job card {0}").format(self.name)) + + if self.total_completed_qty <= 0.0: + frappe.throw(_("Total completed qty must be greater than zero")) + + if self.total_completed_qty > self.for_quantity: + frappe.throw(_("Total completed qty can not be greater than for quantity")) + def update_work_order(self): if not self.work_order: return - data = frappe.db.get_value("Job Card", {'docstatus': 1, 'operation_id': self.operation_id}, - ['sum(time_in_mins)', 'min(actual_start_date)', 'max(actual_end_date)', 'sum(for_quantity)']) + for_quantity, time_in_mins = 0, 0 + from_time_list, to_time_list = [], [] - if data: - time_in_mins, actual_start_date, actual_end_date, for_quantity = data + for d in frappe.get_all('Job Card', + filters = {'docstatus': 1, 'operation_id': self.operation_id}): + doc = frappe.get_doc('Job Card', d.name) + + for_quantity += doc.total_completed_qty + time_in_mins += doc.total_time_in_mins + for time_log in doc.time_logs: + from_time_list.append(time_log.from_time) + to_time_list.append(time_log.to_time) + + if for_quantity: wo = frappe.get_doc('Work Order', self.work_order) for data in wo.operations: if data.name == self.operation_id: data.completed_qty = for_quantity data.actual_operation_time = time_in_mins - data.actual_start_time = actual_start_date - data.actual_end_time = actual_end_date + data.actual_start_time = min(from_time_list) + data.actual_end_time = max(to_time_list) wo.flags.ignore_validate_update_after_submit = True wo.update_operation_status() @@ -132,9 +159,11 @@ class JobCard(Document): break if completed: - job_cards = frappe.get_all('Job Card', filters = {'work_order': self.work_order, + job_cards = frappe.get_all('Job Card', filters = {'work_order': self.work_order, 'docstatus': ('!=', 2)}, fields = 'sum(transferred_qty) as qty', group_by='operation_id') - qty = min([d.qty for d in job_cards]) + + if job_cards: + qty = min([d.qty for d in job_cards]) doc.db_set('material_transferred_for_manufacturing', qty) @@ -147,7 +176,7 @@ class JobCard(Document): 2: "Cancelled" }[self.docstatus or 0] - if self.actual_start_date: + if self.time_logs: self.status = 'Work In Progress' if (self.docstatus == 1 and diff --git a/erpnext/manufacturing/doctype/job_card_time_log/__init__.py b/erpnext/manufacturing/doctype/job_card_time_log/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json new file mode 100644 index 00000000000..2aab71dee4f --- /dev/null +++ b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json @@ -0,0 +1,208 @@ +{ + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2019-03-08 23:56:43.187569", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "from_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": "From 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": 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, + "fetch_if_empty": 0, + "fieldname": "to_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": "To 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": 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, + "fetch_if_empty": 0, + "fieldname": "column_break_2", + "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, + "fetch_if_empty": 0, + "fieldname": "time_in_mins", + "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": "Time In Mins", + "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, + "default": "0", + "fetch_if_empty": 0, + "fieldname": "completed_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": "Completed Qty", + "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 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2019-03-10 17:08:46.504910", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Job Card Time Log", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "ASC", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 +} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py new file mode 100644 index 00000000000..3dc66891216 --- /dev/null +++ b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe.model.document import Document + +class JobCardTimeLog(Document): + pass diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 69381c53b3e..b292047aa63 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -302,6 +302,19 @@ class TestWorkOrder(unittest.TestCase): self.assertEqual(len(ste.additional_costs), 1) self.assertEqual(ste.total_additional_costs, 1000) + def test_job_card(self): + data = frappe.get_cached_value('BOM', + {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item']) + + if data: + bom, bom_item = data + + bom_doc = frappe.get_doc('BOM', bom) + work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom) + + job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order}) + self.assertEqual(len(job_cards), len(bom_doc.operations)) + def test_work_order_with_non_transfer_item(self): items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0} for item, allow_transfer in items.items(): @@ -346,7 +359,7 @@ def make_wo_order_test_record(**args): wo_order = frappe.new_doc("Work Order") wo_order.production_item = args.production_item or args.item or args.item_code or "_Test FG Item" - wo_order.bom_no = frappe.db.get_value("BOM", {"item": wo_order.production_item, + wo_order.bom_no = args.bom_no or frappe.db.get_value("BOM", {"item": wo_order.production_item, "is_active": 1, "is_default": 1}) wo_order.qty = args.qty or 10 wo_order.wip_warehouse = args.wip_warehouse or "_Test Warehouse - _TC" diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 433141cdf67..7d49ad5fe36 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -588,3 +588,4 @@ execute:frappe.delete_doc('DocType', 'Notification Control') erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 erpnext.patches.v11_0.make_italian_localization_fields # 01-03-2019 +erpnext.patches.v11_1.make_job_card_time_logs \ No newline at end of file diff --git a/erpnext/patches/v11_1/make_job_card_time_logs.py b/erpnext/patches/v11_1/make_job_card_time_logs.py new file mode 100644 index 00000000000..6e708df48d8 --- /dev/null +++ b/erpnext/patches/v11_1/make_job_card_time_logs.py @@ -0,0 +1,29 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('manufacturing', 'doctype', 'job_card_time_log') + + if (frappe.db.table_exists("Job Card") + and frappe.get_meta("Job Card").has_field("actual_start_date")): + time_logs = [] + for d in frappe.get_all('Job Card', + fields = ["actual_start_date", "actual_end_date", "time_in_mins", "name", "for_quantity"], + filters = {'docstatus': ("<", 2)}): + if d.actual_start_date: + time_logs.append([d.actual_start_date, d.actual_end_date, d.time_in_mins, + d.for_quantity, d.name, 'Job Card', 'time_logs', frappe.generate_hash("", 10)]) + + if time_logs: + frappe.db.sql(""" INSERT INTO + `tabJob Card Time Log` + (from_time, to_time, time_in_mins, completed_qty, parent, parenttype, parentfield, name) + values {values} + """.format(values = ','.join(['%s'] * len(time_logs))), tuple(time_logs)) + + frappe.reload_doc('manufacturing', 'doctype', 'job_card') + frappe.db.sql(""" update `tabJob Card` set total_completed_qty = for_quantity, + total_time_in_mins = time_in_mins where docstatus < 2 """) \ No newline at end of file From e14758c89713c07ce35f15d6ff1a011aab95e999 Mon Sep 17 00:00:00 2001 From: Bassam Ramadan Date: Thu, 14 Mar 2019 11:31:50 +0200 Subject: [PATCH 10/34] fix: add returns field to cashier closing (#16911) --- .../cashier_closing/cashier_closing.json | 858 +++++++++--------- .../cashier_closing/cashier_closing.py | 4 +- 2 files changed, 435 insertions(+), 427 deletions(-) diff --git a/erpnext/accounts/doctype/cashier_closing/cashier_closing.json b/erpnext/accounts/doctype/cashier_closing/cashier_closing.json index 14e9070f302..115728dc7b6 100644 --- a/erpnext/accounts/doctype/cashier_closing/cashier_closing.json +++ b/erpnext/accounts/doctype/cashier_closing/cashier_closing.json @@ -1,426 +1,434 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2018-06-18 16:51:49.994750", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Cashier-closing-", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Series", - "length": 0, - "no_copy": 0, - "options": "Cashier-closing-", - "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": "user", - "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": 1, - "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": 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, - "default": "Today", - "fieldname": "date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Date", - "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": "from_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "From 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, - "default": "", - "fieldname": "time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "To 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, - "default": "0.00", - "fieldname": "expense", - "fieldtype": "Float", - "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": "Expense", - "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": "0.00", - "fieldname": "custody", - "fieldtype": "Float", - "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": "Custody", - "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": "0.00", - "fieldname": "outstanding_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": "Outstanding Amount", - "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, - "default": "0.0", - "fieldname": "payments", - "fieldtype": "Table", - "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": "Payments", - "length": 0, - "no_copy": 0, - "options": "Cashier Closing Payments", - "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": "net_amount", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Net Amount", - "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": "amended_from", - "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": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Cashier Closing", - "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 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-02-19 08:35:23.157327", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Cashier Closing", - "name_case": "", - "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": 1, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "naming_series:", + "beta": 0, + "creation": "2018-06-18 16:51:49.994750", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "POS-CLO-", + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Series", + "length": 0, + "no_copy": 0, + "options": "POS-CLO-", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "user", + "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": 1, + "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": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Today", + "fieldname": "date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Date", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "from_time", + "fieldtype": "Time", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "From 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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "time", + "fieldtype": "Time", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "To 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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0.00", + "fieldname": "expense", + "fieldtype": "Float", + "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": "Expense", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "2", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0.00", + "fieldname": "custody", + "fieldtype": "Float", + "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": "Custody", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "2", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0.00", + "fieldname": "returns", + "fieldtype": "Float", + "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": "Returns", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "2", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0.00", + "fieldname": "outstanding_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": "Outstanding Amount", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0.0", + "fieldname": "payments", + "fieldtype": "Table", + "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": "Payments", + "length": 0, + "no_copy": 0, + "options": "Cashier Closing Payments", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "net_amount", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Net Amount", + "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, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "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": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Cashier Closing", + "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, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2019-03-14 09:14:26.727129", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Cashier Closing", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 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": 1, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 + } \ No newline at end of file diff --git a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py index 906bc7f18a5..6de62ee5777 100644 --- a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py +++ b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py @@ -29,8 +29,8 @@ class CashierClosing(Document): for i in self.payments: total += flt(i.amount) - self.net_amount = total + self.outstanding_amount + self.expense - self.custody + self.net_amount = total + self.outstanding_amount + self.expense - self.custody + self.returns def validate_time(self): if self.from_time >= self.time: - frappe.throw(_("From Time Should Be Less Than To Time")) + frappe.throw(_("From Time Should Be Less Than To Time")) \ No newline at end of file From 08a209bc529358c0d641e189c6c1c59e74b67937 Mon Sep 17 00:00:00 2001 From: rushin29 Date: Fri, 15 Mar 2019 15:28:50 +0530 Subject: [PATCH 11/34] fix: gst_state_number for address with Unregistered GST (#16798) --- erpnext/regional/india/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index e7d0d5052ec..9747b245694 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -9,6 +9,8 @@ from erpnext.hr.utils import get_salary_assignment from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip def validate_gstin_for_india(doc, method): + if hasattr(doc, 'gst_state') and doc.gst_state: + doc.gst_state_number = state_numbers[doc.gst_state] if not hasattr(doc, 'gstin') or not doc.gstin: return From 2ae7ed4cf0de848f1fbca04e278780f14a9daaf6 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Sun, 17 Mar 2019 09:49:24 +0530 Subject: [PATCH 12/34] fix: Gross profit report fix (#16935) --- erpnext/accounts/report/gross_profit/gross_profit.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 073516fb88e..e5aaafaff49 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -125,10 +125,11 @@ class GrossProfitGenerator(object): # get buying amount if row.item_code in product_bundles: - row.buying_amount = self.get_buying_amount_from_product_bundle(row, - product_bundles[row.item_code]) + row.buying_amount = flt(self.get_buying_amount_from_product_bundle(row, + product_bundles[row.item_code]), self.currency_precision) else: - row.buying_amount = self.get_buying_amount(row, row.item_code) + row.buying_amount = flt(self.get_buying_amount(row, row.item_code), + self.currency_precision) # get buying rate if row.qty: @@ -215,7 +216,7 @@ class GrossProfitGenerator(object): if packed_item.get("parent_detail_docname")==row.item_row: buying_amount += self.get_buying_amount(row, packed_item.item_code) - return buying_amount + return flt(buying_amount, self.currency_precision) def get_buying_amount(self, row, item_code): # IMP NOTE From 3ead70ba3c4304f8f1248a91c128e18cf8996170 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 18 Mar 2019 08:22:57 +0530 Subject: [PATCH 13/34] fix: Change IBAN Account length from 25 to 30 (#16847) --- erpnext/accounts/doctype/bank_account/bank_account.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.json b/erpnext/accounts/doctype/bank_account/bank_account.json index 4897097b4ac..84a8e6857c3 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.json +++ b/erpnext/accounts/doctype/bank_account/bank_account.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 1, @@ -290,7 +291,7 @@ "in_list_view": 1, "in_standard_filter": 0, "label": "IBAN", - "length": 25, + "length": 30, "no_copy": 0, "permlevel": 0, "precision": "", @@ -669,7 +670,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-07-20 13:55:36.996465", + "modified": "2019-03-05 17:56:05.103238", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Account", From aa03ea2a56a9a5d513ba35b43629a4cf04861f07 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Mon, 18 Mar 2019 12:36:42 +0530 Subject: [PATCH 14/34] disbale pl check for Sales and Purchase Invoice --- erpnext/accounts/doctype/gl_entry/gl_entry.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index 810b6f79b51..5c76799e4ea 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -74,7 +74,8 @@ class GLEntry(Document): def check_pl_account(self): if self.is_opening=='Yes' and \ - frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss": + frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss" and \ + self.voucher_type not in ['Purchase Invoice', 'Sales Invoice']: frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry") .format(self.voucher_type, self.voucher_no, self.account)) From 1a4bfdd090c0c5f73bde90f81d3783d2b7d0a4c7 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Mon, 28 Jan 2019 16:35:41 +0530 Subject: [PATCH 15/34] feat: selecting parent_company should disable chart_of_accounts based fields --- erpnext/setup/doctype/company/company.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 70e047a4e80..dbfbc5932ea 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -16,6 +16,14 @@ frappe.ui.form.on("Company", { filters: {"is_additional_component": 1} } }); + + frm.set_df_property("create_chart_of_accounts_based_on", "read_only", frm.doc.parent_company ? 1 : 0); + frm.set_df_property("existing_company", "read_only", frm.doc.parent_company ? 1 : 0); + frm.set_query("parent_company", function() { + return { + filters: {"is_group": 1} + } + }); }, company_name: function(frm) { @@ -28,6 +36,12 @@ frappe.ui.form.on("Company", { } }, + parent_company: function(frm) { + if(!frm.doc.parent_company) return; + frm.set_value("create_chart_of_accounts_based_on", "Existing Company"); + frm.set_value("existing_company", frm.doc.parent_company); + }, + date_of_commencement: function(frm) { if(frm.doc.date_of_commencement Date: Mon, 28 Jan 2019 16:39:14 +0530 Subject: [PATCH 16/34] feat: once company is saved, parent_company cannot be selected --- erpnext/setup/doctype/company/company.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index dbfbc5932ea..5592e9bd64d 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -53,8 +53,9 @@ frappe.ui.form.on("Company", { }, refresh: function(frm) { - if(frm.doc.abbr && !frm.doc.__islocal) { + if(!frm.doc.__islocal) { frm.set_df_property("abbr", "read_only", 1); + frm.set_df_property("parent_company", "read_only", 1); } frm.toggle_display('address_html', !frm.doc.__islocal); From 2def228da88043f944053826d4e7a92f15895c6d Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 29 Jan 2019 12:28:56 +0530 Subject: [PATCH 17/34] feat: allow adding account only if topmost parent company - hidden filter for Parent Company added - Add button overriden with new condition --- .../accounts/doctype/account/account_tree.js | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index a9cbdd5dee7..5a80258e71b 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -4,13 +4,40 @@ frappe.treeview_settings["Account"] = { breadcrumbs: "Accounts", title: __("Chart Of Accounts"), get_tree_root: false, - filters: [{ - fieldname: "company", - fieldtype:"Select", - options: erpnext.utils.get_tree_options("company"), - label: __("Company"), - default: erpnext.utils.get_tree_default("company") - }], + filters: [ + { + fieldname: "company", + fieldtype:"Select", + options: erpnext.utils.get_tree_options("company"), + label: __("Company"), + default: erpnext.utils.get_tree_default("company"), + on_change: function() { + var me = frappe.treeview_settings['Account'].treeview; + var company = me.page.fields_dict.company.get_value(); + frappe.call({ + method: "frappe.client.get_value", + args: { + doctype: "Company", + fieldname: "parent_company", + filters: { name: company}, + }, + callback: function(r, rt) { + if(r.message) { + me.page.fields_dict.parent_company.set_value(r.message["parent_company"] || ""); + } + } + }); + } + }, + { + fieldname: "parent_company", + fieldtype:"Data", + fetch_from: "company.parent_company", + label: __("Parent Company"), + hidden: true, + disable_onchange: true + } + ], root_label: "Accounts", get_tree_nodes: 'erpnext.accounts.utils.get_children', add_tree_node: 'erpnext.accounts.utils.add_ac', @@ -42,8 +69,8 @@ frappe.treeview_settings["Account"] = { ], ignore_fields:["parent_account"], onload: function(treeview) { - frappe.treeview_settings['Account'].page = {}; - $.extend(frappe.treeview_settings['Account'].page, treeview.page); + frappe.treeview_settings['Account'].treeview = {}; + $.extend(frappe.treeview_settings['Account'].treeview, treeview); function get_company() { return treeview.page.fields_dict.company.get_value(); } @@ -93,6 +120,19 @@ frappe.treeview_settings["Account"] = { } }, toolbar: [ + { + label:__("Add Child"), + condition: function(node) { + return frappe.boot.user.can_create.indexOf("Account") !== -1 && + !frappe.treeview_settings['Account'].treeview.page.fields_dict.parent_company.get_value() && + node.expandable && !node.hide_add; + }, + click: function(node) { + var me = frappe.treeview_settings['Account'].treeview; + me.new_node(node); + }, + btnClass: "hidden-xs" + }, { condition: function(node) { return !node.root && frappe.boot.user.can_read.indexOf("GL Entry") !== -1 From 0407bf1e005a316322118bcf7043b834183fb788 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 11:12:15 +0530 Subject: [PATCH 18/34] fix: override primary action button, change filter to root company --- .../accounts/doctype/account/account_tree.js | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index 5a80258e71b..4bedb3c26c7 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -15,25 +15,23 @@ frappe.treeview_settings["Account"] = { var me = frappe.treeview_settings['Account'].treeview; var company = me.page.fields_dict.company.get_value(); frappe.call({ - method: "frappe.client.get_value", + method: "erpnext.accounts.doctype.account.account.get_root_company", args: { - doctype: "Company", - fieldname: "parent_company", - filters: { name: company}, + company: company, }, callback: function(r, rt) { if(r.message) { - me.page.fields_dict.parent_company.set_value(r.message["parent_company"] || ""); + let root_company = r.message.length ? r.message[0] : ""; + me.page.fields_dict.root_company.set_value(root_company); } } }); } }, { - fieldname: "parent_company", + fieldname: "root_company", fieldtype:"Data", - fetch_from: "company.parent_company", - label: __("Parent Company"), + label: __("Root Company"), hidden: true, disable_onchange: true } @@ -105,6 +103,18 @@ frappe.treeview_settings["Account"] = { } }, + post_render: function(treeview) { + frappe.treeview_settings['Account'].treeview["tree"] = treeview.tree; + treeview.page.set_primary_action(__("New"), function() { + let root_company = treeview.page.fields_dict.root_company.get_value(); + + if(root_company) { + frappe.throw(__("Please add the account to root level Company - ") + root_company); + } else { + treeview.new_node(); + } + }, "octicon octicon-plus"); + }, onrender: function(node) { if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){ var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr"; @@ -124,12 +134,12 @@ frappe.treeview_settings["Account"] = { label:__("Add Child"), condition: function(node) { return frappe.boot.user.can_create.indexOf("Account") !== -1 && - !frappe.treeview_settings['Account'].treeview.page.fields_dict.parent_company.get_value() && + !frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value() && node.expandable && !node.hide_add; }, click: function(node) { var me = frappe.treeview_settings['Account'].treeview; - me.new_node(node); + me.new_node(); }, btnClass: "hidden-xs" }, @@ -143,7 +153,7 @@ frappe.treeview_settings["Account"] = { "account": node.label, "from_date": frappe.sys_defaults.year_start_date, "to_date": frappe.sys_defaults.year_end_date, - "company": frappe.treeview_settings['Account'].page.fields_dict.company.get_value() + "company": frappe.treeview_settings['Account'].treeview.page.fields_dict.company.get_value() }; frappe.set_route("query-report", "General Ledger"); }, From 88c990901d5a060a7d2e9c4db27c30d95b064d8f Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 11:12:28 +0530 Subject: [PATCH 19/34] fix: added validation to if account is being added to child company --- erpnext/accounts/doctype/account/account.py | 14 ++++++++++++++ erpnext/setup/doctype/company/company.py | 1 + 2 files changed, 15 insertions(+) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 5d504b94be6..d699146049f 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -34,6 +34,7 @@ class Account(NestedSet): return self.validate_parent() self.validate_root_details() + self.validate_root_company() validate_field_number("Account", self.name, self.account_number, self.company, "account_number") self.validate_group_or_ledger() self.set_root_and_report_type() @@ -90,6 +91,13 @@ class Account(NestedSet): if not self.parent_account and not self.is_group: frappe.throw(_("Root Account must be a group")) + def validate_root_company(self): + # fetch all ancestors in top-down hierarchy + if frappe.local.flags.ignore_root_company_validation: return + ancestors = get_root_company(self.company) + if ancestors: + frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0])) + def validate_group_or_ledger(self): if self.get("__islocal"): return @@ -250,3 +258,9 @@ def merge_account(old, new, is_group, root_type, company): frappe.rename_doc("Account", old, new, merge=1, ignore_permissions=1) return new + +@frappe.whitelist() +def get_root_company(company): + # return the topmost company in the hierarchy + ancestors = frappe.utils.nestedset.get_ancestors_of('Company', company, "lft asc") + return [ancestors[0]] if ancestors else [] diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index c49c2642511..33361e81d46 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -141,6 +141,7 @@ class Company(NestedSet): def create_default_accounts(self): from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts + frappe.local.flags.ignore_root_company_validation = True create_charts(self.name, self.chart_of_accounts, self.existing_company) frappe.db.set(self, "default_receivable_account", frappe.db.get_value("Account", From d787ef8b8e504a499c5fda283861a3f17910f781 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 14:00:56 +0530 Subject: [PATCH 20/34] feat: sync account created for a group company to all its descendants --- erpnext/accounts/doctype/account/account.py | 30 ++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index d699146049f..dea82d8ed6c 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import cint, cstr from frappe import throw, _ -from frappe.utils.nestedset import NestedSet +from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of class RootNotEditable(frappe.ValidationError): pass class BalanceMismatchError(frappe.ValidationError): pass @@ -34,7 +34,6 @@ class Account(NestedSet): return self.validate_parent() self.validate_root_details() - self.validate_root_company() validate_field_number("Account", self.name, self.account_number, self.company, "account_number") self.validate_group_or_ledger() self.set_root_and_report_type() @@ -42,6 +41,7 @@ class Account(NestedSet): self.validate_frozen_accounts_modifier() self.validate_balance_must_be_debit_or_credit() self.validate_account_currency() + self.validate_root_company_and_sync_account_to_children() def validate_parent(self): """Fetch Parent Details and validate parent account""" @@ -91,12 +91,30 @@ class Account(NestedSet): if not self.parent_account and not self.is_group: frappe.throw(_("Root Account must be a group")) - def validate_root_company(self): - # fetch all ancestors in top-down hierarchy - if frappe.local.flags.ignore_root_company_validation: return + def validate_root_company_and_sync_account_to_children(self): + # ignore validation while creating new compnay or while syncing to child companies + if frappe.local.flags.ignore_root_company_validation or self.flags.ignore_root_company_validation: + return + ancestors = get_root_company(self.company) if ancestors: frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0])) + else: + descendants = get_descendants_of('Company', self.company) + acc_name = frappe.db.get_value('Account', self.parent_account, "account_name") + + acc_name_map = {} + for d in frappe.db.get_values('Account', + {"company": ["in", descendants], "account_name": acc_name}, + ["company", "name"], as_dict=True): + acc_name_map[d["company"]] = d["name"] + + for company in descendants: + doc = frappe.copy_doc(self) + doc.flags.ignore_root_company_validation = True + doc.update({"company": company, "account_currency": None, + "parent": acc_name_map[company], "parent_account": acc_name_map[company]}) + doc.save() def validate_group_or_ledger(self): if self.get("__islocal"): @@ -262,5 +280,5 @@ def merge_account(old, new, is_group, root_type, company): @frappe.whitelist() def get_root_company(company): # return the topmost company in the hierarchy - ancestors = frappe.utils.nestedset.get_ancestors_of('Company', company, "lft asc") + ancestors = get_ancestors_of('Company', company, "lft asc") return [ancestors[0]] if ancestors else [] From 73acb8c83702e636a4b126add7a2181ddad2a012 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 13 Feb 2019 16:31:37 +0530 Subject: [PATCH 21/34] fix: set chart of accounts based on parent company on server side --- erpnext/setup/doctype/company/company.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 33361e81d46..ad9d64baf53 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -39,6 +39,7 @@ class Company(NestedSet): self.validate_coa_input() self.validate_perpetual_inventory() self.check_country_change() + self.set_chart_of_accounts() def validate_abbr(self): if not self.abbr: @@ -174,6 +175,12 @@ class Company(NestedSet): self.country != frappe.get_cached_value('Company', self.name, 'country'): frappe.flags.country_change = True + def set_chart_of_accounts(self): + ''' If parent company is set, chart of accounts will be based on that company ''' + if self.parent_company: + self.create_chart_of_accounts_based_on = "Existing Company" + self.existing_company = self.parent_company + def set_default_accounts(self): self._set_default_account("default_cash_account", "Cash") self._set_default_account("default_bank_account", "Bank") From f71cb8dc6db03ee5ddc50aac58ef52b4fc783c71 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 13 Feb 2019 16:32:04 +0530 Subject: [PATCH 22/34] fix: return if no descendants found --- erpnext/accounts/doctype/account/account.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index dea82d8ed6c..e241fc4a3af 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -101,9 +101,10 @@ class Account(NestedSet): frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0])) else: descendants = get_descendants_of('Company', self.company) - acc_name = frappe.db.get_value('Account', self.parent_account, "account_name") + if not descendants: return acc_name_map = {} + acc_name = frappe.db.get_value('Account', self.parent_account, "account_name") for d in frappe.db.get_values('Account', {"company": ["in", descendants], "account_name": acc_name}, ["company", "name"], as_dict=True): From cc65447e62d768354984bb042e6f3a01043fc031 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 13 Feb 2019 16:32:50 +0530 Subject: [PATCH 23/34] fix: chart of accounts field toggling improv --- erpnext/setup/doctype/company/company.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 5592e9bd64d..aff4baf9314 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -17,8 +17,6 @@ frappe.ui.form.on("Company", { } }); - frm.set_df_property("create_chart_of_accounts_based_on", "read_only", frm.doc.parent_company ? 1 : 0); - frm.set_df_property("existing_company", "read_only", frm.doc.parent_company ? 1 : 0); frm.set_query("parent_company", function() { return { filters: {"is_group": 1} @@ -37,9 +35,10 @@ frappe.ui.form.on("Company", { }, parent_company: function(frm) { - if(!frm.doc.parent_company) return; - frm.set_value("create_chart_of_accounts_based_on", "Existing Company"); - frm.set_value("existing_company", frm.doc.parent_company); + var bool = frm.doc.parent_company ? true : false; + frm.set_value('create_chart_of_accounts_based_on', bool ? "Existing Company" : ""); + frm.set_value('existing_company', bool ? frm.doc.parent_company : ""); + disbale_coa_fields(frm, bool); }, date_of_commencement: function(frm) { @@ -54,8 +53,9 @@ frappe.ui.form.on("Company", { refresh: function(frm) { if(!frm.doc.__islocal) { - frm.set_df_property("abbr", "read_only", 1); + frm.doc.abbr && frm.set_df_property("abbr", "read_only", 1); frm.set_df_property("parent_company", "read_only", 1); + disbale_coa_fields(frm); } frm.toggle_display('address_html', !frm.doc.__islocal); @@ -271,3 +271,9 @@ erpnext.company.set_custom_query = function(frm, v) { } }); } + +var disbale_coa_fields = function(frm, bool=true) { + frm.set_df_property("create_chart_of_accounts_based_on", "read_only", bool); + frm.set_df_property("chart_of_accounts", "read_only", bool); + frm.set_df_property("existing_company", "read_only", bool); +}; \ No newline at end of file From 11bba571afb7a6bd49e5ac6bed623bdc8149e7be Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 13 Feb 2019 16:33:28 +0530 Subject: [PATCH 24/34] test case added to check account syncing --- .../accounts/doctype/account/test_account.py | 13 +++++++ .../setup/doctype/company/test_records.json | 34 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py index acaa0966a20..4c057d95492 100644 --- a/erpnext/accounts/doctype/account/test_account.py +++ b/erpnext/accounts/doctype/account/test_account.py @@ -97,6 +97,19 @@ class TestAccount(unittest.TestCase): self.assertRaises(frappe.ValidationError, merge_account, "Capital Stock - _TC",\ "Softwares - _TC", doc.is_group, doc.root_type, doc.company) + def test_account_sync(self): + del frappe.local.flags["ignore_root_company_validation"] + acc = frappe.new_doc("Account") + acc.account_name = "Test Sync Account" + acc.parent_account = "Temporary Accounts - _TC3" + acc.company = "_Test Company 3" + acc.insert() + + acc_tc_4 = frappe.db.get_value('Account', {'account_name': "Test Sync Account", "company": "_Test Company 4"}) + acc_tc_5 = frappe.db.get_value('Account', {'account_name': "Test Sync Account", "company": "_Test Company 5"}) + self.assertEqual(acc_tc_4, "Test Sync Account - _TC4") + self.assertEqual(acc_tc_5, "Test Sync Account - _TC5") + def _make_test_records(verbose): from frappe.test_runner import make_test_objects diff --git a/erpnext/setup/doctype/company/test_records.json b/erpnext/setup/doctype/company/test_records.json index 7e26ca32074..bf9d4bdd190 100644 --- a/erpnext/setup/doctype/company/test_records.json +++ b/erpnext/setup/doctype/company/test_records.json @@ -28,5 +28,39 @@ "domain": "Retail", "chart_of_accounts": "Standard", "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC3", + "company_name": "_Test Company 3", + "is_group": 1, + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC4", + "company_name": "_Test Company 4", + "parent_company": "_Test Company 3", + "is_group": 1, + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC5", + "company_name": "_Test Company 5", + "parent_company": "_Test Company 4", + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" } ] From 01086ff60c54a5463f23f747c2681ac45a531ff9 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 13 Feb 2019 16:33:42 +0530 Subject: [PATCH 25/34] codacy fixes --- erpnext/accounts/doctype/account/account_tree.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index 4bedb3c26c7..df0486cc271 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -19,7 +19,7 @@ frappe.treeview_settings["Account"] = { args: { company: company, }, - callback: function(r, rt) { + callback: function(r) { if(r.message) { let root_company = r.message.length ? r.message[0] : ""; me.page.fields_dict.root_company.set_value(root_company); @@ -137,7 +137,7 @@ frappe.treeview_settings["Account"] = { !frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value() && node.expandable && !node.hide_add; }, - click: function(node) { + click: function() { var me = frappe.treeview_settings['Account'].treeview; me.new_node(); }, From d4e4316d0b9432a0b4ed36a54cdd97bc3a49d2fc Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 18 Mar 2019 10:53:43 +0530 Subject: [PATCH 26/34] fix: test cases and codacy --- erpnext/accounts/doctype/account/account.py | 2 + .../hr/doctype/staffing_plan/staffing_plan.py | 10 ++ .../staffing_plan/test_staffing_plan.py | 10 +- .../setup/doctype/company/test_records.json | 128 +++++++++--------- 4 files changed, 81 insertions(+), 69 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index e241fc4a3af..427f3dba20d 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -116,6 +116,8 @@ class Account(NestedSet): doc.update({"company": company, "account_currency": None, "parent": acc_name_map[company], "parent_account": acc_name_map[company]}) doc.save() + frappe.msgprint(_("Account {0} is added in the child company {1}") + .format(doc.name, company)) def validate_group_or_ledger(self): if self.get("__islocal"): diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py index 70e185cde56..83e53135ef4 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py @@ -20,6 +20,7 @@ class StaffingPlan(Document): self.total_estimated_budget = 0 for detail in self.get("staffing_details"): + self.set_vacancies(detail) self.validate_overlap(detail) self.validate_with_subsidiary_plans(detail) self.validate_with_parent_plan(detail) @@ -39,6 +40,15 @@ class StaffingPlan(Document): else: detail.vacancies = detail.number_of_positions = detail.total_estimated_cost = 0 self.total_estimated_budget += detail.total_estimated_cost + def set_vacancies(self, row): + if not row.vacancies: + current_openings = 0 + for field in ['current_count', 'current_openings']: + if row.get(field): + current_openings += row.get(field) + + row.vacancies = row.number_of_positions - current_openings + def validate_overlap(self, staffing_plan_detail): # Validate if any submitted Staffing Plan exist for any Designations in this plan # and spd.vacancies>0 ? diff --git a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py index 66d9cdd07a5..22dba99af00 100644 --- a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py @@ -18,7 +18,7 @@ class TestStaffingPlan(unittest.TestCase): if frappe.db.exists("Staffing Plan", "Test"): return staffing_plan = frappe.new_doc("Staffing Plan") - staffing_plan.company = "_Test Company 3" + staffing_plan.company = "_Test Company 10" staffing_plan.name = "Test" staffing_plan.from_date = nowdate() staffing_plan.to_date = add_days(nowdate(), 10) @@ -67,7 +67,7 @@ class TestStaffingPlan(unittest.TestCase): if frappe.db.exists("Staffing Plan", "Test 1"): return staffing_plan = frappe.new_doc("Staffing Plan") - staffing_plan.company = "_Test Company 3" + staffing_plan.company = "_Test Company 10" staffing_plan.name = "Test 1" staffing_plan.from_date = nowdate() staffing_plan.to_date = add_days(nowdate(), 10) @@ -85,11 +85,11 @@ def _set_up(): make_company() def make_company(): - if frappe.db.exists("Company", "_Test Company 3"): + if frappe.db.exists("Company", "_Test Company 10"): return company = frappe.new_doc("Company") - company.company_name = "_Test Company 3" - company.abbr = "_TC3" + company.company_name = "_Test Company 10" + company.abbr = "_TC10" company.parent_company = "_Test Company" company.default_currency = "INR" company.country = "India" diff --git a/erpnext/setup/doctype/company/test_records.json b/erpnext/setup/doctype/company/test_records.json index bf9d4bdd190..58d8b5c3346 100644 --- a/erpnext/setup/doctype/company/test_records.json +++ b/erpnext/setup/doctype/company/test_records.json @@ -1,66 +1,66 @@ [ - { - "abbr": "_TC", - "company_name": "_Test Company", - "country": "India", - "default_currency": "INR", - "doctype": "Company", - "domain": "Manufacturing", - "chart_of_accounts": "Standard", - "default_holiday_list": "_Test Holiday List" - }, - { - "abbr": "_TC1", - "company_name": "_Test Company 1", - "country": "United States", - "default_currency": "USD", - "doctype": "Company", - "domain": "Retail", - "chart_of_accounts": "Standard", - "default_holiday_list": "_Test Holiday List" - }, - { - "abbr": "_TC2", - "company_name": "_Test Company 2", - "default_currency": "EUR", - "country": "Germany", - "doctype": "Company", - "domain": "Retail", - "chart_of_accounts": "Standard", - "default_holiday_list": "_Test Holiday List" - }, - { - "abbr": "_TC3", - "company_name": "_Test Company 3", - "is_group": 1, - "country": "India", - "default_currency": "INR", - "doctype": "Company", - "domain": "Manufacturing", - "chart_of_accounts": "Standard", - "default_holiday_list": "_Test Holiday List" - }, - { - "abbr": "_TC4", - "company_name": "_Test Company 4", - "parent_company": "_Test Company 3", - "is_group": 1, - "country": "India", - "default_currency": "INR", - "doctype": "Company", - "domain": "Manufacturing", - "chart_of_accounts": "Standard", - "default_holiday_list": "_Test Holiday List" - }, - { - "abbr": "_TC5", - "company_name": "_Test Company 5", - "parent_company": "_Test Company 4", - "country": "India", - "default_currency": "INR", - "doctype": "Company", - "domain": "Manufacturing", - "chart_of_accounts": "Standard", - "default_holiday_list": "_Test Holiday List" - } + { + "abbr": "_TC", + "company_name": "_Test Company", + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC1", + "company_name": "_Test Company 1", + "country": "United States", + "default_currency": "USD", + "doctype": "Company", + "domain": "Retail", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC2", + "company_name": "_Test Company 2", + "default_currency": "EUR", + "country": "Germany", + "doctype": "Company", + "domain": "Retail", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC3", + "company_name": "_Test Company 3", + "is_group": 1, + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC4", + "company_name": "_Test Company 4", + "parent_company": "_Test Company 3", + "is_group": 1, + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + }, + { + "abbr": "_TC5", + "company_name": "_Test Company 5", + "parent_company": "_Test Company 4", + "country": "India", + "default_currency": "INR", + "doctype": "Company", + "domain": "Manufacturing", + "chart_of_accounts": "Standard", + "default_holiday_list": "_Test Holiday List" + } ] From ac199580af30b82bbb5dd77a5c25b4483b4536bb Mon Sep 17 00:00:00 2001 From: Himanshu Date: Mon, 18 Mar 2019 15:44:54 +0530 Subject: [PATCH 27/34] fix(Customer Ledger): ambiguous error in where clause (#16914) fix for error "InternalError: (1052, u"Column 'company' in where clause is ambiguous")" in Customer Ledger Summary --- .../report/customer_ledger_summary/customer_ledger_summary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index e33bd61411e..eceabf56af7 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -195,7 +195,7 @@ class PartyLedgerSummaryReport(object): conditions = [""] if self.filters.company: - conditions.append("company=%(company)s") + conditions.append("gle.company=%(company)s") self.filters.company_finance_book = erpnext.get_default_finance_book(self.filters.company) From 642a5b69f58337db0911704668e532e8f0457ac0 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Mon, 18 Mar 2019 21:53:33 +0530 Subject: [PATCH 28/34] fix: change customer to supplier --- .../report/supplier_ledger_summary/supplier_ledger_summary.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js index 6fd16f20908..f81297760ed 100644 --- a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js @@ -35,9 +35,9 @@ frappe.query_reports["Supplier Ledger Summary"] = { }, { "fieldname":"party", - "label": __("Customer"), + "label": __("Supplier"), "fieldtype": "Link", - "options": "Customer", + "options": "Supplier", on_change: () => { var party = frappe.query_report.get_filter_value('party'); if (party) { From 1a6e01542afbb4153762e48e29ce862fa2af7c65 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 19 Mar 2019 15:06:01 +0530 Subject: [PATCH 29/34] fix: advance amount is not calculating properly --- erpnext/accounts/party.py | 6 ++++-- .../accounts_receivable_summary.py | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 5855ac3bcd5..70e48007845 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -576,8 +576,10 @@ def get_party_shipping_address(doctype, name): def get_partywise_advanced_payment_amount(party_type="Customer"): data = frappe.db.sql(""" SELECT party, sum({0}) as amount FROM `tabGL Entry` - WHERE party_type = %s and against_voucher is null GROUP BY party""" - .format(("credit - debit") if party_type == "Customer" else "debit") , party_type) + WHERE + party_type = %s and against_voucher is null + GROUP BY party""" + .format(("credit") if party_type == "Customer" else "debit") , party_type) if data: return frappe._dict(data) \ No newline at end of file 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 73ca8b48ef5..b6388f97711 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -144,9 +144,10 @@ class AccountsReceivableSummary(ReceivablePayableReport): row += [self.get_party_name(args.get("party_type"), party)] row += [partywise_advance_amount.get(party, 0)] + paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0)) row += [ - party_dict.invoiced_amt, party_dict.paid_amt, party_dict.credit_amt, party_dict.outstanding_amt, + party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt, party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4, ] From 8808a3fc8ec1d740ad1d4a03e01b073b798a2618 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 19 Mar 2019 15:32:05 +0530 Subject: [PATCH 30/34] fix: POS, cost center not added against debtors --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 62d8ffd8974..9539b0ac3af 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -405,7 +405,7 @@ class SalesInvoice(SellingController): for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name', 'company', 'select_print_heading', 'cash_bank_account', 'company_address', - 'write_off_account', 'write_off_cost_center', 'apply_discount_on'): + 'write_off_account', 'write_off_cost_center', 'apply_discount_on', 'cost_center'): if (not for_validate) or (for_validate and not self.get(fieldname)): self.set(fieldname, pos.get(fieldname)) From a32268789778affa6fa8d022200dbc84519e521c Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 19 Mar 2019 18:10:08 +0530 Subject: [PATCH 31/34] fix: Accounts receivable report, remarks showing in the sales person column --- .../accounts_receivable_summary/accounts_receivable_summary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b6388f97711..8cb5ac1090f 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -206,7 +206,7 @@ class AccountsReceivableSummary(ReceivablePayableReport): cols += ["invoiced_amt", "paid_amt", "credit_amt", "outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency", "pdc/lc_date", "pdc/lc_ref", - "pdc/lc_amount", "remaining_balance"] + "pdc/lc_amount"] if args.get("party_type") == "Supplier": cols += ["supplier_group", "remarks"] From 7fc1bc0b27b96fcc83aa8f29bbee871354dfe051 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Tue, 19 Mar 2019 18:14:02 +0530 Subject: [PATCH 32/34] fix: handle an empty match query condition in leave application (#16931) --- erpnext/hr/doctype/leave_application/leave_application.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index b85f38b295e..692db8e1a54 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -505,8 +505,6 @@ def add_department_leaves(events, start, end, employee, company): def add_leaves(events, start, end, filter_conditions=None): conditions = [] - if filter_conditions: - conditions.append(filter_conditions) if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")): from frappe.desk.reportview import build_match_conditions @@ -520,11 +518,14 @@ def add_leaves(events, start, end, filter_conditions=None): from `tabLeave Application` where from_date <= %(end)s and to_date >= %(start)s <= to_date and docstatus < 2 - and status!="Rejected" """ + and status!='Rejected' """ if conditions: query += ' and ' + ' and '.join(conditions) + if filter_conditions: + query += filter_conditions + for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True): e = { "name": d.name, From f288866130d44403a43e81627e8ca96b75e29d91 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 20 Mar 2019 13:34:28 +0530 Subject: [PATCH 33/34] fix: Cost center from PO to PI is not mapping --- .../doctype/purchase_invoice/purchase_invoice.js | 9 +++++++++ erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 9 +++++++++ erpnext/buying/doctype/purchase_order/purchase_order.py | 7 ++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index b4fd91f6e43..c94c85cb95d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -510,6 +510,15 @@ frappe.ui.form.on("Purchase Invoice", { } } } + + frm.set_query("cost_center", function() { + return { + filters: { + company: frm.doc.company, + is_group: 0 + } + }; + }); }, onload: function(frm) { diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 3816632065c..0399cf95839 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -564,6 +564,15 @@ frappe.ui.form.on('Sales Invoice', { }; }); + frm.set_query("cost_center", function() { + return { + filters: { + company: frm.doc.company, + is_group: 0 + } + }; + }); + frm.custom_make_buttons = { 'Delivery Note': 'Delivery', 'Sales Invoice': 'Sales Return', diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index a4a636d6baa..720160676f2 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -388,9 +388,10 @@ def make_purchase_invoice(source_name, target_doc=None): item = get_item_defaults(target.item_code, source_parent.company) item_group = get_item_group_defaults(target.item_code, source_parent.company) - target.cost_center = frappe.db.get_value("Project", obj.project, "cost_center") \ - or item.get("buying_cost_center") \ - or item_group.get("buying_cost_center") + target.cost_center = (obj.cost_center + or frappe.db.get_value("Project", obj.project, "cost_center") + or item.get("buying_cost_center") + or item_group.get("buying_cost_center")) doc = get_mapped_doc("Purchase Order", source_name, { "Purchase Order": { From 83cc587f8f2753c38f521f093d17a2615621ba7c Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 Mar 2019 15:03:00 +0600 Subject: [PATCH 34/34] bumped to version 11.1.15 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 4870b194e78..8ac608ebce2 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__ = '11.1.14' +__version__ = '11.1.15' def get_default_company(user=None): '''Get default company for user'''