From 647331bbd70a8d1b7c1b47c974175bbcbb70d15e Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Mon, 25 Nov 2019 13:56:00 +0530 Subject: [PATCH 01/98] feat: add search in category --- erpnext/public/js/hub/pages/Category.vue | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue index 3a0e6bfab8..a1d5d729cc 100644 --- a/erpnext/public/js/hub/pages/Category.vue +++ b/erpnext/public/js/hub/pages/Category.vue @@ -3,6 +3,12 @@ class="marketplace-page" :data-page-name="page_name" > + +
{{ page_title }}
From 236140d94ccf4b836933b88023f3c3b70535349b Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 28 Nov 2019 16:36:24 +0530 Subject: [PATCH 02/98] fix: Division by zero error in Stock Entry --- erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index f81fa683ba..2b99f72565 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -657,7 +657,7 @@ class StockEntry(StockController): item_account_wise_additional_cost.setdefault((d.item_code, d.name), {}) item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0) item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \ - (t.amount * d.basic_amount) / total_basic_amount + (t.amount * d.basic_amount) / total_basic_amount if total_basic_amount else 0 if item_account_wise_additional_cost: for d in self.get("items"): From 2597817cdeb025caa1f4d4fb7fee49831761778a Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Thu, 28 Nov 2019 18:57:42 +0530 Subject: [PATCH 03/98] fix: add new routes to handle category wise search --- erpnext/public/js/hub/PageContainer.vue | 2 +- erpnext/public/js/hub/pages/Category.vue | 2 +- erpnext/public/js/hub/pages/Home.vue | 2 +- erpnext/public/js/hub/pages/Search.vue | 15 +++++++++++---- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/erpnext/public/js/hub/PageContainer.vue b/erpnext/public/js/hub/PageContainer.vue index f151add8d5..54c359766d 100644 --- a/erpnext/public/js/hub/PageContainer.vue +++ b/erpnext/public/js/hub/PageContainer.vue @@ -24,7 +24,7 @@ import NotFound from './pages/NotFound.vue'; function get_route_map() { const read_only_routes = { 'marketplace/home': Home, - 'marketplace/search/:keyword': Search, + 'marketplace/search/:category/:keyword': Search, 'marketplace/category/:category': Category, 'marketplace/item/:item': Item, 'marketplace/seller/:seller': Seller, diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue index a1d5d729cc..057fe8bc61 100644 --- a/erpnext/public/js/hub/pages/Category.vue +++ b/erpnext/public/js/hub/pages/Category.vue @@ -67,7 +67,7 @@ export default { }, set_search_route() { - frappe.set_route('marketplace', 'search', this.search_value); + frappe.set_route('marketplace', 'search', this.category, this.search_value); }, } } diff --git a/erpnext/public/js/hub/pages/Home.vue b/erpnext/public/js/hub/pages/Home.vue index 353656957d..aaeaa7eb7c 100644 --- a/erpnext/public/js/hub/pages/Home.vue +++ b/erpnext/public/js/hub/pages/Home.vue @@ -98,7 +98,7 @@ export default { }, set_search_route() { - frappe.set_route('marketplace', 'search', this.search_value); + frappe.set_route('marketplace', 'search', 'All', this.search_value); }, } } diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue index 5118a814e0..2a6088925f 100644 --- a/erpnext/public/js/hub/pages/Search.vue +++ b/erpnext/public/js/hub/pages/Search.vue @@ -29,8 +29,10 @@ export default { return { page_name: frappe.get_route()[1], items: [], - search_value: frappe.get_route()[2], + category: frappe.get_route()[2], + search_value: frappe.get_route()[3], item_id_fieldname: 'name', + filters: {}, // Constants search_placeholder: __('Search for anything ...'), @@ -40,7 +42,7 @@ export default { computed: { page_title() { return this.items.length - ? __(`Results for "${this.search_value}"`) + ? __(`Results for ${this.search_value} in category ${this.category}`) : __('No Items found.'); } }, @@ -49,14 +51,19 @@ export default { }, methods: { get_items() { - hub.call('get_items', { keyword: this.search_value }) + if (this.category !== 'All') { + this.filters['hub_category']=this.category; + } + hub.call('get_items', { keyword: this.search_value, + filters: this.filters + }) .then((items) => { this.items = items; }) }, set_route_and_get_items() { - frappe.set_route('marketplace', 'search', this.search_value); + frappe.set_route('marketplace', 'search', this.category, this.search_value); this.get_items(); }, From ad66677029bccd534639ef8158dcf7f1af03e2d7 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Fri, 29 Nov 2019 23:59:02 +0530 Subject: [PATCH 04/98] fix: add conditional message in template string --- erpnext/public/js/hub/pages/Search.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue index 2a6088925f..8ab48d0e8d 100644 --- a/erpnext/public/js/hub/pages/Search.vue +++ b/erpnext/public/js/hub/pages/Search.vue @@ -42,7 +42,7 @@ export default { computed: { page_title() { return this.items.length - ? __(`Results for ${this.search_value} in category ${this.category}`) + ? __(`Results for "${this.search_value}" ${this.category!=='All'? `in category ${this.category}`: ''}`) : __('No Items found.'); } }, From 4405a2a5f86ff66099a676ec050780b9b8aaf613 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Sat, 30 Nov 2019 16:58:31 +0530 Subject: [PATCH 05/98] fix: add project in child for items --- erpnext/projects/doctype/project/project.js | 50 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 25c97d1fb8..069e3dc6fe 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -16,6 +16,54 @@ frappe.ui.form.on("Project", { time_log.parenttype = 'Timesheet'; new_doc.time_logs = [time_log]; + frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); + }); + }, + 'Purchase Order': () => { + let doctype = 'Purchase Order'; + frappe.model.with_doctype(doctype, () => { + let new_doc = frappe.model.get_new_doc(doctype); + + // add a new row and set the project + let purchase_order_item = frappe.model.get_new_doc('Purchase Order Item'); + purchase_order_item.project = frm.doc.name; + purchase_order_item.parent = new_doc.name; + purchase_order_item.parentfield = 'items'; + purchase_order_item.parenttype = 'Purchase Order'; + new_doc.items = [purchase_order_item]; + + frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); + }); + }, + 'Purchase Receipt': () => { + let doctype = 'Purchase Receipt'; + frappe.model.with_doctype(doctype, () => { + let new_doc = frappe.model.get_new_doc(doctype); + + // add a new row and set the project + let purchase_receipt_item = frappe.model.get_new_doc('Purchase Receipt Item'); + purchase_receipt_item.project = frm.doc.name; + purchase_receipt_item.parent = new_doc.name; + purchase_receipt_item.parentfield = 'items'; + purchase_receipt_item.parenttype = 'Purchase Receipt'; + new_doc.items = [purchase_receipt_item]; + + frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); + }); + }, + 'Purchase Invoice': () => { + let doctype = 'Purchase Invoice'; + frappe.model.with_doctype(doctype, () => { + let new_doc = frappe.model.get_new_doc(doctype); + + // add a new row and set the project + let purchase_invoice_item = frappe.model.get_new_doc('Purchase Invoice Item'); + purchase_invoice_item.project = frm.doc.name; + purchase_invoice_item.parent = new_doc.name; + purchase_invoice_item.parentfield = 'items'; + purchase_invoice_item.parenttype = 'Purchase Invoice'; + new_doc.items = [purchase_invoice_item]; + frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); }); }, @@ -80,7 +128,7 @@ frappe.ui.form.on("Project", { frm.events.set_status(frm, 'Cancelled'); }, __('Set Status')); } - + if (frappe.model.can_read("Task")) { frm.add_custom_button(__("Gantt Chart"), function () { frappe.route_options = { From a639f16dc9080585645b79f6631c3e43cbdd4d79 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Wed, 4 Dec 2019 09:46:42 +0530 Subject: [PATCH 06/98] fix: column data not visible after manual selection of columns --- erpnext/public/js/financial_statements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index 63e057c39d..dead309a5d 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -4,7 +4,7 @@ erpnext.financial_statements = { "filters": get_filters(), "formatter": function(value, row, column, data, default_formatter) { if (column.fieldname=="account") { - value = data.account_name; + value = data.account_name || value; column.link_onclick = "erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")"; From e4274cbfa64d7c364cfd2e0907fda5e459194a70 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Wed, 4 Dec 2019 17:51:08 +0530 Subject: [PATCH 07/98] fix: change formatting --- erpnext/public/js/hub/pages/Search.vue | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue index 8ab48d0e8d..103284289b 100644 --- a/erpnext/public/js/hub/pages/Search.vue +++ b/erpnext/public/js/hub/pages/Search.vue @@ -42,7 +42,7 @@ export default { computed: { page_title() { return this.items.length - ? __(`Results for "${this.search_value}" ${this.category!=='All'? `in category ${this.category}`: ''}`) + ? __(`Results for "${this.search_value}" ${this.category !== 'All'? `in category ${this.category}` : ''}`) : __('No Items found.'); } }, @@ -52,9 +52,10 @@ export default { methods: { get_items() { if (this.category !== 'All') { - this.filters['hub_category']=this.category; + this.filters['hub_category'] = this.category; } - hub.call('get_items', { keyword: this.search_value, + hub.call('get_items', { + keyword: this.search_value, filters: this.filters }) .then((items) => { From 175d604f5ffd98df2ee46da1592babb807bc433d Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 4 Dec 2019 23:08:51 +0530 Subject: [PATCH 08/98] chore: commonize function --- erpnext/projects/doctype/project/project.js | 77 ++++++--------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 069e3dc6fe..3570a0f2be 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -4,68 +4,16 @@ frappe.ui.form.on("Project", { setup(frm) { frm.make_methods = { 'Timesheet': () => { - let doctype = 'Timesheet'; - frappe.model.with_doctype(doctype, () => { - let new_doc = frappe.model.get_new_doc(doctype); - - // add a new row and set the project - let time_log = frappe.model.get_new_doc('Timesheet Detail'); - time_log.project = frm.doc.name; - time_log.parent = new_doc.name; - time_log.parentfield = 'time_logs'; - time_log.parenttype = 'Timesheet'; - new_doc.time_logs = [time_log]; - - frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); - }); + open_form(frm, "Timesheet", "Timesheet Detail", "time_logs"); }, 'Purchase Order': () => { - let doctype = 'Purchase Order'; - frappe.model.with_doctype(doctype, () => { - let new_doc = frappe.model.get_new_doc(doctype); - - // add a new row and set the project - let purchase_order_item = frappe.model.get_new_doc('Purchase Order Item'); - purchase_order_item.project = frm.doc.name; - purchase_order_item.parent = new_doc.name; - purchase_order_item.parentfield = 'items'; - purchase_order_item.parenttype = 'Purchase Order'; - new_doc.items = [purchase_order_item]; - - frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); - }); + open_form(frm, "Purchase Order", "Purchase Order Item", "items"); }, 'Purchase Receipt': () => { - let doctype = 'Purchase Receipt'; - frappe.model.with_doctype(doctype, () => { - let new_doc = frappe.model.get_new_doc(doctype); - - // add a new row and set the project - let purchase_receipt_item = frappe.model.get_new_doc('Purchase Receipt Item'); - purchase_receipt_item.project = frm.doc.name; - purchase_receipt_item.parent = new_doc.name; - purchase_receipt_item.parentfield = 'items'; - purchase_receipt_item.parenttype = 'Purchase Receipt'; - new_doc.items = [purchase_receipt_item]; - - frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); - }); + open_form(frm, "Purchase Receipt", "Purchase Receipt Item", "items"); }, 'Purchase Invoice': () => { - let doctype = 'Purchase Invoice'; - frappe.model.with_doctype(doctype, () => { - let new_doc = frappe.model.get_new_doc(doctype); - - // add a new row and set the project - let purchase_invoice_item = frappe.model.get_new_doc('Purchase Invoice Item'); - purchase_invoice_item.project = frm.doc.name; - purchase_invoice_item.parent = new_doc.name; - purchase_invoice_item.parentfield = 'items'; - purchase_invoice_item.parenttype = 'Purchase Invoice'; - new_doc.items = [purchase_invoice_item]; - - frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); - }); + open_form(frm, "Purchase Invoice", "Purchase Invoice Item", "items"); }, }; }, @@ -171,3 +119,20 @@ frappe.ui.form.on("Project", { }, }); + +function open_form(frm, doctype, child_doctype, parentfield) { + frappe.model.with_doctype(doctype, () => { + let new_doc = frappe.model.get_new_doc(doctype); + + // add a new row and set the project + let new_child_doc = frappe.model.get_new_doc(child_doctype); + new_child_doc.project = frm.doc.name; + new_child_doc.parent = new_doc.name; + new_child_doc.parentfield = parentfield; + new_child_doc.parenttype = doctype; + new_doc[parentfield] = [new_child_doc]; + + frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); + }); + +} \ No newline at end of file From d98ed8047a9232291a7e2f6540c64bb3e37dbe46 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 6 Dec 2019 12:37:24 +0530 Subject: [PATCH 09/98] fix: travis failing --- .../purchase_order_item/purchase_order_item.json | 13 ++++++++++++- erpnext/setup/doctype/email_digest/email_digest.py | 2 +- erpnext/setup/utils.py | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 15bc97c2a4..6768dfabfe 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "hash", "creation": "2013-05-24 19:29:06", "doctype": "DocType", @@ -43,6 +44,7 @@ "base_amount", "pricing_rules", "is_free_item", + "is_fixed_asset", "section_break_29", "net_rate", "net_amount", @@ -708,11 +710,20 @@ "fieldname": "against_blanket_order", "fieldtype": "Check", "label": "Against Blanket Order" + }, + { + "default": "0", + "fetch_from": "item_code.is_fixed_asset", + "fieldname": "is_fixed_asset", + "fieldtype": "Check", + "label": "Is Fixed Asset", + "read_only": 1 } ], "idx": 1, "istable": 1, - "modified": "2019-11-19 14:10:52.865006", + "links": [], + "modified": "2019-12-06 13:17:12.142799", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index 0bcddc2151..4d2d540bbc 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -283,7 +283,7 @@ class EmailDigest(Document): card.value = card.value *-1 card.value = self.fmt_money(card.value,False if key in ("bank_balance", "credit_balance") else True) - cache.setex(cache_key, card, 24 * 60 * 60) + cache.set_value(cache_key, card, expires_in_sec=24 * 60 * 60) context.cards.append(card) diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index d1c206d8b1..1a86b79ad1 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -106,7 +106,8 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=No # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] - cache.setex(key, value, 6 * 60 * 60) + + cache.set_value(key, value, expires_in_sec=6 * 60 * 60) return flt(value) except: frappe.log_error(title="Get Exchange Rate") From 8ab8376975a86d4735d2366f3d278ba8869c5e4a Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 2 Dec 2019 09:37:09 +0530 Subject: [PATCH 10/98] fix: Manufacturing UX, added calendar view for job card --- erpnext/manufacturing/doctype/bom/bom.js | 5 - .../doctype/bom/bom_dashboard.py | 2 +- .../doctype/job_card/job_card.js | 146 +- .../doctype/job_card/job_card.json | 67 +- .../doctype/job_card/job_card.py | 52 +- .../doctype/job_card/job_card_calendar.js | 21 + .../job_card_time_log/job_card_time_log.json | 247 +-- .../production_plan/production_plan.js | 3 +- .../production_plan/production_plan.json | 1618 +++-------------- .../production_plan_dashboard.py | 2 +- .../doctype/work_order/work_order.js | 177 +- .../doctype/work_order/work_order.json | 4 +- .../doctype/work_order/work_order.py | 38 +- .../doctype/work_order/work_order_calendar.js | 2 + .../work_order/work_order_dashboard.py | 3 +- .../work_order_operation.json | 9 +- .../workstation/workstation_dashboard.py | 4 +- 17 files changed, 715 insertions(+), 1685 deletions(-) create mode 100644 erpnext/manufacturing/doctype/job_card/job_card_calendar.js diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 8283fd7e6f..3acaee4ffb 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -6,7 +6,6 @@ frappe.provide("erpnext.bom"); frappe.ui.form.on("BOM", { setup: function(frm) { frm.custom_make_buttons = { - 'BOM': 'Duplicate BOM', 'Work Order': 'Work Order', 'Quality Inspection': 'Quality Inspection' }; @@ -91,10 +90,6 @@ frappe.ui.form.on("BOM", { } if(frm.doc.docstatus!=0) { - frm.add_custom_button(__("Duplicate BOM"), function() { - frm.copy_doc(); - }, __("Create")); - frm.add_custom_button(__("Work Order"), function() { frm.trigger("make_work_order"); }, __("Create")); diff --git a/erpnext/manufacturing/doctype/bom/bom_dashboard.py b/erpnext/manufacturing/doctype/bom/bom_dashboard.py index 060cd53ef1..361826e2d0 100644 --- a/erpnext/manufacturing/doctype/bom/bom_dashboard.py +++ b/erpnext/manufacturing/doctype/bom/bom_dashboard.py @@ -25,5 +25,5 @@ def get_data(): } ], 'disable_create_buttons': ["Item", "Purchase Order", "Purchase Receipt", - "Purchase Invoice", "Job Card", "Stock Entry"] + "Purchase Invoice", "Job Card", "Stock Entry", "BOM"] } diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 95549d5a24..bc8c22998a 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -3,6 +3,9 @@ frappe.ui.form.on('Job Card', { refresh: function(frm) { + frappe.flags.pause_job = 0; + frappe.flags.resume_job = 0; + if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) { if (frm.doc.for_quantity != frm.doc.transferred_qty) { frm.add_custom_button(__("Material Request"), () => { @@ -13,44 +16,99 @@ frappe.ui.form.on('Job Card', { if (frm.doc.for_quantity != frm.doc.transferred_qty) { frm.add_custom_button(__("Material Transfer"), () => { frm.trigger("make_stock_entry"); - }); + }).addClass("btn-primary"); } } - if (frm.doc.docstatus == 0) { - frm.trigger("make_dashboard"); + if (frm.doc.docstatus == 0 && frm.doc.for_quantity > frm.doc.total_completed_qty + && (!frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) { + frm.trigger("prepare_timer_buttons"); + } + }, - if (!frm.doc.job_started) { - frm.add_custom_button(__("Start Job"), () => { - 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 { - frm.add_custom_button(__("Complete Job"), () => { - 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(); + prepare_timer_buttons: function(frm) { + frm.trigger("make_dashboard"); + if (!frm.doc.job_started) { + frm.add_custom_button(__("Start"), () => { + if (!frm.doc.employee) { + frappe.prompt({fieldtype: 'Link', label: __('Employee'), options: "Employee", + fieldname: 'employee'}, d => { + if (d.employee) { + frm.set_value("employee", d.employee); } - }) - }); - } + + frm.events.start_job(frm); + }, __("Enter Value"), __("Start")); + } else { + frm.events.start_job(frm); + } + }).addClass("btn-primary"); + } else if (frm.doc.status == "On Hold") { + frm.add_custom_button(__("Resume"), () => { + frappe.flags.resume_job = 1; + frm.events.start_job(frm); + }).addClass("btn-primary"); + } else { + frm.add_custom_button(__("Pause"), () => { + frappe.flags.pause_job = 1; + frm.set_value("status", "On Hold"); + frm.events.complete_job(frm); + }); + + frm.add_custom_button(__("Complete"), () => { + let completed_time = frappe.datetime.now_datetime(); + frm.trigger("hide_timer"); + + frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'), + fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => { + frm.events.complete_job(frm, completed_time, data.qty); + }, __("Enter Value"), __("Complete")); + }).addClass("btn-primary"); } }, + start_job: function(frm) { + 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.set_value("status", "Work In Progress"); + + if (!frappe.flags.resume_job) { + frm.set_value('current_time' , 0); + } + + frm.save(); + }, + + complete_job: function(frm, completed_time, completed_qty) { + frm.doc.time_logs.forEach(d => { + if (d.from_time && !d.to_time) { + d.to_time = completed_time || frappe.datetime.now_datetime(); + d.completed_qty = completed_qty || 0; + + if(frappe.flags.pause_job) { + let currentIncrement = moment(d.to_time).diff(moment(d.from_time),"seconds") || 0; + frm.set_value('current_time' , currentIncrement + (frm.doc.current_time || 0)); + } else { + frm.set_value('started_time' , ''); + frm.set_value('job_started', 0); + frm.set_value('current_time' , 0); + } + + frm.save(); + } + }); + }, + make_dashboard: function(frm) { if(frm.doc.__islocal) return; frm.dashboard.refresh(); const timer = ` -
+
00 : 00 @@ -58,11 +116,16 @@ frappe.ui.form.on('Job Card', { 00
`; - var section = frm.dashboard.add_section(timer); + var section = frm.toolbar.page.add_inner_message(timer); - if (frm.doc.started_time) { - let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds"); - initialiseTimer(); + let currentIncrement = frm.doc.current_time || 0; + if (frm.doc.started_time || frm.doc.current_time) { + if (frm.doc.status == "On Hold") { + updateStopwatch(currentIncrement); + } else { + currentIncrement += moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds"); + initialiseTimer(); + } function initialiseTimer() { const interval = setInterval(function() { @@ -70,12 +133,12 @@ frappe.ui.form.on('Job Card', { updateStopwatch(current); }, 1000); } - + function updateStopwatch(increment) { var hours = Math.floor(increment / 3600); var minutes = Math.floor((increment - (hours * 3600)) / 60); var seconds = increment - (hours * 3600) - (minutes * 60); - + $(section).find(".hours").text(hours < 10 ? ("0" + hours.toString()) : hours.toString()); $(section).find(".minutes").text(minutes < 10 ? ("0" + minutes.toString()) : minutes.toString()); $(section).find(".seconds").text(seconds < 10 ? ("0" + seconds.toString()) : seconds.toString()); @@ -88,6 +151,10 @@ frappe.ui.form.on('Job Card', { } }, + hide_timer: function(frm) { + frm.toolbar.page.inner_toolbar.find(".stopwatch").remove(); + }, + for_quantity: function(frm) { frm.doc.items = []; frm.call({ @@ -117,5 +184,22 @@ frappe.ui.form.on('Job Card', { timer: function(frm) { return `` + }, + + set_total_completed_qty: function(frm) { + frm.doc.total_completed_qty = 0; + frm.doc.time_logs.forEach(d => { + if (d.completed_qty) { + frm.doc.total_completed_qty += d.completed_qty; + } + }); + + refresh_field("total_completed_qty"); } -}); \ No newline at end of file +}); + +frappe.ui.form.on('Job Card Time Log', { + completed_qty: function(frm) { + frm.events.set_total_completed_qty(frm); + } +}) \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index 2c217028d0..156accee74 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -13,10 +13,18 @@ "column_break_4", "posting_date", "company", + "remarks", + "production_section", + "production_item", + "item_name", "for_quantity", "wip_warehouse", - "timing_detail", + "column_break_12", "employee", + "employee_name", + "status", + "project", + "timing_detail", "time_logs", "section_break_13", "total_completed_qty", @@ -28,12 +36,11 @@ "operation_id", "transferred_qty", "requested_qty", - "project", - "remarks", "column_break_20", - "status", + "barcode", "job_started", "started_time", + "current_time", "amended_from" ], "fields": [ @@ -41,13 +48,14 @@ "fieldname": "work_order", "fieldtype": "Link", "in_list_view": 1, + "in_standard_filter": 1, "label": "Work Order", "options": "Work Order", - "read_only": 1, "reqd": 1, "search_index": 1 }, { + "fetch_from": "work_order.bom_no", "fieldname": "bom_no", "fieldtype": "Link", "label": "BOM No", @@ -91,7 +99,7 @@ "fieldname": "for_quantity", "fieldtype": "Float", "in_list_view": 1, - "label": "For Quantity", + "label": "Qty To Manufacture", "reqd": 1 }, { @@ -109,6 +117,7 @@ { "fieldname": "employee", "fieldtype": "Link", + "in_standard_filter": 1, "label": "Employee", "options": "Employee" }, @@ -198,7 +207,7 @@ "fieldtype": "Select", "label": "Status", "no_copy": 1, - "options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted", + "options": "Open\nWork In Progress\nMaterial Transferred\nOn Hold\nSubmitted\nCancelled\nCompleted", "read_only": 1 }, { @@ -236,10 +245,52 @@ "label": "Naming Series", "options": "PO-JOB.#####", "reqd": 1 + }, + { + "fetch_from": "employee.employee_name", + "fieldname": "employee_name", + "fieldtype": "Read Only", + "label": "Employee Name" + }, + { + "fieldname": "production_section", + "fieldtype": "Section Break", + "label": "Production" + }, + { + "fieldname": "column_break_12", + "fieldtype": "Column Break" + }, + { + "fetch_from": "work_order.production_item", + "fieldname": "production_item", + "fieldtype": "Read Only", + "label": "Production Item" + }, + { + "fieldname": "barcode", + "fieldtype": "Barcode", + "label": "Barcode", + "read_only": 1 + }, + { + "fetch_from": "work_order.item_name", + "fieldname": "item_name", + "fieldtype": "Read Only", + "label": "Item Name" + }, + { + "fieldname": "current_time", + "fieldtype": "Int", + "hidden": 1, + "label": "Current Time", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 } ], "is_submittable": 1, - "modified": "2019-10-30 01:49:19.606178", + "modified": "2019-12-03 13:08:57.926201", "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 e8787ed7db..9a2aaa5b36 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -194,8 +194,9 @@ class JobCard(Document): 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")) + if self.total_completed_qty != self.for_quantity: + frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})" + .format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity)))) def update_work_order(self): if not self.work_order: @@ -271,6 +272,8 @@ class JobCard(Document): self.set_status(update_status) def set_status(self, update_status=False): + if self.status == "On Hold": return + self.status = { 0: "Open", 1: "Submitted", @@ -329,6 +332,7 @@ def make_stock_entry(source_name, target_doc=None): target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0) target.calculate_rate_and_amount() target.set_missing_values() + target.set_stock_entry_type() doclist = get_mapped_doc("Job Card", source_name, { "Job Card": { @@ -352,4 +356,46 @@ def make_stock_entry(source_name, target_doc=None): return doclist def time_diff_in_minutes(string_ed_date, string_st_date): - return time_diff(string_ed_date, string_st_date).total_seconds() / 60 \ No newline at end of file + return time_diff(string_ed_date, string_st_date).total_seconds() / 60 + +@frappe.whitelist() +def get_job_details(start, end, filters=None): + events = [] + + event_color = { + "Completed": "#cdf5a6", + "Material Transferred": "#ffdd9e", + "Work In Progress": "#D3D3D3" + } + + from frappe.desk.reportview import get_filters_cond + conditions = get_filters_cond("Job Card", filters, []) + + job_cards = frappe.db.sql(""" SELECT `tabJob Card`.name, `tabJob Card`.work_order, + `tabJob Card`.employee_name, `tabJob Card`.status, ifnull(`tabJob Card`.remarks, ''), + min(`tabJob Card Time Log`.from_time) as from_time, + max(`tabJob Card Time Log`.to_time) as to_time + FROM `tabJob Card` , `tabJob Card Time Log` + WHERE + `tabJob Card`.name = `tabJob Card Time Log`.parent {0} + group by `tabJob Card`.name""".format(conditions), as_dict=1) + + for d in job_cards: + subject_data = [] + for field in ["name", "work_order", "remarks", "employee_name"]: + if not d.get(field): continue + + subject_data.append(d.get(field)) + + color = event_color.get(d.status) + job_card_data = { + 'from_time': d.from_time, + 'to_time': d.to_time, + 'name': d.name, + 'subject': '\n'.join(subject_data), + 'color': color if color else "#89bcde" + } + + events.append(job_card_data) + + return events diff --git a/erpnext/manufacturing/doctype/job_card/job_card_calendar.js b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js new file mode 100644 index 0000000000..cf07698ad6 --- /dev/null +++ b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js @@ -0,0 +1,21 @@ +frappe.views.calendar["Job Card"] = { + field_map: { + "start": "from_time", + "end": "to_time", + "id": "name", + "title": "subject", + "color": "color", + "allDay": "allDay", + "progress": "progress" + }, + gantt: true, + filters: [ + { + "fieldtype": "Link", + "fieldname": "employee", + "options": "Employee", + "label": __("Employee") + } + ], + get_events_method: "erpnext.manufacturing.doctype.job_card.job_card.get_job_details" +}; 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 index 2aab71dee4..9dd54dd618 100644 --- 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 @@ -1,208 +1,57 @@ { - "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", + "creation": "2019-03-08 23:56:43.187569", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "from_time", + "to_time", + "column_break_2", + "time_in_mins", + "completed_qty" + ], "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 - }, + "fieldname": "from_time", + "fieldtype": "Datetime", + "in_list_view": 1, + "label": "From Time" + }, { - "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 - }, + "fieldname": "to_time", + "fieldtype": "Datetime", + "in_list_view": 1, + "label": "To Time" + }, { - "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 - }, + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, { - "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 - }, + "fieldname": "time_in_mins", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Time In Mins", + "read_only": 1 + }, { - "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 + "default": "0", + "fieldname": "completed_qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Completed Qty", + "reqd": 1 } - ], - "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 + ], + "istable": 1, + "modified": "2019-12-03 12:56:02.285448", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Job Card Time Log", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "ASC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 3b24d0fa0f..2b168d1d76 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -71,12 +71,13 @@ frappe.ui.form.on('Production Plan', { }, __('Create')); } + frm.page.set_inner_btn_group_as_primary(__('Create')); frm.trigger("material_requirement"); const projected_qty_formula = `
-

+

${__("Projected Quantity Formula")} diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 0be9f1a8ee..af844816e8 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -1,1391 +1,321 @@ { - "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": "2017-10-29 11:53:09.523362", - "custom": 0, - "default_print_format": "", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "engine": "InnoDB", + "actions": [], + "autoname": "naming_series:", + "creation": "2017-10-29 11:53:09.523362", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "naming_series", + "company", + "get_items_from", + "column_break1", + "posting_date", + "filters", + "item_code", + "customer", + "warehouse", + "project", + "column_break2", + "from_date", + "to_date", + "sales_orders_detail", + "get_sales_orders", + "sales_orders", + "material_request_detail", + "get_material_request", + "material_requests", + "select_items_to_manufacture_section", + "get_items", + "po_items", + "material_request_planning", + "include_non_stock_items", + "include_subcontracted_items", + "ignore_existing_ordered_qty", + "column_break_25", + "for_warehouse", + "download_materials_required", + "get_items_for_mr", + "section_break_27", + "mr_items", + "other_details", + "total_planned_qty", + "total_produced_qty", + "column_break_32", + "status", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_if_empty": 0, - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Naming Series", - "length": 0, - "no_copy": 0, - "options": "MFG-PP-.YYYY.-", - "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 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Naming Series", + "options": "MFG-PP-.YYYY.-", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fetch_if_empty": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "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 - }, + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_if_empty": 0, - "fieldname": "get_items_from", - "fieldtype": "Select", - "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": "Get Items From", - "length": 0, - "no_copy": 0, - "options": "\nSales Order\nMaterial Request", - "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 - }, + "fieldname": "get_items_from", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Get Items From", + "options": "\nSales Order\nMaterial Request" + }, { - "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_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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 - }, + "fieldname": "column_break1", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fetch_if_empty": 0, - "fieldname": "posting_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Posting Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "posting_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Posting Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "columns": 0, - "depends_on": "eval: doc.get_items_from", - "description": "", - "fetch_if_empty": 0, - "fieldname": "filters", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Filters", - "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 - }, + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "depends_on": "eval: doc.get_items_from", + "fieldname": "filters", + "fieldtype": "Section Break", + "label": "Filters" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "options": "Item", - "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 - }, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "options": "Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Sales Order\"", - "fetch_if_empty": 0, - "fieldname": "customer", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Customer", - "length": 0, - "no_copy": 0, - "options": "Customer", - "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 - }, + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", + "fieldname": "customer", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Customer", + "options": "Customer" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Material Request\"", - "fetch_if_empty": 0, - "fieldname": "warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval: doc.get_items_from == \"Material Request\"", + "fieldname": "warehouse", + "fieldtype": "Link", + "label": "Warehouse", + "options": "Warehouse" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Sales Order\"", - "fetch_if_empty": 0, - "fieldname": "project", - "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": "Project", - "length": 0, - "no_copy": 0, - "options": "Project", - "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 - }, + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, { - "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_break2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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, + "fieldname": "column_break2", + "fieldtype": "Column Break", "width": "50%" - }, + }, { - "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_date", - "fieldtype": "Date", - "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": "From Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "from_date", + "fieldtype": "Date", + "label": "From Date" + }, { - "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_date", - "fieldtype": "Date", - "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": "To Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "to_date", + "fieldtype": "Date", + "label": "To Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Sales Order\"", - "fetch_if_empty": 0, - "fieldname": "sales_orders_detail", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sales Orders Detail", - "length": 0, - "no_copy": 0, - "options": "", - "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 - }, + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", + "fieldname": "sales_orders_detail", + "fieldtype": "Section Break", + "label": "Sales Orders" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fetch_if_empty": 0, - "fieldname": "get_sales_orders", - "fieldtype": "Button", - "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": "Get Sales Orders", - "length": 0, - "no_copy": 0, - "options": "", - "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 - }, + "fieldname": "get_sales_orders", + "fieldtype": "Button", + "label": "Get Sales Orders" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "sales_orders", - "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": "Sales Orders", - "length": 0, - "no_copy": 1, - "options": "Production Plan Sales Order", - "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 - }, + "fieldname": "sales_orders", + "fieldtype": "Table", + "label": "Sales Orders", + "no_copy": 1, + "options": "Production Plan Sales Order" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Material Request\"", - "fetch_if_empty": 0, - "fieldname": "material_request_detail", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Request Detail", - "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 - }, + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "depends_on": "eval: doc.get_items_from == \"Material Request\"", + "fieldname": "material_request_detail", + "fieldtype": "Section Break", + "label": "Material Request Detail" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fetch_if_empty": 0, - "fieldname": "get_material_request", - "fieldtype": "Button", - "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": "Get Material Request", - "length": 0, - "no_copy": 0, - "options": "", - "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 - }, + "fieldname": "get_material_request", + "fieldtype": "Button", + "label": "Get Material Request" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "material_requests", - "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": "Material Requests", - "length": 0, - "no_copy": 1, - "options": "Production Plan Material Request", - "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 - }, + "fieldname": "material_requests", + "fieldtype": "Table", + "label": "Material Requests", + "no_copy": 1, + "options": "Production Plan Material Request" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fetch_if_empty": 0, - "fieldname": "select_items_to_manufacture_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Select Items to Manufacture", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "select_items_to_manufacture_section", + "fieldtype": "Section Break", + "label": "Select Items to Manufacture" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "get_items_from", - "fetch_if_empty": 0, - "fieldname": "get_items", - "fieldtype": "Button", - "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": "Get Items For Work Order", - "length": 0, - "no_copy": 0, - "options": "", - "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 - }, + "depends_on": "get_items_from", + "fieldname": "get_items", + "fieldtype": "Button", + "label": "Get Items For Work Order" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "po_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 1, - "options": "Production Plan Item", - "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 - }, + "fieldname": "po_items", + "fieldtype": "Table", + "no_copy": 1, + "options": "Production Plan Item", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fetch_if_empty": 0, - "fieldname": "material_request_planning", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Request Planning", - "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 - }, + "fieldname": "material_request_planning", + "fieldtype": "Section Break", + "label": "Material Request Planning" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "include_non_stock_items", - "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": "Include Non Stock Items", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "include_non_stock_items", + "fieldtype": "Check", + "label": "Include Non Stock Items" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "include_subcontracted_items", - "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": "Include Subcontracted Items", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "include_subcontracted_items", + "fieldtype": "Check", + "label": "Include Subcontracted Items" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "If enabled, then system will create the material even if the raw materials are available", - "fetch_if_empty": 0, - "fieldname": "ignore_existing_ordered_qty", - "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": "Ignore Existing Projected Quantity", - "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 - }, + "default": "0", + "description": "To know more about projected quantity, click here.", + "fieldname": "ignore_existing_ordered_qty", + "fieldtype": "Check", + "label": "Ignore Existing Projected Quantity" + }, { - "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_25", - "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 - }, + "fieldname": "column_break_25", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "for_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "For Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "for_warehouse", + "fieldtype": "Link", + "label": "For Warehouse", + "options": "Warehouse" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "download_materials_required", - "fieldtype": "Button", - "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": "Download Materials Required", - "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 - }, + "fieldname": "download_materials_required", + "fieldtype": "Button", + "label": "Download Required Materials" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "get_items_for_mr", - "fieldtype": "Button", - "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": "Get Raw Materials For Production", - "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 - }, + "fieldname": "get_items_for_mr", + "fieldtype": "Button", + "label": "Get Raw Materials For Production" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fetch_if_empty": 0, - "fieldname": "section_break_27", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_27", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "mr_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Request Plan Item", - "length": 0, - "no_copy": 1, - "options": "Material Request Plan Item", - "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 - }, + "fieldname": "mr_items", + "fieldtype": "Table", + "label": "Material Request Plan Item", + "no_copy": 1, + "options": "Material Request Plan Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_if_empty": 0, - "fieldname": "projected_qty_formula", - "fieldtype": "HTML", - "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": "Projected Qty Formula", - "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 - }, + "collapsible": 1, + "fieldname": "other_details", + "fieldtype": "Section Break", + "label": "Other Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "other_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Other Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "total_planned_qty", + "fieldtype": "Float", + "label": "Total Planned Qty", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "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": "total_planned_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Planned Qty", - "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 - }, + "default": "0", + "fieldname": "total_produced_qty", + "fieldtype": "Float", + "label": "Total Produced Qty", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "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": "total_produced_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Produced Qty", - "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 - }, + "fieldname": "column_break_32", + "fieldtype": "Column Break" + }, { - "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_32", - "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 - }, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "no_copy": 1, + "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested", + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Draft", - "fetch_if_empty": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 1, - "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested", - "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, - "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": "Production Plan", - "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 + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Production Plan", + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_toolbar": 0, - "icon": "fa fa-calendar", - "idx": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-04-09 12:05:14.300886", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "Production Plan", - "name_case": "", - "owner": "Administrator", + ], + "icon": "fa fa-calendar", + "is_submittable": 1, + "links": [], + "modified": "2019-12-04 15:58:50.940460", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Production Plan", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 0, - "role": "Manufacturing User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "Manufacturing User", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "ASC", - "title_field": "", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py index 91c28555d6..09ec24a67a 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py @@ -6,7 +6,7 @@ def get_data(): 'fieldname': 'production_plan', 'transactions': [ { - 'label': _('Related'), + 'label': _('Transactions'), 'items': ['Work Order', 'Material Request'] }, ] diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index 5c721c723d..8ca89171b6 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -6,6 +6,7 @@ frappe.ui.form.on("Work Order", { frm.custom_make_buttons = { 'Stock Entry': 'Start', 'Pick List': 'Create Pick List', + 'Job Card': 'Create Job Card' }; // Set query for warehouses @@ -131,7 +132,8 @@ frappe.ui.form.on("Work Order", { } if (frm.doc.docstatus===1) { - frm.trigger('show_progress'); + frm.trigger('show_progress_for_items'); + frm.trigger('show_progress_for_operations'); } if (frm.doc.docstatus === 1 @@ -179,89 +181,72 @@ frappe.ui.form.on("Work Order", { make_job_card: function(frm) { let qty = 0; - const fields = [{ - fieldtype: "Link", - fieldname: "operation", - options: "Operation", - label: __("Operation"), - get_query: () => { - const filter_workstation = frm.doc.operations.filter(d => { - if (d.status != "Completed") { - return d; - } - }); + let operations_data = []; - return { - filters: { - name: ["in", (filter_workstation || []).map(d => d.operation)] - } - }; - }, - reqd: true - }, { - fieldtype: "Link", - fieldname: "workstation", - options: "Workstation", - label: __("Workstation"), - get_query: () => { - const operation = dialog.get_value("operation"); - const filter_workstation = frm.doc.operations.filter(d => { - if (d.operation == operation) { - return d; - } - }); - - return { - filters: { - name: ["in", (filter_workstation || []).map(d => d.workstation)] - } - }; - }, - onchange: () => { - const operation = dialog.get_value("operation"); - const workstation = dialog.get_value("workstation"); - if (operation && workstation) { - const row = frm.doc.operations.filter(d => d.operation == operation && d.workstation == workstation)[0]; - qty = frm.doc.qty - row.completed_qty; - - if (qty > 0) { - dialog.set_value("qty", qty); - } - } - }, - reqd: true - }, { - fieldtype: "Float", - fieldname: "qty", - label: __("For Quantity"), - reqd: true - }]; - - const dialog = frappe.prompt(fields, function(data) { - if (data.qty > qty) { - frappe.throw(__("For Quantity must be less than quantity {0}", [qty])); + const dialog = frappe.prompt({fieldname: 'operations', fieldtype: 'Table', label: __('Operations'), + fields: [ + { + fieldtype:'Link', + fieldname:'operation', + label: __('Operation'), + read_only:1, + in_list_view:1 + }, + { + fieldtype:'Link', + fieldname:'workstation', + label: __('Workstation'), + read_only:1, + in_list_view:1 + }, + { + fieldtype:'Data', + fieldname:'name', + label: __('Operation Id') + }, + { + fieldtype:'Float', + fieldname:'pending_qty', + label: __('Pending Qty'), + }, + { + fieldtype:'Float', + fieldname:'qty', + label: __('Quantity to Manufacture'), + read_only:0, + in_list_view:1, + }, + ], + data: operations_data, + in_place_edit: true, + get_data: function() { + return operations_data; } - - if (data.qty <= 0) { - frappe.throw(__("For Quantity must be greater than zero")); - } - + }, function(data) { frappe.call({ method: "erpnext.manufacturing.doctype.work_order.work_order.make_job_card", args: { work_order: frm.doc.name, - operation: data.operation, - workstation: data.workstation, - qty: data.qty - }, - callback: function(r){ - if (r.message) { - var doc = frappe.model.sync(r.message)[0]; - frappe.set_route("Form", doc.doctype, doc.name); - } + operations: data.operations, } }); - }, __("For Job Card")); + }, __("Job Card"), __("Create")); + + var pending_qty = 0; + frm.doc.operations.forEach(data => { + if(data.completed_qty != frm.doc.qty) { + pending_qty = frm.doc.qty - flt(data.completed_qty); + + dialog.fields_dict.operations.df.data.push({ + 'name': data.name, + 'operation': data.operation, + 'workstation': data.workstation, + 'qty': pending_qty, + 'pending_qty': pending_qty, + }); + } + }); + dialog.fields_dict.operations.grid.refresh(); }, make_bom: function(frm) { @@ -277,7 +262,7 @@ frappe.ui.form.on("Work Order", { }); }, - show_progress: function(frm) { + show_progress_for_items: function(frm) { var bars = []; var message = ''; var added_min = false; @@ -311,6 +296,44 @@ frappe.ui.form.on("Work Order", { frm.dashboard.add_progress(__('Status'), bars, message); }, + show_progress_for_operations: function(frm) { + if (frm.doc.operations && frm.doc.operations.length) { + + let progress_class = { + "Work in Progress": "progress-bar-warning", + "Completed": "progress-bar-success" + }; + + let bars = []; + let message = ''; + let title = ''; + let status_wise_oprtation_data = {}; + let total_completed_qty = frm.doc.qty * frm.doc.operations.length; + + frm.doc.operations.forEach(d => { + if (!status_wise_oprtation_data[d.status]) { + status_wise_oprtation_data[d.status] = [d.completed_qty, d.operation]; + } else { + status_wise_oprtation_data[d.status][0] += d.completed_qty; + status_wise_oprtation_data[d.status][1] += ', ' + d.operation; + } + }); + + for (let key in status_wise_oprtation_data) { + title = __("{0} Operations: {1}", [key, status_wise_oprtation_data[key][1].bold()]); + bars.push({ + 'title': title, + 'width': status_wise_oprtation_data[key][0] / total_completed_qty * 100 + '%', + 'progress_class': progress_class[key] + }); + + message += title + '. '; + } + + frm.dashboard.add_progress(__('Status'), bars, message); + } + }, + production_item: function(frm) { if (frm.doc.production_item) { frappe.call({ diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json index 0d073a2312..6152fbb840 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.json +++ b/erpnext/manufacturing/doctype/work_order/work_order.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "autoname": "naming_series:", "creation": "2013-01-10 16:34:16", @@ -468,7 +469,8 @@ "idx": 1, "image_field": "image", "is_submittable": 1, - "modified": "2019-08-28 12:29:35.315239", + "links": [], + "modified": "2019-12-04 11:20:04.695123", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order", diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index ff489542f6..227ef787ca 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -6,7 +6,7 @@ import frappe import json import math from frappe import _ -from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate +from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate, get_link_to_form from frappe.model.document import Document from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict from dateutil.relativedelta import relativedelta @@ -755,21 +755,41 @@ def query_sales_order(production_item): return out @frappe.whitelist() -def make_job_card(work_order, operation, workstation, qty=0): +def make_job_card(work_order, operations): + if isinstance(operations, string_types): + operations = json.loads(operations) + work_order = frappe.get_doc('Work Order', work_order) - row = get_work_order_operation_data(work_order, operation, workstation) - if row: - return create_job_card(work_order, row, qty) + for row in operations: + validate_operation_data(row) + create_job_card(work_order, row, row.get("qty"), auto_create=True) + +def validate_operation_data(row): + if row.get("qty") <= 0: + frappe.throw(_("Quantity to Manufacture can not be zero for the operation {0}") + .format( + frappe.bold(row.get("operation")) + ) + ) + + if row.get("qty") > row.get("pending_qty"): + frappe.throw(_("For operation {0}: Quantity ({1}) can not be greter than pending quantity({2})") + .format( + frappe.bold(row.get("operation")), + frappe.bold(row.get("qty")), + frappe.bold(row.get("pending_qty")) + ) + ) def create_job_card(work_order, row, qty=0, enable_capacity_planning=False, auto_create=False): doc = frappe.new_doc("Job Card") doc.update({ 'work_order': work_order.name, - 'operation': row.operation, - 'workstation': row.workstation, + 'operation': row.get("operation"), + 'workstation': row.get("workstation"), 'posting_date': nowdate(), 'for_quantity': qty or work_order.get('qty', 0), - 'operation_id': row.name, + 'operation_id': row.get("name"), 'bom_no': work_order.bom_no, 'project': work_order.project, 'company': work_order.company, @@ -785,7 +805,7 @@ def create_job_card(work_order, row, qty=0, enable_capacity_planning=False, auto doc.schedule_time_logs(row) doc.insert() - frappe.msgprint(_("Job card {0} created").format(doc.name)) + frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name))) return doc diff --git a/erpnext/manufacturing/doctype/work_order/work_order_calendar.js b/erpnext/manufacturing/doctype/work_order/work_order_calendar.js index c44b1e2700..7ce05e9b88 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order_calendar.js +++ b/erpnext/manufacturing/doctype/work_order/work_order_calendar.js @@ -2,11 +2,13 @@ // For license information, please see license.txt frappe.views.calendar["Work Order"] = { + fields: ["planned_start_date", "planned_end_date", "status", "produced_qty", "qty", "name", "name"], field_map: { "start": "planned_start_date", "end": "planned_end_date", "id": "name", "title": "name", + "status": "status", "allDay": "allDay", "progress": function(data) { return flt(data.produced_qty) / data.qty * 100; diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py index 0d3c30ea6e..87c090f99c 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py +++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py @@ -6,7 +6,8 @@ def get_data(): 'fieldname': 'work_order', 'transactions': [ { - 'items': ['Pick List', 'Stock Entry', 'Job Card'] + 'label': _('Transactions'), + 'items': ['Stock Entry', 'Job Card', 'Pick List'] } ] } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json index 75d42cd061..3f5e18e813 100644 --- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json +++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2014-10-16 14:35:41.950175", "doctype": "DocType", "editable_grid": 1, @@ -68,6 +69,7 @@ "description": "Operation completed for how many finished goods?", "fieldname": "completed_qty", "fieldtype": "Float", + "in_list_view": 1, "label": "Completed Qty", "no_copy": 1, "read_only": 1 @@ -188,8 +190,9 @@ } ], "istable": 1, - "modified": "2019-07-16 23:01:07.720337", - "modified_by": "govindsmenokee@gmail.com", + "links": [], + "modified": "2019-12-03 19:24:29.594189", + "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Operation", "owner": "Administrator", @@ -197,4 +200,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py index 7f0124b503..3ddbe73170 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py +++ b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py @@ -13,5 +13,7 @@ def get_data(): 'label': _('Transaction'), 'items': ['Work Order', 'Job Card', 'Timesheet'] } - ] + ], + 'disable_create_buttons': ['BOM', 'Routing', 'Operation', + 'Work Order', 'Job Card', 'Timesheet'] } From ad53649f41a6c2caa1bdf04514b1308ec95ade4c Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Fri, 6 Dec 2019 19:34:49 +0530 Subject: [PATCH 11/98] fix: Validation msg fix in GSTR-1 report --- erpnext/regional/report/gstr_1/gstr_1.js | 27 +++++++++++++++------ erpnext/regional/report/gstr_1/gstr_1.py | 31 ++++++++++++------------ 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js index ce559218cb..091dfd1253 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.js +++ b/erpnext/regional/report/gstr_1/gstr_1.js @@ -55,14 +55,25 @@ frappe.query_reports["GSTR-1"] = { report.page.add_inner_button(__("Download as JSON"), function () { var filters = report.get_values(); - const args = { - cmd: 'erpnext.regional.report.gstr_1.gstr_1.get_json', - data: report.data, - report_name: report.report_name, - filters: filters - }; - - open_url_post(frappe.request.url, args); + frappe.call({ + method: 'erpnext.regional.report.gstr_1.gstr_1.get_json', + args: { + data: report.data, + report_name: report.report_name, + filters: filters + }, + callback: function(r) { + if (r.message) { + const args = { + cmd: 'erpnext.regional.report.gstr_1.gstr_1.download_json_file', + data: r.message.data, + report_name: r.message.report_name, + report_type: r.message.report_type + }; + open_url_post(frappe.request.url, args); + } + } + }) }); } } diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index 090616b077..4f9cc7ff7a 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -532,16 +532,9 @@ class Gstr1Report(object): self.columns = self.invoice_columns + self.tax_columns + self.other_columns @frappe.whitelist() -def get_json(): - data = frappe._dict(frappe.local.form_dict) - - del data["cmd"] - if "csrf_token" in data: - del data["csrf_token"] - - filters = json.loads(data["filters"]) - report_data = json.loads(data["data"]) - report_name = data["report_name"] +def get_json(filters, report_name, data): + filters = json.loads(filters) + report_data = json.loads(data) gstin = get_company_gstin_number(filters["company"]) fp = "%02d%s" % (getdate(filters["to_date"]).month, getdate(filters["to_date"]).year) @@ -575,7 +568,11 @@ def get_json(): out = get_export_json(res) gst_json["exp"] = out - download_json_file(report_name, filters["type_of_business"], gst_json) + return { + 'report_name': report_name, + 'report_type': filters['type_of_business'], + 'data': gst_json + } def get_b2b_json(res, gstin): inv_type, out = {"Registered Regular": "R", "Deemed Export": "DE", "URD": "URD", "SEZ": "SEZ"}, [] @@ -722,11 +719,15 @@ def get_company_gstin_number(company): if gstin: return gstin[0]["gstin"] else: - frappe.throw(_("Please set valid GSTIN No. in Company Address")) + frappe.throw(_("Please set valid GSTIN No. in Company Address for company {0}".format( + frappe.bold(company) + ))) -def download_json_file(filename, report_type, data): +@frappe.whitelist() +def download_json_file(): ''' download json content in a file ''' - frappe.response['filename'] = frappe.scrub("{0} {1}".format(filename, report_type)) + '.json' - frappe.response['filecontent'] = json.dumps(data) + data = frappe._dict(frappe.local.form_dict) + frappe.response['filename'] = frappe.scrub("{0} {1}".format(data['report_name'], data['report_type'])) + '.json' + frappe.response['filecontent'] = data['data'] frappe.response['content_type'] = 'application/json' frappe.response['type'] = 'download' From 99309229bc082fb1f929f661061f5f9eb1252442 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Fri, 6 Dec 2019 19:59:54 +0530 Subject: [PATCH 12/98] fix: Add missing semicolon --- erpnext/regional/report/gstr_1/gstr_1.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js index 091dfd1253..1a7ff2bf5a 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.js +++ b/erpnext/regional/report/gstr_1/gstr_1.js @@ -73,7 +73,7 @@ frappe.query_reports["GSTR-1"] = { open_url_post(frappe.request.url, args); } } - }) + }); }); } } From 690068142b786f16045ffca0caa8423e7e07af42 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 6 Dec 2019 20:58:26 +0530 Subject: [PATCH 13/98] feat: Continue Slide and New Illustrations for Onboarding Wizard (#19813) * feat: added illustrations for onboarding * refactor: change help label for supplier * refactor (breaking): rename Setup Wizard slide to Onboarding Slide * chore: code cleanup for the old doctype Setup Wizard Slide * fix: added a 'Continue' type slide * fix: change text in continue slide * fix: change text for continue slide --- .../add_a_few_suppliers.json | 11 ++++--- .../images/illustrations/collaboration.png | Bin 3849 -> 0 bytes .../public/images/illustrations/customer.png | Bin 4093 -> 0 bytes .../illustrations/customers-onboard.png | Bin 0 -> 16870 bytes .../images/illustrations/desk-onboard.png | Bin 0 -> 11054 bytes .../illustrations/letterhead-onboard.png | Bin 0 -> 63859 bytes .../images/illustrations/letterhead.png | Bin 1613 -> 0 bytes .../public/images/illustrations/onboard.png | Bin 2742 -> 0 bytes .../public/images/illustrations/product.png | Bin 3136 -> 0 bytes .../images/illustrations/products-onboard.png | Bin 0 -> 33014 bytes .../images/illustrations/supplier-onboard.png | Bin 0 -> 17531 bytes .../public/images/illustrations/supplier.png | Bin 3531 -> 0 bytes erpnext/public/images/illustrations/user.png | Bin 7887 -> 0 bytes .../add_a_few_customers.json | 11 ++++--- .../welcome_back_to_erpnext!.json | 23 ++++++++++++++ .../welcome_to_erpnext!.json | 10 +++---- .../add_a_few_products_you_buy_or_sell.json | 28 +++++++----------- 17 files changed, 49 insertions(+), 34 deletions(-) rename erpnext/buying/{setup_wizard_slide => onboarding_slide}/add_a_few_suppliers/add_a_few_suppliers.json (78%) delete mode 100644 erpnext/public/images/illustrations/collaboration.png delete mode 100644 erpnext/public/images/illustrations/customer.png create mode 100644 erpnext/public/images/illustrations/customers-onboard.png create mode 100644 erpnext/public/images/illustrations/desk-onboard.png create mode 100644 erpnext/public/images/illustrations/letterhead-onboard.png delete mode 100644 erpnext/public/images/illustrations/letterhead.png delete mode 100644 erpnext/public/images/illustrations/onboard.png delete mode 100644 erpnext/public/images/illustrations/product.png create mode 100644 erpnext/public/images/illustrations/products-onboard.png create mode 100644 erpnext/public/images/illustrations/supplier-onboard.png delete mode 100644 erpnext/public/images/illustrations/supplier.png delete mode 100644 erpnext/public/images/illustrations/user.png rename erpnext/selling/{setup_wizard_slide => onboarding_slide}/add_a_few_customers/add_a_few_customers.json (78%) create mode 100644 erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json rename erpnext/setup/{setup_wizard_slide => onboarding_slide}/welcome_to_erpnext!/welcome_to_erpnext!.json (60%) rename erpnext/stock/{setup_wizard_slide => onboarding_slide}/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json (77%) diff --git a/erpnext/buying/setup_wizard_slide/add_a_few_suppliers/add_a_few_suppliers.json b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json similarity index 78% rename from erpnext/buying/setup_wizard_slide/add_a_few_suppliers/add_a_few_suppliers.json rename to erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json index 006d139eb0..d3adcb7981 100644 --- a/erpnext/buying/setup_wizard_slide/add_a_few_suppliers/add_a_few_suppliers.json +++ b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json @@ -3,18 +3,18 @@ "app": "ERPNext", "creation": "2019-11-15 14:45:32.626641", "docstatus": 0, - "doctype": "Setup Wizard Slide", + "doctype": "Onboarding Slide", "domains": [], "help_links": [ { - "label": "Supplier", + "label": "Learn More", "video_id": "zsrrVDk6VBs" } ], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/supplier.png", + "image_src": "/assets/erpnext/images/illustrations/supplier-onboard.png", "max_count": 3, - "modified": "2019-11-26 18:26:25.498325", + "modified": "2019-12-03 22:53:50.552445", "modified_by": "Administrator", "name": "Add A Few Suppliers", "owner": "Administrator", @@ -44,6 +44,5 @@ ], "slide_order": 50, "slide_title": "Add A Few Suppliers", - "slide_type": "Create", - "submit_method": "" + "slide_type": "Create" } \ No newline at end of file diff --git a/erpnext/public/images/illustrations/collaboration.png b/erpnext/public/images/illustrations/collaboration.png deleted file mode 100644 index 12c67e394ccf22e12ff8e0c149139e82e73b321f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3849 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 GfAc@J)HmJ$ diff --git a/erpnext/public/images/illustrations/customer.png b/erpnext/public/images/illustrations/customer.png deleted file mode 100644 index b2ddbf3bb4709407ef493926e3490336568f6543..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4093 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 diff --git a/erpnext/public/images/illustrations/customers-onboard.png b/erpnext/public/images/illustrations/customers-onboard.png new file mode 100644 index 0000000000000000000000000000000000000000..4a517bde29c071b1d7866c2e02aa7115aa0fac60 GIT binary patch literal 16870 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 P7CyXFeOo1K68b*?@SBA4 literal 0 HcmV?d00001 diff --git a/erpnext/public/images/illustrations/desk-onboard.png b/erpnext/public/images/illustrations/desk-onboard.png new file mode 100644 index 0000000000000000000000000000000000000000..74b632dc30b652d250a1077ce4f0735cf0cffc0c GIT binary patch literal 11054 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 literal 0 HcmV?d00001 diff --git a/erpnext/public/images/illustrations/letterhead.png b/erpnext/public/images/illustrations/letterhead.png deleted file mode 100644 index 37df6d7f6fce07fd2604c4c8387dd18869b9bc54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1613 zcmZ`(do>*s zFI0QlN*gjEZq5z>#U~Aj(o7+m;>!V0Y5EyR_Bs_EX;Gf*LUojXtE8bWCtFQ2>IPV% zE zAO>neRn`oW5hBZ7VXw?QZYNlZm{Bz(XXDL+X#NI4iiQD4guQVGUS){JKThOYi~i~u zUKn9?=5jid-;{E~I+I2oX>@1nx3d-XB?-)!;D$=eG#gv?eBS$e$mnw33+4y?n{T_V z@ogT8r~Xvxy{}`BEG@wX3%|C-;@ebW80<+cyOpuljrCbG#yrvWFI#N(e6GP2Of(KD z>^xLx5x>_&B@p`6?S={rG5inv+jpd%`W5J{#fCC3Sv?0&C7zK-G5!&K5#eE7AXZeN z&ufwHzN8M%5x-eY>v^>dQ*VF4zU|~+w0#uz-I%k!Wp(x4S^;Y)awYNFS5C*W^wZNV zQ3w4R%evU&4#)Jzl24bO4KJot)p+#Se_)2L2Kv5sokB-da!!?~v!`?LVxIy;ln-AT zI<`s1c*=VTjC{&9ZMf{VBj9FfOl{ubgf(X>-}&cQ@m1>A&g)s;4@nUCxCb^{zB3;i zcmA;jAzL z2HFtvu#_o8g_ls@yN8}VKn7^1=0^w8vT9#3=4RP;j9b|WN24MiXZ*edQhl53Iz_{^ zx4b8lNO!XvjIhUjG+{QYW%IK5WTmqQ`??EVX7 z!aJTj!xBlCpuZ){W>H;Iw{dwOl%;>J>{fbx#sbRDU3{LL#;bGBbkZTGSk{YZUbC&e z7sxY+ciitmbBfX}21mjp(o2B*QmPrkPlM z6i!d^QncG4(~|5b$FD%Th;UUo(`OJFRXH-2{b0{`S(yGr1RAp4k1Js4*K5&cv&C&CZ>VDdvZ+-k zwN|V&ox2%4w@P6-@ONQ24Nk5Lq?ieki)7@5$1Q= z0C5^F*93GABA5%yRQa);lW6z$D;e@tLFY$(4QBS|$&{`D<0&_E;sxb|?ouu2lB4`% zJy%=kjVHHFK5SDYZNmpZSFNjC{xpBF;^;bTnMHrR_*Wxr=Imz#GvKF-4kAWaDR|}} zdXfB!Wx&K-WdKD-&lE$J0P{UiMA=?QGR^8Y%@@ZM#3qs|anxZGV@FO^pQfPD^F_(| z`xSQm@(3Ib_R}ppH^J}KRrI$-EtL_cqt2U}e4ES7{Bb2oJLy)~{JEl@d|}cx0b6wsGb*4tW{-EP4c22v&$Fc)FJOUEyYd!?)Krs+t8DPX9_=9!lp4MwzWI_3@ zFSLi>Y7zr2+!70mio$-$Hx7sE!j7(P!CV3{94=E5^NSuo`*CD#%jF3089qHWAU@n8SJBA@8AQH^2P0h_si3D%+O(cRPiD0pg zKp+ta8DF;N{!0)U70L|T|Nnx;l2M#gp!L(iD=Li33yxs`kH^C^_wD8E4vuEvqhiAI SCTz8(L*U}*;c#m!dgyN&#IyVW diff --git a/erpnext/public/images/illustrations/onboard.png b/erpnext/public/images/illustrations/onboard.png deleted file mode 100644 index 094aa3f8ddfc1a07762df08cb3c134ae3ce19384..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2742 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 diff --git a/erpnext/public/images/illustrations/product.png b/erpnext/public/images/illustrations/product.png deleted file mode 100644 index f864b7af60ef44849084225da7f601bcbb33a7b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3136 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ŊtfkM0MiHh8uLiGTv}C5RA&KLC=O6 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 literal 0 HcmV?d00001 diff --git a/erpnext/public/images/illustrations/supplier-onboard.png b/erpnext/public/images/illustrations/supplier-onboard.png new file mode 100644 index 0000000000000000000000000000000000000000..30335f2b63be25d769c2104eddb7940389049536 GIT binary patch literal 17531 zcmdtKRahKB*Di{?yGw9La0~A4?h@Q3xCRdpTnBdz5@c`>?(Pik?lQn8-@pI8Z_dTJ zI5+=!o~oIe?y2e3)$gq8de^%;QbkD`6^RH50s;b6Rz^Y%0s_+Sqf#KieY|%6ew_N) z0b?bqC<+1bCk`2G3j6Vy*Fs0uQc)3t@uQ6Z0U2Qf0rSy<{HR196#@b(59+_SK>FoD z|DQI+znyN%e>5Q=L?C1(L^Zr1&$5xT%(V>XJ?ZXa;PbjBt)>VpZv@* zbMta*U1(Gdb`vD)n1fI1{BR^lv?UFwDlrSM!UXzj(F-esuQ8TklNAiu2SVd15ut~v zlX3t7^DlqiL1)j}xxUAp6~|icnhzIaYeE-`58#XU9N&wUQj&;p7?~e1GI{V&3{*~| zhE)r~rlBu<9Dq5hPRw;!p&Ys5jb+6JtwI`(HQt#pwPGyIB?-sRjIwlBgGJDb?unwa zD^)V`p~QF#-QQX&o|@Ky{CS17q^KOlJ=I;N@MWO$AK^|Bq%bwiF``*cbm1k?F;a#5 z(uxx?zeA}eny}-a^0{Z&=##rW;G|G=YoJyM3D^`!<5lV9ef=gA5)MVMY5Ars!}qBj z?R0%bN(f;biipbD*r_PKX(Sdh!k4ff{$f(2nhm1$*GZG1)61~I;m`ATnT%9D|FN2o zFA%xNjTCDTv<_YMd+}uA^tLGRVM&|^>g1^)Y1n*?DqD%4cVJ*3D@JU1*7=T_4{9>Y z(4}I2oMC(>$X`#o$goTKK3QZCn zY?*gIxT+C8ib93x{@E_QK60$tY|++=11P>a-_vDub3n9RwwkD36XfT(LsDl>I0(K$ z`$lgV@?y>ZHnshx)n20R>rnVOHgbI2KDRi-o4DaHxjcUd2T?Zde3$7_35{jlI?fs5 z%=BAyuAlE8nEt!K$#!R1w4OV7!G|;4IIO#^I0|e8N_LVX`F6}{Qn4Og^rrKi(s%m< z2^N}7{U5>xd>u*KeoQ;0vR()Au+cs_GAS|UlJhz=ujI6b7hGL~ON0cE-ZjLO;BVMk zO0NPs?x+burE^FkGz(*#zES$UT-DL<<-1=l z8JYlslY(0T!?#Z?lmmO1-fchOR`bUe%F5gK$EUt^1rXr88as@_`M^F zlc%kl7Z-Tecp?tF!E0He!v==itVkJnE}b#x8TExOUb*JP4$T95H?R+{nrmozqF#aS zZ!Tef%Mr5U$5Z9L6>!gD7aNWYUF_0aY5Uu4A&~PPErL*3B=SwgLy?qm@kB63i`^ zeoZN^Cpwqr);>j|ogKVwby^~Tm-}-U3z7?~Oj57y;nFlgNv>hzb3}WewShFbn1i|O z<1`G~utV@%<7AG$?9O^pmI7{jfCd$+Q%BtMP=qk=Q{qJ+V3i_9n#_Ime&cERcRQ)) z=xlg&Lm>G~5GN7IVEXf*+u(4fIT38CIpA~j|3%3Efl7Gh4^Vb9;eP9$_u#(RD%lIx z{XpwrLDJC1-9h=f)`ky(1un!P?-~y_(c+i(yum2FbH~QMP3U&AwiIRK7g88wCN9nR z@H6w()0!jT%jv`A49nQW!PQBUpYo>T-R5{iyTnu>?Rj2d0Qm7raw`;HgHNV*o)p;;k*n>6e^#=3>Q#>Ig!4DlPNE&0AJ6m&%TRXiJzee$BTCj@1 z71iGSZk(*GNE|E~4Ym+HwTb!NY_=MT7o%Szv^*VHgfm;lQCVG=*{lTcn`u8Mq=R{5sIbc8Ne~*p${svFpjsojpJGJ!tu&;UZ>K76y)s`;gnv(1V zl|~SPP}k5P#l7cxVWMZoI{gNXc{60uMUgMuUgGVX%!im=gl zh)K>ft-`?Z`+7TC{IZ^3v5CFQ+(@N`#ByBDSrEv2^tubiH`fRjhuNRL#;c5If;Cydy?}oO-QYiyOKtW1PHuZWv6d~{sW!nzyP%fXz z@Auz8-2fw*5Fo}w{J$c>n74#t6kGx>HTlbSD+A5>xEN9IWPsDw*aBO`CW&s(vYon}Xu*WQr1flU)d2Sv399K~z`?=` zNyrS7p2J<=u}_lU^BX+S=@!M!E}$m!O3-sa&vQW#Jwv~ zNky5^ZNb+cQA=@2(RtH9kxnDYe13i>jAV!J);j3?%J9^w!-r=7-cw2-i4lMz!Qxj1k4SAurA*YZT8G&PzygaCBtBK@wggfoRg| zCCBj7;9z6B>alb`-wV4$ee}`f41V5n>nSwpy@20Hx4;TeP z3Ier>@8gb4anoi|iWg24HLtIGz<2X#*hRU$7b4kl zAJx&+om#nZ<`ka2PsOn`JZuQQJL(}qK&jmsQ(eCUFr;Iz(XT$~N1ia*{TKk(v*x+u zrv7ykG&7H+;-Fy(w6V3FaY#CMjOO))m^z1;ZEbLa5zb=;ZGJ1?b?j)PqxG{-Lo3Xl z`{FjaLmc@_a_jdG2xY)TotGc?h3Bv$B>pk6Ih;gFG=nFP5~;s4FAecos}`+m|~ z`@>1=C_?I^kHcL0NPxDEZMnut2bqUAZsL)Ie~3Ook`tTsnLM}%7w(zjUj-1H{;`+i z@6NnS-{dk_rM5kwMYUT&($%i-SzzUn-E0Zcf$VA&ZO;^VR&Fs!&26OjfH9Kqr(I;7 zRX@*JAQDg^W`x~8oGz?}sT3KT7}#ha`7uv#KfBPpz)%3`lVJjSjGc7yHb1U_eJbaJ z&wP3z6bu_bTTMW-N*^fa4BJaXEj61J`C6L$^(E~{;dxaRzKB@AS$xJlJeU(f+dUGs zs#r0mH7lX=t2mrd}{D7O4B7@P?B&g`B}FvEb(en-+)Nj z^!2>(*PQjJWD(y{&!SlYj-(dJas0)5oY>j1F?!USN1Ez!7Obm)C(Iv1%4B@amsnK#(n^3pZLP%xbED33 zONGZ{?)iwJ?bV_;WA4>CBh%xC(|iyym@d}{xCLC?!TuC;xAwG&j6R=jc`es?pN&s$ z^vusO=7B$wqCAYzHB?jYUV0C{!N>11KRB9W5w6lmrAs123AQoMyGS@H5VUhi5@Eec zBA?IDW>Zi$$KT)IPaSvNZWT-fjqT#&HMOfMEv9V7xJE2{U{OH+e_oPAcygCLk_LY# zoo`Xqo(S>BVr`c_E?|tnUoH83qaUk%e*~$BAUXbJTXx@W-8{_3-02F^@&b(|^|(bG zd^@Gb>~20ktQ4UOt`T!wId&wTTT8cEOanerL)Sjgq9VG9QB-eM{^;XIpDPYf?${q# z$wBauF+o81i|fa!3A+a5aztqDqm364fO2@@9T?r0Ev5^mizmY(u!PFC_G=@@@yZ;U zxHj{HcYyN{Uyt5ICqg<|C4+k9g9L{foLooCH$32gC0x$SdNmLnh_mNvn@NGNgaOI< zTef!IdYz=zSAwfJ;2g~JcBoyegtfGUB_V&?Pm6JA%<{_-MJ5Q`Xo86LqKlV*SL6SV zJ8Z{%3+fXU3EZhfuUclYXzPN1e|zW(6dQ^7kr|;&(~Hf61OA&38xVxyCHTCaN&Y%b zZkR^C`N&i*4NI=M((Cx*>xc*2WfjWb^y6>w7l;%E-%j7DUgaKi0u(r>b#Js_*wFXW z<$4gUdzj7J-wd%HWfU6ZFG&A7ZUd990uW=lUYph}XQH2Lq7-#Z4w!yd%EnUjP!eWoVNJ+g`vB~)R znAhxjYN|ZmN<6EH4#H4eTA;!TJ2QMJ!9jjbbS)-ap=oBPhj1^~mo-NpTfe+KLOm$< zJq9jx&&ZJW!)L#I6|eDe9?&l*eafzVNXQ6sAj9dl10jz9y_&j>fc?u9Qam?J+h-G{ z1$OL~9z%twJ=;nn-saI@cN;|YN5^NX@Q}4#C@TKqS3MF(jwY1ti9?JU4o1|lxR?mmI)oLea@Uf;`Aq=hxc0_79LJKK4qBt!fUWD`p z><7F@V?)r1sf7pU;tU&VOsq)toP7x;4X)^|@W4Rg-O|LkCt8bhtb%)dW2uEcK!=y6DLTmV(J8I&6kQ|n-e zSeyJk33@)gJ(hlMj6p5kFyCJUesB_WOk*bT8=QKv;XQHX7@Y6saWAi-Ab0zY{rM*2 zl9-d&eJB0O!kDur!vx}Td*+jJ+TljNeZIW!OqDr4+g`MLmJUWrp{i`39+iq)yCzaJaJExL|$tRo0d3clZNnYi?T7$vQ&MvTJDEz z!BHqvQUN!KZG%`~6)ZNYLYM$C7@u$LuLH;-b#<)^6~z?Va3mN3SulN$&c(r-;7KZEN+?Dxt@6p1wBu)qk!+zjCHR zQ;r)b95jL@)73whfO+3|xd_CQBMnWsU^5gIGi;XFRs%F3Vn089MUiukA;3W)89RRV zIbrXr15!e1e&4rDbaHaGYmF8q*O;29{@v)+X3B7|af63nEj`?8V+b>K7GJfect$!G z)zC9ChW?P>|4M5yTh(uqzCz@<%6Mwqb|tt@OCETbKPrj6TN7}f@N%}2c%L?6@qmSN zh8Ps#d?$W5o{Ou8ZOS!XLd!1RyZ)Vn;|rwNh#w>|!mm_7dOF6&a#a8)$wS1J#O9#J zVZOg&2vfe2?${-36C<+X_v2fDuxiuN1`;ZUJo@R9k@a=vk~YDI^psn%YU9PpPEk>5B>8iVWNeXO&gj?q;|1h$crq^vrlz}y zMh;vmG}G%p%~E&Yy5>fH1tHFy>xWocAYF3vVS)z$jg3@EEs;BrVKhW2rV&$pAGFn? zVLXE%bDS#Nk%F0#l!fc#ygWp;R zuj&QmfrPKUNpu21!95xlmPE>`++4ii`}`w}YB+z^S8Zc|F1Y>5^oKqZv|LYMUX9c5 z(WEL}9_I7hsH+luZ;8b9d;KSVTxX`2RGtNmQVm;@1f>Ny%G;+HaIT07W z3f$x`m){@k${G=#`3{zSDSm#JTx*O7w$6k#WutHm%wTm$ERRUr%`dK?AfSD1|&Y_eiX#2LWYXpGy1+C#HTVO(WNw({)L zGVh6NbyKz=J?~!wY7G+4HU-; zKg3(;NblX-xdxPNt(~heg2`CLAo1VSx?P*#Vt;*xK10`nhy~Jz^4JA6hO_{1Z{NXd z{xiI3P4%8IE$KVjTw`Z~C+<&M$409?AsCYRxCU4QhrM!uL&?D4{p93iE?b|ZR1OvU zHBIQ&u{8*vaxD&*vz_5o2A=Bd5hM?PzutUw0x}jiZ%-K-?>GD;Q1cLezesoI|JWXa zT*GeHvJ=Zc;OM`8qVE|NK=%W%G1%evIJGUBdpSe_7*#UzS;nohN-~^_!M+rqp%cuf zIysew@;A?Nglj_x0;%If}U!1PEyo|#eK}DiYj*@)=Y$>wqtqo2f zXc?YgQqNafrgw%j3nxhZ+n-@@A5^jKf69P6mT#BZ@bUJ$mgHBXQ$`+m@8%rX$rfdw z@KZ;M_j$P{iil#&*lnIii~BpemgPyu2G$e?axZgl#>*;~kdR-HdsCS%AWE!iL;ZM~iy-oI_jwgK97-?gcxewq2=R zRxAQO zsBDBzhTUT=-$T9uxC9Y`ASD>%(V*JO?#e2c>g>cRd)ghuleE&0`R#5XHaGDe8C3m+ z=RdcR3(!-XYtXDTJx2{r$#jNTIU0s?`D=7RuG%S>+Lw_1spdB@OPW(l%hPmIk(-50 zjHe}n&p1mVhSCs|_P$*ADS3<6>A5h^N_qM{57vI(cJf;nFDie6sS*ET`stSyf@Ohm z76~H82yT3X7xGj(hf|ofDf+_1&0i*Wx2?ee9vK!%5K48TIo8ZBwth%PbTF;BQ@nbH zqp?ZAB<`1z;?0+Drg@?wurmn9OEzhkv}-cNcp#U(07Cl501W~-sFK=@bE6}Xvc`4_ z$cwg1^-EvUfoy;=>@2XciKzOGm0za0Q0Ye}k}#~W{g8+0npA%1ymD-Nrb`LkU=p>; zZw*GLi9OdYE8Ge?ktxJ)G|B^`rF_HAYiz|Ln=j_Hb<3wt@=qy#LV-zhkTKQp6}N3s zk71M!li|T2j^1o-5%Mrl7}wXYPt!gfZ{@Tt^jjCmCP)FswXp&DuXq7Zz=yC;;P*l4 zM+Yze>1P~2Vvbj6DvI7f@fL%CLQPX+nDvUj{LNK~LvngZz(bcl;U~=+~q1%^lD|9Ph$d7s+mg6@{Z!YKPW%tiN#us1UNd_F0os3sp|(b+ z3Q9h`S4l3Ume!5Evu%9VR~EdRo1f7^VB6IWGjzD^bL(>=`s-3*hL!Joh`763@&ICC zW`671k5n0mbiNtqiO7cN%yumX@mSvc7ELaht}m-fR4ewWGjckeb)C5uZ)!O;2{-_% zRef!2eb})4H0bL=8m;88EH*X%DR^&8VHp(Wrne$8yO@@iW?Wla>ug-Fg%E}mzETC} z@*mrOV#{2By57lINfQIg61h`=rM@_R=x9D35J4^qAwq9gab|=1f{-h%#a0sf5**mQ zTrqgP<+0>dq*&a&>e)cdcrIaG#M|s^m7S)oZ{13i6v~0siJfJ=_ioX_7d@hrN}rrJ zyMsU|$LO%aKT-Omb3{6(5x^PI!NS*lqiAj-A{W|EP?gZu3VazbdcBU^xkR8M(T8eE zksc72ct<7wO359=W1AkChtt8wyXUE=`(#Uooi=)4AU{i&+jcUOW+@{w;;L4p>^#72 zW!Q2s>vYKkk29mAcr%mp@Eic4u>bA%XwPmcHAu=}^z|_K7hPwyb4|hh>JbHbSM4-;Q6|TC99+@q~ zSe06OWMX!ll$^gwC+V7&Tu&Lts7Www;a=%rCgRoPqSv`!({cgJ=z;43cBsMh`c4d= zS=58wBv-Y+87W?6^!@r11lLt295g2f*O5Zp!a0m3zSw%nR3=naa5-S!I2r!7U#&Kk zEXnGgLtVWJTinTG+!do_kFs5(dZa$UPnBS`0a4IZ?UL$IbkpJmhX)tN-@%`X6&}vU zf$Dp7EX7J!6jqM3__5@vrcjRT6?x>As)7%QK($|{DgItzcE z83@2Rru*SNy}`I7%Ds}9mZr1k+EQp4WM|QMJT^HVjwFmU4_wv`PRBiN;a?#y5YfLK zO_sDPpQ?$*L&x^}Z>J!RN=C^u zt#)3{G2l4ovD8i@v~8P9q`(BuS+lg=agzhmT+UO=-^$97Z%kZIz57Hsccp*47$pw5 zNbU7!x5Dj{Q9=VJrWUG86pNXsg?@G`mreOnR{$vF4jV~4b?X{G-3-rKo!bw*;8vN| z?vUuE44&&=-t>=9sePN=^U}lJJZhRM)KkA49hYzCwsN$T%1+>hv9KTW6|H(y0DMAT z8Gt$LYcMD_$aezn4439Sx$usrtoSzAz_wiRjGx*!m+;K?3Vw;>6fBu`KDi9_7Gwk? zpkfDbY^aMVL+R6NDkEfy=U~0;5{6DiaFOzhc-mV2E+1ccUZClitphT3Omf`his_pp zxm5y(JFg~-R-KHv9O4~v477;UhsNpEH^-gb?b@FOJr;vm#NIW(E_;Mcg)BWj?xO-C zj3UTxHuC#^izgWr9n}SJ!l~zAU{ixLB*WGkxF#kY|6+oHa*~JSt4Cr^T`A+{V(PuyN=0)G$(hx7qn_seX|{3ixZJL*Q4-Y?ziT~~3rnt{O$WDT zc)Fa)O2K!J$3C=rnId(n^Y7bA8VIT$nvVmlk@Ljf8Gsnf{P$-M1b@+-Y6u}m?moCt z7Bm*kF=tGlb{fd;yuMS{QNu)w=8g=h!dT-IgbJQN&h=f#Qmbc~b}=EO=3|3^aZd7x zFQwy%_ra`t0t6Y9K|?zKE=m!?>o=%7NjypxF+KDdx;;sZhDbCLdjWl( zS5wD!4YnP-`QsW{XffDIqng(sZgx84afSNUb6hBn36Gu7didL~(y@M`Ghqw465z$0 z$7gigE~{Od#8%Uq(IlF?Ob4lShs%b6PL|~+ClJz%MSXeK;_W>SMx}P;!ic8giPb97 zrzB!ufN?8z-zQk((6@3(B!5MbHiwzT1uxlRXjtO3zr4L&j2R5k& zN!U&*-9XyP(a|sMmT_jMJb+IqOO=8R=SADOzVn*sr87qY&jPeOd))92nc**Y@OF-; zot9a*(PIs2gPHT_G!_}|y8T2}&jk+@8QK}`KwjZEPjP>){9q8yGqk^hXuUHb3POkP z!{dap03Rhe`+GRr*x$!yt4j!+5P1FBvY3`;!P=kvZLa%IYMP&WupREC&Tfi+6SJW< zP{56PB{@m8ooJr+NCfxEM?(YlWi%bh1Fz}c`T{KKJSW>nWovS*(Fu-RQHs<Loi6-EjlJSHuCogc~5ain-wNS;iYe_4~w=f1bG z{Io-l)*E3HOQgP}$g}Ma*3>mR%YLvC{Wh9ZyP)%eSf9W-2NHtU9)hQ;A+DTxGLk)JX3;F8GWp8G^i*`y+(0bz78!zm-2@ zK7qIQ9M?&!2N$NPfKTu>^WwJmDL-=~d2DQi6d$?1+@TMxN5d z;qQ&BTttENBNnR3=Y#NNeVsfABc)pa=od@;Ol@@3lTty>;P>UOm))f=O>5h}b%M83 z;x7Y3MyID3A1grbwX|29Z&u#_3Cnlnme{JBeXKa+=BZNhy|&4!$tCQM``>%|4I zL6#Je*5&)w^U4gShD;reIhfBr_ASmi__l&^IsT<{@};G?-~U3P?wop5PoK#!d$@Rm zvCy;1{^h}5;8V3+AW@@FeuA9;w9TCGcWalegPqt2<5daKz1{EQo{KTrSjXoLT8JV&iM zViDG%4weP=6bhaw6!jE5RE$va@TaCo5tfnGwD!*RFaO121b~JN$#`>!zhl97jsogl z{veRZ7ps9jF_b@=Z4sSIm>F`jAg(7#5E^plE`O+-_^5x}q{wxNTlb~5>xY4CgtzG* zcy0Kq(vD>Rqms*jc`m7Q5C zEut<`AftWTI1$-A?KnPScqnS;aGQCb&x55((nszXxz+oqx8IL?-PW>Aq>b3tUMu`pZ9 z_JHH{nEQ;PY2jobjd4Ed&c`elZsp!_Lm;Nh%R(Od75bC2eW6M#p8GJ1af{~21ADcv z?I)f*+FOlrsYbnyoz9o@mpfv|X48K9VU48{Vp;pHgz=qUnG;Di{DL9Rm$v*bL#-cB z!ukYZfnMk#)_-50e)Q+hpC+Tg*SkrXOr`?xMf=Nn8(oo@LC2~1YW~(SdL2*A579s3 z1WIATp&`Ar3Eiw%Dl|3stU$I3MS#NopkwFLe&Yx66SgxLcXDA>8LX`z9a%WFQ#5@I zTrcSb-BX%Ce?S{fQG`s{(080`F)Ps%^CG2H(r+j4MePc5E3(w57e$QJOv#u|p~uYyNn#cer~%5o^!KD%ArF6{;3o&HXSk;?3r zv2J?&S&Bw31a=n6?UJptUbH7Jw$V`;R=pB^g2VeToptW_PZ$rhpalIKEa=zW-QD$* zlM@i7tftE6s0S%fl79)6z7#sK#M#dx)K|xvh{ca~tI3P%)CTblx&5n9wXQ7j2 z{2Uanx`mFz!$kFgMpvkEWR~{JopJ7pYv5TKv-NYC+y4ayHR~=6bJE>&*Q&i){52X9 z`Em6}*SpJF7i!il7%8QI5H$9>rceErc2doTFEX??g*)&iKik9fviF86Bn zhsDwrb{daVTn6@^5#zfl5Qp$vSQzo5oqm<6vp@w5_ilq{9=LuXb=7$3@*CkIUy_y~K(|5oAh95$92zCe82k(>l%w2Amky|5SV-Pk{Tu2iB>4d?8y( zgzRjMS-8kmk3f9@)Pp`~>?Y@-UD)zV+KM?+IH+7Gh~6-?gFoC06kir#^V zJg>)awCbvrZQ6c%u{P4FvSH+rKN0`QPrKzs?pM5bW|f8gQ$jP4cw+UDk>o3F_!`IA z{ck?JTg`9x}s;@zHk#ag%2|5 z-L!hoVbc`?1}3bY=N(o=9ly-RuxM7$o!r5Bl-_V1X^ae8aCEv9lIWB#Wa$a|p$vXE zt1ACX|B&K9{uOGF8>!gtYGyj03Na}Ws9==&iyD;8iV-nuUvrOR$x&uvSM+?;kpIRvFCm{FD@<)#M?9Gj+JIi z8JQeb{%l0A;H-$skCR!V8knA4(2L&J_n*mwfFvmTLqfknDg4Jvj0NiY=b=BHa!z~m zGK_jlrlUk3`G@zV!eoQ|H;DGgK^lD7ZwY-7=z)^V5V)#ufqs*M4+?Vf3KmX`J{)UJ zJsOXlIs`KRX2Cv5k>vL-|K(95AY;_KXT}$G3nwNYRHqXN+yG)MxPRl_eTjw9|IVk2 zd5b=d2gm5yMW(X#qH6k~c@&`!ifvG^mi=`a{-gcTU&!c^`{vlWEXHJZy&@Q?D=Zl8 z10l^Y&2n_iJzy4M*R*InUh%Tw{+l)_Y%J_> z)?LL~(wK1JyYNjXN7ey8Ocu3$V-d(w$>nm{Wy+}MumihL@uRU{>xzTm;(jZJ3D=1a zh9`ATe1ZrwVAPfv))qwC&}t~bLZ>n*4H1r=X&PN?M@ZJ|d1Na%O$SpqGoEhN@Y zNs8w!880?3gCrKm@r?YRnuL{AG)n=f5u|ulCDA(z%Yk$j+gIqZZhU(Rv2kr4S*<`O zRNOa@1gj2e)?S#_?5!OaRLk26jd{2zil%SuJ6xY-S8Kq{_>k>nOZ1x$W29EDpXgWu zBW{XWa03#t`s!p%(l8F)!i_5zvt#_GHIG$(R~XF0anGI|fY2H&GkcSTw>cg1o4rLd zb4Z-R9HduYkBfRA3VT1CAEYsqifxJOjiNcsr!P1ZI6~JIY8u3{icPs7dgiH*$W8iG zlnRX_?2FGhA7?IMxB_jadrS8g;rm~&iKccT7%8KO^2-;IY)K!)W;Oc2TQh>c+keXz zuM&POxpohHSIH7ND*4tu%I`8`PX(!a5x`Z^gsY!LYuX`@+>vcOs-{0$_e!);Cy6H^ zmO-xG(`a*iEtIG6Wpo8x!K8j|r&9I#SY-J~LvLYml<&oUfiTG;b;xNE@#`-$&fF61 zu6;?~Uhdp0e3G&Iv$W|9k9cm}Hwv4J%htT+KcT2mYn+cVB`Tjsq&f6YJ|fJ`=fAUx z>OXXY8Hdf@>D4??cT)bn%spC;9s*!5tvH%g%N1V7`p+C4ghtGoyMiLa+0^MuY-R2?OSUu~1?<9wQcOdE%$lEsG0$~vA|M;y6VKj4Mn)>zb+2N?#x z+X_nt>`Gy(qy9k}z?clGWHiSBw44#F5mi(j6f~VhV#z1D-LV$UCYdaq4><_?ciUNM zS*_tZ6sU?ZjH0NCpN?Oz)bQBzZRUVCfUT-A_G-TGPGOOS8qEA*`|_$B0*E~4C<}`` zX}TqQXeO4nBiS*TXZ3rl)!MTeBS!1CJC5*nkKbJ**eGT_C%&U1~x98YvV*cQ(KV6n;eu2n`eO#3l@ z6zXXRisfB8Oc~Uin`*%DX650{li2DngVEE7m_hMMyA#K04p*MYWnl%4u5}45zHzhr z4ufT|EdjYBjkz1E{c6+WU)#Gc*+HE!yMqxH{bD^lj!V#N-}_86+s8Ub*pZ{noS{TE z*R9I0)kXy<<3awM)b-UBV~0%hQS|ATYFCe&l-^2@)!&VEANr~bLvJiVHM zS{HOgS-zBC#G_rr7S@bwYl-nQibiYvb1@$JJ7|!qi#|kFu0_p5&J~`BQtNz|CTW6~ zgJZUttZ|p~G&tgUT3WI2HO#p0YFbNbL;3Dm!FXhrdC7w!+*&M1mvEW^l3s#dYW0@y z(!=}pI?ddpAo#bt$k&>xDoI9*tmN7Asyfesvb}U}qm^x-=gorWOiXVyuK{)62DAyO zneE^r50zKj z9e?FvM){q&@J~6Z(mvTa{5k|bqM^~!^S-N{^l-e-H#QEOo{m8S+(!JR%Kd{*;RzKB z52By5Y3sffX8?vQSr%7`WbysK$ylf6$_n|O&Y$O&ZSE<-l>MHos4qd<){Fx z#r378YN!xg^~-rF#pjc_fQQg*jpHnuYnvtse*pNJD$V$bjc`<)(mmEdBOb%O5T;3e z>t+0ujew~#eR=g7$fdB)F;z8XZlLo7-A`_wcZz-ra`_&ScYgn6O?hiIWed;*Qj;m_ z`_-UlYv9}ii>z$j`K{5%tZ<=O`qfriaG*y`u3hCUEi$9~XTbA7PnbV`di|-TzD8HS zjh@O%o^#t+9yT-mT2i2XsmO!ynY7l;PlE` zsQ__vR3Sy&Os!i|Nf(TH-M$bux;TL@z63Yxf7&Jyqr8#^TLc)SdIaANd5d$3;hy4smItirD= zr#3J4_xio6*M-6oE79zjU|v}o&Xs&aKvDZ6#Mdn2q17f-%#oT@#^!+vU1 z=QNpz#`wILl9zI_`RuwEY+8wz=l5rhV`#{Tj6AjZl1J?gU@?#wP!%|59Xitg*fBF> zDuiejl#B)@Cfo<6VG%q4qghJUzSSmL*rR-JReaw!_R?qWJIXDovd1|!3(ncHn;B(p zLy`9)s^hjCSH>tb>Ma0^zMfL#?7?Rw-*}mDM-G!ymD)Zc`Uu`tv&L9(*k?&ebdkShSZp?96e~S=3zXtFL#h71eB22Szg}K z*6zEZ(L-fiK5}^PKi9NN+=d)j@F^+%UP4fV^UCKdt3eEL>Xn)t5JBVn%H3QWnw@n`!?CjAk{iJ`xkE?(uGz(wla+4GV7^y%}wwBN4(YFp^AbA3)X)XYwUT@jF37S}P5^~dM*x+A3Vev zO`PDp4n|G_a^UgpHOnya70)W_LtCHvUTlL`S`kwQ=Nd3Usn4DV%xVd?l(}6m{?!L! z{&N0KriiXT0Z{m(#!nLq%RzEZ56DRDNUEjJBe(nr%-;41wK%_y%xrfy-4&jTrW}ebs3G*L(E`8&t$+9TSdaPd$mb-=vo2=89g*6nEyObVVKO$v70}JTWpY z_}**XOx~L^EXwrFZH$uNv?Y%&W?7f8&d)8N`G=axjfbygKNl+WZlb|vzJ?L1-d|u^ zybsiJ7GfNzu90#sjW254<|e9M``>JcdW)xMIGzYmK)q6Za?6PbFR;E)DkUb*&d7Qz zTi+~O29`v`e~Z*zI>u78Tj7OtHbpdewxq_}5^x!GT6DMs4(Q(EW{p5Y7y9k`B^pY8;BFi3l`6Gu~I4?k0e}tGN#SVQ) z3w5$?r%z~~eRhPONEa&u*`WzwwC)88uL1P|kEa^S-Hxl|kzY27-&BEZYL5knU9y(9 zDz^?z=7lKYI3q6-7)A`ihpM+TrEzN?5tfeUkF=Ka!h}qx&abc17yj?LquUV|jW5Js zUm7@mlFP5mxL%v)q7x`M5*2J#)Ny}x>;IAIa}t+jj@m*2-n76szQothA8s{|UIZo7 zSNeZsE5+W0xogCzFkbN}SGLx7ma(rtO6^RD!{Z0AYpq}^Q{!)TqzS(a9TX9#0StrG z1_}`kC=|_@TxZce<>C5cBn6j(FbG`}=Q_f4`i=Xs0QMw(G^q(ug1;$}z;O#T)v{6b#Sat2&&w^FV* zs{?w0@^4t0_1i&?_nOx&_0vkQW1kDDJQ+31wJU|ax3$h9+E~!wI>vnKvay&9P$GZ3dGmNe;D6b zEk4$5>?n$9a@n%QGdwI`PM?wirP!W-3|?GX=GG`(IW715Bzm1@ML84`9a}WO^-1zw z_BN9_(n+5^2}X_$wsM8Or=bj;MC4z++J+$9f22~(=6a2Pgo^6EHb$yWA4_dDx<-SQ zFm)!8?feq-lII2a^VdlTN`SzMi4#THF zJ<_Ubv6|~ZYs=0}S7=yNr z1K8Iv9+FCz-vMK5>g?aw*d~>wz3lmCOQ_bSvo~(3aXk_(&fLyV$q`ZbAsL@c$ti(x n{||}a|0uctUzR)&%$smjK=NkSA}im&CxFOGDoIp}nFRkYHhIZ@ literal 0 HcmV?d00001 diff --git a/erpnext/public/images/illustrations/supplier.png b/erpnext/public/images/illustrations/supplier.png deleted file mode 100644 index 87f7789600fdb38903b654b3f3785817badb5039..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3531 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 BlxP3| diff --git a/erpnext/public/images/illustrations/user.png b/erpnext/public/images/illustrations/user.png deleted file mode 100644 index 7dd7db210d481d3ad5d78277776102d327fe21a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7887 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 diff --git a/erpnext/selling/setup_wizard_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json similarity index 78% rename from erpnext/selling/setup_wizard_slide/add_a_few_customers/add_a_few_customers.json rename to erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json index a0bb6fe26d..f39fea4896 100644 --- a/erpnext/selling/setup_wizard_slide/add_a_few_customers/add_a_few_customers.json +++ b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json @@ -3,18 +3,18 @@ "app": "ERPNext", "creation": "2019-11-15 14:44:10.065014", "docstatus": 0, - "doctype": "Setup Wizard Slide", + "doctype": "Onboarding Slide", "domains": [], "help_links": [ { - "label": "Customers", + "label": "Learn More", "video_id": "zsrrVDk6VBs" } ], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/customer.png", + "image_src": "/assets/erpnext/images/illustrations/customers-onboard.png", "max_count": 3, - "modified": "2019-11-26 18:26:15.888794", + "modified": "2019-12-03 22:54:28.959549", "modified_by": "Administrator", "name": "Add A Few Customers", "owner": "Administrator", @@ -44,6 +44,5 @@ ], "slide_order": 40, "slide_title": "Add A Few Customers", - "slide_type": "Create", - "submit_method": "" + "slide_type": "Create" } \ No newline at end of file diff --git a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json new file mode 100644 index 0000000000..bf330d09de --- /dev/null +++ b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json @@ -0,0 +1,23 @@ +{ + "add_more_button": 0, + "app": "ERPNext", + "creation": "2019-12-04 19:21:39.995776", + "docstatus": 0, + "doctype": "Onboarding Slide", + "domains": [], + "help_links": [], + "idx": 0, + "image_src": "/assets/erpnext/images/illustrations/desk-onboard.png", + "is_completed": 0, + "max_count": 3, + "modified": "2019-12-04 19:21:39.995776", + "modified_by": "Administrator", + "name": "Welcome back to ERPNext!", + "owner": "Administrator", + "slide_desc": "

Let's continue where you left from!

", + "slide_fields": [], + "slide_module": "Setup", + "slide_order": 0, + "slide_title": "Welcome back to ERPNext!", + "slide_type": "Continue" +} \ No newline at end of file diff --git a/erpnext/setup/setup_wizard_slide/welcome_to_erpnext!/welcome_to_erpnext!.json b/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json similarity index 60% rename from erpnext/setup/setup_wizard_slide/welcome_to_erpnext!/welcome_to_erpnext!.json rename to erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json index 1da9dd44e2..4ea69852af 100644 --- a/erpnext/setup/setup_wizard_slide/welcome_to_erpnext!/welcome_to_erpnext!.json +++ b/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json @@ -3,20 +3,20 @@ "app": "ERPNext", "creation": "2019-11-26 17:01:26.671859", "docstatus": 0, - "doctype": "Setup Wizard Slide", + "doctype": "Onboarding Slide", "domains": [], "help_links": [], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/onboard.png", + "image_src": "/assets/erpnext/images/illustrations/desk-onboard.png", "max_count": 0, - "modified": "2019-11-26 17:17:29.813299", + "modified": "2019-12-03 22:49:12.871260", "modified_by": "Administrator", "name": "Welcome to ERPNext!", "owner": "Administrator", - "slide_desc": "Setting up an ERP can be overwhelming. But don't worry, we have got your back!
\nLet's setup your company.\nThis wizard will help you onboard to ERPNext in a short time!", + "slide_desc": "Setting up an ERP can be overwhelming. But don't worry, we have got your back!\nLet's setup your company.\nThis wizard will help you onboard to ERPNext in a short time!", "slide_fields": [], "slide_module": "Setup", - "slide_order": 10, + "slide_order": 1, "slide_title": "Welcome to ERPNext!", "slide_type": "Information" } \ No newline at end of file diff --git a/erpnext/stock/setup_wizard_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json similarity index 77% rename from erpnext/stock/setup_wizard_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json rename to erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json index c536f7b2ca..27a30627ee 100644 --- a/erpnext/stock/setup_wizard_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json +++ b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json @@ -3,13 +3,13 @@ "app": "ERPNext", "creation": "2019-11-15 14:41:12.007359", "docstatus": 0, - "doctype": "Setup Wizard Slide", + "doctype": "Onboarding Slide", "domains": [], "help_links": [], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/product.png", + "image_src": "/assets/erpnext/images/illustrations/products-onboard.png", "max_count": 3, - "modified": "2019-11-26 18:26:35.305755", + "modified": "2019-12-03 22:54:07.558632", "modified_by": "Administrator", "name": "Add A Few Products You Buy Or Sell", "owner": "Administrator", @@ -26,15 +26,9 @@ }, { "align": "", - "fieldtype": "Column Break", - "reqd": 1 - }, - { - "align": "", - "fieldname": "uom", - "fieldtype": "Link", - "label": "UOM", - "options": "UOM", + "fieldname": "item_price", + "fieldtype": "Currency", + "label": "Item Price", "reqd": 1 }, { @@ -44,14 +38,14 @@ }, { "align": "", - "fieldname": "item_price", - "fieldtype": "Currency", - "label": "Item Price", + "fieldname": "uom", + "fieldtype": "Link", + "label": "UOM", + "options": "UOM", "reqd": 1 } ], "slide_order": 30, "slide_title": "Add A Few Products You Buy Or Sell", - "slide_type": "Create", - "submit_method": "" + "slide_type": "Create" } \ No newline at end of file From 63018747954f7bf229f16a729bd4018bb144730d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 7 Dec 2019 13:20:37 +0530 Subject: [PATCH 14/98] fix: timsheet overlap error --- erpnext/projects/doctype/timesheet/timesheet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index c4481c9aa0..e90821689b 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -188,7 +188,8 @@ class Timesheet(Document): }, as_dict=True) # check internal overlap for time_log in self.time_logs: - if not (time_log.from_time or time_log.to_time): continue + if not (time_log.from_time and time_log.to_time + and args.from_time and args.to_time): continue if (fieldname != 'workstation' or args.get(fieldname) == time_log.get(fieldname)) and \ args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or From 502189913a5339bd43ea166457ab70b65bfc7bf3 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 7 Dec 2019 14:10:11 +0530 Subject: [PATCH 15/98] fix: 'NoneType' object is not iterable --- .../manufacturing/doctype/production_plan/production_plan.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 25c385fb1e..8876253e8e 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -615,6 +615,9 @@ def get_items_for_material_requests(doc, ignore_existing_ordered_qty=None): doc['mr_items'] = [] po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items') + if not po_items: + frappe.throw(_("Items are required to pull the raw materials which is associated with it.")) + company = doc.get('company') warehouse = doc.get('for_warehouse') From da638cd4763ecab50ea2a5a1fa580cbb5db048ae Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 9 Dec 2019 11:28:31 +0530 Subject: [PATCH 16/98] fix: NoneType' object has no attribute '__getitem_'_ (#19859) --- erpnext/stock/doctype/packed_item/packed_item.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 831381c86a..5341f29853 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -65,7 +65,7 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip bin = get_bin_qty(packing_item_code, pi.warehouse) pi.actual_qty = flt(bin.get("actual_qty")) pi.projected_qty = flt(bin.get("projected_qty")) - if old_packed_items_map: + if old_packed_items_map and old_packed_items_map.get((packing_item_code, main_item_row.item_code)): pi.batch_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].batch_no pi.serial_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].serial_no pi.warehouse = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].warehouse From b63101250c9e9bc414bf82cba562b6c8a0c25b49 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 9 Dec 2019 13:03:24 +0530 Subject: [PATCH 17/98] fix: Rounding Adjustment GL entry fix (#19838) * fix: Rounding Adjustment GL entry fix * fix: Spacing in tab * fix: Comment fix --- .../accounts/doctype/purchase_invoice/purchase_invoice.py | 6 +++++- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 3bb3df8dbd..7b2061ac16 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -830,7 +830,11 @@ class PurchaseInvoice(BuyingController): ) def make_gle_for_rounding_adjustment(self, gl_entries): - if self.rounding_adjustment: + # if rounding adjustment in small and conversion rate is also small then + # base_rounding_adjustment may become zero due to small precision + # eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2 + # then base_rounding_adjustment becomes zero and error is thrown in GL Entry + if self.rounding_adjustment and self.base_rounding_adjustment: round_off_account, round_off_cost_center = \ get_round_off_account_and_cost_center(self.company) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index d024a31162..c4d64a72fd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -953,7 +953,7 @@ class SalesInvoice(SellingController): ) def make_gle_for_rounding_adjustment(self, gl_entries): - if flt(self.rounding_adjustment, self.precision("rounding_adjustment")): + if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment: round_off_account, round_off_cost_center = \ get_round_off_account_and_cost_center(self.company) From babc2d1ea4ab382667602916b8ad91f3d16d9ca7 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 9 Dec 2019 13:04:44 +0530 Subject: [PATCH 18/98] fix: Consistency in button positions in Sales Order and Purchase Order (#19833) --- erpnext/selling/doctype/sales_order/sales_order.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 7dc58b582a..2dae0d8063 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -112,7 +112,6 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( let allow_delivery = false; if (doc.docstatus==1) { - this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create')); if(this.frm.has_perm("submit")) { if(doc.status === 'On Hold') { @@ -136,7 +135,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( if(doc.status !== 'Closed') { if(doc.status !== 'On Hold') { - allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty)) + allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty)) && !this.frm.doc.skip_delivery_note if (this.frm.has_perm("submit")) { @@ -148,6 +147,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } } + this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create')); + // delivery note if(flt(doc.per_delivered, 6) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) { this.frm.add_custom_button(__('Delivery Note'), () => this.make_delivery_note_based_on_delivery_date(), __('Create')); @@ -361,7 +362,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }, toggle_delivery_date: function() { - this.frm.fields_dict.items.grid.toggle_reqd("delivery_date", + this.frm.fields_dict.items.grid.toggle_reqd("delivery_date", (this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note)); }, From 39e4f75a76471ce8846d886700b175999cc112dd Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 9 Dec 2019 13:16:35 +0530 Subject: [PATCH 19/98] fix: get outstanding invoices btn working on submitted payment entry (#19858) --- erpnext/accounts/doctype/payment_entry/payment_entry.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index acfc660c4f..997937738b 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -332,6 +332,7 @@ "label": "Reference" }, { + "depends_on": "eval:doc.docstatus==0", "fieldname": "get_outstanding_invoice", "fieldtype": "Button", "label": "Get Outstanding Invoice" @@ -575,7 +576,7 @@ } ], "is_submittable": 1, - "modified": "2019-11-06 12:59:43.151721", + "modified": "2019-12-08 13:02:30.016610", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", From 4350846f1e3e4431ca1a23165b2699d3c3d3327c Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Mon, 9 Dec 2019 14:27:38 +0530 Subject: [PATCH 20/98] fix(compensatory leave request): Create leave ledger entry on submit/cancel (#19476) * fix: allow creation of leave ledger entry * feat(compensatory-leave-request): create leave ledger entry on submit * style: add descriptive comments * test: allow creation of leave period based on company * fix(leave-allocation): check name of leave allocation for determining overlap * fix: validate new leaves allocated before updating leave allocation * test: compensatory leave request creation * fix: skip leave entries for non expired leave allocation * test: creation of leave ledger entry on creation of compensatory leave request * fix: minor changes * fix: fetch leave approver defined in employee in leave application * fix: attendance creation and leave balance calculation * test: create leave period for the compensatory off * style: add descriptive method name * test: updation of leave allocation on submit * fix: remove db_set from compensatory off --- .../compensatory_leave_request.py | 73 ++++---- .../test_compensatory_leave_request.py | 157 ++++++++++++++---- .../leave_allocation/leave_allocation.py | 12 +- .../leave_application/leave_application.js | 4 +- .../leave_application/leave_application.py | 23 +-- .../test_leave_application.py | 4 +- .../doctype/leave_period/test_leave_period.py | 12 +- erpnext/hr/utils.py | 9 +- 8 files changed, 205 insertions(+), 89 deletions(-) diff --git a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py index bc4a1b4034..7a9727f18c 100644 --- a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py +++ b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py @@ -5,9 +5,10 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import date_diff, add_days, getdate +from frappe.utils import date_diff, add_days, getdate, cint from frappe.model.document import Document -from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, get_holidays_for_employee +from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, \ + get_holidays_for_employee, create_additional_leave_ledger_entry class CompensatoryLeaveRequest(Document): @@ -25,16 +26,14 @@ class CompensatoryLeaveRequest(Document): frappe.throw(_("Leave Type is madatory")) def validate_attendance(self): - query = """select attendance_date, status - from `tabAttendance` where - attendance_date between %(work_from_date)s and %(work_end_date)s - and docstatus=1 and status = 'Present' and employee=%(employee)s""" + attendance = frappe.get_all('Attendance', + filters={ + 'attendance_date': ['between', (self.work_from_date, self.work_end_date)], + 'status': 'Present', + 'docstatus': 1, + 'employee': self.employee + }, fields=['attendance_date', 'status']) - attendance = frappe.db.sql(query, { - "work_from_date": self.work_from_date, - "work_end_date": self.work_end_date, - "employee": self.employee - }, as_dict=True) if len(attendance) < date_diff(self.work_end_date, self.work_from_date) + 1: frappe.throw(_("You are not present all day(s) between compensatory leave request days")) @@ -50,13 +49,19 @@ class CompensatoryLeaveRequest(Document): date_difference -= 0.5 leave_period = get_leave_period(self.work_from_date, self.work_end_date, company) if leave_period: - leave_allocation = self.exists_allocation_for_period(leave_period) + leave_allocation = self.get_existing_allocation_for_period(leave_period) if leave_allocation: leave_allocation.new_leaves_allocated += date_difference - leave_allocation.submit() + leave_allocation.validate() + leave_allocation.db_set("new_leaves_allocated", leave_allocation.total_leaves_allocated) + leave_allocation.db_set("total_leaves_allocated", leave_allocation.total_leaves_allocated) + + # generate additional ledger entry for the new compensatory leaves off + create_additional_leave_ledger_entry(leave_allocation, date_difference, add_days(self.work_end_date, 1)) + else: leave_allocation = self.create_leave_allocation(leave_period, date_difference) - self.db_set("leave_allocation", leave_allocation.name) + self.leave_allocation=leave_allocation.name else: frappe.throw(_("There is no leave period in between {0} and {1}").format(self.work_from_date, self.work_end_date)) @@ -68,11 +73,16 @@ class CompensatoryLeaveRequest(Document): leave_allocation = frappe.get_doc("Leave Allocation", self.leave_allocation) if leave_allocation: leave_allocation.new_leaves_allocated -= date_difference - if leave_allocation.total_leaves_allocated - date_difference <= 0: - leave_allocation.total_leaves_allocated = 0 - leave_allocation.submit() + if leave_allocation.new_leaves_allocated - date_difference <= 0: + leave_allocation.new_leaves_allocated = 0 + leave_allocation.validate() + leave_allocation.db_set("new_leaves_allocated", leave_allocation.total_leaves_allocated) + leave_allocation.db_set("total_leaves_allocated", leave_allocation.total_leaves_allocated) - def exists_allocation_for_period(self, leave_period): + # create reverse entry on cancelation + create_additional_leave_ledger_entry(leave_allocation, date_difference * -1, add_days(self.work_end_date, 1)) + + def get_existing_allocation_for_period(self, leave_period): leave_allocation = frappe.db.sql(""" select name from `tabLeave Allocation` @@ -95,17 +105,18 @@ class CompensatoryLeaveRequest(Document): def create_leave_allocation(self, leave_period, date_difference): is_carry_forward = frappe.db.get_value("Leave Type", self.leave_type, "is_carry_forward") - allocation = frappe.new_doc("Leave Allocation") - allocation.employee = self.employee - allocation.employee_name = self.employee_name - allocation.leave_type = self.leave_type - allocation.from_date = add_days(self.work_end_date, 1) - allocation.to_date = leave_period[0].to_date - allocation.new_leaves_allocated = date_difference - allocation.total_leaves_allocated = date_difference - allocation.description = self.reason - if is_carry_forward == 1: - allocation.carry_forward = True - allocation.save(ignore_permissions = True) + allocation = frappe.get_doc(dict( + doctype="Leave Allocation", + employee=self.employee, + employee_name=self.employee_name, + leave_type=self.leave_type, + from_date=add_days(self.work_end_date, 1), + to_date=leave_period[0].to_date, + carry_forward=cint(is_carry_forward), + new_leaves_allocated=date_difference, + total_leaves_allocated=date_difference, + description=self.reason + )) + allocation.insert(ignore_permissions=True) allocation.submit() - return allocation + return allocation \ No newline at end of file diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py index f2ca1f4f5f..1615ab30f1 100644 --- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py +++ b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py @@ -5,37 +5,128 @@ from __future__ import unicode_literals import frappe import unittest +from frappe.utils import today, add_months, add_days +from erpnext.hr.doctype.attendance_request.test_attendance_request import get_employee +from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period +from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on -# class TestCompensatoryLeaveRequest(unittest.TestCase): -# def get_compensatory_leave_request(self): -# return frappe.get_doc('Compensatory Leave Request', dict( -# employee = employee, -# work_from_date = today, -# work_to_date = today, -# reason = 'test' -# )).insert() -# -# def test_creation_of_leave_allocation(self): -# employee = get_employee() -# today = get_today() -# -# compensatory_leave_request = self.get_compensatory_leave_request(today) -# -# before = get_leave_balance(employee, compensatory_leave_request.leave_type) -# -# compensatory_leave_request.submit() -# -# self.assertEqual(get_leave_balance(employee, compensatory_leave_request.leave_type), before + 1) -# -# def test_max_compensatory_leave(self): -# employee = get_employee() -# today = get_today() -# -# compensatory_leave_request = self.get_compensatory_leave_request() -# -# frappe.db.set_value('Leave Type', compensatory_leave_request.leave_type, 'max_leaves_allowed', 0) -# -# self.assertRaises(MaxLeavesLimitCrossed, compensatory_leave_request.submit) -# -# frappe.db.set_value('Leave Type', compensatory_leave_request.leave_type, 'max_leaves_allowed', 10) -# +class TestCompensatoryLeaveRequest(unittest.TestCase): + def setUp(self): + frappe.db.sql(''' delete from `tabCompensatory Leave Request`''') + frappe.db.sql(''' delete from `tabLeave Ledger Entry`''') + frappe.db.sql(''' delete from `tabLeave Allocation`''') + frappe.db.sql(''' delete from `tabAttendance` where attendance_date in {0} '''.format((today(), add_days(today(), -1)))) #nosec + create_leave_period(add_months(today(), -3), add_months(today(), 3), "_Test Company") + create_holiday_list() + + employee = get_employee() + employee.holiday_list = "_Test Compensatory Leave" + employee.save() + + def test_leave_balance_on_submit(self): + ''' check creation of leave allocation on submission of compensatory leave request ''' + employee = get_employee() + mark_attendance(employee) + compensatory_leave_request = get_compensatory_leave_request(employee.name) + + before = get_leave_balance_on(employee.name, compensatory_leave_request.leave_type, today()) + compensatory_leave_request.submit() + + self.assertEqual(get_leave_balance_on(employee.name, compensatory_leave_request.leave_type, add_days(today(), 1)), before + 1) + + def test_leave_allocation_update_on_submit(self): + employee = get_employee() + mark_attendance(employee, date=add_days(today(), -1)) + compensatory_leave_request = get_compensatory_leave_request(employee.name, leave_date=add_days(today(), -1)) + compensatory_leave_request.submit() + + # leave allocation creation on submit + leaves_allocated = frappe.db.get_value('Leave Allocation', { + 'name': compensatory_leave_request.leave_allocation + }, ['total_leaves_allocated']) + self.assertEqual(leaves_allocated, 1) + + mark_attendance(employee) + compensatory_leave_request = get_compensatory_leave_request(employee.name) + compensatory_leave_request.submit() + + # leave allocation updates on submission of second compensatory leave request + leaves_allocated = frappe.db.get_value('Leave Allocation', { + 'name': compensatory_leave_request.leave_allocation + }, ['total_leaves_allocated']) + self.assertEqual(leaves_allocated, 2) + + def test_creation_of_leave_ledger_entry_on_submit(self): + ''' check creation of leave ledger entry on submission of leave request ''' + employee = get_employee() + mark_attendance(employee) + compensatory_leave_request = get_compensatory_leave_request(employee.name) + compensatory_leave_request.submit() + + filters = dict(transaction_name=compensatory_leave_request.leave_allocation) + leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters) + + self.assertEquals(len(leave_ledger_entry), 1) + self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee) + self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type) + self.assertEquals(leave_ledger_entry[0].leaves, 1) + + # check reverse leave ledger entry on cancellation + compensatory_leave_request.cancel() + leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters, order_by = 'creation desc') + + self.assertEquals(len(leave_ledger_entry), 2) + self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee) + self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type) + self.assertEquals(leave_ledger_entry[0].leaves, -1) + +def get_compensatory_leave_request(employee, leave_date=today()): + prev_comp_leave_req = frappe.db.get_value('Compensatory Leave Request', + dict(leave_type='Compensatory Off', + work_from_date=leave_date, + work_end_date=leave_date, + employee=employee), 'name') + if prev_comp_leave_req: + return frappe.get_doc('Compensatory Leave Request', prev_comp_leave_req) + + return frappe.get_doc(dict( + doctype='Compensatory Leave Request', + employee=employee, + leave_type='Compensatory Off', + work_from_date=leave_date, + work_end_date=leave_date, + reason='test' + )).insert() + +def mark_attendance(employee, date=today(), status='Present'): + if not frappe.db.exists(dict(doctype='Attendance', employee=employee.name, attendance_date=date, status='Present')): + attendance = frappe.get_doc({ + "doctype": "Attendance", + "employee": employee.name, + "attendance_date": date, + "status": status + }) + attendance.save() + attendance.submit() + +def create_holiday_list(): + if frappe.db.exists("Holiday List", "_Test Compensatory Leave"): + return + + holiday_list = frappe.get_doc({ + "doctype": "Holiday List", + "from_date": add_months(today(), -3), + "to_date": add_months(today(), 3), + "holidays": [ + { + "description": "Test Holiday", + "holiday_date": today() + }, + { + "description": "Test Holiday 1", + "holiday_date": add_days(today(), -1) + } + ], + "holiday_list_name": "_Test Compensatory Leave" + }) + holiday_list.save() \ No newline at end of file diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py index 874ae7a1bc..d13bb4577c 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -69,10 +69,14 @@ class LeaveAllocation(Document): def validate_allocation_overlap(self): leave_allocation = frappe.db.sql(""" - select name from `tabLeave Allocation` - where employee=%s and leave_type=%s and docstatus=1 - and to_date >= %s and from_date <= %s""", - (self.employee, self.leave_type, self.from_date, self.to_date)) + SELECT + name + FROM `tabLeave Allocation` + WHERE + employee=%s AND leave_type=%s + AND name <> %s AND docstatus=1 + AND to_date >= %s AND from_date <= %s""", + (self.employee, self.leave_type, self.name, self.from_date, self.to_date)) if leave_allocation: frappe.msgprint(_("{0} already allocated for Employee {1} for period {2} to {3}") diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js index db3819eff2..e32d57011d 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.js +++ b/erpnext/hr/doctype/leave_application/leave_application.js @@ -170,7 +170,7 @@ frappe.ui.form.on("Leave Application", { frm.set_value('to_date', ''); return; } - // server call is done to include holidays in leave days calculations + // server call is done to include holidays in leave days calculations return frappe.call({ method: 'erpnext.hr.doctype.leave_application.leave_application.get_number_of_leave_days', args: { @@ -193,7 +193,7 @@ frappe.ui.form.on("Leave Application", { set_leave_approver: function(frm) { if(frm.doc.employee) { - // server call is done to include holidays in leave days calculations + // server call is done to include holidays in leave days calculations return frappe.call({ method: 'erpnext.hr.doctype.leave_application.leave_application.get_leave_approver', args: { diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 0e6630541c..65fcbf7a99 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -549,10 +549,10 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date): leave_days += leave_entry.leaves elif inclusive_period and leave_entry.transaction_type == 'Leave Allocation' \ - and not skip_expiry_leaves(leave_entry, to_date): + and leave_entry.is_expired and not skip_expiry_leaves(leave_entry, to_date): leave_days += leave_entry.leaves - else: + elif leave_entry.transaction_type == 'Leave Application': if leave_entry.from_date < getdate(from_date): leave_entry.from_date = from_date if leave_entry.to_date > getdate(to_date): @@ -579,14 +579,15 @@ def skip_expiry_leaves(leave_entry, date): def get_leave_entries(employee, leave_type, from_date, to_date): ''' Returns leave entries between from_date and to_date ''' return frappe.db.sql(""" - select employee, leave_type, from_date, to_date, leaves, transaction_type, is_carry_forward, transaction_name - from `tabLeave Ledger Entry` - where employee=%(employee)s and leave_type=%(leave_type)s - and docstatus=1 - and leaves<0 - and (from_date between %(from_date)s and %(to_date)s - or to_date between %(from_date)s and %(to_date)s - or (from_date < %(from_date)s and to_date > %(to_date)s)) + SELECT + employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, + is_carry_forward, is_expired + FROM `tabLeave Ledger Entry` + WHERE employee=%(employee)s AND leave_type=%(leave_type)s + AND docstatus=1 AND leaves<0 + AND (from_date between %(from_date)s AND %(to_date)s + OR to_date between %(from_date)s AND %(to_date)s + OR (from_date < %(from_date)s AND to_date > %(to_date)s)) """, { "from_date": from_date, "to_date": to_date, @@ -773,4 +774,4 @@ def get_leave_approver(employee): leave_approver = frappe.db.get_value('Department Approver', {'parent': department, 'parentfield': 'leave_approvers', 'idx': 1}, 'approver') - return leave_approver + return leave_approver \ No newline at end of file diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py index 38ae808f27..b9c02101f1 100644 --- a/erpnext/hr/doctype/leave_application/test_leave_application.py +++ b/erpnext/hr/doctype/leave_application/test_leave_application.py @@ -301,7 +301,7 @@ class TestLeaveApplication(unittest.TestCase): to_date = add_days(date, 2), company = "_Test Company", docstatus = 1, - status = "Approved" + status = "Approved" )) leave_application.submit() @@ -314,7 +314,7 @@ class TestLeaveApplication(unittest.TestCase): to_date = add_days(date, 8), company = "_Test Company", docstatus = 1, - status = "Approved" + status = "Approved" )) self.assertRaises(frappe.ValidationError, leave_application.insert) diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.py b/erpnext/hr/doctype/leave_period/test_leave_period.py index 850a08dd53..1762cf917a 100644 --- a/erpnext/hr/doctype/leave_period/test_leave_period.py +++ b/erpnext/hr/doctype/leave_period/test_leave_period.py @@ -43,10 +43,18 @@ class TestLeavePeriod(unittest.TestCase): leave_period.grant_leave_allocation(employee=employee_doc_name) self.assertEqual(get_leave_balance_on(employee_doc_name, leave_type, today()), 20) -def create_leave_period(from_date, to_date): +def create_leave_period(from_date, to_date, company=None): + leave_period = frappe.db.get_value('Leave Period', + dict(company=company or erpnext.get_default_company(), + from_date=from_date, + to_date=to_date, + is_active=1), 'name') + if leave_period: + return frappe.get_doc("Leave Period", leave_period) + leave_period = frappe.get_doc({ "doctype": "Leave Period", - "company": erpnext.get_default_company(), + "company": company or erpnext.get_default_company(), "from_date": from_date, "to_date": to_date, "is_active": 1 diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 1464a77936..c3e8d27557 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -321,11 +321,11 @@ def allocate_earned_leaves(): if new_allocation == allocation.total_leaves_allocated: continue allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False) - create_earned_leave_ledger_entry(allocation, earned_leaves, today) + create_additional_leave_ledger_entry(allocation, earned_leaves, today) -def create_earned_leave_ledger_entry(allocation, earned_leaves, date): - ''' Create leave ledger entry based on the earned leave frequency ''' - allocation.new_leaves_allocated = earned_leaves +def create_additional_leave_ledger_entry(allocation, leaves, date): + ''' Create leave ledger entry for leave types ''' + allocation.new_leaves_allocated = leaves allocation.from_date = date allocation.unused_leaves = 0 allocation.create_leave_ledger_entry() @@ -389,6 +389,7 @@ def get_sal_slip_total_benefit_given(employee, payroll_period, component=False): def get_holidays_for_employee(employee, start_date, end_date): holiday_list = get_holiday_list_for_employee(employee) + holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday` where parent=%(holiday_list)s From 2944301c87a8726d039a5f9fa38a1e9139d2a369 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Mon, 9 Dec 2019 16:35:54 +0530 Subject: [PATCH 21/98] fix: website showing disabled items in list of products --- erpnext/portal/product_configurator/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index 3a373a4ab1..9c0120d416 100644 --- a/erpnext/portal/product_configurator/utils.py +++ b/erpnext/portal/product_configurator/utils.py @@ -52,7 +52,6 @@ def get_attribute_filter_data(): def get_products_for_website(field_filters=None, attribute_filters=None, search=None): - if attribute_filters: item_codes = get_item_codes_by_attributes(attribute_filters) items_by_attributes = get_items([['name', 'in', item_codes]]) @@ -336,7 +335,9 @@ def get_items(filters=None, search=None): filter_condition = get_conditions(filters, 'and') - where_conditions = ' and '.join( + where_conditions = 'disabled = 0 and ' + + where_conditions += ' and '.join( [condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition] ) From 7e958da6d6062a6d1a363bde8ec42ae4e0d3ec0a Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 9 Dec 2019 17:23:19 +0530 Subject: [PATCH 22/98] fix: sales order reqd only checks for stock items (#19865) --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 6 ++---- .../selling/doctype/selling_settings/selling_settings.json | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index c4d64a72fd..0f4d4451be 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -535,10 +535,8 @@ class SalesInvoice(SellingController): for i in dic: if frappe.db.get_single_value('Selling Settings', dic[i][0]) == 'Yes': for d in self.get('items'): - is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item') - if (d.item_code and is_stock_item == 1\ - and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])): - msgprint(_("{0} is mandatory for Stock Item {1}").format(i,d.item_code), raise_exception=1) + if (d.item_code and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])): + msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1) def validate_proj_cust(self): diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 5033d7aa7f..c04bfd281e 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -77,7 +77,6 @@ "fieldtype": "Column Break" }, { - "description": "Only for Stock Items", "fieldname": "so_required", "fieldtype": "Select", "label": "Sales Order Required", @@ -138,7 +137,7 @@ "icon": "fa fa-cog", "idx": 1, "issingle": 1, - "modified": "2019-11-25 18:35:51.472653", + "modified": "2019-12-09 13:38:36.486298", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", From 9e0b3b29fa71f940eec73ffd514c9d459c3cbdd3 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 9 Dec 2019 18:21:23 +0530 Subject: [PATCH 23/98] feat: better message for serial number creation (#19863) --- erpnext/stock/doctype/serial_no/serial_no.py | 30 ++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 19eb398130..23d00da7c1 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -353,17 +353,19 @@ def get_auto_serial_nos(serial_no_series, qty): def auto_make_serial_nos(args): serial_nos = get_serial_nos(args.get('serial_no')) created_numbers = [] + voucher_type = args.get('voucher_type') + item_code = args.get('item_code') for serial_no in serial_nos: if frappe.db.exists("Serial No", serial_no): sr = frappe.get_doc("Serial No", serial_no) sr.via_stock_ledger = True - sr.item_code = args.get('item_code') + sr.item_code = item_code sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None sr.batch_no = args.get('batch_no') sr.location = args.get('location') sr.company = args.get('company') sr.supplier = args.get('supplier') - if sr.sales_order and args.get('voucher_type') == "Stock Entry" \ + if sr.sales_order and voucher_type == "Stock Entry" \ and not args.get('actual_qty', 0) > 0: sr.sales_order = None sr.save(ignore_permissions=True) @@ -371,10 +373,28 @@ def auto_make_serial_nos(args): created_numbers.append(make_serial_no(serial_no, args)) form_links = list(map(lambda d: frappe.utils.get_link_to_form('Serial No', d), created_numbers)) + + # Setting up tranlated title field for all cases + singular_title = _("Serial Number Created") + multiple_title = _("Serial Numbers Created") + + if voucher_type: + multiple_title = singular_title = _("{0} Created").format(voucher_type) + if len(form_links) == 1: - frappe.msgprint(_("Serial No {0} created").format(form_links[0])) + frappe.msgprint(_("Serial No {0} Created").format(form_links[0]), singular_title) elif len(form_links) > 0: - frappe.msgprint(_("The following serial numbers were created:
{0}").format(', '.join(form_links))) + message = _("The following serial numbers were created:

{0}").format(get_items_html(form_links, item_code)) + frappe.msgprint(message, multiple_title) + +def get_items_html(serial_nos, item_code): + body = ', '.join(serial_nos) + return '''
+ {0}: {1} Serial Numbers + +
{2}
+ '''.format(item_code, len(serial_nos), body) + def get_item_details(item_code): return frappe.db.sql("""select name, has_batch_no, docstatus, @@ -397,7 +417,7 @@ def make_serial_no(serial_no, args): sr.via_stock_ledger = args.get('via_stock_ledger') or True sr.asset = args.get('asset') sr.location = args.get('location') - + if args.get('purchase_document_type'): sr.purchase_document_type = args.get('purchase_document_type') From da4847e46d55dbc2647c91ca15ee8648726599f9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 9 Dec 2019 18:27:50 +0530 Subject: [PATCH 24/98] patch: Set against_blanket_order value in existing SO/PO (#19810) * patch: Set against_blanket_order value in existing SO/PO * Update set_against_blanket_order_in_sales_and_purchase_order.py --- erpnext/patches.txt | 3 ++- ..._against_blanket_order_in_sales_and_purchase_order.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index daedca7a28..68b6cc0f37 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -647,4 +647,5 @@ erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields erpnext.patches.v12_0.set_default_for_add_taxes_from_item_tax_template erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger erpnext.patches.v12_0.update_price_or_product_discount -erpnext.patches.v12_0.set_production_capacity_in_workstation \ No newline at end of file +erpnext.patches.v12_0.set_production_capacity_in_workstation +erpnext.patches.v12_0.set_against_blanket_order_in_sales_and_purchase_order \ No newline at end of file diff --git a/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py new file mode 100644 index 0000000000..555d8ae797 --- /dev/null +++ b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py @@ -0,0 +1,9 @@ +import frappe +def execute(): + for doctype in ['Sales Order Item', 'Purchase Order Item']: + frappe.reload_doctype(doctype) + frappe.db.sql(""" + UPDATE `tab{0}` + SET against_blanket_order = 1 + WHERE ifnull(blanket_order, '') != '' + """.format(doctype)) From ae02b4119dae0482334a512b92301f61f2d85201 Mon Sep 17 00:00:00 2001 From: Pranav Nachnekar Date: Mon, 9 Dec 2019 13:33:35 +0000 Subject: [PATCH 25/98] add init.py for appointment modules (#19823) --- erpnext/www/book-appointment/__init__.py | 0 erpnext/www/book-appointment/verify/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 erpnext/www/book-appointment/__init__.py create mode 100644 erpnext/www/book-appointment/verify/__init__.py diff --git a/erpnext/www/book-appointment/__init__.py b/erpnext/www/book-appointment/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/www/book-appointment/verify/__init__.py b/erpnext/www/book-appointment/verify/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 5998034b02c0bc474769f2ca719e6645beb34ecb Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 9 Dec 2019 19:07:05 +0530 Subject: [PATCH 26/98] fix: error message displays asset category as None (#19873) * fix: error message displays asset category as None * fix: asset gl_entries doesn't considers asset category's cwip account --- erpnext/assets/doctype/asset/asset.py | 10 ++++++++-- .../stock/doctype/purchase_receipt/purchase_receipt.py | 8 +++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index d32f834f0f..3e7f6833a0 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -610,13 +610,19 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non if asset: account = get_asset_category_account(account_name, asset=asset, asset_category = asset_category, company = company) + + if not asset and not account: + account = get_asset_category_account(account_name, asset_category = asset_category, company = company) if not account: account = frappe.get_cached_value('Company', company, account_name) if not account: - frappe.throw(_("Set {0} in asset category {1} or company {2}") - .format(account_name.replace('_', ' ').title(), asset_category, company)) + if not asset_category: + frappe.throw(_("Set {0} in company {2}").format(account_name.replace('_', ' ').title(), company)) + else: + frappe.throw(_("Set {0} in asset category {1} or company {2}") + .format(account_name.replace('_', ' ').title(), asset_category, company)) return account diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index d0fae6a227..9b73d0f271 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -95,7 +95,8 @@ class PurchaseReceipt(BuyingController): # check cwip accounts before making auto assets # Improves UX by not giving messages of "Assets Created" before throwing error of not finding arbnb account arbnb_account = self.get_company_default("asset_received_but_not_billed") - cwip_account = get_asset_account("capital_work_in_progress_account", company = self.company) + cwip_account = get_asset_account("capital_work_in_progress_account", asset_category = item.asset_category, \ + company = self.company) break def validate_with_previous_doc(self): @@ -364,8 +365,9 @@ class PurchaseReceipt(BuyingController): def add_asset_gl_entries(self, item, gl_entries): arbnb_account = self.get_company_default("asset_received_but_not_billed") - # This returns company's default cwip account - cwip_account = get_asset_account("capital_work_in_progress_account", company = self.company) + # This returns category's cwip account if not then fallback to company's default cwip account + cwip_account = get_asset_account("capital_work_in_progress_account", asset_category = item.asset_category, \ + company = self.company) asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate) base_asset_amount = flt(item.base_net_amount + item.item_tax_amount) From 214acc9a42a202f652d33f4b1c9197ac48eb681d Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 9 Dec 2019 20:26:50 +0530 Subject: [PATCH 27/98] fix: Changed check condition and added test --- .../stock/doctype/stock_entry/stock_entry.js | 2 +- .../stock/doctype/stock_entry/stock_entry.py | 9 ++++++- .../doctype/stock_entry/test_stock_entry.py | 27 +++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index d9c94fced7..ca480f969d 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -536,7 +536,7 @@ frappe.ui.form.on('Stock Entry Detail', { if(r.message) { var d = locals[cdt][cdn]; $.each(r.message, function(k, v) { - d[k] = v; + frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered }); refresh_field("items"); erpnext.stock.select_batch_and_serial_no(frm, d); diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 2b99f72565..913656ad02 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -27,6 +27,7 @@ class IncorrectValuationRateError(frappe.ValidationError): pass class DuplicateEntryForWorkOrderError(frappe.ValidationError): pass class OperationsNotCompleteError(frappe.ValidationError): pass class MaxSampleAlreadyRetainedError(frappe.ValidationError): pass +class TotalBasicAmountZeroError(frappe.ValidationError): pass from erpnext.controllers.stock_controller import StockController @@ -649,6 +650,12 @@ class StockEntry(StockController): gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account) total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse]) + + if self.get("additional_costs") and not total_basic_amount: + #If additional costs table is populated and total basic amount is + #somehow 0, interrupt transaction. + frappe.throw(_("Total Basic Amount in Items Table cannot be 0"), TotalBasicAmountZeroError) + item_account_wise_additional_cost = {} for t in self.get("additional_costs"): @@ -657,7 +664,7 @@ class StockEntry(StockController): item_account_wise_additional_cost.setdefault((d.item_code, d.name), {}) item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0) item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \ - (t.amount * d.basic_amount) / total_basic_amount if total_basic_amount else 0 + (t.amount * d.basic_amount) / total_basic_amount if item_account_wise_additional_cost: for d in self.get("items"): diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index eddab5d79d..c5e67092d3 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -16,6 +16,7 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse, make_stock_in_entry from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError +from erpnext.stock.doctype.stock_entry.stock_entry import TotalBasicAmountZeroError from six import iteritems def get_sle(**args): @@ -790,6 +791,32 @@ class TestStockEntry(unittest.TestCase): filters={"voucher_type": "Stock Entry", "voucher_no": mr.name}, fieldname="is_opening") self.assertEqual(is_opening, "Yes") + def test_total_basic_amount_zero(self): + se = frappe.get_doc({"doctype":"Stock Entry", + "purpose":"Material Receipt", + "stock_entry_type":"Material Receipt", + "posting_date": nowdate(), + "company":"_Test Company with perpetual inventory", + "items":[ + {"item_code":"Basil Leaves", + "description":"Basil Leaves", + "qty": 1, + "basic_rate": 0, + "uom":"Nos", + "t_warehouse": "Stores - TCP1", + "allow_zero_valuation_rate": 1, + "cost_center": "Main - TCP1"} + ], + "additional_costs":[ + {"expense_account":"Miscellaneous Expenses - TCP1", + "amount":100, + "description": "miscellanous"} + ] + }) + + se.insert() + self.assertRaises(TotalBasicAmountZeroError, se.submit) + def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None): se = frappe.copy_doc(test_records[0]) se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series" From 6f68f2d02048fc1dca795dd7e610e7478b52f805 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 10 Dec 2019 08:40:10 +0530 Subject: [PATCH 28/98] feat: Cost center for each expenses in expense claim and allowed deferred expense (#19807) * refactor: Expense Claim Cost Center * refactor: Expense Claim Cost Center * refactor: Expense Claim Cost Center * fix: copy cost center from other row * patch: set cost center in children based on parent * fix: test cases for expense claim --- .../hr/doctype/expense_claim/expense_claim.js | 96 +++--- .../doctype/expense_claim/expense_claim.json | 3 +- .../hr/doctype/expense_claim/expense_claim.py | 7 +- .../expense_claim/test_expense_claim.py | 13 +- .../expense_claim_detail.json | 316 ++---------------- .../expense_claim_type/expense_claim_type.js | 2 +- .../expense_claim_type.json | 225 ++++--------- erpnext/patches.txt | 3 +- ..._center_in_child_table_of_expense_claim.py | 8 + 9 files changed, 160 insertions(+), 513 deletions(-) create mode 100644 erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index 0d37c10e9c..570f2ef4c7 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -42,12 +42,6 @@ cur_frm.cscript.onload = function(doc) { cur_frm.set_value("posting_date", frappe.datetime.get_today()); cur_frm.cscript.clear_sanctioned(doc); } - - cur_frm.fields_dict.employee.get_query = function() { - return { - query: "erpnext.controllers.queries.employee_query" - }; - }; }; cur_frm.cscript.clear_sanctioned = function(doc) { @@ -119,7 +113,7 @@ cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){ }; erpnext.expense_claim = { - set_title :function(frm) { + set_title: function(frm) { if (!frm.doc.task) { frm.set_value("title", frm.doc.employee_name); } @@ -131,20 +125,20 @@ erpnext.expense_claim = { frappe.ui.form.on("Expense Claim", { setup: function(frm) { - frm.trigger("set_query_for_cost_center"); - frm.trigger("set_query_for_payable_account"); frm.add_fetch("company", "cost_center", "cost_center"); frm.add_fetch("company", "default_expense_claim_payable_account", "payable_account"); - frm.set_query("employee_advance", "advances", function(doc) { + + frm.set_query("employee_advance", "advances", function() { return { filters: [ ['docstatus', '=', 1], - ['employee', '=', doc.employee], + ['employee', '=', frm.doc.employee], ['paid_amount', '>', 0], ['paid_amount', '>', 'claimed_amount'] ] }; }); + frm.set_query("expense_approver", function() { return { query: "erpnext.hr.doctype.department_approver.department_approver.get_approvers", @@ -154,14 +148,49 @@ frappe.ui.form.on("Expense Claim", { } }; }); - frm.set_query("account_head", "taxes", function(doc) { + + frm.set_query("account_head", "taxes", function() { return { filters: [ - ['company', '=', doc.company], + ['company', '=', frm.doc.company], ['account_type', 'in', ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation"]] ] }; }); + + frm.set_query("cost_center", "expenses", function() { + return { + filters: { + "company": frm.doc.company, + "is_group": 0 + } + }; + }); + + frm.set_query("payable_account", function() { + return { + filters: { + "report_type": "Balance Sheet", + "account_type": "Payable", + "company": frm.doc.company, + "is_group": 0 + } + }; + }); + + frm.set_query("task", function() { + return { + filters: { + 'project': frm.doc.project + } + }; + }); + + frm.set_query("employee", function() { + return { + query: "erpnext.controllers.queries.employee_query" + }; + }); }, onload: function(frm) { @@ -244,30 +273,6 @@ frappe.ui.form.on("Expense Claim", { }); }, - set_query_for_cost_center: function(frm) { - frm.fields_dict["cost_center"].get_query = function() { - return { - filters: { - "company": frm.doc.company, - "is_group": 0 - } - }; - }; - }, - - set_query_for_payable_account: function(frm) { - frm.fields_dict["payable_account"].get_query = function() { - return { - filters: { - "report_type": "Balance Sheet", - "account_type": "Payable", - "company": frm.doc.company, - "is_group": 0 - } - }; - }; - }, - is_paid: function(frm) { frm.trigger("toggle_fields"); }, @@ -329,6 +334,10 @@ frappe.ui.form.on("Expense Claim", { }); frappe.ui.form.on("Expense Claim Detail", { + expenses_add: function(frm, cdt, cdn) { + var row = frappe.get_doc(cdt, cdn); + frm.script_manager.copy_from_first_row("expenses", row, ["cost_center"]); + }, amount: function(frm, cdt, cdn) { var child = locals[cdt][cdn]; var doc = frm.doc; @@ -341,6 +350,9 @@ frappe.ui.form.on("Expense Claim Detail", { cur_frm.cscript.calculate_total(doc,cdt,cdn); frm.trigger("get_taxes"); frm.trigger("calculate_grand_total"); + }, + cost_center: function(frm, cdt, cdn) { + erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "expenses", "cost_center"); } }); @@ -411,12 +423,4 @@ frappe.ui.form.on("Expense Taxes and Charges", { tax_amount: function(frm, cdt, cdn) { frm.trigger("calculate_total_tax", cdt, cdn); } -}); - -cur_frm.fields_dict['task'].get_query = function(doc) { - return { - filters:{ - 'project': doc.project - } - }; -}; +}); \ No newline at end of file diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json index 5c2f490171..b5b6823e1c 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.json +++ b/erpnext/hr/doctype/expense_claim/expense_claim.json @@ -43,7 +43,6 @@ "accounting_dimensions_section", "project", "dimension_col_break", - "cost_center", "more_details", "status", "amended_from", @@ -366,7 +365,7 @@ "icon": "fa fa-money", "idx": 1, "is_submittable": 1, - "modified": "2019-11-08 14:13:08.964547", + "modified": "2019-11-09 14:13:08.964547", "modified_by": "Administrator", "module": "HR", "name": "Expense Claim", diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 59391505fa..dfb0bb96d8 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -127,7 +127,7 @@ class ExpenseClaim(AccountsController): "debit": data.sanctioned_amount, "debit_in_account_currency": data.sanctioned_amount, "against": self.employee, - "cost_center": self.cost_center + "cost_center": data.cost_center }) ) @@ -190,8 +190,9 @@ class ExpenseClaim(AccountsController): ) def validate_account_details(self): - if not self.cost_center: - frappe.throw(_("Cost center is required to book an expense claim")) + for data in self.expenses: + if not data.cost_center: + frappe.throw(_("Cost center is required to book an expense claim")) if self.is_paid: if not self.mode_of_payment: diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index b559dfd81d..6e97f0513d 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -126,7 +126,7 @@ def generate_taxes(): def make_expense_claim(payable_account, amount, sanctioned_amount, company, account, project=None, task_name=None, do_not_submit=False, taxes=None): employee = frappe.db.get_value("Employee", {"status": "Active"}) - currency = frappe.db.get_value('Company', company, 'default_currency') + currency, cost_center = frappe.db.get_value('Company', company, ['default_currency', 'cost_center']) expense_claim = { "doctype": "Expense Claim", "employee": employee, @@ -134,12 +134,15 @@ def make_expense_claim(payable_account, amount, sanctioned_amount, company, acco "approval_status": "Approved", "company": company, 'currency': currency, - "expenses": - [{"expense_type": "Travel", + "expenses": [{ + "expense_type": "Travel", "default_account": account, - 'currency': currency, + "currency": currency, "amount": amount, - "sanctioned_amount": sanctioned_amount}]} + "sanctioned_amount": sanctioned_amount, + "cost_center": cost_center + }] + } if taxes: expense_claim.update(taxes) diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json index b23fb6af0f..b60db2c3af 100644 --- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json +++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json @@ -1,378 +1,118 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, "creation": "2013-02-22 01:27:46", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "expense_date", + "column_break_2", + "expense_type", + "default_account", + "section_break_4", + "description", + "section_break_6", + "amount", + "column_break_8", + "sanctioned_amount", + "cost_center" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "expense_date", "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Expense Date", - "length": 0, - "no_copy": 0, "oldfieldname": "expense_date", "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "150px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "150px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "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 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "expense_type", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Expense Claim Type", - "length": 0, - "no_copy": 0, "oldfieldname": "expense_type", "oldfieldtype": "Link", "options": "Expense Claim Type", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "150px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "150px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "expense_type", "fieldname": "default_account", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Default Account", - "length": 0, - "no_copy": 0, "options": "Account", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_4", - "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 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "", "fieldname": "description", "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Description", - "length": 0, - "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Small Text", - "options": "", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "300px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_6", - "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 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "amount", "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Amount", - "length": 0, - "no_copy": 0, "oldfieldname": "claim_amount", "oldfieldtype": "Currency", "options": "Company:company:default_currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "150px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "150px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_8", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_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 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "sanctioned_amount", "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Sanctioned Amount", - "length": 0, "no_copy": 1, "oldfieldname": "sanctioned_amount", "oldfieldtype": "Currency", "options": "Company:company:default_currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "150px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "150px" + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-06-10 08:41:36.122565", - "modified_by": "Administrator", + "modified": "2019-11-22 11:57:25.110942", + "modified_by": "jangeles@bai.ph", "module": "HR", "name": "Expense Claim Detail", "owner": "harshada@webnotestech.com", "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js index fda6809e6b..c487797677 100644 --- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js +++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js @@ -8,7 +8,7 @@ frappe.ui.form.on("Expense Claim Type", { return{ filters: { "is_group": 0, - "root_type": "Expense", + "root_type": frm.doc.deferred_expense_account ? "Asset" : "Expense", 'company': d.company } } diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json index d0c41221cc..e45f640c07 100644 --- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json +++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json @@ -1,181 +1,72 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:expense_type", - "beta": 0, - "creation": "2012-03-27 14:35:55", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, - "engine": "InnoDB", + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:expense_type", + "creation": "2012-03-27 14:35:55", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "deferred_expense_account", + "expense_type", + "description", + "accounts" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "expense_type", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Expense Claim Type", - "length": 0, - "no_copy": 0, - "oldfieldname": "expense_type", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "fieldname": "expense_type", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Expense Claim Type", + "oldfieldname": "expense_type", + "oldfieldtype": "Data", + "reqd": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Small Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Description", + "oldfieldname": "description", + "oldfieldtype": "Small Text", "width": "300px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "accounts", - "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": "Accounts", - "length": 0, - "no_copy": 0, - "options": "Expense Claim Account", - "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 + "fieldname": "accounts", + "fieldtype": "Table", + "label": "Accounts", + "options": "Expense Claim Account" + }, + { + "default": "0", + "fieldname": "deferred_expense_account", + "fieldtype": "Check", + "label": "Deferred Expense Account" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-flag", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-09-18 14:13:43.770829", - "modified_by": "Administrator", - "module": "HR", - "name": "Expense Claim Type", - "owner": "harshada@webnotestech.com", + ], + "icon": "fa fa-flag", + "idx": 1, + "modified": "2019-11-22 12:00:18.710408", + "modified_by": "jangeles@bai.ph", + "module": "HR", + "name": "Expense Claim Type", + "owner": "harshada@webnotestech.com", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "HR Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Employee", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "read": 1, + "role": "Employee" } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 68b6cc0f37..053cae0567 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -648,4 +648,5 @@ erpnext.patches.v12_0.set_default_for_add_taxes_from_item_tax_template erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger erpnext.patches.v12_0.update_price_or_product_discount erpnext.patches.v12_0.set_production_capacity_in_workstation -erpnext.patches.v12_0.set_against_blanket_order_in_sales_and_purchase_order \ No newline at end of file +erpnext.patches.v12_0.set_against_blanket_order_in_sales_and_purchase_order +erpnext.patches.v12_0.set_cost_center_in_child_table_of_expense_claim diff --git a/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py new file mode 100644 index 0000000000..8ba0d79a83 --- /dev/null +++ b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py @@ -0,0 +1,8 @@ +import frappe +def execute(): + frappe.reload_doc('hr', 'doctype', 'expense_claim_detail') + frappe.db.sql(""" + UPDATE `tabExpense Claim Detail` child, `tabExpense Claim` par + SET child.cost_center = par.cost_center + WHERE child.parent = par.name + """) \ No newline at end of file From ce42f48bfbe8ec13dc5d0da44b718eb1355091b0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 10 Dec 2019 12:15:34 +0530 Subject: [PATCH 29/98] fix: Append expense account only if expense account exists (#19880) --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 7b2061ac16..917acba92c 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -248,7 +248,7 @@ class PurchaseInvoice(BuyingController): def set_against_expense_account(self): against_accounts = [] for item in self.get("items"): - if item.expense_account not in against_accounts: + if item.expense_account and (item.expense_account not in against_accounts): against_accounts.append(item.expense_account) self.against_expense_account = ",".join(against_accounts) From 9cc5c18f36ec8736a688315adb520d995ed0d753 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 10 Dec 2019 15:20:47 +0530 Subject: [PATCH 30/98] fix: removed only custom dashboard --- erpnext/hr/doctype/leave_application/leave_application.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js index e32d57011d..14ffa0ed1f 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.js +++ b/erpnext/hr/doctype/leave_application/leave_application.js @@ -60,6 +60,7 @@ frappe.ui.form.on("Leave Application", { } } }); + $("div").remove(".form-dashboard-section.custom"); frm.dashboard.add_section( frappe.render_template('leave_application_dashboard', { data: leave_details From 6e2c13f4c86c73c09f13c9167717f602b701de71 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 10 Dec 2019 15:55:05 +0530 Subject: [PATCH 31/98] feat(regional): Auto state wise taxation for GST India (#19469) * feat(regional): Auto state wise taxation for GST India * fix: Update gst category on addition of GSTIN * fix: Codacy and travis fixes * fix: Travis * fix(test): Update GST category only if GSTIN field available * fix: Test Cases * fix: Do not skip accounts if place of supply is not present * fix: Auto GST taxation for SEZ Party types * fix: Automatic taxation for multi state * fix: Codacy and travis fixes * fix: Auto GST template selection in Sales Order * fix: Move inter state check and source state to tax category * fix: Remove unique check from tax template * fix: Remove unique check from tax template * fix: Address fetching logic in Sales * fix: fecth tax template on company address change * fix: fetch company gstin on address change * fix: company_gstin set value fix * fix: Mutiple fixes and code refactor * fix: Add missing semicolon * fix: Company address fetching in sales invoice * fix: Remove print statement * fix: Import functools * fix: Naming fixes and code cleanup * fix: Iteritems compatibility for python 3 --- .../purchase_invoice/regional/india.js | 3 + .../purchase_taxes_and_charges_template.json | 374 +++++------------ .../doctype/sales_invoice/regional/india.js | 5 + .../doctype/sales_invoice/sales_invoice.js | 4 +- .../sales_taxes_and_charges_template.json | 382 +++++------------- erpnext/accounts/party.py | 107 ++--- .../doctype/purchase_order/regional/india.js | 3 + erpnext/hooks.py | 6 +- erpnext/patches.txt | 1 + .../add_export_type_field_in_party_master.py | 40 ++ erpnext/public/js/queries.js | 2 +- erpnext/public/js/utils/party.js | 44 ++ .../gstr_3b_report/test_gstr_3b_report.py | 17 +- erpnext/regional/india/__init__.py | 5 +- erpnext/regional/india/setup.py | 59 ++- erpnext/regional/india/taxes.js | 41 ++ erpnext/regional/india/utils.py | 116 +++++- .../doctype/sales_order/regional/india.js | 3 + .../doctype/sales_order/sales_order.py | 16 +- erpnext/setup/doctype/company/company.py | 25 ++ .../doctype/delivery_note/delivery_note.py | 7 +- .../doctype/delivery_note/regional/india.js | 4 + .../purchase_receipt/regional/india.js | 3 + 23 files changed, 598 insertions(+), 669 deletions(-) create mode 100644 erpnext/accounts/doctype/purchase_invoice/regional/india.js create mode 100644 erpnext/buying/doctype/purchase_order/regional/india.js create mode 100644 erpnext/patches/v12_0/add_export_type_field_in_party_master.py create mode 100644 erpnext/regional/india/taxes.js create mode 100644 erpnext/selling/doctype/sales_order/regional/india.js create mode 100644 erpnext/stock/doctype/delivery_note/regional/india.js create mode 100644 erpnext/stock/doctype/purchase_receipt/regional/india.js diff --git a/erpnext/accounts/doctype/purchase_invoice/regional/india.js b/erpnext/accounts/doctype/purchase_invoice/regional/india.js new file mode 100644 index 0000000000..81488a2c52 --- /dev/null +++ b/erpnext/accounts/doctype/purchase_invoice/regional/india.js @@ -0,0 +1,3 @@ +{% include "erpnext/regional/india/taxes.js" %} + +erpnext.setup_auto_gst_taxation('Purchase Invoice'); diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json index bc42630d47..a18fec61cf 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json @@ -1,300 +1,108 @@ { - "allow_copy": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:title", - "beta": 0, - "creation": "2013-01-10 16:34:08", - "custom": 0, - "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, + "allow_import": 1, + "allow_rename": 1, + "creation": "2013-01-10 16:34:08", + "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.", + "doctype": "DocType", + "document_type": "Setup", + "field_order": [ + "title", + "is_default", + "disabled", + "column_break4", + "company", + "tax_category", + "section_break6", + "taxes" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Title", - "length": 0, - "no_copy": 1, - "oldfieldname": "title", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "title", + "fieldtype": "Data", + "label": "Title", + "no_copy": 1, + "oldfieldname": "title", + "oldfieldtype": "Data", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_default", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Default", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "is_default", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Default" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Disabled", - "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, - "unique": 0 - }, + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Disabled" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "column_break4", + "fieldtype": "Column Break" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Company", + "options": "Company", + "remember_last_selected_value": 1, + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "section_break6", + "fieldtype": "Section Break" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "taxes", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Purchase Taxes and Charges", - "length": 0, - "no_copy": 0, - "oldfieldname": "purchase_tax_details", - "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "taxes", + "fieldtype": "Table", + "label": "Purchase Taxes and Charges", + "oldfieldname": "purchase_tax_details", + "oldfieldtype": "Table", + "options": "Purchase Taxes and Charges" + }, + { + "fieldname": "tax_category", + "fieldtype": "Link", + "label": "Tax Category", + "options": "Tax Category" } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-money", - "idx": 1, - "image_view": 0, - "in_create": 0, - - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2016-11-07 05:18:44.095798", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Purchase Taxes and Charges Template", - "owner": "wasim@webnotestech.com", + ], + "icon": "fa fa-money", + "idx": 1, + "modified": "2019-11-25 13:05:26.220275", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Purchase Taxes and Charges Template", + "owner": "wasim@webnotestech.com", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 - }, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Manager" + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase Master Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Master Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Purchase User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "read": 1, + "role": "Purchase User" } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "sort_order": "DESC", - "track_seen": 0 + ], + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js index c8305e325f..48fa364faf 100644 --- a/erpnext/accounts/doctype/sales_invoice/regional/india.js +++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js @@ -1,3 +1,7 @@ +{% include "erpnext/regional/india/taxes.js" %} + +erpnext.setup_auto_gst_taxation('Sales Invoice'); + frappe.ui.form.on("Sales Invoice", { setup: function(frm) { frm.set_query('transporter', function() { @@ -35,4 +39,5 @@ frappe.ui.form.on("Sales Invoice", { }, __("Make")); } } + }); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 2ea74f6d85..7f4ae3c1fc 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -697,8 +697,8 @@ frappe.ui.form.on('Sales Invoice', { if (frm.doc.company) { frappe.call({ - method:"frappe.contacts.doctype.address.address.get_default_address", - args:{ doctype:'Company',name:frm.doc.company}, + method:"erpnext.setup.doctype.company.company.get_default_company_address", + args:{name:frm.doc.company, existing_address: frm.doc.company_address}, callback: function(r){ if (r.message){ frm.set_value("company_address",r.message) diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json index 29e15d165f..19781bdffa 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json @@ -1,299 +1,119 @@ { - "allow_copy": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:title", - "beta": 0, - "creation": "2013-01-10 16:34:09", - "custom": 0, - "description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, + "allow_import": 1, + "allow_rename": 1, + "creation": "2013-01-10 16:34:09", + "description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "title", + "is_default", + "disabled", + "column_break_3", + "company", + "tax_category", + "section_break_5", + "taxes" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Title", - "length": 0, - "no_copy": 1, - "oldfieldname": "title", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "title", + "fieldtype": "Data", + "label": "Title", + "no_copy": 1, + "oldfieldname": "title", + "oldfieldtype": "Data", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_default", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Default", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "is_default", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Default" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disabled", - "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, - "unique": 0 - }, + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Company", - "length": 0, - "no_copy": 0, - "oldfieldname": "company", - "oldfieldtype": "Link", - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "remember_last_selected_value": 1, + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_5", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "section_break_5", + "fieldtype": "Section Break" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "* Will be calculated in the transaction.", - "fieldname": "taxes", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sales Taxes and Charges", - "length": 0, - "no_copy": 0, - "oldfieldname": "other_charges", - "oldfieldtype": "Table", - "options": "Sales Taxes and Charges", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "description": "* Will be calculated in the transaction.", + "fieldname": "taxes", + "fieldtype": "Table", + "label": "Sales Taxes and Charges", + "oldfieldname": "other_charges", + "oldfieldtype": "Table", + "options": "Sales Taxes and Charges" + }, + { + "fieldname": "tax_category", + "fieldtype": "Link", + "label": "Tax Category", + "options": "Tax Category" } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-money", - "idx": 1, - "image_view": 0, - "in_create": 0, - - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2016-11-07 05:18:41.743257", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Sales Taxes and Charges Template", - "owner": "Administrator", + ], + "icon": "fa fa-money", + "idx": 1, + "modified": "2019-11-25 13:06:03.279099", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Sales Taxes and Charges Template", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 1, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 - }, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales User" + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "is_custom": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales Master Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales Master Manager", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "sort_order": "ASC", - "track_seen": 0 + ], + "sort_field": "modified", + "sort_order": "ASC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 59936d5116..156f2181b8 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -23,7 +23,7 @@ class DuplicatePartyAccountError(frappe.ValidationError): pass @frappe.whitelist() def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True, - party_address=None, shipping_address=None, pos_profile=None): + party_address=None, company_address=None, shipping_address=None, pos_profile=None): if not party: return {} @@ -31,14 +31,14 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N frappe.throw(_("{0}: {1} does not exists").format(party_type, party)) return _get_party_details(party, account, party_type, company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions, - fetch_payment_terms_template, party_address, shipping_address, pos_profile) + fetch_payment_terms_template, party_address, company_address, shipping_address, pos_profile) def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, - fetch_payment_terms_template=True, party_address=None, shipping_address=None, pos_profile=None): + fetch_payment_terms_template=True, party_address=None, company_address=None,shipping_address=None, pos_profile=None): - out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype)) - party = out[party_type.lower()] + party_details = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype)) + party = party_details[party_type.lower()] if not ignore_permissions and not frappe.has_permission(party_type, "read", party): frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError) @@ -46,76 +46,81 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= party = frappe.get_doc(party_type, party) currency = party.default_currency if party.get("default_currency") else get_company_currency(company) - party_address, shipping_address = set_address_details(out, party, party_type, doctype, company, party_address, shipping_address) - set_contact_details(out, party, party_type) - set_other_values(out, party, party_type) - set_price_list(out, party, party_type, price_list, pos_profile) + party_address, shipping_address = set_address_details(party_details, party, party_type, doctype, company, party_address, company_address, shipping_address) + set_contact_details(party_details, party, party_type) + set_other_values(party_details, party, party_type) + set_price_list(party_details, party, party_type, price_list, pos_profile) - out["tax_category"] = get_address_tax_category(party.get("tax_category"), + party_details["tax_category"] = get_address_tax_category(party.get("tax_category"), party_address, shipping_address if party_type != "Supplier" else party_address) - out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, - customer_group=out.customer_group, supplier_group=out.supplier_group, tax_category=out.tax_category, - billing_address=party_address, shipping_address=shipping_address) + + if not party_details.get("taxes_and_charges"): + party_details["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, + customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category, + billing_address=party_address, shipping_address=shipping_address) if fetch_payment_terms_template: - out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company) + party_details["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company) - if not out.get("currency"): - out["currency"] = currency + if not party_details.get("currency"): + party_details["currency"] = currency # sales team if party_type=="Customer": - out["sales_team"] = [{ + party_details["sales_team"] = [{ "sales_person": d.sales_person, "allocated_percentage": d.allocated_percentage or None } for d in party.get("sales_team")] # supplier tax withholding category if party_type == "Supplier" and party: - out["supplier_tds"] = frappe.get_value(party_type, party.name, "tax_withholding_category") + party_details["supplier_tds"] = frappe.get_value(party_type, party.name, "tax_withholding_category") - return out + return party_details -def set_address_details(out, party, party_type, doctype=None, company=None, party_address=None, shipping_address=None): +def set_address_details(party_details, party, party_type, doctype=None, company=None, party_address=None, company_address=None, shipping_address=None): billing_address_field = "customer_address" if party_type == "Lead" \ else party_type.lower() + "_address" - out[billing_address_field] = party_address or get_default_address(party_type, party.name) + party_details[billing_address_field] = party_address or get_default_address(party_type, party.name) if doctype: - out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field])) + party_details.update(get_fetch_values(doctype, billing_address_field, party_details[billing_address_field])) # address display - out.address_display = get_address_display(out[billing_address_field]) + party_details.address_display = get_address_display(party_details[billing_address_field]) # shipping address if party_type in ["Customer", "Lead"]: - out.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name) - out.shipping_address = get_address_display(out["shipping_address_name"]) + party_details.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name) + party_details.shipping_address = get_address_display(party_details["shipping_address_name"]) if doctype: - out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) + party_details.update(get_fetch_values(doctype, 'shipping_address_name', party_details.shipping_address_name)) - if doctype and doctype in ['Delivery Note', 'Sales Invoice']: - out.update(get_company_address(company)) - if out.company_address: - out.update(get_fetch_values(doctype, 'company_address', out.company_address)) - get_regional_address_details(out, doctype, company) + if company_address: + party_details.update({'company_address': company_address}) + else: + party_details.update(get_company_address(company)) - elif doctype and doctype == "Purchase Invoice": - out.update(get_company_address(company)) - if out.company_address: - out["shipping_address"] = shipping_address or out["company_address"] - out.shipping_address_display = get_address_display(out["shipping_address"]) - out.update(get_fetch_values(doctype, 'shipping_address', out.shipping_address)) - get_regional_address_details(out, doctype, company) + if doctype and doctype in ['Delivery Note', 'Sales Invoice', 'Sales Order']: + if party_details.company_address: + party_details.update(get_fetch_values(doctype, 'company_address', party_details.company_address)) + get_regional_address_details(party_details, doctype, company) - return out.get(billing_address_field), out.shipping_address_name + elif doctype and doctype in ["Purchase Invoice", "Purchase Order", "Purchase Receipt"]: + if party_details.company_address: + party_details["shipping_address"] = shipping_address or party_details["company_address"] + party_details.shipping_address_display = get_address_display(party_details["shipping_address"]) + party_details.update(get_fetch_values(doctype, 'shipping_address', party_details.shipping_address)) + get_regional_address_details(party_details, doctype, company) + + return party_details.get(billing_address_field), party_details.shipping_address_name @erpnext.allow_regional -def get_regional_address_details(out, doctype, company): +def get_regional_address_details(party_details, doctype, company): pass -def set_contact_details(out, party, party_type): - out.contact_person = get_default_contact(party_type, party.name) +def set_contact_details(party_details, party, party_type): + party_details.contact_person = get_default_contact(party_type, party.name) - if not out.contact_person: - out.update({ + if not party_details.contact_person: + party_details.update({ "contact_person": None, "contact_display": None, "contact_email": None, @@ -125,22 +130,22 @@ def set_contact_details(out, party, party_type): "contact_department": None }) else: - out.update(get_contact_details(out.contact_person)) + party_details.update(get_contact_details(party_details.contact_person)) -def set_other_values(out, party, party_type): +def set_other_values(party_details, party, party_type): # copy if party_type=="Customer": to_copy = ["customer_name", "customer_group", "territory", "language"] else: to_copy = ["supplier_name", "supplier_group", "language"] for f in to_copy: - out[f] = party.get(f) + party_details[f] = party.get(f) # fields prepended with default in Customer doctype for f in ['currency'] \ + (['sales_partner', 'commission_rate'] if party_type=="Customer" else []): if party.get("default_" + f): - out[f] = party.get("default_" + f) + party_details[f] = party.get("default_" + f) def get_default_price_list(party): """Return default price list for party (Document object)""" @@ -155,7 +160,7 @@ def get_default_price_list(party): return None -def set_price_list(out, party, party_type, given_price_list, pos=None): +def set_price_list(party_details, party, party_type, given_price_list, pos=None): # price list price_list = get_permitted_documents('Price List') @@ -173,9 +178,9 @@ def set_price_list(out, party, party_type, given_price_list, pos=None): price_list = get_default_price_list(party) or given_price_list if price_list: - out.price_list_currency = frappe.db.get_value("Price List", price_list, "currency", cache=True) + party_details.price_list_currency = frappe.db.get_value("Price List", price_list, "currency", cache=True) - out["selling_price_list" if party.doctype=="Customer" else "buying_price_list"] = price_list + party_details["selling_price_list" if party.doctype=="Customer" else "buying_price_list"] = price_list def set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype): diff --git a/erpnext/buying/doctype/purchase_order/regional/india.js b/erpnext/buying/doctype/purchase_order/regional/india.js new file mode 100644 index 0000000000..42d3995907 --- /dev/null +++ b/erpnext/buying/doctype/purchase_order/regional/india.js @@ -0,0 +1,3 @@ +{% include "erpnext/regional/india/taxes.js" %} + +erpnext.setup_auto_gst_taxation('Purchase Order'); \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index ed5bf9b5d8..2a5e6d8f49 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -246,10 +246,10 @@ doc_events = { "on_trash": "erpnext.regional.check_deletion_permission" }, 'Address': { - 'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code'] + 'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code', 'erpnext.regional.india.utils.update_gst_category'] }, - ('Sales Invoice', 'Purchase Invoice', 'Delivery Note'): { - 'validate': 'erpnext.regional.india.utils.set_place_of_supply' + ('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): { + 'validate': ['erpnext.regional.india.utils.set_place_of_supply'] }, "Contact": { "on_trash": "erpnext.support.doctype.issue.issue.update_issue", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 053cae0567..e26b1c88a8 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -645,6 +645,7 @@ erpnext.patches.v12_0.replace_accounting_with_accounts_in_home_settings erpnext.patches.v12_0.set_payment_entry_status erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields erpnext.patches.v12_0.set_default_for_add_taxes_from_item_tax_template +erpnext.patches.v12_0.add_export_type_field_in_party_master erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger erpnext.patches.v12_0.update_price_or_product_discount erpnext.patches.v12_0.set_production_capacity_in_workstation diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py new file mode 100644 index 0000000000..c565b7ecd8 --- /dev/null +++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py @@ -0,0 +1,40 @@ +from __future__ import unicode_literals +import frappe +from erpnext.regional.india.setup import make_custom_fields + +def execute(): + + company = frappe.get_all('Company', filters = {'country': 'India'}) + if not company: + return + + make_custom_fields() + + frappe.reload_doctype('Tax Category') + frappe.reload_doctype('Sales Taxes and Charges Template') + frappe.reload_doctype('Purchase Taxes and Charges Template') + + # Create tax category with inter state field checked + tax_category = frappe.db.get_value('Tax Category', {'name': 'OUT OF STATE'}, 'name') + + if not tax_category: + inter_state_category = frappe.get_doc({ + 'doctype': 'Tax Category', + 'title': 'OUT OF STATE', + 'is_inter_state': 1 + }).insert() + + tax_category = inter_state_category.name + + for doctype in ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template'): + template = frappe.db.get_value(doctype, {'is_inter_state': 1, 'disabled': 0}, ['name']) + if template: + frappe.db.set_value(doctype, template, 'tax_category', tax_category) + + frappe.db.sql(""" + DELETE FROM `tabCustom Field` + WHERE fieldname = 'is_inter_state' + AND dt IN ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template') + """) + + diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js index 84d2113c06..560a5617da 100644 --- a/erpnext/public/js/queries.js +++ b/erpnext/public/js/queries.js @@ -65,7 +65,7 @@ $.extend(erpnext.queries, { frappe.throw(__("Please set {0}", [__(frappe.meta.get_label(doc.doctype, frappe.dynamic_link.fieldname, doc.name))])); } - console.log(frappe.dynamic_link) + return { query: 'frappe.contacts.doctype.address.address.address_query', filters: { diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index a8d3888ba0..99c1b8ae8f 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -7,6 +7,21 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { if(!method) { method = "erpnext.accounts.party.get_party_details"; } + + if (args) { + if (in_list(['Sales Invoice', 'Sales Order', 'Delivery Note'], frm.doc.doctype)) { + if (frm.doc.company_address && (!args.company_address)) { + args.company_address = frm.doc.company_address; + } + } + + if (in_list(['Purchase Invoice', 'Purchase Order', 'Purchase Receipt'], frm.doc.doctype)) { + if (frm.doc.shipping_address && (!args.shipping_address)) { + args.shipping_address = frm.doc.shipping_address; + } + } + } + if(!args) { if((frm.doctype != "Purchase Order" && frm.doc.customer) || (frm.doc.party_name && in_list(['Quotation', 'Opportunity'], frm.doc.doctype))) { @@ -30,6 +45,35 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { }; } + if (in_list(['Sales Invoice', 'Sales Order', 'Delivery Note'], frm.doc.doctype)) { + if (!args) { + args = { + party: frm.doc.customer || frm.doc.party_name, + party_type: 'Customer' + } + } + if (frm.doc.company_address && (!args.company_address)) { + args.company_address = frm.doc.company_address; + } + + if (frm.doc.shipping_address_name &&(!args.shipping_address_name)) { + args.shipping_address_name = frm.doc.shipping_address_name; + } + } + + if (in_list(['Purchase Invoice', 'Purchase Order', 'Purchase Receipt'], frm.doc.doctype)) { + if (!args) { + args = { + party: frm.doc.supplier, + party_type: 'Supplier' + } + } + + if (frm.doc.shipping_address && (!args.shipping_address)) { + args.shipping_address = frm.doc.shipping_address; + } + } + if (args) { args.posting_date = frm.doc.posting_date || frm.doc.transaction_date; } diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py index fef73d9a0a..fa6fb706e9 100644 --- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py @@ -64,7 +64,8 @@ class TestGSTR3BReport(unittest.TestCase): self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18), self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100), self.assertEqual(output["inward_sup"]["isup_details"][0]["inter"], 250) - self.assertEqual(output["itc_elg"]["itc_avl"][4]["iamt"], 45) + self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50) + self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50) def make_sales_invoice(): si = create_sales_invoice(company="_Test Company GST", @@ -158,10 +159,18 @@ def create_purchase_invoices(): pi.append("taxes", { "charge_type": "On Net Total", - "account_head": "IGST - _GST", + "account_head": "CGST - _GST", "cost_center": "Main - _GST", - "description": "IGST @ 18.0", - "rate": 18 + "description": "CGST @ 9.0", + "rate": 9 + }) + + pi.append("taxes", { + "charge_type": "On Net Total", + "account_head": "SGST - _GST", + "cost_center": "Main - _GST", + "description": "SGST @ 9.0", + "rate": 9 }) pi.submit() diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py index 46c874b252..0ed98b74ee 100644 --- a/erpnext/regional/india/__init__.py +++ b/erpnext/regional/india/__init__.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from six import iteritems states = [ '', @@ -79,4 +80,6 @@ state_numbers = { "Uttar Pradesh": "09", "Uttarakhand": "05", "West Bengal": "19", -} \ No newline at end of file +} + +number_state_mapping = {v: k for k, v in iteritems(state_numbers)} \ No newline at end of file diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 756c17dc3b..14fdba013c 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -107,7 +107,12 @@ def make_custom_fields(update=True): dict(fieldname='gst_category', label='GST Category', fieldtype='Select', insert_after='gst_section', print_hide=1, options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nUIN Holders', - fetch_from='supplier.gst_category', fetch_if_empty=1) + fetch_from='supplier.gst_category', fetch_if_empty=1), + dict(fieldname='export_type', label='Export Type', + fieldtype='Select', insert_after='gst_category', print_hide=1, + depends_on='eval:in_list(["SEZ", "Overseas"], doc.gst_category)', + options='\nWith Payment of Tax\nWithout Payment of Tax', fetch_from='supplier.export_type', + fetch_if_empty=1), ] sales_invoice_gst_category = [ @@ -116,20 +121,21 @@ def make_custom_fields(update=True): dict(fieldname='gst_category', label='GST Category', fieldtype='Select', insert_after='gst_section', print_hide=1, options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders', - fetch_from='customer.gst_category', fetch_if_empty=1) + fetch_from='customer.gst_category', fetch_if_empty=1), + dict(fieldname='export_type', label='Export Type', + fieldtype='Select', insert_after='gst_category', print_hide=1, + depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', + options='\nWith Payment of Tax\nWithout Payment of Tax', fetch_from='customer.export_type', + fetch_if_empty=1), ] invoice_gst_fields = [ dict(fieldname='invoice_copy', label='Invoice Copy', - fieldtype='Select', insert_after='gst_category', print_hide=1, allow_on_submit=1, + fieldtype='Select', insert_after='export_type', print_hide=1, allow_on_submit=1, options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier'), dict(fieldname='reverse_charge', label='Reverse Charge', fieldtype='Select', insert_after='invoice_copy', print_hide=1, options='Y\nN', default='N'), - dict(fieldname='export_type', label='Export Type', - fieldtype='Select', insert_after='reverse_charge', print_hide=1, - depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', - options='\nWith Payment of Tax\nWithout Payment of Tax'), dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN', fieldtype='Data', insert_after='export_type', print_hide=1), dict(fieldname='gst_col_break', fieldtype='Column Break', insert_after='ecommerce_gstin'), @@ -142,13 +148,13 @@ def make_custom_fields(update=True): purchase_invoice_gst_fields = [ dict(fieldname='supplier_gstin', label='Supplier GSTIN', fieldtype='Data', insert_after='supplier_address', - fetch_from='supplier_address.gstin', print_hide=1), + fetch_from='supplier_address.gstin', print_hide=1, read_only=1), dict(fieldname='company_gstin', label='Company GSTIN', fieldtype='Data', insert_after='shipping_address_display', - fetch_from='shipping_address.gstin', print_hide=1), + fetch_from='shipping_address.gstin', print_hide=1, read_only=1), dict(fieldname='place_of_supply', label='Place of Supply', fieldtype='Data', insert_after='shipping_address', - print_hide=1, read_only=0), + print_hide=1, read_only=1), ] purchase_invoice_itc_fields = [ @@ -167,17 +173,17 @@ def make_custom_fields(update=True): sales_invoice_gst_fields = [ dict(fieldname='billing_address_gstin', label='Billing Address GSTIN', - fieldtype='Data', insert_after='customer_address', + fieldtype='Data', insert_after='customer_address', read_only=1, fetch_from='customer_address.gstin', print_hide=1), dict(fieldname='customer_gstin', label='Customer GSTIN', fieldtype='Data', insert_after='shipping_address_name', fetch_from='shipping_address_name.gstin', print_hide=1), dict(fieldname='place_of_supply', label='Place of Supply', fieldtype='Data', insert_after='customer_gstin', - print_hide=1, read_only=0), + print_hide=1, read_only=1), dict(fieldname='company_gstin', label='Company GSTIN', fieldtype='Data', insert_after='company_address', - fetch_from='company_address.gstin', print_hide=1), + fetch_from='company_address.gstin', print_hide=1, read_only=1), ] sales_invoice_shipping_fields = [ @@ -194,7 +200,11 @@ def make_custom_fields(update=True): inter_state_gst_field = [ dict(fieldname='is_inter_state', label='Is Inter State', - fieldtype='Check', insert_after='disabled', print_hide=1) + fieldtype='Check', insert_after='disabled', print_hide=1), + dict(fieldname='tax_category_column_break', fieldtype='Column Break', + insert_after='is_inter_state'), + dict(fieldname='gst_state', label='Source State', fieldtype='Select', + options='\n'.join(states), insert_after='company') ] ewaybill_fields = [ @@ -374,8 +384,7 @@ def make_custom_fields(update=True): 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields, 'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields, 'Sales Order': sales_invoice_gst_fields, - 'Sales Taxes and Charges Template': inter_state_gst_field, - 'Purchase Taxes and Charges Template': inter_state_gst_field, + 'Tax Category': inter_state_gst_field, 'Item': [ dict(fieldname='gst_hsn_code', label='HSN/SAC', fieldtype='Link', options='GST HSN Code', insert_after='item_group'), @@ -459,6 +468,15 @@ def make_custom_fields(update=True): 'insert_after': 'gst_transporter_id', 'options': 'Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nUIN Holders', 'default': 'Unregistered' + }, + { + 'fieldname': 'export_type', + 'label': 'Export Type', + 'fieldtype': 'Select', + 'insert_after': 'gst_category', + 'default': 'Without Payment of Tax', + 'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)', + 'options': '\nWith Payment of Tax\nWithout Payment of Tax' } ], 'Customer': [ @@ -469,6 +487,15 @@ def make_custom_fields(update=True): 'insert_after': 'customer_type', 'options': 'Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders', 'default': 'Unregistered' + }, + { + 'fieldname': 'export_type', + 'label': 'Export Type', + 'fieldtype': 'Select', + 'insert_after': 'gst_category', + 'default': 'Without Payment of Tax', + 'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', + 'options': '\nWith Payment of Tax\nWithout Payment of Tax' } ] } diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js new file mode 100644 index 0000000000..1e59032db1 --- /dev/null +++ b/erpnext/regional/india/taxes.js @@ -0,0 +1,41 @@ +erpnext.setup_auto_gst_taxation = (doctype) => { + frappe.ui.form.on(doctype, { + company_address: function(frm) { + frm.trigger('get_tax_template'); + }, + shipping_address: function(frm) { + frm.trigger('get_tax_template'); + }, + tax_category: function(frm) { + frm.trigger('get_tax_template'); + }, + get_tax_template: function(frm) { + let party_details = { + 'shipping_address': frm.doc.shipping_address || '', + 'shipping_address_name': frm.doc.shipping_address_name || '', + 'customer_address': frm.doc.customer_address || '', + 'customer': frm.doc.customer, + 'supplier': frm.doc.supplier, + 'supplier_gstin': frm.doc.supplier_gstin, + 'company_gstin': frm.doc.company_gstin, + 'tax_category': frm.doc.tax_category + }; + + frappe.call({ + method: 'erpnext.regional.india.utils.get_regional_address_details', + args: { + party_details: JSON.stringify(party_details), + doctype: frm.doc.doctype, + company: frm.doc.company, + return_taxes: 1 + }, + callback: function(r) { + if(r.message) { + frm.set_value('taxes_and_charges', r.message.taxes_and_charges); + } + } + }); + } + }); +}; + diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index aae07797a1..77bcc80aba 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -7,6 +7,8 @@ from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_ from erpnext.controllers.accounts_controller import get_taxes_and_charges from erpnext.hr.utils import get_salary_assignment from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip +from erpnext.regional.india import number_state_mapping +from six import string_types def validate_gstin_for_india(doc, method): if hasattr(doc, 'gst_state') and doc.gst_state: @@ -46,6 +48,14 @@ def validate_gstin_for_india(doc, method): frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.") .format(doc.gst_state_number)) +def update_gst_category(doc, method): + for link in doc.links: + if link.link_doctype in ['Customer', 'Supplier']: + if doc.get('gstin'): + frappe.db.sql(""" + UPDATE `tab{0}` SET gst_category = %s WHERE name = %s AND gst_category = 'Unregistered' + """.format(link.link_doctype), ("Registered Regular", link.link_name)) #nosec + def set_gst_state_and_state_number(doc): if not doc.gst_state: if not doc.state: @@ -122,44 +132,106 @@ def test_method(): '''test function''' return 'overridden' -def get_place_of_supply(out, doctype): +def get_place_of_supply(party_details, doctype): if not frappe.get_meta('Address').has_field('gst_state'): return - if doctype in ("Sales Invoice", "Delivery Note"): - address_name = out.shipping_address_name or out.customer_address - elif doctype == "Purchase Invoice": - address_name = out.shipping_address or out.supplier_address + if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"): + address_name = party_details.shipping_address_name or party_details.customer_address + elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"): + address_name = party_details.shipping_address or party_details.supplier_address if address_name: address = frappe.db.get_value("Address", address_name, ["gst_state", "gst_state_number"], as_dict=1) if address and address.gst_state and address.gst_state_number: return cstr(address.gst_state_number) + "-" + cstr(address.gst_state) -def get_regional_address_details(out, doctype, company): - out.place_of_supply = get_place_of_supply(out, doctype) +@frappe.whitelist() +def get_regional_address_details(party_details, doctype, company, return_taxes=None): - if not out.place_of_supply: return + if isinstance(party_details, string_types): + party_details = json.loads(party_details) + party_details = frappe._dict(party_details) - if doctype in ("Sales Invoice", "Delivery Note"): + party_details.place_of_supply = get_place_of_supply(party_details, doctype) + if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"): master_doctype = "Sales Taxes and Charges Template" - if not out.company_gstin: - return - elif doctype == "Purchase Invoice": - master_doctype = "Purchase Taxes and Charges Template" - if not out.supplier_gstin: + + get_tax_template_for_sez(party_details, master_doctype, company, 'Customer') + get_tax_template_based_on_category(master_doctype, company, party_details) + + if party_details.get('taxes_and_charges') and return_taxes: + return party_details + + if not party_details.company_gstin: return - if ((doctype in ("Sales Invoice", "Delivery Note") and out.company_gstin - and out.company_gstin[:2] != out.place_of_supply[:2]) or (doctype == "Purchase Invoice" - and out.supplier_gstin and out.supplier_gstin[:2] != out.place_of_supply[:2])): - default_tax = frappe.db.get_value(master_doctype, {"company": company, "is_inter_state":1, "disabled":0}) + elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"): + master_doctype = "Purchase Taxes and Charges Template" + + get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier') + get_tax_template_based_on_category(master_doctype, company, party_details) + + if party_details.get('taxes_and_charges') and return_taxes: + return party_details + + if not party_details.supplier_gstin: + return + + if not party_details.place_of_supply: return + + if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin + and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice", + "Purchase Order", "Purchase Receipt") and party_details.supplier_gstin and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2])): + default_tax = get_tax_template(master_doctype, company, 1, party_details.company_gstin[:2]) else: - default_tax = frappe.db.get_value(master_doctype, {"company": company, "disabled":0, "is_default": 1}) + default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2]) if not default_tax: return - out["taxes_and_charges"] = default_tax - out.taxes = get_taxes_and_charges(master_doctype, default_tax) + party_details["taxes_and_charges"] = default_tax + party_details.taxes = get_taxes_and_charges(master_doctype, default_tax) + + if return_taxes: + return party_details + +def get_tax_template_based_on_category(master_doctype, company, party_details): + if not party_details.get('tax_category'): + return + + default_tax = frappe.db.get_value(master_doctype, {'company': company, 'tax_category': party_details.get('tax_category')}, + 'name') + + if default_tax: + party_details["taxes_and_charges"] = default_tax + party_details.taxes = get_taxes_and_charges(master_doctype, default_tax) + +def get_tax_template(master_doctype, company, is_inter_state, state_code): + tax_categories = frappe.get_all('Tax Category', fields = ['name', 'is_inter_state', 'gst_state'], + filters = {'is_inter_state': is_inter_state}) + + default_tax = '' + + for tax_category in tax_categories: + if tax_category.gst_state == number_state_mapping[state_code] or \ + (not default_tax and not tax_category.gst_state): + default_tax = frappe.db.get_value(master_doctype, + {'disabled': 0, 'tax_category': tax_category.name}, 'name') + + return default_tax + +def get_tax_template_for_sez(party_details, master_doctype, company, party_type): + + gst_details = frappe.db.get_value(party_type, {'name': party_details.get(frappe.scrub(party_type))}, + ['gst_category', 'export_type'], as_dict=1) + + if gst_details: + if gst_details.gst_category == 'SEZ' and gst_details.export_type == 'With Payment of Tax': + default_tax = frappe.db.get_value(master_doctype, {"company": company, "is_inter_state":1, "disabled":0, + "gst_state": number_state_mapping[party_details.company_gstin[:2]]}) + + party_details["taxes_and_charges"] = default_tax + party_details.taxes = get_taxes_and_charges(master_doctype, default_tax) + def calculate_annual_eligible_hra_exemption(doc): basic_component = frappe.get_cached_value('Company', doc.company, "basic_component") @@ -555,7 +627,7 @@ def get_gst_accounts(company, account_wise=False): filters={"parent": "GST Settings", "company": company}, fields=["cgst_account", "sgst_account", "igst_account", "cess_account"]) - if not gst_settings_accounts: + if not gst_settings_accounts and not frappe.flags.in_test: frappe.throw(_("Please set GST Accounts in GST Settings")) for d in gst_settings_accounts: diff --git a/erpnext/selling/doctype/sales_order/regional/india.js b/erpnext/selling/doctype/sales_order/regional/india.js new file mode 100644 index 0000000000..c11cfcc50b --- /dev/null +++ b/erpnext/selling/doctype/sales_order/regional/india.js @@ -0,0 +1,3 @@ +{% include "erpnext/regional/india/taxes.js" %} + +erpnext.setup_auto_gst_taxation('Sales Order'); diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index e97a4ee461..2112a4174b 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -578,8 +578,12 @@ def make_delivery_note(source_name, target_doc=None, skip_item_mapping=False): target.run_method("set_po_nos") target.run_method("calculate_taxes_and_totals") - # set company address - target.update(get_company_address(target.company)) + if source.company_address: + target.update({'company_address': source.company_address}) + else: + # set company address + target.update(get_company_address(target.company)) + if target.company_address: target.update(get_fetch_values("Delivery Note", 'company_address', target.company_address)) @@ -645,8 +649,12 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): target.run_method("set_po_nos") target.run_method("calculate_taxes_and_totals") - # set company address - target.update(get_company_address(target.company)) + if source.company_address: + target.update({'company_address': source.company_address}) + else: + # set company address + target.update(get_company_address(target.company)) + if target.company_address: target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address)) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 04e8a83e7f..2eee919b53 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -14,6 +14,8 @@ from frappe.model.document import Document from frappe.contacts.address_and_contact import load_address_and_contact from frappe.utils.nestedset import NestedSet +import functools + class Company(NestedSet): nsm_parent_field = 'parent_company' @@ -560,3 +562,26 @@ def get_timeline_data(doctype, name): return json.loads(history) if history and '{' in history else {} return date_to_value_dict + +@frappe.whitelist() +def get_default_company_address(name, sort_key='is_primary_address', existing_address=None): + if sort_key not in ['is_shipping_address', 'is_primary_address']: + return None + + out = frappe.db.sql(""" SELECT + addr.name, addr.%s + FROM + `tabAddress` addr, `tabDynamic Link` dl + WHERE + dl.parent = addr.name and dl.link_doctype = 'Company' and + dl.link_name = %s and ifnull(addr.disabled, 0) = 0 + """ %(sort_key, '%s'), (name)) #nosec + + if existing_address: + if existing_address in [d[0] for d in out]: + return existing_address + + if out: + return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0] + else: + return None \ No newline at end of file diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index c98dfe35fb..39aad2e007 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -424,7 +424,12 @@ def make_sales_invoice(source_name, target_doc=None): target.run_method("calculate_taxes_and_totals") # set company address - target.update(get_company_address(target.company)) + if source.company_address: + target.update({'company_address': source.company_address}) + else: + # set company address + target.update(get_company_address(target.company)) + if target.company_address: target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address)) diff --git a/erpnext/stock/doctype/delivery_note/regional/india.js b/erpnext/stock/doctype/delivery_note/regional/india.js new file mode 100644 index 0000000000..22f4716ea5 --- /dev/null +++ b/erpnext/stock/doctype/delivery_note/regional/india.js @@ -0,0 +1,4 @@ +{% include "erpnext/regional/india/taxes.js" %} + +erpnext.setup_auto_gst_taxation('Delivery Note'); + diff --git a/erpnext/stock/doctype/purchase_receipt/regional/india.js b/erpnext/stock/doctype/purchase_receipt/regional/india.js new file mode 100644 index 0000000000..b4f1201f36 --- /dev/null +++ b/erpnext/stock/doctype/purchase_receipt/regional/india.js @@ -0,0 +1,3 @@ +{% include "erpnext/regional/india/taxes.js" %} + +erpnext.setup_auto_gst_taxation('Purchase Receipt'); \ No newline at end of file From 664d0d89b53f4a39df3566a4c87694e432c234c3 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 10 Dec 2019 21:32:17 +0530 Subject: [PATCH 32/98] fix: incorrect account mapping for child companies (#19887) * fix: incorrect account mapping for child companies on adding account to parent company * Update account.py --- erpnext/accounts/doctype/account/account.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index cccced8e0b..cf1748f6a7 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -109,12 +109,13 @@ class Account(NestedSet): if not descendants: return parent_acc_name_map = {} - parent_acc_name = frappe.db.get_value('Account', self.parent_account, "account_name") + parent_acc_name, parent_acc_number = frappe.db.get_value('Account', self.parent_account, \ + ["account_name", "account_number"]) for d in frappe.db.get_values('Account', - {"company": ["in", descendants], "account_name": parent_acc_name}, + { "company": ["in", descendants], "account_name": parent_acc_name, + "account_number": parent_acc_number }, ["company", "name"], as_dict=True): parent_acc_name_map[d["company"]] = d["name"] - if not parent_acc_name_map: return self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name) From c58495dceedad0031fa946abc862c0de37956c26 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 10 Dec 2019 21:34:03 +0530 Subject: [PATCH 33/98] fix: Item-wise Sales History report not working (#19889) --- .../item_wise_sales_history/item_wise_sales_history.js | 4 ++++ .../item_wise_sales_history/item_wise_sales_history.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js index ee806a78fb..daca2e3bd0 100644 --- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js +++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js @@ -20,11 +20,15 @@ frappe.query_reports["Item-wise Sales History"] = { }, { fieldname:"from_date", + reqd: 1, label: __("From Date"), fieldtype: "Date", + default: frappe.datetime.add_months(frappe.datetime.get_today(), -1), }, { fieldname:"to_date", + reqd: 1, + default: frappe.datetime.get_today(), label: __("To Date"), fieldtype: "Date", }, diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py index 226c34f735..1fc3663bed 100644 --- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py +++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py @@ -196,6 +196,7 @@ def get_customer_details(): def get_sales_order_details(company_list, filters): conditions = get_conditions(filters) + return frappe.db.sql(""" SELECT so_item.item_code, so_item.item_name, so_item.item_group, @@ -208,7 +209,6 @@ def get_sales_order_details(company_list, filters): `tabSales Order` so, `tabSales Order Item` so_item WHERE so.name = so_item.parent - AND so.company in (%s) - AND so.docstatus = 1 - {0} - """.format(conditions), company_list, as_dict=1) #nosec + AND so.company in ({0}) + AND so.docstatus = 1 {1} + """.format(','.join(["%s"] * len(company_list)), conditions), tuple(company_list), as_dict=1) From 6aa763221b658453d59b01706ce788ea0914d7a3 Mon Sep 17 00:00:00 2001 From: Pranav Nachnekar Date: Tue, 10 Dec 2019 16:05:28 +0000 Subject: [PATCH 34/98] fix: rename appointment booking route (#19886) * rename appoinment booking route * fix: replace all references to book-appointment route --- erpnext/crm/doctype/appointment/appointment.py | 2 +- erpnext/support/web_form/issues/issues.json | 2 +- .../{book-appointment => book_appointment}/__init__.py | 0 .../www/{book-appointment => book_appointment}/index.css | 0 .../www/{book-appointment => book_appointment}/index.html | 2 +- .../www/{book-appointment => book_appointment}/index.js | 8 ++++---- .../www/{book-appointment => book_appointment}/index.py | 0 .../verify/__init__.py | 0 .../verify/index.html | 0 .../verify/index.py | 0 10 files changed, 7 insertions(+), 7 deletions(-) rename erpnext/www/{book-appointment => book_appointment}/__init__.py (100%) rename erpnext/www/{book-appointment => book_appointment}/index.css (100%) rename erpnext/www/{book-appointment => book_appointment}/index.html (98%) rename erpnext/www/{book-appointment => book_appointment}/index.js (96%) rename erpnext/www/{book-appointment => book_appointment}/index.py (100%) rename erpnext/www/{book-appointment => book_appointment}/verify/__init__.py (100%) rename erpnext/www/{book-appointment => book_appointment}/verify/index.html (100%) rename erpnext/www/{book-appointment => book_appointment}/verify/index.py (100%) diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py index 2affba2ac4..b6c4c4707d 100644 --- a/erpnext/crm/doctype/appointment/appointment.py +++ b/erpnext/crm/doctype/appointment/appointment.py @@ -171,7 +171,7 @@ class Appointment(Document): self.save(ignore_permissions=True) def _get_verify_url(self): - verify_route = '/book-appointment/verify' + verify_route = '/book_appointment/verify' params = { 'email': self.customer_email, 'appointment': self.name diff --git a/erpnext/support/web_form/issues/issues.json b/erpnext/support/web_form/issues/issues.json index 652114f738..9b904ad796 100644 --- a/erpnext/support/web_form/issues/issues.json +++ b/erpnext/support/web_form/issues/issues.json @@ -18,7 +18,7 @@ "is_standard": 1, "login_required": 1, "max_attachment_size": 0, - "modified": "2019-06-27 22:58:49.609672", + "modified": "2019-12-10 13:48:19.894186", "modified_by": "Administrator", "module": "Support", "name": "issues", diff --git a/erpnext/www/book-appointment/__init__.py b/erpnext/www/book_appointment/__init__.py similarity index 100% rename from erpnext/www/book-appointment/__init__.py rename to erpnext/www/book_appointment/__init__.py diff --git a/erpnext/www/book-appointment/index.css b/erpnext/www/book_appointment/index.css similarity index 100% rename from erpnext/www/book-appointment/index.css rename to erpnext/www/book_appointment/index.css diff --git a/erpnext/www/book-appointment/index.html b/erpnext/www/book_appointment/index.html similarity index 98% rename from erpnext/www/book-appointment/index.html rename to erpnext/www/book_appointment/index.html index 96774d5656..f242f43ad5 100644 --- a/erpnext/www/book-appointment/index.html +++ b/erpnext/www/book_appointment/index.html @@ -4,7 +4,7 @@ {% block script %} - + {% endblock %} {% block page_content %} diff --git a/erpnext/www/book-appointment/index.js b/erpnext/www/book_appointment/index.js similarity index 96% rename from erpnext/www/book-appointment/index.js rename to erpnext/www/book_appointment/index.js index 13c87ddbcf..c8dd5013d5 100644 --- a/erpnext/www/book-appointment/index.js +++ b/erpnext/www/book_appointment/index.js @@ -15,10 +15,10 @@ async function initialise_select_date() { async function get_global_variables() { // Using await through this file instead of then. window.appointment_settings = (await frappe.call({ - method: 'erpnext.www.book-appointment.index.get_appointment_settings' + method: 'erpnext.www.book_appointment.index.get_appointment_settings' })).message; window.timezones = (await frappe.call({ - method:'erpnext.www.book-appointment.index.get_timezones' + method:'erpnext.www.book_appointment.index.get_timezones' })).message; window.holiday_list = window.appointment_settings.holiday_list; } @@ -79,7 +79,7 @@ function on_date_or_timezone_select() { async function get_time_slots(date, timezone) { let slots = (await frappe.call({ - method: 'erpnext.www.book-appointment.index.get_appointment_slots', + method: 'erpnext.www.book_appointment.index.get_appointment_slots', args: { date: date, timezone: timezone @@ -201,7 +201,7 @@ async function submit() { } let contact = get_form_data(); let appointment = frappe.call({ - method: 'erpnext.www.book-appointment.index.create_appointment', + method: 'erpnext.www.book_appointment.index.create_appointment', args: { 'date': window.selected_date, 'time': window.selected_time, diff --git a/erpnext/www/book-appointment/index.py b/erpnext/www/book_appointment/index.py similarity index 100% rename from erpnext/www/book-appointment/index.py rename to erpnext/www/book_appointment/index.py diff --git a/erpnext/www/book-appointment/verify/__init__.py b/erpnext/www/book_appointment/verify/__init__.py similarity index 100% rename from erpnext/www/book-appointment/verify/__init__.py rename to erpnext/www/book_appointment/verify/__init__.py diff --git a/erpnext/www/book-appointment/verify/index.html b/erpnext/www/book_appointment/verify/index.html similarity index 100% rename from erpnext/www/book-appointment/verify/index.html rename to erpnext/www/book_appointment/verify/index.html diff --git a/erpnext/www/book-appointment/verify/index.py b/erpnext/www/book_appointment/verify/index.py similarity index 100% rename from erpnext/www/book-appointment/verify/index.py rename to erpnext/www/book_appointment/verify/index.py From 9046c13858be493e53be47312fbb3d5c1670cb2d Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Tue, 10 Dec 2019 21:37:27 +0530 Subject: [PATCH 35/98] fix: added extra condition (#19884) --- erpnext/hr/doctype/leave_application/leave_application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 65fcbf7a99..915cea149d 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -351,7 +351,7 @@ class LeaveApplication(Document): pass def create_leave_ledger_entry(self, submit=True): - if self.status != 'Approved': + if self.status != 'Approved' and submit: return expiry_date = get_allocation_expiry(self.employee, self.leave_type, From 5380a4c3db67cf8e69fce0c7c06661c893a4fee4 Mon Sep 17 00:00:00 2001 From: Khushal Trivedi Date: Tue, 10 Dec 2019 21:38:42 +0530 Subject: [PATCH 36/98] fix-education: date of birth validation on student form (#19875) * fix: date validation on inpatient record, else condition removing on clinical prcd templ which is not req * fix:Pricing Rule error AttributeError: 'str' object has no attribute 'get' #19770 * fix:Pricing Rule error AttributeError: 'str' object has no attribute 'get' #19770 * fix: joining and relieving Date can be on same date as valid use case * fix-education: date of birth validation --- erpnext/education/doctype/student/student.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py index 76825cec1b..8e4b4e16f9 100644 --- a/erpnext/education/doctype/student/student.py +++ b/erpnext/education/doctype/student/student.py @@ -5,12 +5,14 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe.utils import getdate,today from frappe import _ from frappe.desk.form.linked_with import get_linked_doctypes from erpnext.education.utils import check_content_completion, check_quiz_completion class Student(Document): def validate(self): self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name])) + self.validate_dates() if self.student_applicant: self.check_unique() @@ -19,6 +21,10 @@ class Student(Document): if frappe.get_value("Student", self.name, "title") != self.title: self.update_student_name_in_linked_doctype() + def validate_dates(self): + if self.date_of_birth and getdate(self.date_of_birth) >= getdate(today()): + frappe.throw(_("Date of Birth cannot be greater than today.")) + def update_student_name_in_linked_doctype(self): linked_doctypes = get_linked_doctypes("Student") for d in linked_doctypes: From 9e32f587f5ab35142c4945ace04ba48718a32335 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Tue, 10 Dec 2019 17:11:05 +0100 Subject: [PATCH 37/98] fix: remove contact info, use international format (#19828) - for international letters, city and country should be upper case: https://www.deutschepost.de/content/dam/dpag/images/B_b/Briefe_ins_Ausland/downloads/dp-brief-international-handlingbroschuere-072019.pdf#page=15 - it is not customary, to use contact information such as phone number in the address --- erpnext/regional/germany/address_template.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/regional/germany/address_template.html b/erpnext/regional/germany/address_template.html index 0df786713c..7fa4c32612 100644 --- a/erpnext/regional/germany/address_template.html +++ b/erpnext/regional/germany/address_template.html @@ -1,8 +1,8 @@ {{ address_line1 }}
{% if address_line2 %}{{ address_line2 }}
{% endif -%} -{{ pincode }} {{ city }}
-{% if country %}{{ country }}
{% endif -%} -
-{% if phone %}Tel: {{ phone }}
{% endif -%} -{% if fax %}Fax: {{ fax }}
{% endif -%} -{% if email_id %}E-Mail: {{ email_id }}
{% endif -%} +{% if country in ["Germany", "Deutschland"] %} + {{ pincode }} {{ city }} +{% else %} + {{ pincode }} {{ city | upper }}
+ {{ country | upper }} +{% endif %} From ca6dbad7cb8c4566cd811dd21162035b2279795f Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 11 Dec 2019 12:10:05 +0530 Subject: [PATCH 38/98] fix: Disable Rounded Total always showing field default value --- erpnext/public/js/controllers/buying.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 02c30587f6..926227b24c 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -30,7 +30,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ && frappe.meta.has_field(this.frm.doc.doctype, "disable_rounded_total")) { var df = frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total"); - var disable = df.default || cint(frappe.sys_defaults.disable_rounded_total); + var disable = cint(df.default) || cint(frappe.sys_defaults.disable_rounded_total); this.frm.set_value("disable_rounded_total", disable); } From 45e4b73e08e231862b264687d10849b3b9e4864e Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 11 Dec 2019 13:07:41 +0530 Subject: [PATCH 39/98] fix: rename fields --- .../quality_action_resolution/quality_action_resolution.json | 2 +- .../quality_procedure_process/quality_procedure_process.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json index 74370cc3ef..a4e6aed86a 100644 --- a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json +++ b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json @@ -13,7 +13,7 @@ "fieldname": "problem", "fieldtype": "Long Text", "in_list_view": 1, - "label": "Problem" + "label": "Review" }, { "fieldname": "sb_00", diff --git a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json index f5c0fbc252..0a67fa505e 100644 --- a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json +++ b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json @@ -18,7 +18,7 @@ "fieldname": "procedure", "fieldtype": "Link", "in_list_view": 1, - "label": "Procedure", + "label": "Child Procedure", "options": "Quality Procedure" } ], From 37cf096102abf4b9520a7a78b4fa2867700d1488 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 11 Dec 2019 13:33:23 +0530 Subject: [PATCH 40/98] fix: not able to cancel the landed cost voucher --- erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index d0fae6a227..ad2f07d084 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -609,7 +609,7 @@ def make_stock_entry(source_name,target_doc=None): def get_item_account_wise_additional_cost(purchase_document): landed_cost_voucher = frappe.get_value("Landed Cost Purchase Receipt", - {"receipt_document": purchase_document}, "parent") + {"receipt_document": purchase_document, "docstatus": 1}, "parent") if not landed_cost_voucher: return From 2ef26fbb0704b6ddd560708584625acca2e437ac Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 11 Dec 2019 14:21:04 +0530 Subject: [PATCH 41/98] fix: empty fname and fcontent of uploaded file --- .../doctype/bank_transaction/bank_transaction_upload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py index deedafdfb5..33ae45439e 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py @@ -15,8 +15,8 @@ def upload_bank_statement(): with open(frappe.uploaded_file, "rb") as upfile: fcontent = upfile.read() else: - from frappe.utils.file_manager import get_uploaded_content - fname, fcontent = get_uploaded_content() + fcontent = frappe.local.uploaded_file + fname = frappe.local.uploaded_filename if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')): from frappe.utils.csvutils import read_csv_content From d3605d235400813ae62ef2b346f8e83bcbf7445f Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Wed, 11 Dec 2019 15:02:23 +0530 Subject: [PATCH 42/98] fix: issue in javascript timezones --- erpnext/www/book_appointment/index.js | 2 +- erpnext/www/book_appointment/index.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js index c8dd5013d5..5a814c6381 100644 --- a/erpnext/www/book_appointment/index.js +++ b/erpnext/www/book_appointment/index.js @@ -114,7 +114,7 @@ function get_timeslot_div_layout(timeslot) { timeslot_div.classList.add('unavailable') } timeslot_div.innerHTML = get_slot_layout(start_time); - timeslot_div.id = timeslot.time.substr(11, 20); + timeslot_div.id = timeslot.time.substring(11, 19); timeslot_div.addEventListener('click', select_time); return timeslot_div } diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py index 5b60dd5e7b..e4af7e8e43 100644 --- a/erpnext/www/book_appointment/index.py +++ b/erpnext/www/book_appointment/index.py @@ -90,7 +90,7 @@ def get_available_slots_between(query_start_time, query_end_time, settings): @frappe.whitelist(allow_guest=True) def create_appointment(date, time, tz, contact): - format_string = '%Y-%m-%d %H:%M:%S%z' + format_string = '%Y-%m-%d %H:%M:%S' scheduled_time = datetime.datetime.strptime(date + " " + time, format_string) # Strip tzinfo from datetime objects since it's handled by the doctype scheduled_time = scheduled_time.replace(tzinfo = None) From 5b622eace1d0c3602ecb820cccf6d0c769560e8f Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Wed, 11 Dec 2019 16:08:31 +0530 Subject: [PATCH 43/98] fix: handle scenario with no condition --- erpnext/portal/product_configurator/utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index 9c0120d416..2220892118 100644 --- a/erpnext/portal/product_configurator/utils.py +++ b/erpnext/portal/product_configurator/utils.py @@ -335,11 +335,13 @@ def get_items(filters=None, search=None): filter_condition = get_conditions(filters, 'and') - where_conditions = 'disabled = 0 and ' - - where_conditions += ' and '.join( + where_conditions = ' and '.join( [condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition] ) + if where_conditions: + where_conditions += ' and disabled = 0' + else: + where_conditions += 'disabled = 0' left_joins = [] for f in filters: From 9b0d7b93dd8c3e8a4d33a986fee256a8ee449699 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 12 Dec 2019 12:10:25 +0530 Subject: [PATCH 44/98] fix: not able to submit the landed cost voucher --- erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 8e34a8a479..060175f904 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -245,7 +245,7 @@ class PurchaseReceipt(BuyingController): negative_expense_to_be_booked += flt(d.item_tax_amount) # Amount added through landed-cost-voucher - if landed_cost_entries: + if d.landed_cost_voucher_amount and landed_cost_entries: for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]): gl_entries.append(self.get_gl_dict({ "account": account, @@ -622,8 +622,7 @@ def get_item_account_wise_additional_cost(purchase_document): based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on) for item in landed_cost_voucher_doc.items: - if item.receipt_document == purchase_document: - total_item_cost += item.get(based_on_field) + total_item_cost += item.get(based_on_field) for item in landed_cost_voucher_doc.items: if item.receipt_document == purchase_document: From f95267041da8b4c6ebda77ab9ffaa1d70e8dba23 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 12 Dec 2019 13:06:17 +0530 Subject: [PATCH 45/98] fix: Financial statement report - Hidden column should note be considered in the report - Remove hardcoded currency formatting - Remove duplicate letterhead in the report (print_template already adds one) - Remove extra quotes from Total Amount text --- .../accounts/report/financial_statements.html | 34 +++++++++++-------- .../accounts/report/financial_statements.py | 4 +-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/erpnext/accounts/report/financial_statements.html b/erpnext/accounts/report/financial_statements.html index 4081723bf0..50947ecf5e 100644 --- a/erpnext/accounts/report/financial_statements.html +++ b/erpnext/accounts/report/financial_statements.html @@ -1,5 +1,6 @@ {% var report_columns = report.get_columns_for_print(); + report_columns = report_columns.filter(col => !col.hidden); if (report_columns.length > 8) { frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application.")); @@ -15,34 +16,35 @@ height: 37px; } -{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) %} -{% if(letterhead) { %} -
- {%= frappe.boot.letter_heads[letterhead].header %} -
-{% } %} +

{%= __(report.report_name) %}

{%= filters.company %}

+ {% if 'cost_center' in filters %}

{%= filters.cost_center %}

{% endif %} +

{%= filters.fiscal_year %}

-
{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
+
+ {%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %} +
{% if (filters.from_date) { %} -

{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}

+
+ {%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %} +
{% } %}
- - {% for(var i=2, l=report_columns.length; i + {% for (let i=1, l=report_columns.length; i{%= report_columns[i].label %} {% } %} - {% for(var j=0, k=data.length-1; j {%= row.account_name %} - {% for(var i=2, l=report_columns.length; i - {% var fieldname = report_columns[i].fieldname; %} + {% const fieldname = report_columns[i].fieldname; %} {% if (!is_null(row[fieldname])) { %} - {%= format_currency(row[fieldname], filters.presentation_currency) %} + {%= frappe.format(row[fieldname], report_columns[i], {}, row) %} {% } %} {% } %} @@ -64,4 +66,6 @@ {% } %}
-

Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}

+

+ Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %} +

diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 3c8de6026a..40d5682726 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -264,8 +264,8 @@ def filter_out_zero_value_rows(data, parent_children_map, show_zero_values=False def add_total_row(out, root_type, balance_must_be, period_list, company_currency): total_row = { - "account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'", - "account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'", + "account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)), + "account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)), "currency": company_currency } From c58dc873d501b38edbc41c6100e60b277fe04d84 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 12 Dec 2019 14:55:57 +0530 Subject: [PATCH 46/98] fix: Get regional address details fix --- 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 77bcc80aba..0f9156a6b4 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -179,6 +179,8 @@ def get_regional_address_details(party_details, doctype, company, return_taxes=N if not party_details.place_of_supply: return + if not party_details.company_gstin: return + if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt") and party_details.supplier_gstin and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2])): From 0e33f792d3aae99c781e804b5fc27ceb497ad5eb Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 12 Dec 2019 16:34:41 +0530 Subject: [PATCH 47/98] fix: Distribute charges based on quantity if Total Basic Amount is Zero. --- .../stock/doctype/stock_entry/stock_entry.py | 12 +++--- .../doctype/stock_entry/test_stock_entry.py | 39 +++++++++++++------ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 913656ad02..00d27ef232 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -27,7 +27,6 @@ class IncorrectValuationRateError(frappe.ValidationError): pass class DuplicateEntryForWorkOrderError(frappe.ValidationError): pass class OperationsNotCompleteError(frappe.ValidationError): pass class MaxSampleAlreadyRetainedError(frappe.ValidationError): pass -class TotalBasicAmountZeroError(frappe.ValidationError): pass from erpnext.controllers.stock_controller import StockController @@ -650,11 +649,11 @@ class StockEntry(StockController): gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account) total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse]) + divide_based_on = total_basic_amount if self.get("additional_costs") and not total_basic_amount: - #If additional costs table is populated and total basic amount is - #somehow 0, interrupt transaction. - frappe.throw(_("Total Basic Amount in Items Table cannot be 0"), TotalBasicAmountZeroError) + # if total_basic_amount is 0, distribute additional charges based on qty + divide_based_on = sum(item.qty for item in list(self.get("items"))) item_account_wise_additional_cost = {} @@ -663,8 +662,11 @@ class StockEntry(StockController): if d.t_warehouse: item_account_wise_additional_cost.setdefault((d.item_code, d.name), {}) item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0) + + multiply_based_on = d.basic_amount if total_basic_amount else d.qty + item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \ - (t.amount * d.basic_amount) / total_basic_amount + (t.amount * multiply_based_on) / divide_based_on if item_account_wise_additional_cost: for d in self.get("items"): diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index c5e67092d3..ee5f237098 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -16,7 +16,6 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse, make_stock_in_entry from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError -from erpnext.stock.doctype.stock_entry.stock_entry import TotalBasicAmountZeroError from six import iteritems def get_sle(**args): @@ -798,14 +797,26 @@ class TestStockEntry(unittest.TestCase): "posting_date": nowdate(), "company":"_Test Company with perpetual inventory", "items":[ - {"item_code":"Basil Leaves", - "description":"Basil Leaves", - "qty": 1, - "basic_rate": 0, - "uom":"Nos", - "t_warehouse": "Stores - TCP1", - "allow_zero_valuation_rate": 1, - "cost_center": "Main - TCP1"} + { + "item_code":"Basil Leaves", + "description":"Basil Leaves", + "qty": 1, + "basic_rate": 0, + "uom":"Nos", + "t_warehouse": "Stores - TCP1", + "allow_zero_valuation_rate": 1, + "cost_center": "Main - TCP1" + }, + { + "item_code":"Basil Leaves", + "description":"Basil Leaves", + "qty": 2, + "basic_rate": 0, + "uom":"Nos", + "t_warehouse": "Stores - TCP1", + "allow_zero_valuation_rate": 1, + "cost_center": "Main - TCP1" + }, ], "additional_costs":[ {"expense_account":"Miscellaneous Expenses - TCP1", @@ -813,9 +824,15 @@ class TestStockEntry(unittest.TestCase): "description": "miscellanous"} ] }) - se.insert() - self.assertRaises(TotalBasicAmountZeroError, se.submit) + se.submit() + + self.check_gl_entries("Stock Entry", se.name, + sorted([ + ["Stock Adjustment - TCP1", 100.0, 0.0], + ["Miscellaneous Expenses - TCP1", 0.0, 100.0] + ]) + ) def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None): se = frappe.copy_doc(test_records[0]) From 81990aee9ff7fc385e3a6eb5a2e124f081d19829 Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 13 Dec 2019 13:12:10 +0530 Subject: [PATCH 48/98] fix: Removed 'manufacturers' table from Item Master --- erpnext/stock/doctype/item/item.json | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index a2aab3f69e..af8e13288a 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -135,8 +135,7 @@ "publish_in_hub", "hub_category_to_publish", "hub_warehouse", - "synced_with_hub", - "manufacturers" + "synced_with_hub" ], "fields": [ { @@ -1016,12 +1015,6 @@ "label": "Synced With Hub", "read_only": 1 }, - { - "fieldname": "manufacturers", - "fieldtype": "Table", - "label": "Manufacturers", - "options": "Item Manufacturer" - }, { "depends_on": "eval:!doc.__islocal", "fieldname": "over_delivery_receipt_allowance", @@ -1049,7 +1042,7 @@ "idx": 2, "image_field": "image", "max_attachments": 1, - "modified": "2019-10-09 17:05:59.576119", + "modified": "2019-12-13 12:15:56.197246", "modified_by": "Administrator", "module": "Stock", "name": "Item", From 8c9c6ec919570ce73432286b563e2f930b4f3212 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Fri, 13 Dec 2019 13:47:15 +0530 Subject: [PATCH 49/98] fix: Price rule filtering fix --- erpnext/accounts/doctype/pricing_rule/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 637e503e65..7af6748254 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -284,7 +284,7 @@ def filter_pricing_rules_for_qty_amount(qty, rate, pricing_rules, args=None): status = True # if user has created item price against the transaction UOM - if rule.get("uom") == args.get("uom"): + if args and rule.get("uom") == args.get("uom"): conversion_factor = 1.0 if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor) From bfc43d3b15d3dba788eeef5ad7d98777b0717a0b Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Fri, 13 Dec 2019 15:09:51 +0530 Subject: [PATCH 50/98] fix: gl entries doesn't filter based on debit precision --- erpnext/accounts/general_ledger.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index feb598a2e5..bb1b7e392d 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -90,8 +90,12 @@ def merge_similar_entries(gl_map): else: merged_gl_map.append(entry) + company = gl_map[0].company if gl_map else erpnext.get_default_company() + company_currency = erpnext.get_company_currency(company) + precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency) + # filter zero debit and credit entries - merged_gl_map = filter(lambda x: flt(x.debit, 9)!=0 or flt(x.credit, 9)!=0, merged_gl_map) + merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map) merged_gl_map = list(merged_gl_map) return merged_gl_map From 5da7e729a59db35c3616a56b7fc833d595cb6169 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Fri, 13 Dec 2019 15:44:39 +0530 Subject: [PATCH 51/98] fix: remove mandatory purchase reference for existing asset --- erpnext/assets/doctype/asset/asset.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 6b3f2c777c..f6a7fa20d0 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -144,6 +144,10 @@ frappe.ui.form.on('Asset', { frm.set_df_property('purchase_invoice', 'read_only', 1); frm.set_df_property('purchase_receipt', 'read_only', 1); } + else if (frm.doc.is_existing_asset) { + frm.toggle_reqd('purchase_receipt', 0); + frm.toggle_reqd('purchase_invoice', 0); + } else if (frm.doc.purchase_receipt) { // if purchase receipt link is set then set PI disabled frm.toggle_reqd('purchase_invoice', 0); @@ -256,6 +260,7 @@ frappe.ui.form.on('Asset', { }, is_existing_asset: function(frm) { + frm.trigger("toggle_reference_doc"); // frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation)); }, From 94ff8058acf448f4f7f60f8ea1535c1408676c4d Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Sat, 14 Dec 2019 21:25:30 +0530 Subject: [PATCH 52/98] fix: Add missing import --- erpnext/patches/v12_0/set_gst_category.py | 2 ++ erpnext/setup/doctype/company/company.py | 1 + 2 files changed, 3 insertions(+) diff --git a/erpnext/patches/v12_0/set_gst_category.py b/erpnext/patches/v12_0/set_gst_category.py index 54bc5b3c74..55bbdee7ed 100644 --- a/erpnext/patches/v12_0/set_gst_category.py +++ b/erpnext/patches/v12_0/set_gst_category.py @@ -7,6 +7,8 @@ def execute(): if not company: return + frappe.reload_doc('accounts', 'doctype', 'Tax Category') + make_custom_fields() for doctype in ['Sales Invoice', 'Purchase Invoice']: diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 2eee919b53..ff3515485c 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -14,6 +14,7 @@ from frappe.model.document import Document from frappe.contacts.address_and_contact import load_address_and_contact from frappe.utils.nestedset import NestedSet +from past.builtins import cmp import functools class Company(NestedSet): From 21fe97e72373cfae21572de39fa37a39732679c5 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 13 Dec 2019 16:18:38 +0530 Subject: [PATCH 53/98] fix: pricing rule not working for production discount --- .../doctype/pricing_rule/pricing_rule.json | 9 ++- .../doctype/pricing_rule/pricing_rule.py | 12 ++-- .../accounts/doctype/pricing_rule/utils.py | 57 +++++++++++++------ erpnext/controllers/accounts_controller.py | 4 +- erpnext/controllers/buying_controller.py | 8 +-- erpnext/public/js/controllers/transaction.js | 18 ++++++ 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 971d308368..f73fb10d32 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:title", @@ -439,19 +440,20 @@ }, { "default": "0", - "depends_on": "eval:!doc.mixed_conditions", + "depends_on": "eval:!doc.mixed_conditions && doc.price_or_product_discount == 'Price'", "fieldname": "same_item", "fieldtype": "Check", "label": "Same Item" }, { - "depends_on": "eval:!doc.same_item || doc.mixed_conditions", + "depends_on": "eval:(!doc.same_item || doc.apply_on == 'Transaction') || doc.mixed_conditions", "fieldname": "free_item", "fieldtype": "Link", "label": "Free Item", "options": "Item" }, { + "default": "0", "fieldname": "free_qty", "fieldtype": "Float", "label": "Qty" @@ -554,7 +556,8 @@ ], "icon": "fa fa-gift", "idx": 1, - "modified": "2019-10-15 12:39:40.399792", + "links": [], + "modified": "2019-12-13 15:48:48.331495", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index e871d98af6..af6e4c87af 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -182,7 +182,7 @@ def get_serial_no_for_item(args): def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False): from erpnext.accounts.doctype.pricing_rule.utils import (get_pricing_rules, - get_applied_pricing_rules, get_pricing_rule_items) + get_applied_pricing_rules, get_pricing_rule_items, get_product_discount_rule) if isinstance(doc, string_types): doc = json.loads(doc) @@ -241,9 +241,11 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa if pricing_rule.coupon_code_based==1 and args.coupon_code==None: return item_details - if (not pricing_rule.validate_applied_rule and - pricing_rule.price_or_product_discount == "Price"): - apply_price_discount_pricing_rule(pricing_rule, item_details, args) + if not pricing_rule.validate_applied_rule: + if pricing_rule.price_or_product_discount == "Price": + apply_price_discount_rule(pricing_rule, item_details, args) + else: + get_product_discount_rule(pricing_rule, item_details) item_details.has_pricing_rule = 1 @@ -293,7 +295,7 @@ def get_pricing_rule_details(args, pricing_rule): 'child_docname': args.get('child_docname') }) -def apply_price_discount_pricing_rule(pricing_rule, item_details, args): +def apply_price_discount_rule(pricing_rule, item_details, args): item_details.pricing_rule_for = pricing_rule.rate_or_discount if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 637e503e65..346eba259b 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import frappe, copy, json from frappe import throw, _ from six import string_types -from frappe.utils import flt, cint, get_datetime +from frappe.utils import flt, cint, get_datetime, get_link_to_form from erpnext.setup.doctype.item_group.item_group import get_child_item_groups from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses from erpnext.stock.get_item_details import get_conversion_factor @@ -408,7 +408,8 @@ def apply_pricing_rule_on_transaction(doc): conditions = get_other_conditions(conditions, values, doc) pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule` - where {conditions} """.format(conditions = conditions), values, as_dict=1) + where {conditions} and `tabPricing Rule`.disable = 0 + """.format(conditions = conditions), values, as_dict=1) if pricing_rules: pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty, @@ -420,39 +421,59 @@ def apply_pricing_rule_on_transaction(doc): doc.set('apply_discount_on', d.apply_discount_on) for field in ['additional_discount_percentage', 'discount_amount']: - if not d.get(field): continue - pr_field = ('discount_percentage' if field == 'additional_discount_percentage' else field) + if not d.get(pr_field): continue + if d.validate_applied_rule and doc.get(field) < d.get(pr_field): frappe.msgprint(_("User has not applied rule on the invoice {0}") .format(doc.name)) else: doc.set(field, d.get(pr_field)) + + doc.calculate_taxes_and_totals() elif d.price_or_product_discount == 'Product': - apply_pricing_rule_for_free_items(doc, d) + item_details = frappe._dict() + get_product_discount_rule(d, item_details) + apply_pricing_rule_for_free_items(doc, item_details.free_item_data) + doc.set_missing_values() def get_applied_pricing_rules(item_row): return (item_row.get("pricing_rules").split(',') if item_row.get("pricing_rules") else []) -def apply_pricing_rule_for_free_items(doc, pricing_rule): - if pricing_rule.get('free_item'): +def get_product_discount_rule(pricing_rule, item_details): + free_item = (pricing_rule.free_item + if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.item_code) + + if not free_item: + frappe.throw(_("Free item not set in the pricing rule {0}") + .format(get_link_to_form("Pricing Rule", pricing_rule.name))) + + item_details.free_item_data = { + 'item_code': free_item, + 'qty': pricing_rule.free_qty or 1, + 'rate': pricing_rule.free_item_rate or 0, + 'price_list_rate': pricing_rule.free_item_rate or 0, + 'is_free_item': 1 + } + + item_data = frappe.get_cached_value('Item', free_item, ['item_name', + 'description', 'stock_uom'], as_dict=1) + + item_details.free_item_data.update(item_data) + item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom + item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item, + item_details.free_item_data['uom']).get("conversion_factor", 1) + +def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False): + if pricing_rule_args.get('item_code'): items = [d.item_code for d in doc.items - if d.item_code == (d.item_code - if pricing_rule.get('same_item') else pricing_rule.get('free_item')) and d.is_free_item] + if d.item_code == (pricing_rule_args.get("item_code")) and d.is_free_item] if not items: - doc.append('items', { - 'item_code': pricing_rule.get('free_item'), - 'qty': pricing_rule.get('free_qty'), - 'uom': pricing_rule.get('free_item_uom'), - 'rate': pricing_rule.get('free_item_rate') or 0, - 'is_free_item': 1 - }) - - doc.set_missing_values() + doc.append('items', pricing_rule_args) def get_pricing_rule_items(pr_doc): apply_on_data = [] diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 75564afe59..6150516ac8 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -319,8 +319,8 @@ class AccountsController(TransactionBase): if item.get('discount_amount'): item.rate = item.price_list_rate - item.discount_amount - elif pricing_rule_args.get('free_item'): - apply_pricing_rule_for_free_items(self, pricing_rule_args) + elif pricing_rule_args.get('free_item_data'): + apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data')) elif pricing_rule_args.get("validate_applied_rule"): for pricing_rule in get_applied_pricing_rules(item): diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 3ec7aff9cb..17fba8ec4f 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -735,10 +735,6 @@ class BuyingController(StockController): if not self.get("items"): return - earliest_schedule_date = min([d.schedule_date for d in self.get("items")]) - if earliest_schedule_date: - self.schedule_date = earliest_schedule_date - if self.schedule_date: for d in self.get('items'): if not d.schedule_date: @@ -750,6 +746,10 @@ class BuyingController(StockController): else: frappe.throw(_("Please enter Reqd by Date")) + earliest_schedule_date = min([d.schedule_date for d in self.get("items")]) + if earliest_schedule_date: + self.schedule_date = earliest_schedule_date + def validate_items(self): # validate items to see if they have is_purchase_item or is_subcontracted_item enabled if self.doctype=="Material Request": return diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 46a58fba7c..1be4f27289 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1305,6 +1305,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ me.remove_pricing_rule(frappe.get_doc(d.doctype, d.name)); } + if (d.free_item_data) { + me.apply_product_discount(d.free_item_data); + } + if (d.apply_rule_on_other_items) { items_rule_dict[d.name] = d; } @@ -1334,6 +1338,20 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }, + apply_product_discount: function(free_item_data) { + const items = this.frm.doc.items.filter(d => (d.item_code == free_item_data.item_code + && d.is_free_item)) || []; + + if (!items.length) { + let row_to_modify = frappe.model.add_child(this.frm.doc, + this.frm.doc.doctype + ' Item', 'items'); + + for (let key in free_item_data) { + row_to_modify[key] = free_item_data[key]; + } + } + }, + apply_price_list: function(item, reset_plc_conversion) { // We need to reset plc_conversion_rate sometimes because the call to // `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value From 5ab823beab4d3b7e1f7093ec696984cf98d651ca Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 16 Dec 2019 12:08:41 +0530 Subject: [PATCH 54/98] fix: Removed validation from non existent manufacturers table --- erpnext/stock/doctype/item/item.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 189261cb2d..151be110fc 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -125,7 +125,6 @@ class Item(WebsiteGenerator): self.validate_auto_reorder_enabled_in_stock_settings() self.cant_change() self.update_show_in_website() - self.validate_manufacturer() if not self.get("__islocal"): self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group") @@ -145,13 +144,6 @@ class Item(WebsiteGenerator): if cint(frappe.db.get_single_value('Stock Settings', 'clean_description_html')): self.description = clean_html(self.description) - def validate_manufacturer(self): - list_man = [(x.manufacturer, x.manufacturer_part_no) for x in self.get('manufacturers')] - set_man = set(list_man) - - if len(list_man) != len(set_man): - frappe.throw(_("Duplicate entry in Manufacturers table")) - def validate_customer_provided_part(self): if self.is_customer_provided_item: if self.is_purchase_item: From 8bd84b28cae9cd513b3374dadad3c82202c12591 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 16 Dec 2019 12:29:07 +0530 Subject: [PATCH 55/98] fix: schedule date --- .../accounts/doctype/pricing_rule/pricing_rule.py | 2 +- erpnext/accounts/doctype/pricing_rule/utils.py | 14 ++++++++++---- erpnext/controllers/buying_controller.py | 8 ++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index af6e4c87af..b99c07e636 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -245,7 +245,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa if pricing_rule.price_or_product_discount == "Price": apply_price_discount_rule(pricing_rule, item_details, args) else: - get_product_discount_rule(pricing_rule, item_details) + get_product_discount_rule(pricing_rule, item_details, doc) item_details.has_pricing_rule = 1 diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 346eba259b..bd5a14971c 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import frappe, copy, json from frappe import throw, _ from six import string_types -from frappe.utils import flt, cint, get_datetime, get_link_to_form +from frappe.utils import flt, cint, get_datetime, get_link_to_form, today from erpnext.setup.doctype.item_group.item_group import get_child_item_groups from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses from erpnext.stock.get_item_details import get_conversion_factor @@ -434,8 +434,8 @@ def apply_pricing_rule_on_transaction(doc): doc.calculate_taxes_and_totals() elif d.price_or_product_discount == 'Product': - item_details = frappe._dict() - get_product_discount_rule(d, item_details) + item_details = frappe._dict({'parenttype': doc.doctype}) + get_product_discount_rule(d, item_details, doc) apply_pricing_rule_for_free_items(doc, item_details.free_item_data) doc.set_missing_values() @@ -443,7 +443,7 @@ def get_applied_pricing_rules(item_row): return (item_row.get("pricing_rules").split(',') if item_row.get("pricing_rules") else []) -def get_product_discount_rule(pricing_rule, item_details): +def get_product_discount_rule(pricing_rule, item_details, doc=None): free_item = (pricing_rule.free_item if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.item_code) @@ -467,6 +467,12 @@ def get_product_discount_rule(pricing_rule, item_details): item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item, item_details.free_item_data['uom']).get("conversion_factor", 1) + if item_details.get("parenttype") == 'Purchase Order': + item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today() + + if item_details.get("parenttype") == 'Sales Order': + item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today() + def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False): if pricing_rule_args.get('item_code'): items = [d.item_code for d in doc.items diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 17fba8ec4f..3ec7aff9cb 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -735,6 +735,10 @@ class BuyingController(StockController): if not self.get("items"): return + earliest_schedule_date = min([d.schedule_date for d in self.get("items")]) + if earliest_schedule_date: + self.schedule_date = earliest_schedule_date + if self.schedule_date: for d in self.get('items'): if not d.schedule_date: @@ -746,10 +750,6 @@ class BuyingController(StockController): else: frappe.throw(_("Please enter Reqd by Date")) - earliest_schedule_date = min([d.schedule_date for d in self.get("items")]) - if earliest_schedule_date: - self.schedule_date = earliest_schedule_date - def validate_items(self): # validate items to see if they have is_purchase_item or is_subcontracted_item enabled if self.doctype=="Material Request": return From e9c9cbd2fe981bd68d9a9fc36ce458b17e156821 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Mon, 16 Dec 2019 14:49:59 +0530 Subject: [PATCH 56/98] fix: display serial no selection on adding items to cart --- erpnext/selling/page/point_of_sale/point_of_sale.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js index b213a29ae7..33fbc229b6 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.js +++ b/erpnext/selling/page/point_of_sale/point_of_sale.js @@ -286,14 +286,14 @@ erpnext.pos.PointOfSale = class PointOfSale { if (in_list(['serial_no', 'batch_no'], field)) { args[field] = value; } - + // add to cur_frm const item = this.frm.add_child('items', args); frappe.flags.hide_serial_batch_dialog = true; frappe.run_serially([ () => { - this.frm.script_manager.trigger('item_code', item.doctype, item.name) + return this.frm.script_manager.trigger('item_code', item.doctype, item.name) .then(() => { this.frm.script_manager.trigger('qty', item.doctype, item.name) .then(() => { From f195ccd85ff7ca7b859c6606bb4f5476429fc884 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Mon, 16 Dec 2019 15:03:27 +0530 Subject: [PATCH 57/98] fix: review changes --- erpnext/portal/product_configurator/utils.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index 2220892118..0993e69e04 100644 --- a/erpnext/portal/product_configurator/utils.py +++ b/erpnext/portal/product_configurator/utils.py @@ -301,6 +301,8 @@ def get_items(filters=None, search=None): if isinstance(filters, dict): filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()] + enabled_items_filter = get_conditions({ 'disabled': 0 }, 'and') + show_in_website_condition = '' if products_settings.hide_variants: show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and') @@ -336,12 +338,9 @@ def get_items(filters=None, search=None): filter_condition = get_conditions(filters, 'and') where_conditions = ' and '.join( - [condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition] + [condition for condition in [enabled_items_filter, show_in_website_condition, \ + search_condition, filter_condition] if condition] ) - if where_conditions: - where_conditions += ' and disabled = 0' - else: - where_conditions += 'disabled = 0' left_joins = [] for f in filters: From 197a99ee354a1a67f4cb2fbc1d80ba4f40f61318 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 16 Dec 2019 16:18:33 +0530 Subject: [PATCH 58/98] fix: incorrect children boms fetched --- erpnext/manufacturing/doctype/bom/bom.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index e3ece56964..f8146bb01e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -65,6 +65,7 @@ class BOM(WebsiteGenerator): context.parents = [{'name': 'boms', 'title': _('All BOMs') }] def on_update(self): + frappe.cache().hdel('bom_children', self.name) self.check_recursion() self.update_stock_qty() self.update_exploded_items() From b5bf22a821fc84923a7bd3fa33496c880716e4c2 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 16 Dec 2019 16:53:00 +0530 Subject: [PATCH 59/98] fix: now allow to over production against work order --- erpnext/manufacturing/doctype/work_order/work_order.js | 2 ++ erpnext/manufacturing/doctype/work_order/work_order.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index 8ca89171b6..176ca2e4f5 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -605,6 +605,8 @@ erpnext.work_order = { description: __('Max: {0}', [max]), default: max }, data => { + max += (max * (frm.doc.__onload.overproduction_percentage || 0.0)) / 100; + if (data.qty > max) { frappe.msgprint(__('Quantity must not be more than {0}', [max])); reject(); diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 227ef787ca..2b936be798 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -38,7 +38,7 @@ class WorkOrder(Document): ms = frappe.get_doc("Manufacturing Settings") self.set_onload("material_consumption", ms.material_consumption) self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on) - + self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order) def validate(self): self.validate_production_item() From 0f583b8c5a3c284d8029bcb7589e041e8e2f49a0 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 17 Dec 2019 12:44:19 +0530 Subject: [PATCH 60/98] fix: incorrect outstanding amount shwoing in the AP/AR report --- .../accounts/report/accounts_receivable/accounts_receivable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 2c53f6e997..c70a2cd1a7 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -171,7 +171,7 @@ class ReceivablePayableReport(object): row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision) row.invoice_grand_total = row.invoiced - if abs(row.outstanding) > 0.1/10 ** self.currency_precision: + if abs(row.outstanding) > 1.0/10 ** self.currency_precision: # non-zero oustanding, we must consider this row if self.is_invoice(row) and self.filters.based_on_payment_terms: From 4203eb4ee12638c67293152bc0e3dc4f305a991b Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 17 Dec 2019 18:13:54 +0530 Subject: [PATCH 61/98] fix: not able to make work order from BOM --- erpnext/manufacturing/doctype/work_order/work_order.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 2b936be798..c4238accac 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -657,8 +657,9 @@ def make_work_order(item, qty=0, project=None): wo_doc = frappe.new_doc("Work Order") wo_doc.production_item = item wo_doc.update(item_details) - if qty > 0: - wo_doc.qty = qty + + if flt(qty) > 0: + wo_doc.qty = flt(qty) wo_doc.get_items_and_operations_from_bom() return wo_doc From be8c4068082ea59fa8b75f8f268438db200e97a4 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 17 Dec 2019 22:27:23 +0530 Subject: [PATCH 62/98] fix: Update sales register report --- .../report/sales_register/sales_register.py | 235 +++++++++++++++--- 1 file changed, 205 insertions(+), 30 deletions(-) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 0e2821ac16..afdd31df16 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -38,32 +38,46 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", []))) warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", []))) - row = [ - inv.name, inv.posting_date, inv.customer, inv.customer_name - ] + row = { + 'invoice': inv.name, + 'posting_date': inv.posting_date, + 'customer': inv.customer, + 'customer_name': inv.customer_name + } if additional_query_columns: for col in additional_query_columns: - row.append(inv.get(col)) + row.update({ + col: inv.get(col) + }) + + row.update({ + 'customer_group': inv.get("customer_group"), + 'territory': inv.get("territory"), + 'tax_id': inv.get("tax_id"), + 'receivable_account': inv.debit_to, + 'mode_of_payment': ", ".join(mode_of_payments.get(inv.name, [])), + 'project': inv.project, + 'owner': inv.owner, + 'remarks': inv.remarks, + 'sales_order': ", ".join(sales_order), + 'delivery_note': ", ".join(delivery_note), + 'cost_center': ", ".join(cost_center), + 'warehouse': ", ".join(warehouse), + 'currency': company_currency + }) - row +=[ - inv.get("customer_group"), - inv.get("territory"), - inv.get("tax_id"), - inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])), - inv.project, inv.owner, inv.remarks, - ", ".join(sales_order), ", ".join(delivery_note),", ".join(cost_center), - ", ".join(warehouse), company_currency - ] # map income values base_net_total = 0 for income_acc in income_accounts: income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc)) base_net_total += income_amount - row.append(income_amount) + row.update({ + frappe.scrub(income_acc): income_amount + }) # net total - row.append(base_net_total or inv.base_net_total) + row.update({'net_total': base_net_total or inv.base_net_total}) # tax account total_tax = 0 @@ -72,10 +86,18 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2 tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision) total_tax += tax_amount - row.append(tax_amount) + row.update({ + frappe.scrub(tax_acc): tax_amount + }) # total tax, grand total, outstanding amount & rounded total - row += [total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount] + + row.update({ + 'tax_total': total_tax, + 'grand_total': inv.base_grand_total, + 'rounded_total': inv.base_rounded_total, + 'outstanding_amount': inv.outstanding_amount + }) data.append(row) @@ -84,19 +106,118 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No def get_columns(invoice_list, additional_table_columns): """return columns based on filters""" columns = [ - _("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80", - _("Customer") + ":Link/Customer:120", _("Customer Name") + "::120" + { + 'label': _("Invoice"), + 'fieldname': 'invoice', + 'fieldtype': 'Link', + 'options': 'Sales Invoice', + 'width': 120 + }, + { + 'label': _("Posting Date"), + 'fieldname': 'posting_date', + 'fieldtype': 'Date', + 'width': 80 + }, + { + 'label': _("Customer"), + 'fieldname': 'customer', + 'fieldtype': 'Link', + 'options': 'Customer', + 'width': 120 + }, + { + 'label': _("Customer Name"), + 'fieldname': 'customer_name', + 'fieldtype': 'Data', + 'width': 120 + }, ] if additional_table_columns: columns += additional_table_columns columns +=[ - _("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80", - _("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120", - _("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150", - _("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100", - _("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100", + { + 'label': _("Custmer Group"), + 'fieldname': 'customer_group', + 'fieldtype': 'Link', + 'options': 'Customer Group', + 'width': 120 + }, + { + 'label': _("Territory"), + 'fieldname': 'territory', + 'fieldtype': 'Link', + 'options': 'Territory', + 'width': 80 + }, + { + 'label': _("Tax Id"), + 'fieldname': 'tax_id', + 'fieldtype': 'Data', + 'width': 120 + }, + { + 'label': _("Receivable Account"), + 'fieldname': 'receivable_account', + 'fieldtype': 'Link', + 'options': 'Account', + 'width': 80 + }, + { + 'label': _("Mode Of Payment"), + 'fieldname': 'mode_of_payment', + 'fieldtype': 'Data', + 'width': 120 + }, + { + 'label': _("Project"), + 'fieldname': 'project', + 'fieldtype': 'Link', + 'options': 'project', + 'width': 80 + }, + { + 'label': _("Owner"), + 'fieldname': 'owner', + 'fieldtype': 'Data', + 'width': 150 + }, + { + 'label': _("Remarks"), + 'fieldname': 'remarks', + 'fieldtype': 'Data', + 'width': 150 + }, + { + 'label': _("Sales Order"), + 'fieldname': 'sales_order', + 'fieldtype': 'Link', + 'options': 'Sales Order', + 'width': 100 + }, + { + 'label': _("Delivery Note"), + 'fieldname': 'delivery_note', + 'fieldtype': 'Link', + 'options': 'Delivery Note', + 'width': 100 + }, + { + 'label': _("Cost Center"), + 'fieldname': 'cost_center', + 'fieldtype': 'Link', + 'options': 'Cost Center', + 'width': 100 + }, + { + 'label': _("Warehouse"), + 'fieldname': 'warehouse', + 'fieldtype': 'Link', + 'options': 'Warehouse', + 'width': 100 + }, { "fieldname": "currency", "label": _("Currency"), @@ -105,7 +226,10 @@ def get_columns(invoice_list, additional_table_columns): } ] - income_accounts = tax_accounts = income_columns = tax_columns = [] + income_accounts = [] + tax_accounts = [] + income_columns = [] + tax_columns = [] if invoice_list: income_accounts = frappe.db.sql_list("""select distinct income_account @@ -119,14 +243,65 @@ def get_columns(invoice_list, additional_table_columns): and parent in (%s) order by account_head""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list])) - income_columns = [(account + ":Currency/currency:120") for account in income_accounts] + for account in income_accounts: + income_columns.append({ + "label": account, + "fieldname": frappe.scrub(account), + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + }) + for account in tax_accounts: if account not in income_accounts: - tax_columns.append(account + ":Currency/currency:120") + tax_columns.append({ + "label": account, + "fieldname": frappe.scrub(account), + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + }) - columns = columns + income_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \ - [_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120", - _("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"] + net_total_column = [{ + "label": _("Net Total"), + "fieldname": "net_total", + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + }] + + total_columns = [ + { + "label": _("Tax Total"), + "fieldname": "tax_total", + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + }, + { + "label": _("Grand Total"), + "fieldname": "grand_total", + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + }, + { + "label": _("Rounded Total"), + "fieldname": "rounded_total", + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + }, + { + "label": _("Outstanding Amount"), + "fieldname": "outstanding_amount", + "fieldtype": "Currency", + "options": 'currency', + "width": 120 + } + ] + + columns = columns + income_columns + net_total_column + tax_columns + total_columns return columns, income_accounts, tax_accounts From f597ba82ea41a93228ed83c3d4fbe3aae4fae28f Mon Sep 17 00:00:00 2001 From: Ben Knowles Date: Tue, 17 Dec 2019 13:07:02 -0600 Subject: [PATCH 63/98] fix: task validation error when adding tasks to projects (#19919) * fix: task validation error when adding tasks to projects When adding a task to a project, if the project didn't have an Expected End Date the validation would fail. This is because passing a None value to getdate() returns today's date, rather than being optional as expected. * update task.py --- erpnext/projects/doctype/task/task.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 7083d694f8..45f26814a6 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -47,11 +47,11 @@ class Task(NestedSet): if not self.project or frappe.flags.in_test: return - expected_end_date = getdate(frappe.db.get_value("Project", self.project, "expected_end_date")) + expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date") if expected_end_date: - validate_project_dates(expected_end_date, self, "exp_start_date", "exp_end_date", "Expected") - validate_project_dates(expected_end_date, self, "act_start_date", "act_end_date", "Actual") + validate_project_dates(getdate(expected_end_date), self, "exp_start_date", "exp_end_date", "Expected") + validate_project_dates(getdate(expected_end_date), self, "act_start_date", "act_end_date", "Actual") def validate_status(self): if self.status!=self.get_db_value("status") and self.status == "Completed": @@ -278,4 +278,4 @@ def validate_project_dates(project_end_date, task, task_start, task_end, actual_ frappe.throw(_("Task's {0} Start Date cannot be after Project's End Date.").format(actual_or_expected_date)) if task.get(task_end) and date_diff(project_end_date, getdate(task.get(task_end))) < 0: - frappe.throw(_("Task's {0} End Date cannot be after Project's End Date.").format(actual_or_expected_date)) \ No newline at end of file + frappe.throw(_("Task's {0} End Date cannot be after Project's End Date.").format(actual_or_expected_date)) From e7aa20ebef1b3442d7f962434e8ae285f2ad8933 Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Mon, 16 Dec 2019 16:52:42 +0530 Subject: [PATCH 64/98] fix: replace sql query by orm in delete_communications and added tests --- .../company/delete_company_transactions.py | 11 ++-- erpnext/setup/doctype/company/test_company.py | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py index 637e65578a..1503adb504 100644 --- a/erpnext/setup/doctype/company/delete_company_transactions.py +++ b/erpnext/setup/doctype/company/delete_company_transactions.py @@ -106,7 +106,10 @@ def delete_lead_addresses(company_name): frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads))) def delete_communications(doctype, company_name, company_fieldname): - frappe.db.sql(""" - DELETE FROM `tabCommunication` WHERE reference_doctype = %s AND - EXISTS (SELECT name FROM `tab{0}` WHERE {1} = %s AND `tabCommunication`.reference_name = name) - """.format(doctype, company_fieldname), (doctype, company_name)) + reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name}) + reference_doc_names = [r.name for r in reference_docs] + + communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]}) + communication_names = [c.name for c in communications] + + frappe.delete_doc("Communication", communication_names) diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index 8d9c23a37d..1664b660b8 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -88,6 +88,57 @@ class TestCompany(unittest.TestCase): self.delete_mode_of_payment(template) frappe.delete_doc("Company", template) + def test_delete_communication(self): + from erpnext.setup.doctype.company.delete_company_transactions import delete_communications + company = create_child_company() + lead = create_test_lead_in_company(company) + communication = create_company_communication("Lead", lead) + delete_communications("Lead", "Test Company", "company") + self.assertFalse(frappe.db.exists("Communcation", communication)) + self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication})) + def delete_mode_of_payment(self, company): frappe.db.sql(""" delete from `tabMode of Payment Account` where company =%s """, (company)) + +def create_company_communication(doctype, docname): + comm = frappe.get_doc({ + "doctype": "Communication", + "communication_type": "Communication", + "content": "Deduplication of Links", + "communication_medium": "Email", + "reference_doctype":doctype, + "reference_name":docname + }) + comm.insert() + +def create_child_company(): + child_company = frappe.db.exists("Company", "Test Company") + if not child_company: + child_company = frappe.get_doc({ + "doctype":"Company", + "company_name":"Test Company", + "abbr":"test_company", + "default_currency":"INR" + }) + child_company.insert() + else: + child_company = frappe.get_doc("Company", child_company) + + return child_company.name + +def create_test_lead_in_company(company): + lead = frappe.db.exists("Lead", "Test Lead in new company") + if not lead: + lead = frappe.get_doc({ + "doctype": "Lead", + "lead_name": "Test Lead in new company", + "scompany": company + }) + lead.insert() + else: + lead = frappe.get_doc("Lead", lead) + lead.company = company + lead.save() + return lead.name + From 1202e64403eb50222e6012347ba76c0f56553c4d Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Wed, 18 Dec 2019 11:43:16 +0530 Subject: [PATCH 65/98] fix: Training Event Email Tenplate (#19652) --- .../training_scheduled.html | 51 ++++++++++++++++--- .../training_scheduled.json | 6 ++- .../training_scheduled/training_scheduled.md | 51 ++++++++++++++++--- 3 files changed, 90 insertions(+), 18 deletions(-) diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.html b/erpnext/hr/notification/training_scheduled/training_scheduled.html index b1aeb2c873..374038ac20 100644 --- a/erpnext/hr/notification/training_scheduled/training_scheduled.html +++ b/erpnext/hr/notification/training_scheduled/training_scheduled.html @@ -1,9 +1,44 @@ -

{{_("Training Event")}}

+ + + + + + + + +
+
+ {{_("Training Event:")}} {{ doc.event_name }} +
+
-

{{ doc.introduction }}

- -

{{_("Details")}}

-{{_("Event Name")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }} -
{{_("Event Location")}}: {{ doc.location }} -
{{_("Start Time")}}: {{ doc.start_time }} -
{{_("End Time")}}: {{ doc.end_time }} + + + + + + + + +
+
+ {{ doc.introduction }} +
    +
  • {{_("Event Location")}}: {{ doc.location }}
  • + {% set start = frappe.utils.get_datetime(doc.start_time) %} + {% set end = frappe.utils.get_datetime(doc.end_time) %} + {% if start.date() == end.date() %} +
  • {{_("Date")}}: {{ start.strftime("%A, %d %b %Y") }}
  • +
  • + {{_("Timing")}}: {{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }} +
  • + {% else %} +
  • {{_("Start Time")}}: {{ start.strftime("%A, %d %b %Y at %I:%M %p") }} +
  • +
  • {{_("End Time")}}: {{ end.strftime("%A, %d %b %Y at %I:%M %p") }} +
  • + {% endif %} +
  • {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
  • +
+
+
\ No newline at end of file diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.json b/erpnext/hr/notification/training_scheduled/training_scheduled.json index c07e1a6285..966b887572 100644 --- a/erpnext/hr/notification/training_scheduled/training_scheduled.json +++ b/erpnext/hr/notification/training_scheduled/training_scheduled.json @@ -1,5 +1,7 @@ { "attach_print": 0, + "channel": "Email", + "condition": "", "creation": "2017-08-11 03:13:40.519614", "days_in_advance": 0, "docstatus": 0, @@ -9,8 +11,8 @@ "event": "Submit", "idx": 0, "is_standard": 1, - "message": "

{{_(\"Training Event\")}}

\n\n

{{ doc.introduction }}

\n\n

{{_(\"Details\")}}

\n{{_(\"Event Name\")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n
{{_(\"Event Location\")}}: {{ doc.location }}\n
{{_(\"Start Time\")}}: {{ doc.start_time }}\n
{{_(\"End Time\")}}: {{ doc.end_time }}\n", - "modified": "2017-08-13 22:49:42.338881", + "message": "\n \n \n \n \n \n \n \n
\n
\n {{_(\"Training Event:\")}} {{ doc.event_name }}\n
\n
\n\n\n \n \n \n \n \n \n \n
\n
\n
    \n
  • {{ doc.introduction }}
  • \n
  • {{_(\"Event Location\")}}: {{ doc.location }}
  • \n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n
  • {{_(\"Date\")}}: {{ start.strftime(\"%A, %d %b %Y\") }}
  • \n
  • \n {{_(\"Timing\")}}: {{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}\n
  • \n {% else %}\n
  • {{_(\"Start Time\")}}: {{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}\n
  • \n
  • {{_(\"End Time\")}}: {{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}\n
  • \n {% endif %}\n
\n {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n
\n
", + "modified": "2019-11-29 15:38:31.805409", "modified_by": "Administrator", "module": "HR", "name": "Training Scheduled", diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.md b/erpnext/hr/notification/training_scheduled/training_scheduled.md index bcadf7df59..374038ac20 100644 --- a/erpnext/hr/notification/training_scheduled/training_scheduled.md +++ b/erpnext/hr/notification/training_scheduled/training_scheduled.md @@ -1,9 +1,44 @@ -

{{_("Training Event")}}

-

{{ message }}

+ + + + + + + + +
+
+ {{_("Training Event:")}} {{ doc.event_name }} +
+
-

{{_("Details")}}

-{{_("Event Name")}}: {{ name }} -
{{_("Event Location")}}: {{ location }} -
{{_("Start Time")}}: {{ start_time }} -
{{_("End Time")}}: {{ end_time }} -
{{_("Attendance")}}: {{ attendance }} + + + + + + + + +
+
+ {{ doc.introduction }} +
    +
  • {{_("Event Location")}}: {{ doc.location }}
  • + {% set start = frappe.utils.get_datetime(doc.start_time) %} + {% set end = frappe.utils.get_datetime(doc.end_time) %} + {% if start.date() == end.date() %} +
  • {{_("Date")}}: {{ start.strftime("%A, %d %b %Y") }}
  • +
  • + {{_("Timing")}}: {{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }} +
  • + {% else %} +
  • {{_("Start Time")}}: {{ start.strftime("%A, %d %b %Y at %I:%M %p") }} +
  • +
  • {{_("End Time")}}: {{ end.strftime("%A, %d %b %Y at %I:%M %p") }} +
  • + {% endif %} +
  • {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
  • +
+
+
\ No newline at end of file From 5150c69ee6af5d21e44eb0c0d4eb2c6967221654 Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Wed, 18 Dec 2019 12:07:24 +0530 Subject: [PATCH 66/98] use open_mapped_doc instead of create_new_doc --- erpnext/selling/doctype/customer/customer.js | 12 ++-- erpnext/selling/doctype/customer/customer.py | 59 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index cca8efeca4..aa1b92f9a4 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -5,13 +5,13 @@ frappe.ui.form.on("Customer", { setup: function(frm) { frm.make_methods = { - 'Quotation': () => erpnext.utils.create_new_doc('Quotation', { - 'quotation_to': frm.doc.doctype, - 'party_name': frm.doc.name + 'Quotation': () => frappe.model.open_mapped_doc({ + method: "erpnext.selling.doctype.customer.customer.make_quotation", + frm: cur_frm }), - 'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', { - 'opportunity_from': frm.doc.doctype, - 'party_name': frm.doc.name + 'Opportunity': () => frappe.model.open_mapped_doc({ + method: "erpnext.selling.doctype.customer.customer.make_opportunity", + frm: cur_frm }) } diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 57308cea41..73ab7e6bb7 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -12,6 +12,7 @@ from erpnext.utilities.transaction_base import TransactionBase from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address from frappe.model.rename_doc import update_linked_doctypes +from frappe.model.mapper import get_mapped_doc class Customer(TransactionBase): def get_feed(self): @@ -238,6 +239,64 @@ def create_contact(contact, party_type, party, email): contact.append('links', dict(link_doctype=party_type, link_name=party)) contact.insert() +@frappe.whitelist() +def make_quotation(source_name, target_doc=None): + + def set_missing_values(source, target): + _set_missing_values(source,target) + + target_doc = get_mapped_doc("Customer", source_name, + {"Customer": { + "doctype": "Quotation", + "field_map": { + "name":"party_name" + } + }}, target_doc, set_missing_values) + + target_doc.quotation_to = "Customer" + target_doc.run_method("set_missing_values") + target_doc.run_method("set_other_charges") + target_doc.run_method("calculate_taxes_and_totals") + + target_doc.selling_price_list = frappe.get_doc("Customer",source_name).default_price_list + return target_doc + +@frappe.whitelist() +def make_opportunity(source_name, target_doc=None): + def set_missing_values(source, target): + _set_missing_values(source,target) + + target_doc = get_mapped_doc("Customer", source_name, + {"Customer": { + "doctype": "Opportunity", + "field_map": { + "name": "party_name", + "doctype": "opportunity_from", + } + }}, target_doc, set_missing_values + ) + + return target_doc + +def _set_missing_values(source, target): + address = frappe.get_all('Dynamic Link', { + 'link_doctype': source.doctype, + 'link_name': source.name, + 'parenttype': 'Address', + }, ['parent'], limit=1) + + contact = frappe.get_all('Dynamic Link', { + 'link_doctype': source.doctype, + 'link_name': source.name, + 'parenttype': 'Contact', + }, ['parent'], limit=1) + + if address: + target.customer_address = address[0].parent + + if contact: + target.contact_person = contact[0].parent + @frappe.whitelist() def get_loyalty_programs(doc): ''' returns applicable loyalty programs for a customer ''' From 84ae2cc5431972e0eb6483ccddd34f32950f5bc2 Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Wed, 18 Dec 2019 15:44:04 +0530 Subject: [PATCH 67/98] fix: defualt timezone not getting selected --- erpnext/www/book_appointment/index.js | 13 ++++--------- erpnext/www/book_appointment/index.py | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js index 5a814c6381..262e31b3e4 100644 --- a/erpnext/www/book_appointment/index.js +++ b/erpnext/www/book_appointment/index.js @@ -24,20 +24,15 @@ async function get_global_variables() { } function setup_timezone_selector() { - /** - * window.timezones is a dictionary with the following structure - * { IANA name: Pretty name} - * For example : { Asia/Kolkata : "India Time - Asia/Kolkata"} - */ let timezones_element = document.getElementById('appointment-timezone'); - let offset = new Date().getTimezoneOffset(); - Object.keys(window.timezones).forEach((timezone) => { + let local_timezone = moment.tz.guess() + window.timezones.forEach(timezone => { let opt = document.createElement('option'); opt.value = timezone; - if (timezone == moment.tz.guess()) { + if (timezone == local_timezone) { opt.selected = true; } - opt.innerHTML = window.timezones[timezone] + opt.innerHTML = timezone; timezones_element.appendChild(opt) }); } diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py index e4af7e8e43..fe98c7a0e9 100644 --- a/erpnext/www/book_appointment/index.py +++ b/erpnext/www/book_appointment/index.py @@ -25,18 +25,20 @@ def get_appointment_settings(): @frappe.whitelist(allow_guest=True) def get_timezones(): - from babel.dates import get_timezone, get_timezone_name, Locale - from frappe.utils.momentjs import get_all_timezones + import pytz + return pytz.all_timezones + # from babel.dates import get_timezone, get_timezone_name, Locale + # from frappe.utils.momentjs import get_all_timezones - translated_dict = {} - locale = Locale.parse(frappe.local.lang, sep="-") + # translated_dict = {} + # locale = Locale.parse(frappe.local.lang, sep="-") - for tz in get_all_timezones(): - timezone_name = get_timezone_name(get_timezone(tz), locale=locale, width='short') - if timezone_name: - translated_dict[tz] = timezone_name + ' - ' + tz + # for tz in get_all_timezones(): + # timezone_name = get_timezone_name(get_timezone(tz), locale=locale, width='short') + # if timezone_name: + # translated_dict[tz] = timezone_name + ' - ' + tz - return translated_dict + # return translated_dict @frappe.whitelist(allow_guest=True) def get_appointment_slots(date, timezone): From 0db86204cf86d0aff2d8c5c16ba3afef2341ac35 Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Wed, 18 Dec 2019 16:00:58 +0530 Subject: [PATCH 68/98] fix : only set price list if it exists for customer --- erpnext/selling/doctype/customer/customer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 73ab7e6bb7..9fd37adc13 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -258,7 +258,10 @@ def make_quotation(source_name, target_doc=None): target_doc.run_method("set_other_charges") target_doc.run_method("calculate_taxes_and_totals") - target_doc.selling_price_list = frappe.get_doc("Customer",source_name).default_price_list + price_list = frappe.get_value("Customer",source_name, 'default_price_list') + if price_list: + target_doc.selling_price_list = price_list + return target_doc @frappe.whitelist() From 5f5c725ef99153b8489c6755cac84515aed66c16 Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Wed, 18 Dec 2019 16:21:50 +0530 Subject: [PATCH 69/98] add book appointment to the sidebar --- erpnext/hooks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 2a5e6d8f49..c99ae7da5e 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -180,6 +180,7 @@ standard_portal_menu_items = [ {"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"}, {"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"}, {"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"}, + {"title": _("Appointment Booking"), "route": "/book_appointment"}, ] default_roles = [ From e786eea7dbcf78c272ca8d90440d0afc783faf2e Mon Sep 17 00:00:00 2001 From: 0Pranav Date: Wed, 18 Dec 2019 16:25:26 +0530 Subject: [PATCH 70/98] remove comments --- erpnext/www/book_appointment/index.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py index fe98c7a0e9..7bfac89f30 100644 --- a/erpnext/www/book_appointment/index.py +++ b/erpnext/www/book_appointment/index.py @@ -27,18 +27,6 @@ def get_appointment_settings(): def get_timezones(): import pytz return pytz.all_timezones - # from babel.dates import get_timezone, get_timezone_name, Locale - # from frappe.utils.momentjs import get_all_timezones - - # translated_dict = {} - # locale = Locale.parse(frappe.local.lang, sep="-") - - # for tz in get_all_timezones(): - # timezone_name = get_timezone_name(get_timezone(tz), locale=locale, width='short') - # if timezone_name: - # translated_dict[tz] = timezone_name + ' - ' + tz - - # return translated_dict @frappe.whitelist(allow_guest=True) def get_appointment_slots(date, timezone): From 2ae79b8ac2c64df86bd33971b6e8ed39ae5d8b41 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 18 Dec 2019 17:48:39 +0530 Subject: [PATCH 71/98] fix: Pricing Rule Discount for Product --- erpnext/accounts/doctype/pricing_rule/pricing_rule.json | 9 +++------ erpnext/accounts/doctype/pricing_rule/pricing_rule.py | 3 +++ erpnext/public/js/controllers/transaction.js | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index f73fb10d32..29d83783d0 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -1,5 +1,4 @@ { - "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:title", @@ -390,8 +389,7 @@ "fieldname": "rate_or_discount", "fieldtype": "Select", "label": "Rate or Discount", - "options": "\nRate\nDiscount Percentage\nDiscount Amount", - "reqd": 1 + "options": "\nRate\nDiscount Percentage\nDiscount Amount" }, { "default": "Grand Total", @@ -440,7 +438,7 @@ }, { "default": "0", - "depends_on": "eval:!doc.mixed_conditions && doc.price_or_product_discount == 'Price'", + "depends_on": "eval:!doc.mixed_conditions && doc.apply_on != 'Transaction'", "fieldname": "same_item", "fieldtype": "Check", "label": "Same Item" @@ -556,8 +554,7 @@ ], "icon": "fa fa-gift", "idx": 1, - "links": [], - "modified": "2019-12-13 15:48:48.331495", + "modified": "2019-12-18 17:29:22.957077", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index b99c07e636..3c14819e6f 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -47,6 +47,9 @@ class PricingRule(Document): if tocheck and not self.get(tocheck): throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError) + if self.price_or_product_discount == 'Price' and not self.rate_or_discount: + throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError) + def validate_applicable_for_selling_or_buying(self): if not self.selling and not self.buying: throw(_("Atleast one of the Selling or Buying must be selected")) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 1be4f27289..6db849aca7 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -500,6 +500,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ () => { var d = locals[cdt][cdn]; me.add_taxes_from_item_tax_template(d.item_tax_rate); + if (d.free_item_data) { + me.apply_product_discount(d.free_item_data); + } }, () => me.frm.script_manager.trigger("price_list_rate", cdt, cdn), () => me.toggle_conversion_factor(item), From aba58ba50ef19ea3d9dd464b9798f9f736a7f5ca Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 19 Dec 2019 11:02:37 +0530 Subject: [PATCH 72/98] fix: Spacing after commas --- erpnext/selling/doctype/customer/customer.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 9fd37adc13..136236c417 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -243,9 +243,9 @@ def create_contact(contact, party_type, party, email): def make_quotation(source_name, target_doc=None): def set_missing_values(source, target): - _set_missing_values(source,target) + _set_missing_values(source, target) - target_doc = get_mapped_doc("Customer", source_name, + target_doc = get_mapped_doc("Customer", source_name, {"Customer": { "doctype": "Quotation", "field_map": { @@ -258,7 +258,7 @@ def make_quotation(source_name, target_doc=None): target_doc.run_method("set_other_charges") target_doc.run_method("calculate_taxes_and_totals") - price_list = frappe.get_value("Customer",source_name, 'default_price_list') + price_list = frappe.get_value("Customer", source_name, 'default_price_list') if price_list: target_doc.selling_price_list = price_list @@ -267,17 +267,16 @@ def make_quotation(source_name, target_doc=None): @frappe.whitelist() def make_opportunity(source_name, target_doc=None): def set_missing_values(source, target): - _set_missing_values(source,target) + _set_missing_values(source, target) - target_doc = get_mapped_doc("Customer", source_name, + target_doc = get_mapped_doc("Customer", source_name, {"Customer": { "doctype": "Opportunity", "field_map": { "name": "party_name", "doctype": "opportunity_from", } - }}, target_doc, set_missing_values - ) + }}, target_doc, set_missing_values) return target_doc From 9d9a78442e849dd248781f9917361f3e77681852 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Thu, 19 Dec 2019 13:10:57 +0530 Subject: [PATCH 73/98] fix: bad filter query --- .../purchase_invoice/purchase_invoice.js | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index d7e64cf36f..643de7d300 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -382,21 +382,11 @@ cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(do cur_frm.fields_dict['credit_to'].get_query = function(doc) { // filter on Account - if (doc.supplier) { - return { - filters: { - 'account_type': 'Payable', - 'is_group': 0, - 'company': doc.company - } - } - } else { - return { - filters: { - 'report_type': 'Balance Sheet', - 'is_group': 0, - 'company': doc.company - } + return { + filters: { + 'account_type': 'Payable', + 'is_group': 0, + 'company': doc.company } } } From e9cb561d8d1ae27b1d505d820a07424bfb76b9fc Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Thu, 19 Dec 2019 13:18:46 +0530 Subject: [PATCH 74/98] fix: no role has cancelling permission for share transfer doctype --- erpnext/accounts/doctype/share_transfer/share_transfer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.json b/erpnext/accounts/doctype/share_transfer/share_transfer.json index f17bf04caf..9e549e0685 100644 --- a/erpnext/accounts/doctype/share_transfer/share_transfer.json +++ b/erpnext/accounts/doctype/share_transfer/share_transfer.json @@ -188,7 +188,7 @@ } ], "is_submittable": 1, - "modified": "2019-11-07 13:31:17.999744", + "modified": "2019-12-19 13:15:59.001301", "modified_by": "Administrator", "module": "Accounts", "name": "Share Transfer", @@ -196,6 +196,7 @@ "permissions": [ { "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "email": 1, From 457ca0fe6cc0e66c25cdf05c85098f3d0483b07c Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 19 Dec 2019 13:34:29 +0530 Subject: [PATCH 75/98] fix: Company None not found in get_valuation_rate --- erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 00d27ef232..1b9660e6d2 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -372,7 +372,7 @@ class StockEntry(StockController): elif d.t_warehouse and not d.basic_rate: d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse, self.doctype, self.name, d.allow_zero_valuation_rate, - currency=erpnext.get_company_currency(self.company)) + currency=erpnext.get_company_currency(self.company), company=self.company) def set_actual_qty(self): allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")) From ad9eb9b72c18d96d8521181b82e41066593c93a6 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 19 Dec 2019 20:57:40 +0530 Subject: [PATCH 76/98] fix: Tax amount not visible for some invoices --- erpnext/regional/report/gstr_2/gstr_2.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py index a362269007..f326fe07ca 100644 --- a/erpnext/regional/report/gstr_2/gstr_2.py +++ b/erpnext/regional/report/gstr_2/gstr_2.py @@ -44,12 +44,16 @@ class Gstr2Report(Gstr1Report): for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): invoice_details = self.invoices.get(inv) for rate, items in items_based_on_rate.items(): - row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) - tax_amount = taxable_value * rate / 100 - if inv in self.igst_invoices: - row += [tax_amount, 0, 0] + if inv not in self.igst_invoices: + rate = rate / 2 + row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) + tax_amount = taxable_value * rate / 100 + row += [0, tax_amount, tax_amount] else: - row += [0, tax_amount / 2, tax_amount / 2] + row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) + tax_amount = taxable_value * rate / 100 + row += [tax_amount, 0, 0] + row += [ self.invoice_cess.get(inv), From c2a5f99a387e66f6495d42d328f71399c20d91d4 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 20 Dec 2019 12:56:01 +0530 Subject: [PATCH 77/98] fix: incorrect consumed qty for partial purchase receipt in subcontracting --- erpnext/controllers/buying_controller.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 3ec7aff9cb..75b896bb13 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -265,16 +265,17 @@ class BuyingController(StockController): fg_yet_to_be_received = qty_to_be_received_map.get(item_key) - raw_material_data = backflushed_raw_materials_map.get(item_key, {}) - - consumed_qty = raw_material_data.get('qty', 0) - consumed_serial_nos = raw_material_data.get('serial_nos', '') - consumed_batch_nos = raw_material_data.get('batch_nos', '') - transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code) backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code) for raw_material in transferred_raw_materials + non_stock_items: + rm_item_key = '{}{}'.format(raw_material.rm_item_code, item.purchase_order) + raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {}) + + consumed_qty = raw_material_data.get('qty', 0) + consumed_serial_nos = raw_material_data.get('serial_nos', '') + consumed_batch_nos = raw_material_data.get('batch_nos', '') + transferred_qty = raw_material.qty rm_qty_to_be_consumed = transferred_qty - consumed_qty From 7e68f050d9f1a4e86c7d12d3527ca722f1b61a88 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Fri, 20 Dec 2019 14:49:18 +0530 Subject: [PATCH 78/98] fix: account manager doesn't have cancel submit perm for share transfer --- erpnext/accounts/doctype/share_transfer/share_transfer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.json b/erpnext/accounts/doctype/share_transfer/share_transfer.json index 9e549e0685..59a305317d 100644 --- a/erpnext/accounts/doctype/share_transfer/share_transfer.json +++ b/erpnext/accounts/doctype/share_transfer/share_transfer.json @@ -188,7 +188,7 @@ } ], "is_submittable": 1, - "modified": "2019-12-19 13:15:59.001301", + "modified": "2019-12-20 14:48:01.990600", "modified_by": "Administrator", "module": "Accounts", "name": "Share Transfer", @@ -222,6 +222,7 @@ "write": 1 }, { + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -231,6 +232,7 @@ "report": 1, "role": "Accounts Manager", "share": 1, + "submit": 1, "write": 1 } ], From 0dba4345f3af0b0476c1fb4bb0b7b3174e575098 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 20 Dec 2019 17:04:22 +0530 Subject: [PATCH 79/98] fix: patch --- erpnext/patches/v12_0/add_export_type_field_in_party_master.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py index c565b7ecd8..5bb6e3fb33 100644 --- a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py +++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py @@ -27,6 +27,8 @@ def execute(): tax_category = inter_state_category.name for doctype in ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template'): + if not frappe.get_meta(doctype).has_field('is_inter_state'): continue + template = frappe.db.get_value(doctype, {'is_inter_state': 1, 'disabled': 0}, ['name']) if template: frappe.db.set_value(doctype, template, 'tax_category', tax_category) From 0e83a5754b890bf04b58e15ce500f71dff5ad52d Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 23 Dec 2019 08:24:46 +0530 Subject: [PATCH 80/98] fix: remove illustrations from onboarding slides (#19872) * fix: remove illustrations from onboarding slides * fix: change Welcome slide's description * fix: justify text in slide --- .../add_a_few_suppliers.json | 5 +++-- .../images/illustrations/customers-onboard.png | Bin 16870 -> 0 bytes .../images/illustrations/desk-onboard.png | Bin 11054 -> 0 bytes .../images/illustrations/letterhead-onboard.png | Bin 63859 -> 0 bytes .../images/illustrations/products-onboard.png | Bin 33014 -> 0 bytes .../images/illustrations/supplier-onboard.png | Bin 17531 -> 0 bytes .../add_a_few_customers.json | 5 +++-- .../welcome_back_to_erpnext!.json | 4 ++-- .../welcome_to_erpnext!.json | 7 ++++--- .../add_a_few_products_you_buy_or_sell.json | 5 +++-- 10 files changed, 15 insertions(+), 11 deletions(-) delete mode 100644 erpnext/public/images/illustrations/customers-onboard.png delete mode 100644 erpnext/public/images/illustrations/desk-onboard.png delete mode 100644 erpnext/public/images/illustrations/letterhead-onboard.png delete mode 100644 erpnext/public/images/illustrations/products-onboard.png delete mode 100644 erpnext/public/images/illustrations/supplier-onboard.png diff --git a/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json index d3adcb7981..ce3d8cfb7b 100644 --- a/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json +++ b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json @@ -12,9 +12,10 @@ } ], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/supplier-onboard.png", + "image_src": "", + "is_completed": 0, "max_count": 3, - "modified": "2019-12-03 22:53:50.552445", + "modified": "2019-12-09 17:54:18.452038", "modified_by": "Administrator", "name": "Add A Few Suppliers", "owner": "Administrator", diff --git a/erpnext/public/images/illustrations/customers-onboard.png b/erpnext/public/images/illustrations/customers-onboard.png deleted file mode 100644 index 4a517bde29c071b1d7866c2e02aa7115aa0fac60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16870 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 P7CyXFeOo1K68b*?@SBA4 diff --git a/erpnext/public/images/illustrations/desk-onboard.png b/erpnext/public/images/illustrations/desk-onboard.png deleted file mode 100644 index 74b632dc30b652d250a1077ce4f0735cf0cffc0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11054 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 diff --git a/erpnext/public/images/illustrations/products-onboard.png b/erpnext/public/images/illustrations/products-onboard.png deleted file mode 100644 index 2dee2039e7d8330926042167b3186843996b2566..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33014 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ŊtfkM0MiHh8uLiGTv}C5RA&KLC=O6 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 diff --git a/erpnext/public/images/illustrations/supplier-onboard.png b/erpnext/public/images/illustrations/supplier-onboard.png deleted file mode 100644 index 30335f2b63be25d769c2104eddb7940389049536..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17531 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 diff --git a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json index f39fea4896..92d00bcb38 100644 --- a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json +++ b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json @@ -12,9 +12,10 @@ } ], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/customers-onboard.png", + "image_src": "", + "is_completed": 0, "max_count": 3, - "modified": "2019-12-03 22:54:28.959549", + "modified": "2019-12-09 17:54:01.686006", "modified_by": "Administrator", "name": "Add A Few Customers", "owner": "Administrator", diff --git a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json index bf330d09de..f00dc947d2 100644 --- a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json +++ b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext!/welcome_back_to_erpnext!.json @@ -7,10 +7,10 @@ "domains": [], "help_links": [], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/desk-onboard.png", + "image_src": "", "is_completed": 0, "max_count": 3, - "modified": "2019-12-04 19:21:39.995776", + "modified": "2019-12-09 17:53:53.849953", "modified_by": "Administrator", "name": "Welcome back to ERPNext!", "owner": "Administrator", diff --git a/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json b/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json index 4ea69852af..37eb67b1d7 100644 --- a/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json +++ b/erpnext/setup/onboarding_slide/welcome_to_erpnext!/welcome_to_erpnext!.json @@ -7,13 +7,14 @@ "domains": [], "help_links": [], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/desk-onboard.png", + "image_src": "", + "is_completed": 0, "max_count": 0, - "modified": "2019-12-03 22:49:12.871260", + "modified": "2019-12-22 21:26:28.414597", "modified_by": "Administrator", "name": "Welcome to ERPNext!", "owner": "Administrator", - "slide_desc": "Setting up an ERP can be overwhelming. But don't worry, we have got your back!\nLet's setup your company.\nThis wizard will help you onboard to ERPNext in a short time!", + "slide_desc": "
Setting up an ERP can be overwhelming. But don't worry, we have got your back! This wizard will help you onboard to ERPNext in a short time!
", "slide_fields": [], "slide_module": "Setup", "slide_order": 1, diff --git a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json index 27a30627ee..5ee316786c 100644 --- a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json +++ b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json @@ -7,9 +7,10 @@ "domains": [], "help_links": [], "idx": 0, - "image_src": "/assets/erpnext/images/illustrations/products-onboard.png", + "image_src": "", + "is_completed": 0, "max_count": 3, - "modified": "2019-12-03 22:54:07.558632", + "modified": "2019-12-09 17:54:09.602885", "modified_by": "Administrator", "name": "Add A Few Products You Buy Or Sell", "owner": "Administrator", From ee10f2f50d6aaedeaaff469007d7ac5f2276065c Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Mon, 23 Dec 2019 13:07:00 +0530 Subject: [PATCH 81/98] fix: bad query for debit_to field in sales invoice --- .../doctype/sales_invoice/sales_invoice.js | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 7f4ae3c1fc..db6ac55a11 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -556,22 +556,11 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) { } cur_frm.set_query("debit_to", function(doc) { - // filter on Account - if (doc.customer) { - return { - filters: { - 'account_type': 'Receivable', - 'is_group': 0, - 'company': doc.company - } - } - } else { - return { - filters: { - 'report_type': 'Balance Sheet', - 'is_group': 0, - 'company': doc.company - } + return { + filters: { + 'account_type': 'Receivable', + 'is_group': 0, + 'company': doc.company } } }); From 6edd3580d1cbe534d17c65a05eb21e16fb57ce64 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Mon, 23 Dec 2019 15:48:34 +0530 Subject: [PATCH 82/98] fix(expense-claim): update status (#20030) * fix(expense-claim): update status * fix(expense-claim): compare using grandtotal precision --- erpnext/hr/doctype/expense_claim/expense_claim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index dfb0bb96d8..38bafb1d2f 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -43,9 +43,9 @@ class ExpenseClaim(AccountsController): }[cstr(self.docstatus or 0)] paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount) - precision = self.precision("total_sanctioned_amount") + precision = self.precision("grand_total") if (self.is_paid or (flt(self.total_sanctioned_amount) > 0 - and flt(self.total_sanctioned_amount, precision) == flt(paid_amount, precision))) \ + and flt(self.grand_total, precision) == flt(paid_amount, precision))) \ and self.docstatus == 1 and self.approval_status == 'Approved': self.status = "Paid" elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved': From e6b3da0f5949c4390b737df08e12c79bae476c5f Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 23 Dec 2019 15:50:29 +0530 Subject: [PATCH 83/98] feat: fixed party and party type in Accrual journal entry (#20021) --- .../hr/doctype/payroll_entry/payroll_entry.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py index 2de01e6394..dfd38ebbe3 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py @@ -163,7 +163,7 @@ class PayrollEntry(Document): """ cond = self.get_filter_condition() return frappe.db.sql(""" select eld.loan_account, eld.loan, - eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment + eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment,t1.employee from `tabSalary Slip` t1, `tabSalary Slip Loan` eld where @@ -246,6 +246,7 @@ class PayrollEntry(Document): accounts.append({ "account": acc, "debit_in_account_currency": flt(amount, precision), + "party_type": '', "cost_center": self.cost_center, "project": self.project }) @@ -257,6 +258,7 @@ class PayrollEntry(Document): "account": acc, "credit_in_account_currency": flt(amount, precision), "cost_center": self.cost_center, + "party_type": '', "project": self.project }) @@ -264,7 +266,9 @@ class PayrollEntry(Document): for data in loan_details: accounts.append({ "account": data.loan_account, - "credit_in_account_currency": data.principal_amount + "credit_in_account_currency": data.principal_amount, + "party_type": "Employee", + "party": data.employee }) if data.interest_amount and not data.interest_income_account: @@ -275,14 +279,17 @@ class PayrollEntry(Document): "account": data.interest_income_account, "credit_in_account_currency": data.interest_amount, "cost_center": self.cost_center, - "project": self.project + "project": self.project, + "party_type": "Employee", + "party": data.employee }) payable_amount -= flt(data.total_payment, precision) # Payable amount accounts.append({ "account": default_payroll_payable_account, - "credit_in_account_currency": flt(payable_amount, precision) + "credit_in_account_currency": flt(payable_amount, precision), + "party_type": '', }) journal_entry.set("accounts", accounts) @@ -546,7 +553,6 @@ def submit_salary_slips_for_employees(payroll_entry, salary_slips, publish_progr count += 1 if publish_progress: frappe.publish_progress(count*100/len(salary_slips), title = _("Submitting Salary Slips...")) - if submitted_ss: payroll_entry.make_accrual_jv_entry() frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}") From 1263515a922002e940adeeb6970afd7cfdf1b0a1 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 23 Dec 2019 15:51:31 +0530 Subject: [PATCH 84/98] fix: exchange rate not fetching correctly (#20010) --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index e25942ca34..88973373ed 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -968,7 +968,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company # The date used to retreive the exchange rate here is the date passed # in as an argument to this function. - elif (not exchange_rate or exchange_rate==1) and account_currency and posting_date: + elif (not exchange_rate or flt(exchange_rate)==1) and account_currency and posting_date: exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date) else: exchange_rate = 1 From 4f18d2548df9ce8cc9093972cedeab78c43bc1c0 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 23 Dec 2019 16:01:38 +0530 Subject: [PATCH 85/98] fix: none type object updates AR report row (#19958) --- .../accounts/report/accounts_receivable/accounts_receivable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index c70a2cd1a7..f82146a1df 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -285,7 +285,7 @@ class ReceivablePayableReport(object): def set_party_details(self, row): # customer / supplier name - party_details = self.get_party_details(row.party) + party_details = self.get_party_details(row.party) or {} row.update(party_details) if self.filters.get(scrub(self.filters.party_type)): row.currency = row.account_currency From 06f9538e519ba0ae74b965d5eeafc31a73b94eb3 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 23 Dec 2019 16:08:21 +0530 Subject: [PATCH 86/98] fix: bad condition while checking last asset movement entry (#20047) --- erpnext/assets/doctype/asset_movement/asset_movement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 4e1822b2ce..3a08baa714 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -110,7 +110,7 @@ class AssetMovement(Document): ORDER BY asm.transaction_date asc """, (d.asset, self.company, 'Receipt'), as_dict=1) - if auto_gen_movement_entry[0].get('name') == self.name: + if auto_gen_movement_entry and auto_gen_movement_entry[0].get('name') == self.name: frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \ auto generated for Asset {1}').format(self.name, d.asset)) From 90786076009f6a2ca35ae4bf961ff5399b28dee0 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 23 Dec 2019 16:25:16 +0530 Subject: [PATCH 87/98] fix: paid amount gets overwritten by get_outstanding_invoices (#20050) --- .../accounts/doctype/payment_entry/payment_entry.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index adf47ed276..2192b7bf98 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -652,14 +652,16 @@ frappe.ui.form.on('Payment Entry', { (frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student") ) { if(total_positive_outstanding > total_negative_outstanding) - frm.set_value("paid_amount", - total_positive_outstanding - total_negative_outstanding); + if (!frm.doc.paid_amount) + frm.set_value("paid_amount", + total_positive_outstanding - total_negative_outstanding); } else if ( total_negative_outstanding && total_positive_outstanding < total_negative_outstanding ) { - frm.set_value("received_amount", - total_negative_outstanding - total_positive_outstanding); + if (!frm.doc.received_amount) + frm.set_value("received_amount", + total_negative_outstanding - total_positive_outstanding); } } From c1b6b4ed3598719ad710d9b6c5d7a89540dfbcbc Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 23 Dec 2019 17:28:00 +0530 Subject: [PATCH 88/98] fix: breadcrumb for company list (#20051) --- erpnext/setup/doctype/company/company_list.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 erpnext/setup/doctype/company/company_list.js diff --git a/erpnext/setup/doctype/company/company_list.js b/erpnext/setup/doctype/company/company_list.js new file mode 100644 index 0000000000..017286560f --- /dev/null +++ b/erpnext/setup/doctype/company/company_list.js @@ -0,0 +1,10 @@ +frappe.listview_settings['Company'] = { + onload: () => { + frappe.breadcrumbs.add({ + type: 'Custom', + module: __('Accounts'), + label: __('Accounts'), + route: '#modules/Accounts' + }); + } +} \ No newline at end of file From 2b3482d5dd41aac82c959b270e2f7ab513249d79 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 23 Dec 2019 17:58:50 +0530 Subject: [PATCH 89/98] fix: Do not validate accounting dimensions if from repost (#20042) * fix: Do not check for accounting dimensions in case of repost * fix: Do not validate accounting dimensions if from repost --- erpnext/accounts/doctype/gl_entry/gl_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index 078e05816d..041e419752 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -29,7 +29,6 @@ class GLEntry(Document): self.validate_and_set_fiscal_year() self.pl_must_have_cost_center() self.validate_cost_center() - self.validate_dimensions_for_pl_and_bs() if not self.flags.from_repost: self.check_pl_account() @@ -39,6 +38,7 @@ class GLEntry(Document): def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False): if not from_repost: self.validate_account_details(adv_adj) + self.validate_dimensions_for_pl_and_bs() check_freezing_date(self.posting_date, adv_adj) validate_frozen_account(self.account, adv_adj) From bd5f5dabbd72764b2ad860fd5266019d48863eff Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 23 Dec 2019 18:01:41 +0530 Subject: [PATCH 90/98] fix: Salary Structure Fixes (#19923) --- .../salary_structure/salary_structure.js | 87 ++++++++++--------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js index dd34ef2ae2..9f42c917a4 100755 --- a/erpnext/hr/doctype/salary_structure/salary_structure.js +++ b/erpnext/hr/doctype/salary_structure/salary_structure.js @@ -46,7 +46,7 @@ frappe.ui.form.on('Salary Structure', { frm.trigger("toggle_fields"); frm.fields_dict['earnings'].grid.set_column_disp("default_amount", false); frm.fields_dict['deductions'].grid.set_column_disp("default_amount", false); - + if(frm.doc.docstatus === 1) { frm.add_custom_button(__("Preview Salary Slip"), function() { frm.trigger('preview_salary_slip'); @@ -119,47 +119,52 @@ frappe.ui.form.on('Salary Structure', { }, callback: function(r) { var employees = r.message; - var d = new frappe.ui.Dialog({ - title: __("Preview Salary Slip"), - fields: [ - { - "label":__("Employee"), - "fieldname":"employee", - "fieldtype":"Select", - "reqd": true, - options: employees - }, { - fieldname:"fetch", - "label":__("Show Salary Slip"), - "fieldtype":"Button" - } - ] - }); - d.get_input("fetch").on("click", function() { - var values = d.get_values(); - if(!values) return; - var print_format; - frm.doc.salary_slip_based_on_timesheet ? - print_format="Salary Slip based on Timesheet" : - print_format="Salary Slip Standard"; - - frappe.call({ - method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip", - args: { - source_name: frm.doc.name, - employee: values.employee, - as_print: 1, - print_format: print_format, - for_preview: 1 - }, - callback: function(r) { - var new_window = window.open(); - new_window.document.write(r.message); - // frappe.msgprint(r.message); - } + if(!employees) return; + if (employees.length == 1){ + frm.events.open_salary_slip(frm, employees[0]); + } else { + var d = new frappe.ui.Dialog({ + title: __("Preview Salary Slip"), + fields: [ + { + "label":__("Employee"), + "fieldname":"employee", + "fieldtype":"Select", + "reqd": true, + options: employees + }, { + fieldname:"fetch", + "label":__("Show Salary Slip"), + "fieldtype":"Button" + } + ] }); - }); - d.show(); + d.get_input("fetch").on("click", function() { + var values = d.get_values(); + if(!values) return; + frm.events.open_salary_slip(frm, values.employee) + + }); + d.show(); + } + } + }); + }, + + open_salary_slip: function(frm, employee){ + var print_format = frm.doc.salary_slip_based_on_timesheet ? "Salary Slip based on Timesheet" : "Salary Slip Standard"; + frappe.call({ + method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip", + args: { + source_name: frm.doc.name, + employee: employee, + as_print: 1, + print_format: print_format, + for_preview: 1 + }, + callback: function(r) { + var new_window = window.open(); + new_window.document.write(r.message); } }); }, From 8bada8759a63c330d6c41c3a53efd45d1f99312c Mon Sep 17 00:00:00 2001 From: Pranav Nachnekar Date: Mon, 23 Dec 2019 12:49:29 +0000 Subject: [PATCH 91/98] fix: wrap `scheduled_time` with `getdate()` (#20044) * fix: wrap `scheduled_time` with `getdate()` Handles inconsistent data returned from the ORM. * fix: use `getdate()` instead of `date()` --- erpnext/crm/doctype/appointment/appointment.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py index b6c4c4707d..f50293043b 100644 --- a/erpnext/crm/doctype/appointment/appointment.py +++ b/erpnext/crm/doctype/appointment/appointment.py @@ -11,7 +11,7 @@ from datetime import timedelta import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import get_url +from frappe.utils import get_url, getdate from frappe.utils.verified_command import verify_request, get_signed_params @@ -117,7 +117,7 @@ class Appointment(Document): if self._assign: return available_agents = _get_agents_sorted_by_asc_workload( - self.scheduled_time.date()) + getdate(self.scheduled_time)) for agent in available_agents: if(_check_agent_availability(agent, self.scheduled_time)): agent = agent[0] @@ -189,7 +189,7 @@ def _get_agents_sorted_by_asc_workload(date): assigned_to = frappe.parse_json(appointment._assign) if not assigned_to: continue - if (assigned_to[0] in agent_list) and appointment.scheduled_time.date() == date: + if (assigned_to[0] in agent_list) and getdate(appointment.scheduled_time) == date: appointment_counter[assigned_to[0]] += 1 sorted_agent_list = appointment_counter.most_common() sorted_agent_list.reverse() From 93cb64ee305455e5ffd624b47ca8479d5fb7c485 Mon Sep 17 00:00:00 2001 From: Marica Date: Mon, 23 Dec 2019 18:24:56 +0530 Subject: [PATCH 92/98] enhancement`: Added Set Reserve Warehouse field in Purchase Order. (#19991) --- .../purchase_order/purchase_order.json | 12 ++++++++++- erpnext/public/js/controllers/transaction.js | 20 ++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 5dce349782..8cd44c789d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "autoname": "naming_series:", "creation": "2013-05-21 16:16:39", @@ -47,6 +48,7 @@ "ignore_pricing_rule", "sec_warehouse", "set_warehouse", + "set_reserve_warehouse", "col_break_warehouse", "is_subcontracted", "supplier_warehouse", @@ -1039,12 +1041,20 @@ "fieldtype": "Link", "label": "Tax Category", "options": "Tax Category" + }, + { + "depends_on": "supplied_items", + "fieldname": "set_reserve_warehouse", + "fieldtype": "Link", + "label": "Set Reserve Warehouse", + "options": "Warehouse" } ], "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, - "modified": "2019-07-11 18:25:49.509343", + "links": [], + "modified": "2019-12-18 13:13:22.852412", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 6db849aca7..6ca095869f 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1775,14 +1775,28 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }, + set_reserve_warehouse: function() { + this.autofill_warehouse("reserve_warehouse"); + }, + set_warehouse: function() { + this.autofill_warehouse("warehouse"); + }, + + autofill_warehouse : function (warehouse_field) { + // set warehouse in all child table rows var me = this; - if(this.frm.doc.set_warehouse) { - $.each(this.frm.doc.items || [], function(i, item) { - frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse); + let warehouse = (warehouse_field === "warehouse") ? me.frm.doc.set_warehouse : me.frm.doc.set_reserve_warehouse; + let child_table = (warehouse_field === "warehouse") ? me.frm.doc.items : me.frm.doc.supplied_items; + let doctype = (warehouse_field === "warehouse") ? (me.frm.doctype + " Item") : (me.frm.doctype + " Item Supplied"); + + if(warehouse) { + $.each(child_table || [], function(i, item) { + frappe.model.set_value(doctype, item.name, warehouse_field, warehouse); }); } }, + coupon_code: function() { var me = this; frappe.run_serially([ From 4f72c0b8b5b592318329cd836dd088ca59a7cd8a Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Mon, 23 Dec 2019 18:27:12 +0530 Subject: [PATCH 93/98] fix: wrong items in table being deleted (#19994) --- erpnext/public/js/utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index d5a78d4f1f..f363999ebe 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -501,6 +501,7 @@ erpnext.utils.update_child_items = function(opts) { frm.doc[opts.child_docname].forEach(d => { dialog.fields_dict.trans_items.df.data.push({ "docname": d.name, + "name": d.name, "item_code": d.item_code, "qty": d.qty, "rate": d.rate, From d8c10bcedbb3f2ce71f98ee9eca24fbffd802fc2 Mon Sep 17 00:00:00 2001 From: Khushal Trivedi Date: Mon, 23 Dec 2019 18:38:11 +0530 Subject: [PATCH 94/98] fix:Sibling child table filtering for duplicate entry on student form (#19908) * fix: date validation on inpatient record, else condition removing on clinical prcd templ which is not req * fix:Pricing Rule error AttributeError: 'str' object has no attribute 'get' #19770 * fix:Pricing Rule error AttributeError: 'str' object has no attribute 'get' #19770 * fix: joining and relieving Date can be on same date as valid use case * fix-education: date of birth validation * fix:Sibling child table filtering for duplacacy on student form * fix:Sibling child table filtering for duplacacy on student form * fix:Sibling child table filtering for duplacacy on student form --- erpnext/education/doctype/student/student.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/erpnext/education/doctype/student/student.js b/erpnext/education/doctype/student/student.js index b6e741c4da..1936dcbd3e 100644 --- a/erpnext/education/doctype/student/student.js +++ b/erpnext/education/doctype/student/student.js @@ -31,7 +31,7 @@ frappe.ui.form.on('Student', { frappe.ui.form.on('Student Guardian', { guardians_add: function(frm){ frm.fields_dict['guardians'].grid.get_field('guardian').get_query = function(doc){ - var guardian_list = []; + let guardian_list = []; if(!doc.__islocal) guardian_list.push(doc.guardian); $.each(doc.guardians, function(idx, val){ if (val.guardian) guardian_list.push(val.guardian); @@ -40,3 +40,18 @@ frappe.ui.form.on('Student Guardian', { }; } }); + + +frappe.ui.form.on('Student Sibling', { + siblings_add: function(frm){ + frm.fields_dict['siblings'].grid.get_field('student').get_query = function(doc){ + let sibling_list = [frm.doc.name]; + $.each(doc.siblings, function(idx, val){ + if (val.student && val.studying_in_same_institute == 'YES') { + sibling_list.push(val.student); + } + }); + return { filters: [['Student', 'name', 'not in', sibling_list]] }; + }; + } +}); \ No newline at end of file From da5d5c4941f860b8152e40f1ab605838225eff22 Mon Sep 17 00:00:00 2001 From: "Parth J. Kharwar" Date: Mon, 23 Dec 2019 18:41:17 +0530 Subject: [PATCH 95/98] fix(hr): update leave application status on cancel (#19883) --- erpnext/hr/doctype/leave_application/leave_application.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 915cea149d..5222712ea2 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -54,9 +54,11 @@ class LeaveApplication(Document): self.create_leave_ledger_entry() self.reload() + def before_cancel(self): + self.status = "Cancelled" + def on_cancel(self): self.create_leave_ledger_entry(submit=False) - self.status = "Cancelled" # notify leave applier about cancellation self.notify_employee() self.cancel_attendance() From b3e50d846b8ddc1152789cf97efc953d826203c9 Mon Sep 17 00:00:00 2001 From: Prasad Ramesh Date: Mon, 23 Dec 2019 18:47:25 +0530 Subject: [PATCH 96/98] Update README.md (#20049) --- README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 64f8d67d8e..ed57a17279 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,26 @@

-Includes: Accounting, Inventory, Manufacturing, CRM, Sales, Purchase, Project Management, HRMS. Requires MariaDB. +ERPNext as a monolith includes the following areas for managing businesses: -ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript. +1. [Accounting](https://erpnext.com/docs/user/manual/en/accounts) +1. [Inventory](https://erpnext.com/docs/user/manual/en/stock) +1. [CRM](https://erpnext.com/docs/user/manual/en/CRM) +1. [Sales](https://erpnext.com/docs/user/manual/en/selling) +1. [Purchase](https://erpnext.com/docs/user/manual/en/buying) +1. [HRMS](https://erpnext.com/docs/user/manual/en/human-resources) +1. [Project Management](https://erpnext.com/docs/user/manual/en/projects) +1. [Support](https://erpnext.com/docs/user/manual/en/support) +1. [Asset Management](https://erpnext.com/docs/user/manual/en/asset) +1. [Quality Management](https://erpnext.com/docs/user/manual/en/quality-management) +1. [Manufacturing](https://erpnext.com/docs/user/manual/en/manufacturing) +1. [Website Management](https://erpnext.com/docs/user/manual/en/website) +1. [Customize ERPNext](https://erpnext.com/docs/user/manual/en/customize-erpnext) +1. [And More](https://erpnext.com/docs/user/manual/en/) + +ERPNext requires MariaDB. + +ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript. - [User Guide](https://erpnext.com/docs/user) - [Discussion Forum](https://discuss.erpnext.com/) From 964cbc03ba9fb56f7fc1456ce1bfe94f451ef600 Mon Sep 17 00:00:00 2001 From: Wolfram Schmidt Date: Mon, 23 Dec 2019 14:20:40 +0100 Subject: [PATCH 97/98] Update employee.json (#20057) unnecessary description. Should be added by customer manually if needed individually. --- erpnext/hr/doctype/employee/employee.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json index 9291820524..a45b41d917 100644 --- a/erpnext/hr/doctype/employee/employee.json +++ b/erpnext/hr/doctype/employee/employee.json @@ -232,7 +232,6 @@ "reqd": 1 }, { - "description": "You can enter any date manually", "fieldname": "date_of_birth", "fieldtype": "Date", "label": "Date of Birth", @@ -831,4 +830,4 @@ "sort_order": "DESC", "title_field": "employee_name", "track_changes": 1 -} \ No newline at end of file +} From 152c6be209425c1682c8f2ae7d6510cca95c75e5 Mon Sep 17 00:00:00 2001 From: DeeMysterio Date: Mon, 23 Dec 2019 19:02:29 +0530 Subject: [PATCH 98/98] fix(employee onboarding): stop showing irrelevant job offer links for a job applicant (#20053) --- .../hr/doctype/employee_onboarding/employee_onboarding.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js index 996dcdf848..c1285675e5 100644 --- a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js +++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js @@ -7,6 +7,14 @@ frappe.ui.form.on('Employee Onboarding', { frm.add_fetch("employee_onboarding_template", "department", "department"); frm.add_fetch("employee_onboarding_template", "designation", "designation"); frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade"); + + frm.set_query('job_offer', function () { + return { + filters: { + 'job_applicant': frm.doc.job_applicant + } + }; + }); }, refresh: function(frm) {