From a93b514b2f433eb5f4c0ad3dd28e5f219cbb5ae4 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Tue, 6 Apr 2021 17:10:52 +0530 Subject: [PATCH 001/180] feat: create Quality Inspections from account and stock documents --- erpnext/controllers/accounts_controller.py | 32 +++++ erpnext/public/js/controllers/transaction.js | 133 ++++++++++++++++++- 2 files changed, 161 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 36d399cf19..0c966566fd 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1412,6 +1412,38 @@ def validate_and_delete_children(parent, data): for d in deleted_children: update_bin_on_delete(d, parent.doctype) + +@frappe.whitelist() +def make_quality_inspections(doctype, docname, items): + items = json.loads(items).get('items') + inspections = [] + + for item in items: + if item.get("sample_size") > item.get("qty"): + frappe.throw(_("{item_name}'s Sample Size ({sample_size}) cannot be greater than the Accepted Quantity ({accepted_quantity})").format( + item_name=item.get("item_name"), + sample_size=item.get("sample_size"), + accepted_quantity=item.get("qty") + )) + + quality_inspection = frappe.get_doc({ + "doctype": "Quality Inspection", + "inspection_type": "Incoming", + "inspected_by": frappe.session.user, + "reference_type": doctype, + "reference_name": docname, + "item_code": item.get("item_code"), + "description": item.get("description"), + "sample_size": item.get("sample_size"), + "item_serial_no": item.get("serial_no").split("\n")[0] if item.get("serial_no") else None, + "batch_no": item.get("batch_no") + }).insert() + quality_inspection.save() + inspections.append(quality_inspection) + + return [get_link_to_form("Quality Inspection", inspection.name) for inspection in inspections] + + @frappe.whitelist() def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"): def check_doc_permissions(doc, perm_type='create'): diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 21a20a7bce..da0c87dd85 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -261,11 +261,19 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ if(!in_list(["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype)) { return; } - var me = this; - var inspection_type = in_list(["Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype) + + const me = this; + if (!this.frm.is_new() && this.frm.doc.docstatus === 0) { + this.frm.add_custom_button(__("Quality Inspection(s)"), () => { + me.make_quality_inspection(); + }, __("Create")); + this.frm.page.set_inner_btn_group_as_primary(__('Create')); + } + + const inspection_type = in_list(["Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype) ? "Incoming" : "Outgoing"; - var quality_inspection_field = this.frm.get_docfield("items", "quality_inspection"); + let quality_inspection_field = this.frm.get_docfield("items", "quality_inspection"); quality_inspection_field.get_route_options_for_new_doc = function(row) { if(me.frm.is_new()) return; return { @@ -280,7 +288,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } this.frm.set_query("quality_inspection", "items", function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; + let d = locals[cdt][cdn]; return { filters: { docstatus: 1, @@ -1909,6 +1917,123 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }); }, + make_quality_inspection: function () { + let data = []; + const fields = [ + { + label: "Items", + fieldtype: "Table", + fieldname: "items", + cannot_add_rows: true, + in_place_edit: true, + data: data, + get_data: () => { return data }, + fields: [ + { + fieldtype: "Data", + fieldname: "docname", + hidden: true + }, + { + fieldtype: "Read Only", + fieldname: "item_code", + label: __("Item Code"), + in_list_view: true + }, + { + fieldtype: "Read Only", + fieldname: "item_name", + label: __("Item Name"), + in_list_view: true + }, + { + fieldtype: "Float", + fieldname: "qty", + label: __("Accepted Quantity"), + in_list_view: true, + read_only: true + }, + { + fieldtype: "Float", + fieldname: "sample_size", + label: __("Sample Size"), + reqd: true, + in_list_view: true + }, + { + fieldtype: "Data", + fieldname: "description", + label: __("Description"), + hidden: true + }, + { + fieldtype: "Data", + fieldname: "serial_no", + label: __("Serial No"), + hidden: true + }, + { + fieldtype: "Data", + fieldname: "batch_no", + label: __("Batch No"), + hidden: true + } + ] + } + ]; + + const me = this; + const dialog = new frappe.ui.Dialog({ + title: __("Select Items for Quality Inspection"), + fields: fields, + primary_action: function () { + const data = dialog.get_values(); + frappe.call({ + method: "erpnext.controllers.accounts_controller.make_quality_inspections", + args: { + doctype: me.frm.doc.doctype, + docname: me.frm.doc.name, + items: data + }, + freeze: true, + callback: function (r) { + if (r.message) { + frappe.msgprint({ + message: __("Quality Inspections Created: {0}", [r.message.join(", ")]), + indicator: "green" + }) + } + dialog.hide(); + } + }); + }, + primary_action_label: __("Create") + }); + + this.frm.doc.items.forEach(item => { + if (!item.quality_inspection) { + let dialog_items = dialog.fields_dict.items; + dialog_items.df.data.push({ + "docname": item.name, + "item_code": item.item_code, + "item_name": item.item_name, + "qty": item.qty, + "description": item.description, + "serial_no": item.serial_no, + "batch_no": item.batch_no + }); + dialog_items.grid.refresh(); + } + }) + + data = dialog.fields_dict.items.df.data; + if (!data.length) { + frappe.msgprint(__("All items in this document already have a linked Quality Inspection.")); + } else { + dialog.show(); + } + }, + get_method_for_payment: function(){ var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry"; if(cur_frm.doc.__onload && cur_frm.doc.__onload.make_payment_via_journal_entry){ From 7f8b95efe8c6c16cf50faf85480b8f97f8eda089 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 14 Apr 2021 14:12:03 +0530 Subject: [PATCH 002/180] fix: move QI logic to stock module --- erpnext/controllers/accounts_controller.py | 31 ------------ erpnext/controllers/stock_controller.py | 53 ++++++++++++++++---- erpnext/public/js/controllers/transaction.js | 2 +- 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 0c966566fd..ea0b495c10 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1413,37 +1413,6 @@ def validate_and_delete_children(parent, data): update_bin_on_delete(d, parent.doctype) -@frappe.whitelist() -def make_quality_inspections(doctype, docname, items): - items = json.loads(items).get('items') - inspections = [] - - for item in items: - if item.get("sample_size") > item.get("qty"): - frappe.throw(_("{item_name}'s Sample Size ({sample_size}) cannot be greater than the Accepted Quantity ({accepted_quantity})").format( - item_name=item.get("item_name"), - sample_size=item.get("sample_size"), - accepted_quantity=item.get("qty") - )) - - quality_inspection = frappe.get_doc({ - "doctype": "Quality Inspection", - "inspection_type": "Incoming", - "inspected_by": frappe.session.user, - "reference_type": doctype, - "reference_name": docname, - "item_code": item.get("item_code"), - "description": item.get("description"), - "sample_size": item.get("sample_size"), - "item_serial_no": item.get("serial_no").split("\n")[0] if item.get("serial_no") else None, - "batch_no": item.get("batch_no") - }).insert() - quality_inspection.save() - inspections.append(quality_inspection) - - return [get_link_to_form("Quality Inspection", inspection.name) for inspection in inspections] - - @frappe.whitelist() def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"): def check_doc_permissions(doc, perm_type='create'): diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index f352bae30e..7f8da516aa 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1,17 +1,21 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals -import frappe, erpnext -from frappe.utils import cint, flt, cstr, get_link_to_form, today, getdate -from frappe import _ -import frappe.defaults +import json from collections import defaultdict -from erpnext.accounts.utils import get_fiscal_year, check_if_stock_and_account_balance_synced + +import frappe +import frappe.defaults +from frappe import _ +from frappe.utils import cint, cstr, flt, get_link_to_form, getdate + +import erpnext from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries, process_gl_map +from erpnext.accounts.utils import check_if_stock_and_account_balance_synced, get_fiscal_year from erpnext.controllers.accounts_controller import AccountsController -from erpnext.stock.stock_ledger import get_valuation_rate from erpnext.stock import get_warehouse_account_map +from erpnext.stock.stock_ledger import get_valuation_rate + class QualityInspectionRequiredError(frappe.ValidationError): pass class QualityInspectionRejectedError(frappe.ValidationError): pass @@ -190,7 +194,6 @@ class StockController(AccountsController): if hasattr(self, "items"): item_doclist = self.get("items") elif self.doctype == "Stock Reconciliation": - import json item_doclist = [] data = json.loads(self.reconciliation_json) for row in data[data.index(self.head_row)+1:]: @@ -320,7 +323,7 @@ class StockController(AccountsController): return serialized_items def validate_warehouse(self): - from erpnext.stock.utils import validate_warehouse_company, validate_disabled_warehouse + from erpnext.stock.utils import validate_disabled_warehouse, validate_warehouse_company warehouses = list(set([d.warehouse for d in self.get("items") if getattr(d, "warehouse", None)])) @@ -501,6 +504,38 @@ class StockController(AccountsController): check_if_stock_and_account_balance_synced(self.posting_date, self.company, self.doctype, self.name) + +@frappe.whitelist() +def make_quality_inspections(doctype, docname, items): + items = json.loads(items).get('items') + inspections = [] + + for item in items: + if item.get("sample_size") > item.get("qty"): + frappe.throw(_("{item_name}'s Sample Size ({sample_size}) cannot be greater than the Accepted Quantity ({accepted_quantity})").format( + item_name=item.get("item_name"), + sample_size=item.get("sample_size"), + accepted_quantity=item.get("qty") + )) + + quality_inspection = frappe.get_doc({ + "doctype": "Quality Inspection", + "inspection_type": "Incoming", + "inspected_by": frappe.session.user, + "reference_type": doctype, + "reference_name": docname, + "item_code": item.get("item_code"), + "description": item.get("description"), + "sample_size": item.get("sample_size"), + "item_serial_no": item.get("serial_no").split("\n")[0] if item.get("serial_no") else None, + "batch_no": item.get("batch_no") + }).insert() + quality_inspection.save() + inspections.append(quality_inspection) + + return [get_link_to_form("Quality Inspection", inspection.name) for inspection in inspections] + + def is_reposting_pending(): return frappe.db.exists("Repost Item Valuation", {'docstatus': 1, 'status': ['in', ['Queued','In Progress']]}) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index da0c87dd85..0e0a87a8b5 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1989,7 +1989,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ primary_action: function () { const data = dialog.get_values(); frappe.call({ - method: "erpnext.controllers.accounts_controller.make_quality_inspections", + method: "erpnext.controllers.stock_controller.make_quality_inspections", args: { doctype: me.frm.doc.doctype, docname: me.frm.doc.name, From 03f711e3a2c6ce12fad80a4f375728a077a8a958 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 14 Apr 2021 14:41:55 +0530 Subject: [PATCH 003/180] style: sider issues --- erpnext/public/js/controllers/transaction.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 0e0a87a8b5..478b21b441 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1927,7 +1927,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ cannot_add_rows: true, in_place_edit: true, data: data, - get_data: () => { return data }, + get_data: () => { + return data; + }, fields: [ { fieldtype: "Data", @@ -2001,7 +2003,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ frappe.msgprint({ message: __("Quality Inspections Created: {0}", [r.message.join(", ")]), indicator: "green" - }) + }); } dialog.hide(); } @@ -2024,7 +2026,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }); dialog_items.grid.refresh(); } - }) + }); data = dialog.fields_dict.items.df.data; if (!data.length) { From 1ac471e04ff995ad0591b68280ecf1c7939fe432 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 15 Apr 2021 16:48:01 +0530 Subject: [PATCH 004/180] feat: generate schedule is also triggered on save. --- .../doctype/maintenance_schedule/maintenance_schedule.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 0aefe19c8d..9acb6c29ae 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -33,7 +33,7 @@ class MaintenanceSchedule(TransactionBase): count = count + 1 child.sales_person = d.sales_person - self.save() + def on_submit(self): if not self.get('schedules'): @@ -169,9 +169,12 @@ class MaintenanceSchedule(TransactionBase): self.validate_maintenance_detail() self.validate_dates_with_periodicity() self.validate_sales_order() + self.generate_schedule() def on_update(self): frappe.db.set(self, 'status', 'Draft') + + def update_amc_date(self, serial_nos, amc_expiry_date=None): for serial_no in serial_nos: From 2c802720c30c254c0b87e69af4af32d2509bc494 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 15 Apr 2021 16:52:23 +0530 Subject: [PATCH 005/180] feat: Automated setting end_date based on periodicity, no of visits and improved ux. --- .../maintenance_schedule.js | 71 ++- .../maintenance_schedule_item.json | 551 +++++------------- 2 files changed, 184 insertions(+), 438 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index ddbcdfde57..d954d905d9 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -2,9 +2,8 @@ // License: GNU General Public License v3. See license.txt frappe.provide("erpnext.maintenance"); - frappe.ui.form.on('Maintenance Schedule', { - setup: function(frm) { + setup: function (frm) { frm.set_query('contact_person', erpnext.queries.contact_query); frm.set_query('customer_address', erpnext.queries.address_query); frm.set_query('customer', erpnext.queries.customer); @@ -12,30 +11,30 @@ frappe.ui.form.on('Maintenance Schedule', { frm.add_fetch('item_code', 'item_name', 'item_name'); frm.add_fetch('item_code', 'description', 'description'); }, - onload: function(frm) { + onload: function (frm) { if (!frm.doc.status) { - frm.set_value({status:'Draft'}); + frm.set_value({ status: 'Draft' }); } if (frm.doc.__islocal) { - frm.set_value({transaction_date: frappe.datetime.get_today()}); + frm.set_value({ transaction_date: frappe.datetime.get_today() }); } }, - refresh: function(frm) { + refresh: function (frm) { setTimeout(() => { frm.toggle_display('generate_schedule', !(frm.is_new())); frm.toggle_display('schedule', !(frm.is_new())); - },10); + }, 10); }, - customer: function(frm) { + customer: function (frm) { erpnext.utils.get_party_details(frm) }, - customer_address: function(frm) { + customer_address: function (frm) { erpnext.utils.get_address_display(frm, 'customer_address', 'address_display'); }, - contact_person: function(frm) { + contact_person: function (frm) { erpnext.utils.get_contact_details(frm); }, - generate_schedule: function(frm) { + generate_schedule: function (frm) { if (frm.is_new()) { frappe.msgprint(__('Please save first')); } else { @@ -46,14 +45,14 @@ frappe.ui.form.on('Maintenance Schedule', { // TODO commonify this code erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ - refresh: function() { - frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'} + refresh: function () { + frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' } var me = this; if (this.frm.doc.docstatus === 0) { this.frm.add_custom_button(__('Sales Order'), - function() { + function () { erpnext.utils.map_current_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule", source_doctype: "Sales Order", @@ -68,7 +67,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ }); }, __("Get Items From")); } else if (this.frm.doc.docstatus === 1) { - this.frm.add_custom_button(__('Create Maintenance Visit'), function() { + this.frm.add_custom_button(__('Create Maintenance Visit'), function () { frappe.model.open_mapped_doc({ method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", source_name: me.frm.doc.name, @@ -78,26 +77,26 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ } }, - start_date: function(doc, cdt, cdn) { + start_date: function (doc, cdt, cdn) { this.set_no_of_visits(doc, cdt, cdn); }, - end_date: function(doc, cdt, cdn) { + end_date: function (doc, cdt, cdn) { this.set_no_of_visits(doc, cdt, cdn); }, - periodicity: function(doc, cdt, cdn) { + periodicity: function (doc, cdt, cdn) { this.set_no_of_visits(doc, cdt, cdn); - }, - set_no_of_visits: function(doc, cdt, cdn) { + }, + no_of_visits: function(doc,cdt,cdn){ + this.set_no_of_visits(doc,cdt,cdn); + }, + + set_no_of_visits: function (doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); - if (item.start_date && item.end_date && item.periodicity) { - if(item.start_date > item.end_date) { - frappe.msgprint(__("Row {0}:Start Date must be before End Date", [item.idx])); - return; - } + if (item.start_date && item.periodicity) { var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1; @@ -110,10 +109,28 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ } var no_of_visits = cint(date_diff / days_in_period[item.periodicity]); - frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits); + if (no_of_visits == 0 || !no_of_visits) { + + let end_date = frappe.datetime.add_days(item.start_date, days_in_period[item.periodicity]) + frappe.model.set_value(item.doctype, item.name, "end_date", end_date) + var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1; + var no_of_visits = cint(date_diff / days_in_period[item.periodicity]); + frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits); + + } + else if(item.no_of_visits > no_of_visits){ + var end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits*days_in_period[item.periodicity]) + frappe.model.set_value(item.doctype, item.name, "end_date", end_date) + + } + else if(item.no_of_visits < no_of_visits){ + var end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits*days_in_period[item.periodicity]) + frappe.model.set_value(item.doctype, item.name, "end_date", end_date) + + } } }, }); -$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm})); +$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({ frm: cur_frm })); diff --git a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json index b371dfc4f5..3dacdead62 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json @@ -1,431 +1,160 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "hash", - "beta": 0, - "creation": "2013-02-22 01:28:05", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "autoname": "hash", + "creation": "2013-02-22 01:28:05", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_code", + "item_name", + "description", + "column_break_4", + "start_date", + "end_date", + "periodicity", + "schedule_details", + "no_of_visits", + "column_break_10", + "sales_person", + "reference", + "serial_no", + "sales_order" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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, - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "columns": 1, "fetch_from": "item_code.item_name", - "fieldname": "item_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Name", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_name", - "oldfieldtype": "Data", - "options": "", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_name", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "label": "Item Name", + "oldfieldname": "item_name", + "oldfieldtype": "Data", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "item_code.description", - "fieldname": "description", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Data", - "options": "", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "300px", - "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": "description", + "fieldtype": "Text Editor", + "label": "Description", + "oldfieldname": "description", + "oldfieldtype": "Data", + "print_width": "300px", + "read_only": 1, "width": "300px" - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule_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": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "schedule_details", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "start_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Start Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "start_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "start_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Start Date", + "oldfieldname": "start_date", + "oldfieldtype": "Date", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "end_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": "End Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "end_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "end_date", + "fieldtype": "Date", + "label": "End Date", + "oldfieldname": "end_date", + "oldfieldtype": "Date", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "periodicity", - "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": "Periodicity", - "length": 0, - "no_copy": 0, - "oldfieldname": "periodicity", - "oldfieldtype": "Select", - "options": "\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly\nRandom", - "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 - }, + "columns": 1, + "fieldname": "periodicity", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Periodicity", + "oldfieldname": "periodicity", + "oldfieldtype": "Select", + "options": "\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly\nRandom" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "no_of_visits", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "No of Visits", - "length": 0, - "no_copy": 0, - "oldfieldname": "no_of_visits", - "oldfieldtype": "Int", - "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 - }, + "columns": 1, + "fieldname": "no_of_visits", + "fieldtype": "Int", + "in_list_view": 1, + "label": "No of Visits", + "oldfieldname": "no_of_visits", + "oldfieldtype": "Int", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sales_person", - "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": "Sales Person", - "length": 0, - "no_copy": 0, - "oldfieldname": "incharge_name", - "oldfieldtype": "Link", - "options": "Sales Person", - "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": "sales_person", + "fieldtype": "Link", + "label": "Sales Person", + "oldfieldname": "incharge_name", + "oldfieldtype": "Link", + "options": "Sales Person" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reference", - "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": "Reference", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "reference", + "fieldtype": "Section Break", + "label": "Reference" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "serial_no", - "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": "Serial No", - "length": 0, - "no_copy": 0, - "oldfieldname": "serial_no", - "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": "serial_no", + "fieldtype": "Small Text", + "label": "Serial No", + "oldfieldname": "serial_no", + "oldfieldtype": "Small Text" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sales_order", - "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": "Sales Order", - "length": 0, - "no_copy": 1, - "oldfieldname": "prevdoc_docname", - "oldfieldtype": "Data", - "options": "Sales Order", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "150px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "sales_order", + "fieldtype": "Link", + "label": "Sales Order", + "no_copy": 1, + "oldfieldname": "prevdoc_docname", + "oldfieldtype": "Data", + "options": "Sales Order", + "print_hide": 1, + "print_width": "150px", + "read_only": 1, + "search_index": 1, "width": "150px" + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_10", + "fieldtype": "Column Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-05-16 22:43:14.260729", - "modified_by": "Administrator", - "module": "Maintenance", - "name": "Maintenance Schedule Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 0, - "track_seen": 0 + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2021-04-15 16:09:47.311994", + "modified_by": "Administrator", + "module": "Maintenance", + "name": "Maintenance Schedule Item", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file From e6fd3b86bdca28e45568484e6ee0e9256a2b5f6c Mon Sep 17 00:00:00 2001 From: noahjacob Date: Fri, 16 Apr 2021 15:48:36 +0530 Subject: [PATCH 006/180] fix: fixed sider issues and translation syntax. --- .../maintenance_schedule.js | 37 ++++++++----------- .../maintenance_schedule.py | 3 +- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index d954d905d9..124524684e 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -7,9 +7,6 @@ frappe.ui.form.on('Maintenance Schedule', { frm.set_query('contact_person', erpnext.queries.contact_query); frm.set_query('customer_address', erpnext.queries.address_query); frm.set_query('customer', erpnext.queries.customer); - - frm.add_fetch('item_code', 'item_name', 'item_name'); - frm.add_fetch('item_code', 'description', 'description'); }, onload: function (frm) { if (!frm.doc.status) { @@ -46,7 +43,7 @@ frappe.ui.form.on('Maintenance Schedule', { // TODO commonify this code erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ refresh: function () { - frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' } + frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' }; var me = this; @@ -89,10 +86,10 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ this.set_no_of_visits(doc, cdt, cdn); }, - no_of_visits: function(doc,cdt,cdn){ - this.set_no_of_visits(doc,cdt,cdn); + no_of_visits: function (doc, cdt, cdn) { + this.set_no_of_visits(doc, cdt, cdn); }, - + set_no_of_visits: function (doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); @@ -111,23 +108,21 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ var no_of_visits = cint(date_diff / days_in_period[item.periodicity]); if (no_of_visits == 0 || !no_of_visits) { - let end_date = frappe.datetime.add_days(item.start_date, days_in_period[item.periodicity]) - frappe.model.set_value(item.doctype, item.name, "end_date", end_date) - var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1; - var no_of_visits = cint(date_diff / days_in_period[item.periodicity]); + let end_date = frappe.datetime.add_days(item.start_date, days_in_period[item.periodicity]); + frappe.model.set_value(item.doctype, item.name, "end_date", end_date); + date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1; + no_of_visits = cint(date_diff / days_in_period[item.periodicity]); frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits); + } else if (item.no_of_visits > no_of_visits) { + let end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]); + frappe.model.set_value(item.doctype, item.name, "end_date", end_date); + + } else if (item.no_of_visits < no_of_visits) { + let end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]); + frappe.model.set_value(item.doctype, item.name, "end_date", end_date); + } - else if(item.no_of_visits > no_of_visits){ - var end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits*days_in_period[item.periodicity]) - frappe.model.set_value(item.doctype, item.name, "end_date", end_date) - - } - else if(item.no_of_visits < no_of_visits){ - var end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits*days_in_period[item.periodicity]) - frappe.model.set_value(item.doctype, item.name, "end_date", end_date) - - } } }, }); diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 9acb6c29ae..60dd2983b9 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -135,8 +135,7 @@ class MaintenanceSchedule(TransactionBase): } if date_diff < days_in_period[d.periodicity]: - throw(_("Row {0}: To set {1} periodicity, difference between from and to date \ - must be greater than or equal to {2}") + throw(_("Row {0}: To set {1} periodicity, difference between from and to date must be greater than or equal to {2}") .format(d.idx, d.periodicity, days_in_period[d.periodicity])) def validate_maintenance_detail(self): From 5ebc6abfadff17f7a0320317b660d67a324405b0 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Fri, 16 Apr 2021 16:59:10 +0530 Subject: [PATCH 007/180] feat: Sales Person field is now editable after submitting. --- .../maintenance_schedule.json | 1046 ++++------------- .../maintenance_schedule_detail.json | 298 ++--- 2 files changed, 313 insertions(+), 1031 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json index 606d22f52b..1871228711 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json @@ -1,852 +1,258 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2013-01-10 16:34:30", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, + "actions": [], + "autoname": "naming_series:", + "creation": "2013-01-10 16:34:30", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "customer_details", + "naming_series", + "customer", + "column_break0", + "status", + "transaction_date", + "items_section", + "items", + "schedule", + "generate_schedule", + "schedules", + "contact_info", + "customer_name", + "contact_person", + "contact_mobile", + "contact_email", + "contact_display", + "column_break_17", + "customer_address", + "address_display", + "territory", + "customer_group", + "company", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_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": "", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-user", - "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": "customer_details", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-user" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "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": "Series", - "length": 0, - "no_copy": 1, - "options": "MAT-MSH-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "MAT-MSH-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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": 0, - "in_standard_filter": 1, - "label": "Customer", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer", - "oldfieldtype": "Link", - "options": "Customer", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "customer", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Customer", + "oldfieldname": "customer", + "oldfieldtype": "Link", + "options": "Customer", + "print_hide": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break0", - "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, - "oldfieldtype": "Column Break", - "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": "column_break0", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Draft", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Status", - "length": 0, - "no_copy": 1, - "oldfieldname": "status", - "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nCancelled", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "in_standard_filter": 1, + "label": "Status", + "no_copy": 1, + "oldfieldname": "status", + "oldfieldtype": "Select", + "options": "\nDraft\nSubmitted\nCancelled", + "read_only": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "transaction_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": "Transaction Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "transaction_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "transaction_date", + "fieldtype": "Date", + "label": "Transaction Date", + "oldfieldname": "transaction_date", + "oldfieldtype": "Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "items_section", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-shopping-cart" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "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": "Items", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_maintenance_detail", - "oldfieldtype": "Table", - "options": "Maintenance Schedule Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "items", + "fieldtype": "Table", + "label": "Items", + "oldfieldname": "item_maintenance_detail", + "oldfieldtype": "Table", + "options": "Maintenance Schedule Item", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule", - "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": "Schedule", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-time", - "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": "schedule", + "fieldtype": "Section Break", + "label": "Schedule", + "oldfieldtype": "Section Break", + "options": "fa fa-time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "generate_schedule", - "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": "Generate Schedule", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Button", - "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": "generate_schedule", + "fieldtype": "Button", + "label": "Generate Schedule", + "oldfieldtype": "Button" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedules", - "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": "Schedules", - "length": 0, - "no_copy": 0, - "oldfieldname": "schedules", - "oldfieldtype": "Table", - "options": "Maintenance Schedule Detail", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "schedules", + "fieldtype": "Table", + "label": "Schedules", + "oldfieldname": "schedules", + "oldfieldtype": "Table", + "options": "Maintenance Schedule Detail" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_info", - "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": "Contact Info", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_info", + "fieldtype": "Section Break", + "label": "Contact Info" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "customer_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Customer Name", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer_name", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "depends_on": "customer", + "fieldname": "customer_name", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "label": "Customer Name", + "oldfieldname": "customer_name", + "oldfieldtype": "Data", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_person", - "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": "Contact Person", - "length": 0, - "no_copy": 0, - "options": "Contact", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "contact_person", + "fieldtype": "Link", + "label": "Contact Person", + "options": "Contact", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_mobile", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Mobile No", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "contact_mobile", + "fieldtype": "Data", + "hidden": 1, + "label": "Mobile No", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_email", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact Email", - "length": 0, - "no_copy": 0, - "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 - }, + "depends_on": "customer", + "fieldname": "contact_email", + "fieldtype": "Data", + "hidden": 1, + "label": "Contact Email", + "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, - "fieldname": "contact_display", - "fieldtype": "Small Text", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_display", + "fieldtype": "Small Text", + "hidden": 1, + "in_global_search": 1, + "label": "Contact", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_17", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_17", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "customer_address", - "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": "Customer Address", - "length": 0, - "no_copy": 0, - "options": "Address", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "customer", + "fieldname": "customer_address", + "fieldtype": "Link", + "label": "Customer Address", + "options": "Address", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address_display", - "fieldtype": "Small Text", - "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": "Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "address_display", + "fieldtype": "Small Text", + "hidden": 1, + "label": "Address", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "description": "", - "fieldname": "territory", - "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": "Territory", - "length": 0, - "no_copy": 0, - "oldfieldname": "territory", - "oldfieldtype": "Link", - "options": "Territory", - "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 - }, + "depends_on": "customer", + "fieldname": "territory", + "fieldtype": "Link", + "label": "Territory", + "oldfieldname": "territory", + "oldfieldtype": "Link", + "options": "Territory" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "description": "", - "fieldname": "customer_group", - "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": "Customer Group", - "length": 0, - "no_copy": 0, - "options": "Customer Group", - "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 - }, + "depends_on": "customer", + "fieldname": "customer_group", + "fieldtype": "Link", + "label": "Customer Group", + "options": "Customer Group" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "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": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "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, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "remember_last_selected_value": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Maintenance Schedule", - "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": "Maintenance Schedule", + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-calendar", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Maintenance", - "name": "Maintenance Schedule", - "owner": "Administrator", + ], + "icon": "fa fa-calendar", + "idx": 1, + "is_submittable": 1, + "links": [], + "modified": "2021-04-16 15:53:36.670816", + "modified_by": "Administrator", + "module": "Maintenance", + "name": "Maintenance Schedule", + "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": 1, - "role": "Maintenance Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Maintenance Manager", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "status,customer,customer_name", - "show_name_in_global_search": 0, - "sort_order": "DESC", - "timeline_field": "customer", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "search_fields": "status,customer,customer_name", + "sort_field": "modified", + "sort_order": "DESC", + "timeline_field": "customer" } \ No newline at end of file diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json index 7cd3086155..73536f6549 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json @@ -1,222 +1,98 @@ { - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "hash", - "beta": 0, - "creation": "2013-02-22 01:28:05", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "autoname": "hash", + "creation": "2013-02-22 01:28:05", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_code", + "item_name", + "scheduled_date", + "actual_date", + "sales_person", + "serial_no" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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, - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item", + "read_only": 1, + "search_index": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Name", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_name", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "item_name", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "label": "Item Name", + "oldfieldname": "item_name", + "oldfieldtype": "Data", + "read_only": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "scheduled_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": "Scheduled Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "scheduled_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "scheduled_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Scheduled Date", + "oldfieldname": "scheduled_date", + "oldfieldtype": "Date", + "reqd": 1, + "search_index": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "actual_date", - "fieldtype": "Date", - "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": "Actual Date", - "length": 0, - "no_copy": 1, - "oldfieldname": "actual_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "actual_date", + "fieldtype": "Date", + "label": "Actual Date", + "no_copy": 1, + "oldfieldname": "actual_date", + "oldfieldtype": "Date", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sales_person", - "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": "Sales Person", - "length": 0, - "no_copy": 0, - "oldfieldname": "incharge_name", - "oldfieldtype": "Link", - "options": "Sales Person", - "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 - }, + "allow_on_submit": 1, + "columns": 2, + "fieldname": "sales_person", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Sales Person", + "oldfieldname": "incharge_name", + "oldfieldtype": "Link", + "options": "Sales Person" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "serial_no", - "fieldtype": "Small Text", - "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": "Serial No", - "length": 0, - "no_copy": 0, - "oldfieldname": "serial_no", - "oldfieldtype": "Small Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "160px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, + "fieldname": "serial_no", + "fieldtype": "Small Text", + "in_list_view": 1, + "label": "Serial No", + "oldfieldname": "serial_no", + "oldfieldtype": "Small Text", + "print_width": "160px", + "read_only": 1, "width": "160px" } - ], - "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": "2017-02-17 17:05:44.644663", - "modified_by": "Administrator", - "module": "Maintenance", - "name": "Maintenance Schedule Detail", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 1, - "track_seen": 0 + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2021-04-16 16:01:53.271287", + "modified_by": "Administrator", + "module": "Maintenance", + "name": "Maintenance Schedule Detail", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file From 9a0a561ec65f5a1d9cf5ced858aa99c0ef49301c Mon Sep 17 00:00:00 2001 From: noahjacob Date: Mon, 19 Apr 2021 16:42:50 +0530 Subject: [PATCH 008/180] feat: Created Dialog Box on trying to create a maintenance visit. --- .../maintenance_schedule.js | 92 +++++++++++++++++- .../maintenance_schedule.py | 93 ++++++++++--------- .../maintenance_schedule_detail.json | 12 ++- .../maintenance_visit_purpose.json | 10 +- 4 files changed, 153 insertions(+), 54 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index 124524684e..d07710878d 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -65,11 +65,93 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ }, __("Get Items From")); } else if (this.frm.doc.docstatus === 1) { this.frm.add_custom_button(__('Create Maintenance Visit'), function () { - frappe.model.open_mapped_doc({ - method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", - source_name: me.frm.doc.name, - frm: me.frm - }); + let items = me.frm.doc.items; + let s = me.frm.doc.schedules; + let options = ""; + let dates = ""; + for (let i in items) { + for(let d in s){ + if (s[d].item_name == items[i].item_name && s[d].completion_status == "Pending") { + options = options + '\n' + items[i].item_name + break + } + } + } + function formatDate(date) { + var d = new Date(date), + month = '' + (d.getMonth() + 1), + day = '' + d.getDate(), + year = d.getFullYear(); + + if (month.length < 2) + month = '0' + month; + if (day.length < 2) + day = '0' + day; + + return [day, month, year].join('-'); + } + var schedule_id = "" + var d = new frappe.ui.Dialog({ + title: __("Enter Visit Details"), + fields: [{ + fieldtype: "Select", + fieldname: "item_name", + label: __("Item Name"), + options: options, + reqd: 1, + onchange: function () { + let field = d.get_field("scheduled_date"); + dates = "" + for (let i in s) { + if (s[i].item_name == this.value) { + dates = dates + '\n' + formatDate(s[i].scheduled_date); + } + + } + field.df.options = dates; + field.refresh(); + } + }, + { + label: __('Scheduled Date'), + fieldname: 'scheduled_date', + fieldtype: 'Select', + options: dates, + reqd: 1, + onchange: function(){ + let field = d.get_field('item_name'); + for(let i in s ){ + if(s[i].item_name == field.value && formatDate(s[i].scheduled_date) == this.value){ + schedule_id = s[i].name; + } + } + } + }, + ], + primary_action_label: 'Create Visit', + primary_action(values) { + frappe.call({ + method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", + args: { + item_name: values.item_name, + s_id: schedule_id, + source_name: me.frm.doc.name, + + }, + callback: function (r) { + if (!r.exc) { + frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + + + }); + d.hide(); + } + }) + d.show() + }, __('Create')); } }, diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 60dd2983b9..fd06a4ef9b 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -32,8 +32,7 @@ class MaintenanceSchedule(TransactionBase): child.idx = count count = count + 1 child.sales_person = d.sales_person - - + child.completion_status = "Pending" def on_submit(self): if not self.get('schedules'): @@ -58,9 +57,9 @@ class MaintenanceSchedule(TransactionBase): if no_email_sp: frappe.msgprint( - frappe._("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format( - self.owner, "
" + "
".join(no_email_sp) - )) + frappe._("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format( + self.owner, "
" + "
".join(no_email_sp) + )) scheduled_date = frappe.db.sql("""select scheduled_date from `tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and @@ -69,12 +68,12 @@ class MaintenanceSchedule(TransactionBase): for key in scheduled_date: description =frappe._("Reference: {0}, Item Code: {1} and Customer: {2}").format(self.name, d.item_code, self.customer) event = frappe.get_doc({ - "doctype": "Event", - "owner": email_map.get(d.sales_person, self.owner), - "subject": description, - "description": description, - "starts_on": cstr(key["scheduled_date"]) + " 10:00:00", - "event_type": "Private", + "doctype": "Event", + "owner": email_map.get(d.sales_person, self.owner), + "subject": description, + "description": description, + "starts_on": cstr(key["scheduled_date"]) + " 10:00:00", + "event_type": "Private", }) event.add_participant(self.doctype, self.name) event.insert(ignore_permissions=1) @@ -92,7 +91,7 @@ class MaintenanceSchedule(TransactionBase): start_date_copy = add_days(start_date_copy, add_by) if len(schedule_list) < no_of_visit: schedule_date = self.validate_schedule_date_for_holiday_list(getdate(start_date_copy), - sales_person) + sales_person) if schedule_date > getdate(end_date): schedule_date = getdate(end_date) schedule_list.append(schedule_date) @@ -127,16 +126,16 @@ class MaintenanceSchedule(TransactionBase): if d.start_date and d.end_date and d.periodicity and d.periodicity!="Random": date_diff = (getdate(d.end_date) - getdate(d.start_date)).days + 1 days_in_period = { - "Weekly": 7, - "Monthly": 30, - "Quarterly": 90, - "Half Yearly": 180, - "Yearly": 365 + "Weekly": 7, + "Monthly": 30, + "Quarterly": 90, + "Half Yearly": 180, + "Yearly": 365 } if date_diff < days_in_period[d.periodicity]: throw(_("Row {0}: To set {1} periodicity, difference between from and to date must be greater than or equal to {2}") - .format(d.idx, d.periodicity, days_in_period[d.periodicity])) + .format(d.idx, d.periodicity, days_in_period[d.periodicity])) def validate_maintenance_detail(self): if not self.get('items'): @@ -172,8 +171,8 @@ class MaintenanceSchedule(TransactionBase): def on_update(self): frappe.db.set(self, 'status', 'Draft') - - + + def update_amc_date(self, serial_nos, amc_expiry_date=None): for serial_no in serial_nos: @@ -184,27 +183,27 @@ class MaintenanceSchedule(TransactionBase): def validate_serial_no(self, item_code, serial_nos, amc_start_date): for serial_no in serial_nos: sr_details = frappe.db.get_value("Serial No", serial_no, - ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date", "item_code"], as_dict=1) + ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date", "item_code"], as_dict=1) if not sr_details: frappe.throw(_("Serial No {0} not found").format(serial_no)) if sr_details.get("item_code") != item_code: frappe.throw(_("Serial No {0} does not belong to Item {1}") - .format(frappe.bold(serial_no), frappe.bold(item_code)), title="Invalid") + .format(frappe.bold(serial_no), frappe.bold(item_code)), title="Invalid") if sr_details.warranty_expiry_date \ - and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date): + and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date): throw(_("Serial No {0} is under warranty upto {1}") - .format(serial_no, sr_details.warranty_expiry_date)) + .format(serial_no, sr_details.warranty_expiry_date)) if sr_details.amc_expiry_date and getdate(sr_details.amc_expiry_date) >= getdate(amc_start_date): throw(_("Serial No {0} is under maintenance contract upto {1}") - .format(serial_no, sr_details.amc_expiry_date)) + .format(serial_no, sr_details.amc_expiry_date)) if not sr_details.warehouse and sr_details.delivery_date and \ - getdate(sr_details.delivery_date) >= getdate(amc_start_date): - throw(_("Maintenance start date can not be before delivery date for Serial No {0}") + getdate(sr_details.delivery_date) >= getdate(amc_start_date): + throw(_("Maintenance start date can not be before delivery date for Serial No {0}") .format(serial_no)) def validate_schedule(self): @@ -248,31 +247,37 @@ class MaintenanceSchedule(TransactionBase): delete_events(self.doctype, self.name) @frappe.whitelist() -def make_maintenance_visit(source_name, target_doc=None): +def make_maintenance_visit(source_name, target_doc=None,item_name=None,s_id=None): from frappe.model.mapper import get_mapped_doc def update_status(source, target, parent): target.maintenance_type = "Scheduled" + def update_sid(source, target, parent): + target.prevdoc_detail_docname = s_id + doclist = get_mapped_doc("Maintenance Schedule", source_name, { - "Maintenance Schedule": { - "doctype": "Maintenance Visit", - "field_map": { - "name": "maintenance_schedule" + "Maintenance Schedule": { + "doctype": "Maintenance Visit", + "field_map": { + "name": "maintenance_schedule" + }, + "validation": { + "docstatus": ["=", 1] + }, + "postprocess": update_status }, - "validation": { - "docstatus": ["=", 1] - }, - "postprocess": update_status - }, - "Maintenance Schedule Item": { - "doctype": "Maintenance Visit Purpose", - "field_map": { - "parent": "prevdoc_docname", - "parenttype": "prevdoc_doctype", - "sales_person": "service_person" + "Maintenance Schedule Item": { + "doctype": "Maintenance Visit Purpose", + "field_map": { + "parent": "prevdoc_docname", + "parenttype": "prevdoc_doctype", + }, + "condition": lambda doc: doc.item_name == item_name, + + "postprocess": update_sid + } - } }, target_doc) return doclist diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json index 73536f6549..7fda687ca4 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json @@ -12,7 +12,8 @@ "scheduled_date", "actual_date", "sales_person", - "serial_no" + "serial_no", + "completion_status" ], "fields": [ { @@ -52,6 +53,7 @@ { "fieldname": "actual_date", "fieldtype": "Date", + "in_list_view": 1, "label": "Actual Date", "no_copy": 1, "oldfieldname": "actual_date", @@ -81,12 +83,18 @@ "print_width": "160px", "read_only": 1, "width": "160px" + }, + { + "fieldname": "completion_status", + "fieldtype": "Select", + "label": "Completion Status", + "options": "Pending\nPartially Completed\nFully Completed" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-16 16:01:53.271287", + "modified": "2021-04-19 16:18:36.723319", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule Detail", diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json index 467441d841..60e5afe806 100644 --- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json +++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "hash", "creation": "2013-02-22 01:28:06", "doctype": "DocType", @@ -62,6 +63,8 @@ "fieldtype": "Section Break" }, { + "fetch_from": "prevdoc_detail_docname.sales_person", + "fetch_if_empty": 1, "fieldname": "service_person", "fieldtype": "Link", "in_list_view": 1, @@ -110,12 +113,12 @@ }, { "fieldname": "prevdoc_detail_docname", - "fieldtype": "Data", - "hidden": 1, + "fieldtype": "Link", "label": "Against Document Detail No", "no_copy": 1, "oldfieldname": "prevdoc_detail_docname", "oldfieldtype": "Data", + "options": "Maintenance Schedule Detail", "print_hide": 1, "print_width": "160px", "read_only": 1, @@ -125,7 +128,8 @@ ], "idx": 1, "istable": 1, - "modified": "2020-09-18 17:26:09.703215", + "links": [], + "modified": "2021-04-19 16:08:10.671163", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Visit Purpose", From 5d7d338d2ae407ad2b48511405465311355e4a09 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Mon, 19 Apr 2021 18:39:34 +0530 Subject: [PATCH 009/180] feat: Schedule status is now updated on submitting a visit. --- .../maintenance_schedule.js | 11 +++++++- .../maintenance_schedule.py | 9 +++--- .../maintenance_schedule_detail.json | 23 ++++++++++----- .../maintenance_visit/maintenance_visit.py | 28 +++++++++++++++++++ 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index d07710878d..45e632cd35 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -64,6 +64,14 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ }); }, __("Get Items From")); } else if (this.frm.doc.docstatus === 1) { + var s = me.frm.doc.schedules; + let flag = 0 + for(let i in s){ + if (s[i].completion_status == pending){ + flag = 1 + } + } + if(count){ this.frm.add_custom_button(__('Create Maintenance Visit'), function () { let items = me.frm.doc.items; let s = me.frm.doc.schedules; @@ -103,7 +111,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ let field = d.get_field("scheduled_date"); dates = "" for (let i in s) { - if (s[i].item_name == this.value) { + if (s[i].item_name == this.value && s[i].completion_status == "Pending") { dates = dates + '\n' + formatDate(s[i].scheduled_date); } @@ -154,6 +162,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ }, __('Create')); } + } }, start_date: function (doc, cdt, cdn) { diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index fd06a4ef9b..aa582ee219 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -33,6 +33,7 @@ class MaintenanceSchedule(TransactionBase): count = count + 1 child.sales_person = d.sales_person child.completion_status = "Pending" + child.item_ref = d.name def on_submit(self): if not self.get('schedules'): @@ -171,9 +172,7 @@ class MaintenanceSchedule(TransactionBase): def on_update(self): frappe.db.set(self, 'status', 'Draft') - - - + def update_amc_date(self, serial_nos, amc_expiry_date=None): for serial_no in serial_nos: serial_no_doc = frappe.get_doc("Serial No", serial_no) @@ -255,6 +254,8 @@ def make_maintenance_visit(source_name, target_doc=None,item_name=None,s_id=None def update_sid(source, target, parent): target.prevdoc_detail_docname = s_id + sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person') + target.service_person = sales_person doclist = get_mapped_doc("Maintenance Schedule", source_name, { "Maintenance Schedule": { @@ -275,7 +276,7 @@ def make_maintenance_visit(source_name, target_doc=None,item_name=None,s_id=None }, "condition": lambda doc: doc.item_name == item_name, - "postprocess": update_sid + "postprocess": update_sid } }, target_doc) diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json index 7fda687ca4..f1e2e21a12 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json @@ -10,10 +10,11 @@ "item_code", "item_name", "scheduled_date", - "actual_date", "sales_person", + "actual_date", + "completion_status", "serial_no", - "completion_status" + "item_ref" ], "fields": [ { @@ -29,11 +30,9 @@ "search_index": 1 }, { - "columns": 2, "fieldname": "item_name", "fieldtype": "Data", "in_global_search": 1, - "in_list_view": 1, "label": "Item Name", "oldfieldname": "item_name", "oldfieldtype": "Data", @@ -71,7 +70,8 @@ "label": "Sales Person", "oldfieldname": "incharge_name", "oldfieldtype": "Link", - "options": "Sales Person" + "options": "Sales Person", + "read_only_depends_on": "eval:doc.completion_status != \"Pending\"" }, { "fieldname": "serial_no", @@ -85,16 +85,25 @@ "width": "160px" }, { + "columns": 2, "fieldname": "completion_status", "fieldtype": "Select", + "in_list_view": 1, "label": "Completion Status", - "options": "Pending\nPartially Completed\nFully Completed" + "options": "Pending\nPartially Completed\nFully Completed", + "read_only": 1 + }, + { + "fieldname": "item_ref", + "fieldtype": "Data", + "label": "Item Reference", + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-19 16:18:36.723319", + "modified": "2021-04-19 17:42:31.685710", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule Detail", diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index 2f2ad00e02..9505a36545 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ +from frappe.utils import get_datetime from erpnext.utilities.transaction_base import TransactionBase @@ -16,8 +17,33 @@ class MaintenanceVisit(TransactionBase): if d.serial_no and not frappe.db.exists("Serial No", d.serial_no): frappe.throw(_("Serial No {0} does not exist").format(d.serial_no)) + def validate_mntc_date(self): + if self.maintenance_type == "Scheduled": + p = self.purposes + for i in p: + detail_ref = i.prevdoc_detail_docname + item_ref = frappe.db.get_value('Maintenance Schedule Detail', detail_ref , 'item_ref') + start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date']) + if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date): + frappe.throw(_("Date must be between {0} and {1}").format(start_date,end_date)) + def validate(self): self.validate_serial_no() + self.validate_mntc_date() + + def update_completion_status(self): + if self.maintenance_type == "Scheduled": + p = self.purposes + for i in p: + detail_ref = i.prevdoc_detail_docname + frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'completion_status', self.completion_status) + + def update_actual_date(self): + if self.maintenance_type == "Scheduled": + p = self.purposes + for i in p: + detail_ref = i.prevdoc_detail_docname + frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'actual_date', self.mntc_date) def update_customer_issue(self, flag): for d in self.get('purposes'): @@ -77,6 +103,8 @@ class MaintenanceVisit(TransactionBase): def on_submit(self): self.update_customer_issue(1) frappe.db.set(self, 'status', 'Submitted') + self.update_completion_status() + self.update_actual_date() def on_cancel(self): self.check_if_last_visit() From 57f487a16b03e337b51f7889e51c39bed8e54091 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Tue, 20 Apr 2021 13:12:14 +0530 Subject: [PATCH 010/180] fix: Updated serial_no filters in maintenance visit. --- .../maintenance_schedule.js | 178 +++++++++--------- .../maintenance_schedule.py | 15 +- .../maintenance_visit/maintenance_visit.js | 67 ++++--- .../maintenance_visit/maintenance_visit.py | 21 ++- 4 files changed, 158 insertions(+), 123 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index 45e632cd35..3c05526496 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -65,104 +65,104 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ }, __("Get Items From")); } else if (this.frm.doc.docstatus === 1) { var s = me.frm.doc.schedules; - let flag = 0 - for(let i in s){ - if (s[i].completion_status == pending){ - flag = 1 + let flag = 0; + for (let i in s) { + if (s[i].completion_status == "Pending") { + flag = 1; } } - if(count){ - this.frm.add_custom_button(__('Create Maintenance Visit'), function () { - let items = me.frm.doc.items; - let s = me.frm.doc.schedules; - let options = ""; - let dates = ""; - for (let i in items) { - for(let d in s){ - if (s[d].item_name == items[i].item_name && s[d].completion_status == "Pending") { - options = options + '\n' + items[i].item_name - break + if (flag) { + this.frm.add_custom_button(__('Create Maintenance Visit'), function () { + let items = me.frm.doc.items; + let s = me.frm.doc.schedules; + let options = ""; + let dates = ""; + for (let i in items) { + for (let d in s) { + if (s[d].item_name == items[i].item_name && s[d].completion_status == "Pending") { + options = options + '\n' + items[i].item_name; + break; + } } } - } - function formatDate(date) { - var d = new Date(date), - month = '' + (d.getMonth() + 1), - day = '' + d.getDate(), - year = d.getFullYear(); + function formatDate(date) { + var d = new Date(date), + month = '' + (d.getMonth() + 1), + day = '' + d.getDate(), + year = d.getFullYear(); - if (month.length < 2) - month = '0' + month; - if (day.length < 2) - day = '0' + day; + if (month.length < 2) + month = '0' + month; + if (day.length < 2) + day = '0' + day; - return [day, month, year].join('-'); - } - var schedule_id = "" - var d = new frappe.ui.Dialog({ - title: __("Enter Visit Details"), - fields: [{ - fieldtype: "Select", - fieldname: "item_name", - label: __("Item Name"), - options: options, - reqd: 1, - onchange: function () { - let field = d.get_field("scheduled_date"); - dates = "" - for (let i in s) { - if (s[i].item_name == this.value && s[i].completion_status == "Pending") { - dates = dates + '\n' + formatDate(s[i].scheduled_date); - } - - } - field.df.options = dates; - field.refresh(); - } - }, - { - label: __('Scheduled Date'), - fieldname: 'scheduled_date', - fieldtype: 'Select', - options: dates, - reqd: 1, - onchange: function(){ - let field = d.get_field('item_name'); - for(let i in s ){ - if(s[i].item_name == field.value && formatDate(s[i].scheduled_date) == this.value){ - schedule_id = s[i].name; - } - } - } - }, - ], - primary_action_label: 'Create Visit', - primary_action(values) { - frappe.call({ - method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", - args: { - item_name: values.item_name, - s_id: schedule_id, - source_name: me.frm.doc.name, - - }, - callback: function (r) { - if (!r.exc) { - frappe.model.sync(r.message); - frappe.set_route("Form", r.message.doctype, r.message.name); - } - } - - - }); - d.hide(); + return [day, month, year].join('-'); } - }) - d.show() + var schedule_id = ""; + var d = new frappe.ui.Dialog({ + title: __("Enter Visit Details"), + fields: [{ + fieldtype: "Select", + fieldname: "item_name", + label: __("Item Name"), + options: options, + reqd: 1, + onchange: function () { + let field = d.get_field("scheduled_date"); + dates = ""; + for (let i in s) { + if (s[i].item_name == this.value && s[i].completion_status == "Pending") { + dates = dates + '\n' + formatDate(s[i].scheduled_date); + } - }, __('Create')); + } + field.df.options = dates; + field.refresh(); + } + }, + { + label: __('Scheduled Date'), + fieldname: 'scheduled_date', + fieldtype: 'Select', + options: dates, + reqd: 1, + onchange: function () { + let field = d.get_field('item_name'); + for (let i in s) { + if (s[i].item_name == field.value && formatDate(s[i].scheduled_date) == this.value) { + schedule_id = s[i].name; + } + } + } + }, + ], + primary_action_label: 'Create Visit', + primary_action(values) { + frappe.call({ + method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", + args: { + item_name: values.item_name, + s_id: schedule_id, + source_name: me.frm.doc.name, + + }, + callback: function (r) { + if (!r.exc) { + frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + + + }); + d.hide(); + } + }); + d.show(); + + }, __('Create')); + } } - } }, start_date: function (doc, cdt, cdn) { diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index aa582ee219..b89d540ebb 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -10,6 +10,7 @@ from frappe import throw, _ from erpnext.utilities.transaction_base import TransactionBase, delete_events from erpnext.stock.utils import get_valid_serial_nos from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee +from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos class MaintenanceSchedule(TransactionBase): @frappe.whitelist() @@ -245,18 +246,28 @@ class MaintenanceSchedule(TransactionBase): def on_trash(self): delete_events(self.doctype, self.name) +@frappe.whitelist() +def update_serial_nos(s_id): + serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no') + if serial_nos: + serial_nos = get_serial_nos(serial_nos) + return serial_nos + else: + return False + @frappe.whitelist() def make_maintenance_visit(source_name, target_doc=None,item_name=None,s_id=None): from frappe.model.mapper import get_mapped_doc def update_status(source, target, parent): target.maintenance_type = "Scheduled" - + def update_sid(source, target, parent): target.prevdoc_detail_docname = s_id sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person') target.service_person = sales_person - + target.serial_no = '' + doclist = get_mapped_doc("Maintenance Schedule", source_name, { "Maintenance Schedule": { "doctype": "Maintenance Visit", diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js index 4cbb02a5b3..d5e8e51dfd 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js @@ -2,39 +2,62 @@ // License: GNU General Public License v3. See license.txt frappe.provide("erpnext.maintenance"); - +var serial_nos = []; frappe.ui.form.on('Maintenance Visit', { - refresh: function(frm) { + refresh: function (frm) { //filters for serial_no based on item_code - frm.set_query('serial_no', 'purposes', function(frm, cdt, cdn) { + frm.set_query('serial_no', 'purposes', function (frm, cdt, cdn) { let item = locals[cdt][cdn]; - return { - filters: { - 'item_code': item.item_code - } - }; + if (serial_nos) { + return { + filters: { + 'item_code': item.item_code, + 'name': ["in", serial_nos] + } + }; + + } else { + + return { + filters: { + 'item_code': item.item_code + } + }; + } + }); }, - setup: function(frm) { + setup: function (frm) { frm.set_query('contact_person', erpnext.queries.contact_query); frm.set_query('customer_address', erpnext.queries.address_query); frm.set_query('customer', erpnext.queries.customer); }, - onload: function(frm) { + onload: function (frm, cdt, cdn) { + let item = locals[cdt][cdn]; + let s_id = item.purposes[0].prevdoc_detail_docname; + frappe.call({ + method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos", + args: { + s_id: s_id + }, + callback: function (r) { + serial_nos = r.message; + } + }); if (!frm.doc.status) { - frm.set_value({status:'Draft'}); + frm.set_value({ status: 'Draft' }); } if (frm.doc.__islocal) { - frm.set_value({mntc_date: frappe.datetime.get_today()}); + frm.set_value({ mntc_date: frappe.datetime.get_today() }); } }, - customer: function(frm) { + customer: function (frm) { erpnext.utils.get_party_details(frm); }, - customer_address: function(frm) { + customer_address: function (frm) { erpnext.utils.get_address_display(frm, 'customer_address', 'address_display'); }, - contact_person: function(frm) { + contact_person: function (frm) { erpnext.utils.get_contact_details(frm); } @@ -42,14 +65,14 @@ frappe.ui.form.on('Maintenance Visit', { // TODO commonify this code erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({ - refresh: function() { - frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'} + refresh: function () { + frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' }; var me = this; - if (this.frm.doc.docstatus===0) { + if (this.frm.doc.docstatus === 0) { this.frm.add_custom_button(__('Maintenance Schedule'), - function() { + function () { erpnext.utils.map_current_doc({ method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", source_doctype: "Maintenance Schedule", @@ -64,7 +87,7 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({ }) }, __("Get Items From")); this.frm.add_custom_button(__('Warranty Claim'), - function() { + function () { erpnext.utils.map_current_doc({ method: "erpnext.support.doctype.warranty_claim.warranty_claim.make_maintenance_visit", source_doctype: "Warranty Claim", @@ -80,7 +103,7 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({ }) }, __("Get Items From")); this.frm.add_custom_button(__('Sales Order'), - function() { + function () { erpnext.utils.map_current_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit", source_doctype: "Sales Order", @@ -99,4 +122,4 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({ }, }); -$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm})); \ No newline at end of file +$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({ frm: cur_frm })); \ No newline at end of file diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index 9505a36545..8a3094cb36 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -30,20 +30,21 @@ class MaintenanceVisit(TransactionBase): def validate(self): self.validate_serial_no() self.validate_mntc_date() + + def get_schedule_datail_ref(self): + if self.maintenance_type == "Scheduled": + p = self.purposes + for i in p: + detail_ref = i.prevdoc_detail_docname + return detail_ref def update_completion_status(self): - if self.maintenance_type == "Scheduled": - p = self.purposes - for i in p: - detail_ref = i.prevdoc_detail_docname - frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'completion_status', self.completion_status) + detail_ref = self.get_schedule_datail_ref() + frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'completion_status', self.completion_status) def update_actual_date(self): - if self.maintenance_type == "Scheduled": - p = self.purposes - for i in p: - detail_ref = i.prevdoc_detail_docname - frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'actual_date', self.mntc_date) + detail_ref = self.get_schedule_datail_ref() + frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'actual_date', self.mntc_date) def update_customer_issue(self, flag): for d in self.get('purposes'): From fa9629c1e1cf110b7c55230da3ea65b0ecd7d0d6 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Wed, 21 Apr 2021 11:29:40 +0530 Subject: [PATCH 011/180] fix: Updated forms and fixed an error. --- .../maintenance_schedule.json | 9 ++++-- .../maintenance_schedule_detail.json | 28 +++++++++++++++++-- .../maintenance_visit/maintenance_visit.js | 25 ++++++++++------- .../maintenance_visit_purpose.json | 16 +++++++++-- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json index 1871228711..4df0c6c0f7 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json @@ -229,8 +229,13 @@ "icon": "fa fa-calendar", "idx": 1, "is_submittable": 1, - "links": [], - "modified": "2021-04-16 15:53:36.670816", + "links": [ + { + "link_doctype": "Maintenance Visit Purpose", + "link_fieldname": "prevdoc_docname" + } + ], + "modified": "2021-04-21 11:27:05.744109", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule", diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json index f1e2e21a12..76acefbf61 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json @@ -9,10 +9,14 @@ "field_order": [ "item_code", "item_name", + "column_break_3", "scheduled_date", - "sales_person", "actual_date", + "section_break_6", + "sales_person", + "column_break_8", "completion_status", + "section_break_10", "serial_no", "item_ref" ], @@ -95,15 +99,33 @@ }, { "fieldname": "item_ref", - "fieldtype": "Data", + "fieldtype": "Link", + "hidden": 1, "label": "Item Reference", + "options": "Maintenance Schedule Item", "read_only": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_10", + "fieldtype": "Section Break" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-19 17:42:31.685710", + "modified": "2021-04-21 11:07:29.524071", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule Detail", diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js index d5e8e51dfd..403d1ab4cc 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js @@ -34,16 +34,21 @@ frappe.ui.form.on('Maintenance Visit', { }, onload: function (frm, cdt, cdn) { let item = locals[cdt][cdn]; - let s_id = item.purposes[0].prevdoc_detail_docname; - frappe.call({ - method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos", - args: { - s_id: s_id - }, - callback: function (r) { - serial_nos = r.message; - } - }); + if (frm.maintenance_type == 'Scheduled') { + + let s_id = item.purposes[0].prevdoc_detail_docname; + frappe.call({ + method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos", + args: { + s_id: s_id + }, + callback: function (r) { + serial_nos = r.message; + } + }); + + } + if (!frm.doc.status) { frm.set_value({ status: 'Draft' }); } diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json index 60e5afe806..0d19d708d9 100644 --- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json +++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json @@ -9,10 +9,12 @@ "field_order": [ "item_code", "item_name", + "column_break_3", + "service_person", "serial_no", + "section_break_6", "description", "work_details", - "service_person", "work_done", "prevdoc_doctype", "prevdoc_docname", @@ -86,6 +88,7 @@ { "fieldname": "prevdoc_doctype", "fieldtype": "Link", + "hidden": 1, "label": "Document Type", "no_copy": 1, "oldfieldname": "prevdoc_doctype", @@ -114,6 +117,7 @@ { "fieldname": "prevdoc_detail_docname", "fieldtype": "Link", + "hidden": 1, "label": "Against Document Detail No", "no_copy": 1, "oldfieldname": "prevdoc_detail_docname", @@ -124,12 +128,20 @@ "read_only": 1, "report_hide": 1, "width": "160px" + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_6", + "fieldtype": "Section Break" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-19 16:08:10.671163", + "modified": "2021-04-21 11:16:52.025914", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Visit Purpose", From 1e912db3bb43afcff98947e46149c1c848287c0e Mon Sep 17 00:00:00 2001 From: noahjacob Date: Mon, 26 Apr 2021 15:46:18 +0530 Subject: [PATCH 012/180] feat: Added check box to combine items --- .../production_plan/production_plan.js | 18 +- .../production_plan/production_plan.json | 22 +- .../production_plan/production_plan.py | 43 +- .../production_plan_item.json | 950 ++++-------------- .../__init__.py | 0 .../production_plan_item_reference.json | 52 + .../production_plan_item_reference.py | 10 + .../doctype/work_order/work_order.py | 27 +- 8 files changed, 355 insertions(+), 767 deletions(-) create mode 100644 erpnext/manufacturing/doctype/production_plan_item_reference/__init__.py create mode 100644 erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json create mode 100644 erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 288c1d0cd6..39b8c94bc1 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -211,16 +211,30 @@ frappe.ui.form.on('Production Plan', { }); }, - get_items: function(frm) { + get_items: function (frm) { + frm.clear_table('prod_plan_ref'); + frappe.call({ method: "get_items", freeze: true, doc: frm.doc, - callback: function() { + callback: function () { refresh_field('po_items'); } }); }, + combine_items: function (frm) { + frm.clear_table('po_items'); + frm.clear_table('prod_plan_ref'); + + frappe.call({ + method: "get_items", + freeze: true, + doc: frm.doc, + }); + + + }, get_items_for_mr: function(frm) { if (!frm.doc.for_warehouse) { diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index f11470086a..5c73992d1b 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -28,7 +28,10 @@ "material_requests", "select_items_to_manufacture_section", "get_items", + "combine_items", "po_items", + "section_break_25", + "prod_plan_ref", "material_request_planning", "include_non_stock_items", "include_subcontracted_items", @@ -316,13 +319,30 @@ "fieldname": "include_safety_stock", "fieldtype": "Check", "label": "Include Safety Stock in Required Qty Calculation" + }, + { + "fieldname": "prod_plan_ref", + "fieldtype": "Table", + "hidden": 1, + "label": "Production Plan Item Reference", + "options": "Production Plan Item Reference" + }, + { + "default": "0", + "fieldname": "combine_items", + "fieldtype": "Check", + "label": "Consolidate Items" + }, + { + "fieldname": "section_break_25", + "fieldtype": "Section Break" } ], "icon": "fa fa-calendar", "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-03-08 11:17:25.470147", + "modified": "2021-04-26 14:11:43.564957", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index a3e23a6897..b2bc21fb6d 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -96,8 +96,10 @@ class ProductionPlan(Document): @frappe.whitelist() def get_items(self): + self.set('po_items', []) if self.get_items_from == "Sales Order": - self.get_so_items() + self.get_so_items() + elif self.get_items_from == "Material Request": self.get_mr_items() @@ -165,10 +167,24 @@ class ProductionPlan(Document): self.calculate_total_planned_qty() def add_items(self, items): - self.set('po_items', []) + refs = {} for data in items: item_details = get_item_details(data.item_code) + if self.combine_items: + if item_details.bom_no in refs.keys(): + refs[item_details.bom_no]['qty'] = refs[item_details.bom_no]['qty'] + data.pending_qty + refs[item_details.bom_no]['so'].append(data.parent) + refs[item_details.bom_no]['so_items'].append(data.name) + refs[item_details.bom_no]['planned_qty'].append(data.pending_qty) + continue + else: + refs[item_details.bom_no] = {'qty': data.pending_qty, 'ref': data.name} + refs[item_details.bom_no]['so'] = [data.parent] + refs[item_details.bom_no]['so_items'] = [data.name] + refs[item_details.bom_no]['planned_qty'] = [data.pending_qty] + pi = self.append('po_items', { + 'name': data.name, 'include_exploded_items': 1, 'warehouse': data.warehouse, 'item_code': data.item_code, @@ -185,11 +201,32 @@ class ProductionPlan(Document): pi.sales_order = data.parent pi.sales_order_item = data.name pi.description = data.description - + + elif self.get_items_from == "Material Request": pi.material_request = data.parent pi.material_request_item = data.name pi.description = data.description + + if refs: + for d in self.po_items: + d.planned_qty = refs[d.bom_no]['qty'] + d.pending_qty = refs[d.bom_no]['qty'] + d.sales_order = '' + self.add_pp_ref(refs) + + def add_pp_ref(self, refs): + for r in refs: + idx = 0 + for so in refs[r]['so']: + self.append('prod_plan_ref', { + 'item_ref': refs[r]['ref'], + 'sales_order': so, + 'sales_order_item':refs[r]['so_items'][idx], + 'qty':refs[r]['planned_qty'][idx] + }) + idx+=1 + def calculate_total_planned_qty(self): self.total_planned_qty = 0 diff --git a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json index d0dce53437..9ff1717e70 100644 --- a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json +++ b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json @@ -1,792 +1,222 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "hash", - "beta": 0, - "creation": "2013-02-22 01:27:49", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 1, + "actions": [], + "autoname": "hash", + "creation": "2013-02-22 01:27:49", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "include_exploded_items", + "item_code", + "bom_no", + "planned_qty", + "column_break_6", + "make_work_order_for_sub_assembly_items", + "warehouse", + "planned_start_date", + "section_break_9", + "pending_qty", + "ordered_qty", + "produced_qty", + "column_break_17", + "description", + "stock_uom", + "reference_section", + "sales_order", + "sales_order_item", + "column_break_19", + "material_request", + "material_request_item", + "product_bundle_item" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fetch_if_empty": 0, - "fieldname": "include_exploded_items", - "fieldtype": "Check", - "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": "Include Exploded 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 - }, + "columns": 2, + "default": "0", + "fieldname": "include_exploded_items", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Include Exploded Items" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "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, - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "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, + "columns": 2, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item", + "print_width": "150px", + "reqd": 1, "width": "150px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fetch_if_empty": 0, - "fieldname": "bom_no", - "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": "BOM No", - "length": 0, - "no_copy": 0, - "oldfieldname": "bom_no", - "oldfieldtype": "Link", - "options": "BOM", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "100px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "columns": 2, + "fieldname": "bom_no", + "fieldtype": "Link", + "in_list_view": 1, + "label": "BOM No", + "oldfieldname": "bom_no", + "oldfieldtype": "Link", + "options": "BOM", + "print_width": "100px", + "reqd": 1, "width": "100px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "planned_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": "Planned Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "planned_qty", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "100px", - "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": "planned_qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Planned Qty", + "oldfieldname": "planned_qty", + "oldfieldtype": "Currency", + "print_width": "100px", + "reqd": 1, "width": "100px" - }, + }, { - "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_6", - "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_6", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "description": "If enabled, system will create the work order for the exploded items against which BOM is available.", - "fetch_if_empty": 0, - "fieldname": "make_work_order_for_sub_assembly_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": "Make Work Order for Sub Assembly 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": "0", + "description": "If enabled, system will create the work order for the exploded items against which BOM is available.", + "fieldname": "make_work_order_for_sub_assembly_items", + "fieldtype": "Check", + "label": "Make Work Order for Sub Assembly Items" + }, { - "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": "warehouse", - "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": "For Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "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": "warehouse", + "fieldtype": "Link", + "in_list_view": 1, + "label": "For Warehouse", + "options": "Warehouse" + }, { - "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": "planned_start_date", - "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": "Planned Start 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": "planned_start_date", + "fieldtype": "Datetime", + "in_list_view": 1, + "label": "Planned Start Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "section_break_9", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Quantity and Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_9", + "fieldtype": "Section Break", + "label": "Quantity and Description" + }, { - "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": "pending_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": "Pending Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "prevdoc_reqd_qty", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "100px", - "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": "pending_qty", + "fieldtype": "Float", + "label": "Pending Qty", + "oldfieldname": "prevdoc_reqd_qty", + "oldfieldtype": "Currency", + "print_width": "100px", + "read_only": 1, "width": "100px" - }, + }, { - "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": "ordered_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": "Ordered Qty", - "length": 0, - "no_copy": 0, - "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": "ordered_qty", + "fieldtype": "Float", + "label": "Ordered Qty", + "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": "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": "Produced Qty", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "produced_qty", + "fieldtype": "Float", + "label": "Produced Qty", + "no_copy": 1, + "read_only": 1 + }, { - "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_17", - "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_17", + "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": "description", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "200px", - "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": "description", + "fieldtype": "Text Editor", + "label": "Description", + "oldfieldname": "description", + "oldfieldtype": "Text", + "print_width": "200px", + "read_only": 1, "width": "200px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "stock_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "oldfieldname": "stock_uom", - "oldfieldtype": "Data", - "options": "UOM", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "80px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "stock_uom", + "fieldtype": "Link", + "label": "UOM", + "oldfieldname": "stock_uom", + "oldfieldtype": "Data", + "options": "UOM", + "print_width": "80px", + "read_only": 1, + "reqd": 1, "width": "80px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "reference_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": "Reference", - "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": "reference_section", + "fieldtype": "Section Break", + "label": "Reference" + }, { - "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_order", - "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": "Sales Order", - "length": 0, - "no_copy": 0, - "oldfieldname": "source_docname", - "oldfieldtype": "Data", - "options": "Sales Order", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sales_order", + "fieldtype": "Link", + "label": "Sales Order", + "oldfieldname": "source_docname", + "oldfieldtype": "Data", + "options": "Sales Order", + "read_only": 1 + }, { - "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_order_item", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sales Order Item", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sales_order_item", + "fieldtype": "Data", + "hidden": 1, + "label": "Sales Order Item", + "no_copy": 1, + "print_hide": 1 + }, { - "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_19", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_19", + "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": "material_request", - "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": "Material Request", - "length": 0, - "no_copy": 0, - "options": "Material Request", - "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": "material_request", + "fieldtype": "Link", + "label": "Material Request", + "options": "Material Request", + "read_only": 1 + }, { - "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_request_item", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "material_request_item", - "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_item", + "fieldtype": "Data", + "hidden": 1, + "label": "material_request_item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "product_bundle_item", - "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": "Product Bundle Item", - "length": 0, - "no_copy": 1, - "options": "Item", - "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": "product_bundle_item", + "fieldtype": "Link", + "label": "Product Bundle Item", + "no_copy": 1, + "options": "Item", + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_toolbar": 0, - "idx": 1, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2019-04-08 23:09:57.199423", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "Production Plan Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2021-04-22 12:10:01.102440", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Production Plan Item", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan_item_reference/__init__.py b/erpnext/manufacturing/doctype/production_plan_item_reference/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json new file mode 100644 index 0000000000..19e813c5b3 --- /dev/null +++ b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json @@ -0,0 +1,52 @@ +{ + "actions": [], + "creation": "2021-04-22 10:32:58.896330", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_ref", + "sales_order", + "sales_order_item", + "qty" + ], + "fields": [ + { + "fieldname": "item_ref", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Item Reference" + }, + { + "fieldname": "sales_order", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Sales Order Reference", + "options": "Sales Order" + }, + { + "fieldname": "sales_order_item", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Sales Order Item" + }, + { + "fieldname": "qty", + "fieldtype": "Data", + "in_list_view": 1, + "label": "qty" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-04-23 16:55:22.161418", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Production Plan Item Reference", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py new file mode 100644 index 0000000000..51fbc3633b --- /dev/null +++ b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class ProductionPlanItemReference(Document): + pass diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 8507f5eb34..bd286507ec 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -241,7 +241,13 @@ class WorkOrder(Document): if not self.fg_warehouse: frappe.throw(_("For Warehouse is required before Submit")) - self.update_work_order_qty_in_so() + prod_plan = frappe.get_doc('Production Plan', self.production_plan) + pp_ref = prod_plan.prod_plan_ref + if pp_ref: + self.update_work_order_qty_in_combined_so() + else: + self.update_work_order_qty_in_so() + self.update_reserved_qty_for_production() self.update_completed_qty_in_material_request() self.update_planned_qty() @@ -357,6 +363,25 @@ class WorkOrder(Document): work_order_qty = qty[0][0] if qty and qty[0][0] else 0 frappe.db.set_value('Sales Order Item', self.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) + + def update_work_order_qty_in_combined_so(self): + total_bundle_qty = 1 + if self.product_bundle_item: + total_bundle_qty = frappe.db.sql(""" select sum(qty) from + `tabProduct Bundle Item` where parent = %s""", (frappe.db.escape(self.product_bundle_item)))[0][0] + + if not total_bundle_qty: + # product bundle is 0 (product bundle allows 0 qty for items) + total_bundle_qty = 1 + + prod_plan = frappe.get_doc('Production Plan', self.production_plan) + pp_ref = prod_plan.prod_plan_ref + for p in pp_ref: + if p.item_ref == self.production_plan_item: + work_order_qty = int(p.qty) + frappe.db.set_value('Sales Order Item', + p.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) + def update_completed_qty_in_material_request(self): if self.material_request: From 82905166d988f162b6fa84a49ee63a0704bda661 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Wed, 28 Apr 2021 10:12:17 +0530 Subject: [PATCH 013/180] fix: Fixed updating sales order work qty after cancelling work order --- .../doctype/production_plan/production_plan.js | 1 - .../manufacturing/doctype/work_order/work_order.py | 12 +++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 39b8c94bc1..29c3d5b18e 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -224,7 +224,6 @@ frappe.ui.form.on('Production Plan', { }); }, combine_items: function (frm) { - frm.clear_table('po_items'); frm.clear_table('prod_plan_ref'); frappe.call({ diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index bd286507ec..87d57ad42c 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -258,7 +258,13 @@ class WorkOrder(Document): self.validate_cancel() frappe.db.set(self,'status', 'Cancelled') - self.update_work_order_qty_in_so() + prod_plan = frappe.get_doc('Production Plan', self.production_plan) + pp_ref = prod_plan.prod_plan_ref + if pp_ref: + self.update_work_order_qty_in_combined_so(cancel = True) + else: + self.update_work_order_qty_in_so() + self.delete_job_card() self.update_completed_qty_in_material_request() self.update_planned_qty() @@ -364,7 +370,7 @@ class WorkOrder(Document): frappe.db.set_value('Sales Order Item', self.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) - def update_work_order_qty_in_combined_so(self): + def update_work_order_qty_in_combined_so(self, cancel = None): total_bundle_qty = 1 if self.product_bundle_item: total_bundle_qty = frappe.db.sql(""" select sum(qty) from @@ -378,7 +384,7 @@ class WorkOrder(Document): pp_ref = prod_plan.prod_plan_ref for p in pp_ref: if p.item_ref == self.production_plan_item: - work_order_qty = int(p.qty) + work_order_qty = int(p.qty) if not cancel else 0 frappe.db.set_value('Sales Order Item', p.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) From b7ca9139042784530157d104126f3569bcd1d1d8 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Wed, 28 Apr 2021 19:21:36 +0530 Subject: [PATCH 014/180] fix: Added Item Reference field to link tables and update work_order_qty --- .../doctype/production_plan/production_plan.py | 1 + .../production_plan_item/production_plan_item.json | 11 +++++++++-- .../manufacturing/doctype/work_order/work_order.py | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index b2bc21fb6d..088089f87f 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -201,6 +201,7 @@ class ProductionPlan(Document): pi.sales_order = data.parent pi.sales_order_item = data.name pi.description = data.description + pi.item_reference = data.name elif self.get_items_from == "Material Request": diff --git a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json index 9ff1717e70..89ab7aa0a0 100644 --- a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json +++ b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.json @@ -27,7 +27,8 @@ "column_break_19", "material_request", "material_request_item", - "product_bundle_item" + "product_bundle_item", + "item_reference" ], "fields": [ { @@ -206,12 +207,18 @@ "options": "Item", "print_hide": 1, "read_only": 1 + }, + { + "fieldname": "item_reference", + "fieldtype": "Data", + "hidden": 1, + "label": "Item Reference" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-22 12:10:01.102440", + "modified": "2021-04-28 19:14:57.772123", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan Item", diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 87d57ad42c..d77c46fb03 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -382,8 +382,10 @@ class WorkOrder(Document): prod_plan = frappe.get_doc('Production Plan', self.production_plan) pp_ref = prod_plan.prod_plan_ref + pp_item = frappe.get_doc('Production Plan Item', self.production_plan_item) + item_ref = pp_item.item_reference for p in pp_ref: - if p.item_ref == self.production_plan_item: + if p.item_ref == item_ref: work_order_qty = int(p.qty) if not cancel else 0 frappe.db.set_value('Sales Order Item', p.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) From 56f697052cc01f3beab8a12d5b9978e2bf86ebbe Mon Sep 17 00:00:00 2001 From: noahjacob Date: Wed, 28 Apr 2021 19:25:22 +0530 Subject: [PATCH 015/180] test: added test case for combining items --- .../production_plan/test_production_plan.py | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 27335aa204..2f52ad9021 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -100,7 +100,7 @@ class TestProductionPlan(unittest.TestCase): def test_production_plan_sales_orders(self): item = 'Test Production Item 1' - so = make_sales_order(item_code=item, qty=5) + so = make_sales_order(item_code=item, qty=1) sales_order = so.name sales_order_item = so.items[0].name @@ -124,8 +124,8 @@ class TestProductionPlan(unittest.TestCase): wo_doc = frappe.get_doc('Work Order', work_order) wo_doc.update({ - 'wip_warehouse': '_Test Warehouse 1 - _TC', - 'fg_warehouse': '_Test Warehouse - _TC' + 'wip_warehouse': 'Work In Progress - _TC', + 'fg_warehouse': 'Finished Goods - _TC' }) wo_doc.submit() @@ -145,6 +145,57 @@ class TestProductionPlan(unittest.TestCase): self.assertEqual(sales_orders, []) + def test_production_plan_combine_items(self): + item = 'Test Production Item 1' + so = make_sales_order(item_code=item, qty=1) + sales_order = so.name + sales_order_item = so.items[0].name + + pln = frappe.new_doc('Production Plan') + pln.company = so.company + pln.get_items_from = 'Sales Order' + pln.append('sales_orders', { + 'sales_order': so.name, + 'sales_order_date': so.transaction_date, + 'customer': so.customer, + 'grand_total': so.grand_total + }) + so = make_sales_order(item_code=item, qty=2) + pln.append('sales_orders', { + 'sales_order': so.name, + 'sales_order_date': so.transaction_date, + 'customer': so.customer, + 'grand_total': so.grand_total + }) + pln.combine_items = 1 + pln.get_so_items() + pln.save() + pp = frappe.get_doc('Production Plan',pln.name) + for d in pp.prod_plan_ref: + d.item_ref = pp.po_items[0].name + pln.submit() + + self.assertTrue(pln.po_items[0].planned_qty,3) + + + pln.make_work_order() + + work_order = frappe.db.get_value('Work Order', {'production_plan_item': pln.po_items[0].name, + 'production_plan': pln.name,}, 'name') + + wo_doc = frappe.get_doc('Work Order', work_order) + wo_doc.update({ + 'wip_warehouse': 'Work In Progress - _TC', + }) + + wo_doc.submit() + for d in pln.prod_plan_ref: + so_wo_qty = frappe.db.get_value('Sales Order Item', d.sales_order_item, 'work_order_qty') + self.assertTrue(so_wo_qty,d.qty) + + + + def test_pp_to_mr_customer_provided(self): #Material Request from Production Plan for Customer Provided create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0) From 93c22ebbb98324153b6644475478c62ee15f8ff8 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 29 Apr 2021 12:57:41 +0530 Subject: [PATCH 016/180] refactor: created separate function to update work_order on cancel --- .../doctype/work_order/work_order.py | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index d77c46fb03..d9956e5bca 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -242,8 +242,8 @@ class WorkOrder(Document): frappe.throw(_("For Warehouse is required before Submit")) prod_plan = frappe.get_doc('Production Plan', self.production_plan) - pp_ref = prod_plan.prod_plan_ref - if pp_ref: + + if prod_plan.prod_plan_ref: self.update_work_order_qty_in_combined_so() else: self.update_work_order_qty_in_so() @@ -259,9 +259,9 @@ class WorkOrder(Document): frappe.db.set(self,'status', 'Cancelled') prod_plan = frappe.get_doc('Production Plan', self.production_plan) - pp_ref = prod_plan.prod_plan_ref - if pp_ref: - self.update_work_order_qty_in_combined_so(cancel = True) + + if prod_plan.prod_plan_ref: + self.update_work_order_combined_on_cancel() else: self.update_work_order_qty_in_so() @@ -370,7 +370,7 @@ class WorkOrder(Document): frappe.db.set_value('Sales Order Item', self.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) - def update_work_order_qty_in_combined_so(self, cancel = None): + def update_work_order_qty_in_combined_so(self): total_bundle_qty = 1 if self.product_bundle_item: total_bundle_qty = frappe.db.sql(""" select sum(qty) from @@ -381,14 +381,22 @@ class WorkOrder(Document): total_bundle_qty = 1 prod_plan = frappe.get_doc('Production Plan', self.production_plan) - pp_ref = prod_plan.prod_plan_ref pp_item = frappe.get_doc('Production Plan Item', self.production_plan_item) - item_ref = pp_item.item_reference - for p in pp_ref: - if p.item_ref == item_ref: - work_order_qty = int(p.qty) if not cancel else 0 + + for p in prod_plan.prod_plan_ref: + if p.item_ref == pp_item.item_reference: + work_order_qty = int(p.qty) frappe.db.set_value('Sales Order Item', p.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) + + def update_work_order_combined_on_cancel(self): + prod_plan = frappe.get_doc('Production Plan', self.production_plan) + pp_item = frappe.get_doc('Production Plan Item', self.production_plan_item) + + for p in prod_plan.prod_plan_ref: + if p.item_ref == pp_item.item_reference: + frappe.db.set_value('Sales Order Item', + p.sales_order_item, 'work_order_qty', 0.0) def update_completed_qty_in_material_request(self): From 90c667205adce829d9e0f9c4d74c4dd9effaa065 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 29 Apr 2021 12:58:35 +0530 Subject: [PATCH 017/180] test: added on_cancel test --- .../production_plan/test_production_plan.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 2f52ad9021..19b06bc8dd 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -148,8 +148,6 @@ class TestProductionPlan(unittest.TestCase): def test_production_plan_combine_items(self): item = 'Test Production Item 1' so = make_sales_order(item_code=item, qty=1) - sales_order = so.name - sales_order_item = so.items[0].name pln = frappe.new_doc('Production Plan') pln.company = so.company @@ -169,17 +167,13 @@ class TestProductionPlan(unittest.TestCase): }) pln.combine_items = 1 pln.get_so_items() - pln.save() - pp = frappe.get_doc('Production Plan',pln.name) - for d in pp.prod_plan_ref: - d.item_ref = pp.po_items[0].name + for d in pln.prod_plan_ref: + d.item_ref = pln.po_items[0].name pln.submit() - self.assertTrue(pln.po_items[0].planned_qty,3) - - - pln.make_work_order() + self.assertTrue(pln.po_items[0].planned_qty,3) + pln.make_work_order() work_order = frappe.db.get_value('Work Order', {'production_plan_item': pln.po_items[0].name, 'production_plan': pln.name,}, 'name') @@ -189,13 +183,19 @@ class TestProductionPlan(unittest.TestCase): }) wo_doc.submit() + so_items = [] for d in pln.prod_plan_ref: + so_items.append(d.sales_order_item) so_wo_qty = frappe.db.get_value('Sales Order Item', d.sales_order_item, 'work_order_qty') - self.assertTrue(so_wo_qty,d.qty) - - - - + self.assertEqual(so_wo_qty, d.qty) + wo_doc.cancel() + for s in so_items: + so_wo_qty = frappe.db.get_value('Sales Order Item', s, 'work_order_qty') + self.assertEqual(so_wo_qty, 0.0) + + lat_plan = frappe.get_doc('Production Plan',pln.name) + lat_plan.cancel() + def test_pp_to_mr_customer_provided(self): #Material Request from Production Plan for Customer Provided create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0) From 7ad66caf7f656347d2e9b3fe253ba64b6fd35ae0 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Fri, 30 Apr 2021 11:42:16 +0530 Subject: [PATCH 018/180] refactor: migrated calculation and validation logic in js to py --- .../maintenance_schedule.js | 84 ++++--------------- .../maintenance_schedule.py | 60 ++++++++++++- 2 files changed, 74 insertions(+), 70 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index 3c05526496..79167ae45f 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -73,31 +73,11 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ } if (flag) { this.frm.add_custom_button(__('Create Maintenance Visit'), function () { - let items = me.frm.doc.items; - let s = me.frm.doc.schedules; let options = ""; - let dates = ""; - for (let i in items) { - for (let d in s) { - if (s[d].item_name == items[i].item_name && s[d].completion_status == "Pending") { - options = options + '\n' + items[i].item_name; - break; - } - } - } - function formatDate(date) { - var d = new Date(date), - month = '' + (d.getMonth() + 1), - day = '' + d.getDate(), - year = d.getFullYear(); - - if (month.length < 2) - month = '0' + month; - if (day.length < 2) - day = '0' + day; - - return [day, month, year].join('-'); - } + + me.frm.call('get_pending_data',{data_type:"items"}).then(r =>{ + options = r.message + var schedule_id = ""; var d = new frappe.ui.Dialog({ title: __("Enter Visit Details"), @@ -109,30 +89,23 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ reqd: 1, onchange: function () { let field = d.get_field("scheduled_date"); - dates = ""; - for (let i in s) { - if (s[i].item_name == this.value && s[i].completion_status == "Pending") { - dates = dates + '\n' + formatDate(s[i].scheduled_date); - } - - } - field.df.options = dates; - field.refresh(); + me.frm.call('get_pending_data',{item_name:this.value,data_type:"date"}).then(r =>{ + field.df.options = r.message; + field.refresh(); + }) } }, { label: __('Scheduled Date'), fieldname: 'scheduled_date', fieldtype: 'Select', - options: dates, + options: "", reqd: 1, onchange: function () { let field = d.get_field('item_name'); - for (let i in s) { - if (s[i].item_name == field.value && formatDate(s[i].scheduled_date) == this.value) { - schedule_id = s[i].name; - } - } + me.frm.call('get_pending_data',{item_name:field.value,s_date:this.value,data_type:"id"}).then(r =>{ + schedule_id = r.message; + }) } }, ], @@ -159,7 +132,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ } }); d.show(); - + }); }, __('Create')); } } @@ -185,35 +158,8 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ var item = frappe.get_doc(cdt, cdn); if (item.start_date && item.periodicity) { - - var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1; - - var days_in_period = { - "Weekly": 7, - "Monthly": 30, - "Quarterly": 91, - "Half Yearly": 182, - "Yearly": 365 - } - - var no_of_visits = cint(date_diff / days_in_period[item.periodicity]); - if (no_of_visits == 0 || !no_of_visits) { - - let end_date = frappe.datetime.add_days(item.start_date, days_in_period[item.periodicity]); - frappe.model.set_value(item.doctype, item.name, "end_date", end_date); - date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1; - no_of_visits = cint(date_diff / days_in_period[item.periodicity]); - frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits); - - } else if (item.no_of_visits > no_of_visits) { - let end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]); - frappe.model.set_value(item.doctype, item.name, "end_date", end_date); - - } else if (item.no_of_visits < no_of_visits) { - let end_date = frappe.datetime.add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]); - frappe.model.set_value(item.doctype, item.name, "end_date", end_date); - - } + me.frm.call('validate_end_date_visits') + } }, }); diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index b89d540ebb..d11bf7e735 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import add_days, getdate, cint, cstr +from frappe.utils import add_days, getdate, cint, cstr, date_diff, formatdate from frappe import throw, _ from erpnext.utilities.transaction_base import TransactionBase, delete_events @@ -36,6 +36,39 @@ class MaintenanceSchedule(TransactionBase): child.completion_status = "Pending" child.item_ref = d.name + @frappe.whitelist() + def validate_end_date_visits(self): + days_in_period = { + "Weekly": 7, + "Monthly": 30, + "Quarterly": 91, + "Half Yearly": 182, + "Yearly": 365 + } + for i in self.items: + + if i.periodicity and i.start_date: + if not i.end_date: + if i.no_of_visits: + i.end_date = add_days(i.start_date, i.no_of_visits * days_in_period[i.periodicity]) + else: + i.end_date = add_days(i.start_date, days_in_period[i.periodicity]) + + diff = date_diff(i.end_date, i.start_date) + 1 + no_of_visits = cint(diff / days_in_period[i.periodicity]) + + if not i.no_of_visits or i.no_of_visits == 0: + i.end_date = add_days(i.start_date, days_in_period[i.periodicity]) + diff = date_diff(i.end_date, i.start_date ) + 1 + i.no_of_visits = cint(diff / days_in_period[i.periodicity]) + + elif i.no_of_visits > no_of_visits: + i.end_date = add_days(i.start_date, i.no_of_visits * days_in_period[i.periodicity]) + + elif i.no_of_visits < no_of_visits: + i.end_date = add_days(i.start_date, i.no_of_visits * days_in_period[i.periodicity]) + + def on_submit(self): if not self.get('schedules'): throw(_("Please click on 'Generate Schedule' to get schedule")) @@ -166,6 +199,7 @@ class MaintenanceSchedule(TransactionBase): throw(_("Maintenance Schedule {0} exists against {1}").format(chk[0][0], d.sales_order)) def validate(self): + self.validate_end_date_visits() self.validate_maintenance_detail() self.validate_dates_with_periodicity() self.validate_sales_order() @@ -246,6 +280,30 @@ class MaintenanceSchedule(TransactionBase): def on_trash(self): delete_events(self.doctype, self.name) + + @frappe.whitelist() + def get_pending_data(self,data_type,s_date = None, item_name = None): + if data_type == "date": + dates = "" + for i in self.schedules: + if i.item_name == item_name and i.completion_status == "Pending": + dates = dates + "\n" + formatdate(i.scheduled_date, "dd-MM-yyyy") + return dates + elif data_type == "items": + items = "" + for i in self.items: + for s in self.schedules: + if i.item_name == s.item_name and s.completion_status == "Pending": + items = items + "\n" + i.item_name + break + return items + elif data_type == "id": + for s in self.schedules: + if s.item_name == item_name and s_date == formatdate(s.scheduled_date,"dd-mm-yyyy"): + return s.name + + + @frappe.whitelist() def update_serial_nos(s_id): serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no') From c0352010d360870d7ae2a057a1edefb72e72399b Mon Sep 17 00:00:00 2001 From: noahjacob Date: Fri, 30 Apr 2021 14:09:30 +0530 Subject: [PATCH 019/180] test: creating schedule and visit --- .../test_maintenance_schedule.py | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py index 3c307e920f..834c05476e 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py @@ -2,7 +2,8 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals -from frappe.utils.data import get_datetime, add_days +from frappe.utils.data import add_days, today +from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import make_maintenance_visit import frappe import unittest @@ -21,6 +22,52 @@ class TestMaintenanceSchedule(unittest.TestCase): ms.cancel() events_after_cancel = get_events(ms) self.assertTrue(len(events_after_cancel) == 0) + + def test_make_schedule(self): + ms = make_maintenance_schedule() + ms.save() + i = ms.items[0] + expected_end_date = add_days(i.start_date, i.no_of_visits * 7) + self.assertEqual(i.end_date, expected_end_date) + + i.no_of_visits = 2 + ms.save() + expected_end_date = add_days(i.start_date, i.no_of_visits * 7) + self.assertEqual(i.end_date, expected_end_date) + + items = ms.get_pending_data(data_type = "items") + items = items.split('\n') + items.pop(0) + expected_items = ['_Test Item'] + self.assertTrue(items,expected_items) + + dates = ms.get_pending_data(data_type = "date",item_name = i.item_name) + dates = dates.split('\n') + dates.pop(0) + expected_dates = ['07-05-2021','14-05-2021'] + self.assertEqual(dates,expected_dates) + + + ms.submit() + s_id = ms.get_pending_data(data_type = "id",item_name = i.item_name, s_date = "14-05-2021") + test = make_maintenance_visit(source_name = ms.name, item_name = "_Test Item", s_id = s_id) + visit = frappe.new_doc('Maintenance Visit') + visit = test + visit.completion_status = "Partially Completed" + + visit.set('purposes',[{ + 'item_code':i.item_code, + 'description':"test", + 'work_done':"test", + 'prevdoc_docname':ms.name, + 'prevdoc_doctype':ms.doctype, + 'prevdoc_detail_docname':s_id + }]) + visit.submit() + ms = frappe.get_doc('Maintenance Schedule',ms.name) + self.assertTrue(ms.schedules[1].completion_status,"Partially Completed") + + def get_events(ms): return frappe.get_all("Event Participants", filters={ @@ -29,16 +76,16 @@ def get_events(ms): "parenttype": "Event" }) + def make_maintenance_schedule(): ms = frappe.new_doc("Maintenance Schedule") ms.company = "_Test Company" ms.customer = "_Test Customer" - ms.transaction_date = get_datetime() + ms.transaction_date = today() ms.append("items", { "item_code": "_Test Item", - "start_date": get_datetime(), - "end_date": add_days(get_datetime(), 32), + "start_date": today(), "periodicity": "Weekly", "no_of_visits": 4, "sales_person": "Sales Team", From 50f52dfbcbf3124c1f9468807f1f22e6df2cb10c Mon Sep 17 00:00:00 2001 From: noahjacob Date: Fri, 7 May 2021 17:18:48 +0530 Subject: [PATCH 020/180] refactor: variable names and refactored cancel function into submit function --- .../production_plan/production_plan.json | 18 +++++------ .../production_plan/production_plan.py | 16 +++++----- .../production_plan/test_production_plan.py | 17 +++++----- .../production_plan_item_reference.json | 16 +++++----- .../doctype/work_order/work_order.py | 32 ++++++------------- 5 files changed, 44 insertions(+), 55 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 5c73992d1b..3041507caf 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -31,7 +31,7 @@ "combine_items", "po_items", "section_break_25", - "prod_plan_ref", + "prod_plan_references", "material_request_planning", "include_non_stock_items", "include_subcontracted_items", @@ -320,13 +320,6 @@ "fieldtype": "Check", "label": "Include Safety Stock in Required Qty Calculation" }, - { - "fieldname": "prod_plan_ref", - "fieldtype": "Table", - "hidden": 1, - "label": "Production Plan Item Reference", - "options": "Production Plan Item Reference" - }, { "default": "0", "fieldname": "combine_items", @@ -336,13 +329,20 @@ { "fieldname": "section_break_25", "fieldtype": "Section Break" + }, + { + "fieldname": "prod_plan_references", + "fieldtype": "Table", + "hidden": 1, + "label": "Production Plan Item Reference", + "options": "Production Plan Item Reference" } ], "icon": "fa fa-calendar", "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-04-26 14:11:43.564957", + "modified": "2021-05-07 16:56:00.255001", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 088089f87f..8d578fd935 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -172,7 +172,7 @@ class ProductionPlan(Document): item_details = get_item_details(data.item_code) if self.combine_items: if item_details.bom_no in refs.keys(): - refs[item_details.bom_no]['qty'] = refs[item_details.bom_no]['qty'] + data.pending_qty + refs[item_details.bom_no]['qty'] += data.pending_qty refs[item_details.bom_no]['so'].append(data.parent) refs[item_details.bom_no]['so_items'].append(data.name) refs[item_details.bom_no]['planned_qty'].append(data.pending_qty) @@ -217,15 +217,15 @@ class ProductionPlan(Document): self.add_pp_ref(refs) def add_pp_ref(self, refs): - for r in refs: + for bom_no in refs: idx = 0 - for so in refs[r]['so']: - self.append('prod_plan_ref', { - 'item_ref': refs[r]['ref'], + for so in refs[bom_no]['so']: + self.append('prod_plan_references', { + 'item_reference': refs[bom_no]['ref'], 'sales_order': so, - 'sales_order_item':refs[r]['so_items'][idx], - 'qty':refs[r]['planned_qty'][idx] - }) + 'sales_order_item':refs[bom_no]['so_items'][idx], + 'qty':refs[bom_no]['planned_qty'][idx] + }) idx+=1 diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 19b06bc8dd..ec5c5e0e13 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -167,8 +167,8 @@ class TestProductionPlan(unittest.TestCase): }) pln.combine_items = 1 pln.get_so_items() - for d in pln.prod_plan_ref: - d.item_ref = pln.po_items[0].name + for plan_reference in pln.prod_plan_references: + plan_reference.item_reference = pln.po_items[0].name pln.submit() self.assertTrue(pln.po_items[0].planned_qty,3) @@ -184,13 +184,14 @@ class TestProductionPlan(unittest.TestCase): wo_doc.submit() so_items = [] - for d in pln.prod_plan_ref: - so_items.append(d.sales_order_item) - so_wo_qty = frappe.db.get_value('Sales Order Item', d.sales_order_item, 'work_order_qty') - self.assertEqual(so_wo_qty, d.qty) + for plan_reference in pln.prod_plan_references: + so_items.append(plan_reference.sales_order_item) + so_wo_qty = frappe.db.get_value('Sales Order Item', plan_reference.sales_order_item, 'work_order_qty') + self.assertEqual(so_wo_qty, plan_reference.qty) + wo_doc.cancel() - for s in so_items: - so_wo_qty = frappe.db.get_value('Sales Order Item', s, 'work_order_qty') + for so_item in so_items: + so_wo_qty = frappe.db.get_value('Sales Order Item', so_item, 'work_order_qty') self.assertEqual(so_wo_qty, 0.0) lat_plan = frappe.get_doc('Production Plan',pln.name) diff --git a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json index 19e813c5b3..84dee4ad28 100644 --- a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json +++ b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.json @@ -5,18 +5,12 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "item_ref", + "item_reference", "sales_order", "sales_order_item", "qty" ], "fields": [ - { - "fieldname": "item_ref", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Item Reference" - }, { "fieldname": "sales_order", "fieldtype": "Link", @@ -35,12 +29,18 @@ "fieldtype": "Data", "in_list_view": 1, "label": "qty" + }, + { + "fieldname": "item_reference", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Item Reference" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-04-23 16:55:22.161418", + "modified": "2021-05-07 17:03:49.707487", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan Item Reference", diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index d9956e5bca..bb6450b775 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -240,10 +240,8 @@ class WorkOrder(Document): frappe.throw(_("Work-in-Progress Warehouse is required before Submit")) if not self.fg_warehouse: frappe.throw(_("For Warehouse is required before Submit")) - - prod_plan = frappe.get_doc('Production Plan', self.production_plan) - if prod_plan.prod_plan_ref: + if self.production_plan and frappe.db.exists('Production Plan Item Reference',{'parent':self.production_plan}): self.update_work_order_qty_in_combined_so() else: self.update_work_order_qty_in_so() @@ -256,12 +254,10 @@ class WorkOrder(Document): def on_cancel(self): self.validate_cancel() - frappe.db.set(self,'status', 'Cancelled') - prod_plan = frappe.get_doc('Production Plan', self.production_plan) - if prod_plan.prod_plan_ref: - self.update_work_order_combined_on_cancel() + if self.production_plan and frappe.db.exists('Production Plan Item Reference',{'parent':self.production_plan}): + self.update_work_order_qty_in_combined_so() else: self.update_work_order_qty_in_so() @@ -381,24 +377,16 @@ class WorkOrder(Document): total_bundle_qty = 1 prod_plan = frappe.get_doc('Production Plan', self.production_plan) - pp_item = frappe.get_doc('Production Plan Item', self.production_plan_item) + item_reference = frappe.get_value('Production Plan Item', self.production_plan_item,'item_reference') - for p in prod_plan.prod_plan_ref: - if p.item_ref == pp_item.item_reference: - work_order_qty = int(p.qty) + for plan_reference in prod_plan.prod_plan_references: + work_order_qty = 0.0 + if plan_reference.item_reference == item_reference: + if self.docstatus == 1: + work_order_qty = cint(plan_reference.qty) / total_bundle_qty frappe.db.set_value('Sales Order Item', - p.sales_order_item, 'work_order_qty', flt(work_order_qty/total_bundle_qty, 2)) + plan_reference.sales_order_item, 'work_order_qty', work_order_qty) - def update_work_order_combined_on_cancel(self): - prod_plan = frappe.get_doc('Production Plan', self.production_plan) - pp_item = frappe.get_doc('Production Plan Item', self.production_plan_item) - - for p in prod_plan.prod_plan_ref: - if p.item_ref == pp_item.item_reference: - frappe.db.set_value('Sales Order Item', - p.sales_order_item, 'work_order_qty', 0.0) - - def update_completed_qty_in_material_request(self): if self.material_request: frappe.get_doc("Material Request", self.material_request).update_completed_qty([self.material_request_item]) From 516c789127d8514368fc35392368b197534d5e0b Mon Sep 17 00:00:00 2001 From: noahjacob Date: Wed, 19 May 2021 13:29:30 +0530 Subject: [PATCH 021/180] refactor: variable names and suggested changes --- .../production_plan/production_plan.js | 6 +-- .../production_plan/production_plan.py | 51 ++++++++++--------- .../production_plan/test_production_plan.py | 16 +++--- .../doctype/work_order/work_order.py | 2 +- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 29c3d5b18e..64d584118f 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -212,7 +212,7 @@ frappe.ui.form.on('Production Plan', { }, get_items: function (frm) { - frm.clear_table('prod_plan_ref'); + frm.clear_table('prod_plan_references'); frappe.call({ method: "get_items", @@ -224,15 +224,13 @@ frappe.ui.form.on('Production Plan', { }); }, combine_items: function (frm) { - frm.clear_table('prod_plan_ref'); + frm.clear_table('prod_plan_references'); frappe.call({ method: "get_items", freeze: true, doc: frm.doc, }); - - }, get_items_for_mr: function(frm) { diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 8d578fd935..46e047654b 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -171,20 +171,28 @@ class ProductionPlan(Document): for data in items: item_details = get_item_details(data.item_code) if self.combine_items: - if item_details.bom_no in refs.keys(): + if item_details.bom_no in refs: + refs[item_details.bom_no]['so_details'].append({ + 'sales_order': data.parent, + 'sales_order_item': data.name, + 'qty': data.pending_qty + }) refs[item_details.bom_no]['qty'] += data.pending_qty - refs[item_details.bom_no]['so'].append(data.parent) - refs[item_details.bom_no]['so_items'].append(data.name) - refs[item_details.bom_no]['planned_qty'].append(data.pending_qty) continue + else: - refs[item_details.bom_no] = {'qty': data.pending_qty, 'ref': data.name} - refs[item_details.bom_no]['so'] = [data.parent] - refs[item_details.bom_no]['so_items'] = [data.name] - refs[item_details.bom_no]['planned_qty'] = [data.pending_qty] - + refs[item_details.bom_no] = { + 'qty': data.pending_qty, + 'po_item_ref': data.name, + 'so_details': [] + } + refs[item_details.bom_no]['so_details'].append({ + 'sales_order': data.parent, + 'sales_order_item': data.name, + 'qty': data.pending_qty + }) + pi = self.append('po_items', { - 'name': data.name, 'include_exploded_items': 1, 'warehouse': data.warehouse, 'item_code': data.item_code, @@ -201,8 +209,6 @@ class ProductionPlan(Document): pi.sales_order = data.parent pi.sales_order_item = data.name pi.description = data.description - pi.item_reference = data.name - elif self.get_items_from == "Material Request": pi.material_request = data.parent @@ -210,24 +216,21 @@ class ProductionPlan(Document): pi.description = data.description if refs: - for d in self.po_items: - d.planned_qty = refs[d.bom_no]['qty'] - d.pending_qty = refs[d.bom_no]['qty'] - d.sales_order = '' + for po_item in self.po_items: + po_item.planned_qty = refs[po_item.bom_no]['qty'] + po_item.pending_qty = refs[po_item.bom_no]['qty'] + po_item.sales_order = '' self.add_pp_ref(refs) def add_pp_ref(self, refs): for bom_no in refs: - idx = 0 - for so in refs[bom_no]['so']: + for so_detail in refs[bom_no]['so_details']: self.append('prod_plan_references', { - 'item_reference': refs[bom_no]['ref'], - 'sales_order': so, - 'sales_order_item':refs[bom_no]['so_items'][idx], - 'qty':refs[bom_no]['planned_qty'][idx] + 'item_reference': refs[bom_no]['po_item_ref'], + 'sales_order': so_detail['sales_order'], + 'sales_order_item': so_detail['sales_order_item'], + 'qty': so_detail['qty'] }) - idx+=1 - def calculate_total_planned_qty(self): self.total_planned_qty = 0 diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index ec5c5e0e13..768f99eb43 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -166,16 +166,16 @@ class TestProductionPlan(unittest.TestCase): 'grand_total': so.grand_total }) pln.combine_items = 1 - pln.get_so_items() - for plan_reference in pln.prod_plan_references: - plan_reference.item_reference = pln.po_items[0].name + pln.get_items() pln.submit() - self.assertTrue(pln.po_items[0].planned_qty,3) + self.assertTrue(pln.po_items[0].planned_qty, 3) pln.make_work_order() - work_order = frappe.db.get_value('Work Order', {'production_plan_item': pln.po_items[0].name, - 'production_plan': pln.name,}, 'name') + work_order = frappe.db.get_value('Work Order', { + 'production_plan_item': pln.po_items[0].name, + 'production_plan': pln.name + }, 'name') wo_doc = frappe.get_doc('Work Order', work_order) wo_doc.update({ @@ -194,8 +194,8 @@ class TestProductionPlan(unittest.TestCase): so_wo_qty = frappe.db.get_value('Sales Order Item', so_item, 'work_order_qty') self.assertEqual(so_wo_qty, 0.0) - lat_plan = frappe.get_doc('Production Plan',pln.name) - lat_plan.cancel() + latest_plan = frappe.get_doc('Production Plan', pln.name) + latest_plan.cancel() def test_pp_to_mr_customer_provided(self): #Material Request from Production Plan for Customer Provided diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index bb6450b775..a154464a8b 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -377,7 +377,7 @@ class WorkOrder(Document): total_bundle_qty = 1 prod_plan = frappe.get_doc('Production Plan', self.production_plan) - item_reference = frappe.get_value('Production Plan Item', self.production_plan_item,'item_reference') + item_reference = frappe.get_value('Production Plan Item', self.production_plan_item, 'sales_order_item') for plan_reference in prod_plan.prod_plan_references: work_order_qty = 0.0 From 08598238d73f4f033048baeedf9c96b4e7fc5102 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 20 May 2021 13:23:10 +0530 Subject: [PATCH 022/180] refactor: suggested changes --- .../maintenance_schedule.js | 26 +++--- .../maintenance_schedule.py | 79 +++++++++---------- .../maintenance_visit/maintenance_visit.js | 9 +-- 3 files changed, 52 insertions(+), 62 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index 79167ae45f..075bd40660 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -64,22 +64,17 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ }); }, __("Get Items From")); } else if (this.frm.doc.docstatus === 1) { - var s = me.frm.doc.schedules; - let flag = 0; - for (let i in s) { - if (s[i].completion_status == "Pending") { - flag = 1; - } - } + let schedules = me.frm.doc.schedules; + let flag = schedules.some(schedule => schedule.completion_status === "Pending"); if (flag) { this.frm.add_custom_button(__('Create Maintenance Visit'), function () { let options = ""; - me.frm.call('get_pending_data',{data_type:"items"}).then(r =>{ + me.frm.call('get_pending_data', {data_type: "items"}).then(r =>{ options = r.message - var schedule_id = ""; - var d = new frappe.ui.Dialog({ + let schedule_id = ""; + let d = new frappe.ui.Dialog({ title: __("Enter Visit Details"), fields: [{ fieldtype: "Select", @@ -103,7 +98,13 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ reqd: 1, onchange: function () { let field = d.get_field('item_name'); - me.frm.call('get_pending_data',{item_name:field.value,s_date:this.value,data_type:"id"}).then(r =>{ + me.frm.call( + 'get_pending_data', + { + item_name: field.value, + s_date: this.value, + data_type: "id" + }).then(r =>{ schedule_id = r.message; }) } @@ -117,7 +118,6 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ item_name: values.item_name, s_id: schedule_id, source_name: me.frm.doc.name, - }, callback: function (r) { if (!r.exc) { @@ -125,8 +125,6 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ frappe.set_route("Form", r.message.doctype, r.message.name); } } - - }); d.hide(); } diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index d11bf7e735..0bc2e87a6c 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -45,28 +45,27 @@ class MaintenanceSchedule(TransactionBase): "Half Yearly": 182, "Yearly": 365 } - for i in self.items: - - if i.periodicity and i.start_date: - if not i.end_date: - if i.no_of_visits: - i.end_date = add_days(i.start_date, i.no_of_visits * days_in_period[i.periodicity]) + for item in self.items: + if item.periodicity and item.start_date: + if not item.end_date: + if item.no_of_visits: + item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]) else: - i.end_date = add_days(i.start_date, days_in_period[i.periodicity]) + item.end_date = add_days(item.start_date, days_in_period[item.periodicity]) - diff = date_diff(i.end_date, i.start_date) + 1 - no_of_visits = cint(diff / days_in_period[i.periodicity]) + diff = date_diff(item.end_date, item.start_date) + 1 + no_of_visits = cint(diff / days_in_period[item.periodicity]) - if not i.no_of_visits or i.no_of_visits == 0: - i.end_date = add_days(i.start_date, days_in_period[i.periodicity]) - diff = date_diff(i.end_date, i.start_date ) + 1 - i.no_of_visits = cint(diff / days_in_period[i.periodicity]) + if not item.no_of_visits or item.no_of_visits == 0: + item.end_date = add_days(item.start_date, days_in_period[item.periodicity]) + diff = date_diff(item.end_date, item.start_date ) + 1 + item.no_of_visits = cint(diff / days_in_period[item.periodicity]) - elif i.no_of_visits > no_of_visits: - i.end_date = add_days(i.start_date, i.no_of_visits * days_in_period[i.periodicity]) + elif item.no_of_visits > no_of_visits: + item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]) - elif i.no_of_visits < no_of_visits: - i.end_date = add_days(i.start_date, i.no_of_visits * days_in_period[i.periodicity]) + elif item.no_of_visits < no_of_visits: + item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]) def on_submit(self): @@ -92,9 +91,10 @@ class MaintenanceSchedule(TransactionBase): if no_email_sp: frappe.msgprint( - frappe._("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format( - self.owner, "
" + "
".join(no_email_sp) - )) + _("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format( + self.owner, "
" + "
".join(no_email_sp) + ) + ) scheduled_date = frappe.db.sql("""select scheduled_date from `tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and @@ -103,12 +103,12 @@ class MaintenanceSchedule(TransactionBase): for key in scheduled_date: description =frappe._("Reference: {0}, Item Code: {1} and Customer: {2}").format(self.name, d.item_code, self.customer) event = frappe.get_doc({ - "doctype": "Event", - "owner": email_map.get(d.sales_person, self.owner), - "subject": description, - "description": description, - "starts_on": cstr(key["scheduled_date"]) + " 10:00:00", - "event_type": "Private", + "doctype": "Event", + "owner": email_map.get(d.sales_person, self.owner), + "subject": description, + "description": description, + "starts_on": cstr(key["scheduled_date"]) + " 10:00:00", + "event_type": "Private", }) event.add_participant(self.doctype, self.name) event.insert(ignore_permissions=1) @@ -126,7 +126,7 @@ class MaintenanceSchedule(TransactionBase): start_date_copy = add_days(start_date_copy, add_by) if len(schedule_list) < no_of_visit: schedule_date = self.validate_schedule_date_for_holiday_list(getdate(start_date_copy), - sales_person) + sales_person) if schedule_date > getdate(end_date): schedule_date = getdate(end_date) schedule_list.append(schedule_date) @@ -280,30 +280,27 @@ class MaintenanceSchedule(TransactionBase): def on_trash(self): delete_events(self.doctype, self.name) - @frappe.whitelist() def get_pending_data(self,data_type,s_date = None, item_name = None): if data_type == "date": dates = "" - for i in self.schedules: - if i.item_name == item_name and i.completion_status == "Pending": - dates = dates + "\n" + formatdate(i.scheduled_date, "dd-MM-yyyy") + for schedule in self.schedules: + if schedule.item_name == item_name and schedule.completion_status == "Pending": + dates = dates + "\n" + formatdate(schedule.scheduled_date, "dd-MM-yyyy") return dates elif data_type == "items": items = "" - for i in self.items: - for s in self.schedules: - if i.item_name == s.item_name and s.completion_status == "Pending": - items = items + "\n" + i.item_name + for item in self.items: + for schedule in self.schedules: + if item.item_name == schedule.item_name and schedule.completion_status == "Pending": + items = items + "\n" + item.item_name break return items elif data_type == "id": - for s in self.schedules: - if s.item_name == item_name and s_date == formatdate(s.scheduled_date,"dd-mm-yyyy"): - return s.name + for schedule in self.schedules: + if schedule.item_name == item_name and s_date == formatdate(schedule.scheduled_date,"dd-mm-yyyy"): + return schedule.name - - @frappe.whitelist() def update_serial_nos(s_id): serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no') @@ -314,7 +311,7 @@ def update_serial_nos(s_id): return False @frappe.whitelist() -def make_maintenance_visit(source_name, target_doc=None,item_name=None,s_id=None): +def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None): from frappe.model.mapper import get_mapped_doc def update_status(source, target, parent): diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js index 403d1ab4cc..d6105c657e 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js @@ -15,16 +15,13 @@ frappe.ui.form.on('Maintenance Visit', { 'name': ["in", serial_nos] } }; - } else { - return { filters: { 'item_code': item.item_code } }; } - }); }, setup: function (frm) { @@ -35,18 +32,16 @@ frappe.ui.form.on('Maintenance Visit', { onload: function (frm, cdt, cdn) { let item = locals[cdt][cdn]; if (frm.maintenance_type == 'Scheduled') { - - let s_id = item.purposes[0].prevdoc_detail_docname; + let schedule_id = item.purposes[0].prevdoc_detail_docname; frappe.call({ method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos", args: { - s_id: s_id + s_id: schedule_id }, callback: function (r) { serial_nos = r.message; } }); - } if (!frm.doc.status) { From 0169cd845ac9d6d00eba92b61195650a88fa05d0 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 20 May 2021 14:20:50 +0530 Subject: [PATCH 023/180] fix: sider --- .../maintenance_schedule.js | 122 +++++++++--------- .../maintenance_schedule.py | 4 +- 2 files changed, 65 insertions(+), 61 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index 075bd40660..1e5773c8bc 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -71,65 +71,69 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ let options = ""; me.frm.call('get_pending_data', {data_type: "items"}).then(r =>{ - options = r.message + options = r.message; - let schedule_id = ""; - let d = new frappe.ui.Dialog({ - title: __("Enter Visit Details"), - fields: [{ - fieldtype: "Select", - fieldname: "item_name", - label: __("Item Name"), - options: options, - reqd: 1, - onchange: function () { - let field = d.get_field("scheduled_date"); - me.frm.call('get_pending_data',{item_name:this.value,data_type:"date"}).then(r =>{ - field.df.options = r.message; - field.refresh(); - }) - } - }, - { - label: __('Scheduled Date'), - fieldname: 'scheduled_date', - fieldtype: 'Select', - options: "", - reqd: 1, - onchange: function () { - let field = d.get_field('item_name'); - me.frm.call( - 'get_pending_data', - { - item_name: field.value, - s_date: this.value, - data_type: "id" - }).then(r =>{ - schedule_id = r.message; - }) - } - }, - ], - primary_action_label: 'Create Visit', - primary_action(values) { - frappe.call({ - method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", - args: { - item_name: values.item_name, - s_id: schedule_id, - source_name: me.frm.doc.name, - }, - callback: function (r) { - if (!r.exc) { - frappe.model.sync(r.message); - frappe.set_route("Form", r.message.doctype, r.message.name); - } + let schedule_id = ""; + let d = new frappe.ui.Dialog({ + title: __("Enter Visit Details"), + fields: [{ + fieldtype: "Select", + fieldname: "item_name", + label: __("Item Name"), + options: options, + reqd: 1, + onchange: function () { + let field = d.get_field("scheduled_date"); + me.frm.call('get_pending_data', + { + item_name: this.value, + data_type: "date" + }).then(r => { + field.df.options = r.message; + field.refresh(); + }); } - }); - d.hide(); - } - }); - d.show(); + }, + { + label: __('Scheduled Date'), + fieldname: 'scheduled_date', + fieldtype: 'Select', + options: "", + reqd: 1, + onchange: function () { + let field = d.get_field('item_name'); + me.frm.call( + 'get_pending_data', + { + item_name: field.value, + s_date: this.value, + data_type: "id" + }).then(r =>{ + schedule_id = r.message; + }); + } + }, + ], + primary_action_label: 'Create Visit', + primary_action(values) { + frappe.call({ + method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit", + args: { + item_name: values.item_name, + s_id: schedule_id, + source_name: me.frm.doc.name, + }, + callback: function (r) { + if (!r.exc) { + frappe.model.sync(r.message); + frappe.set_route("Form", r.message.doctype, r.message.name); + } + } + }); + d.hide(); + } + }); + d.show(); }); }, __('Create')); } @@ -154,9 +158,9 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ set_no_of_visits: function (doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); - + let me = this; if (item.start_date && item.periodicity) { - me.frm.call('validate_end_date_visits') + me.frm.call('validate_end_date_visits'); } }, diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 0bc2e87a6c..5d573c5524 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -58,7 +58,7 @@ class MaintenanceSchedule(TransactionBase): if not item.no_of_visits or item.no_of_visits == 0: item.end_date = add_days(item.start_date, days_in_period[item.periodicity]) - diff = date_diff(item.end_date, item.start_date ) + 1 + diff = date_diff(item.end_date, item.start_date) + 1 item.no_of_visits = cint(diff / days_in_period[item.periodicity]) elif item.no_of_visits > no_of_visits: @@ -93,8 +93,8 @@ class MaintenanceSchedule(TransactionBase): frappe.msgprint( _("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format( self.owner, "
" + "
".join(no_email_sp) - ) ) + ) scheduled_date = frappe.db.sql("""select scheduled_date from `tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and From f0e6a169101fe92994d93e1e6f91bee40f8baf9c Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 20 May 2021 19:29:12 +0530 Subject: [PATCH 024/180] test: updated test for generated schedule dates --- .../test_maintenance_schedule.py | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py index 834c05476e..58ee964fb5 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py @@ -2,7 +2,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals -from frappe.utils.data import add_days, today +from frappe.utils.data import add_days, today, formatdate from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import make_maintenance_visit import frappe @@ -27,6 +27,7 @@ class TestMaintenanceSchedule(unittest.TestCase): ms = make_maintenance_schedule() ms.save() i = ms.items[0] + expected_dates = [] expected_end_date = add_days(i.start_date, i.no_of_visits * 7) self.assertEqual(i.end_date, expected_end_date) @@ -39,36 +40,39 @@ class TestMaintenanceSchedule(unittest.TestCase): items = items.split('\n') items.pop(0) expected_items = ['_Test Item'] - self.assertTrue(items,expected_items) + self.assertTrue(items, expected_items) - dates = ms.get_pending_data(data_type = "date",item_name = i.item_name) + # "dates" contains all generated schedule dates + dates = ms.get_pending_data(data_type = "date", item_name = i.item_name) dates = dates.split('\n') dates.pop(0) - expected_dates = ['07-05-2021','14-05-2021'] - self.assertEqual(dates,expected_dates) + expected_dates.append(formatdate(add_days(i.start_date, 7), "dd-MM-yyyy")) + expected_dates.append(formatdate(add_days(i.start_date, 14), "dd-MM-yyyy")) + + # test for generated schedule dates + self.assertEqual(dates, expected_dates) - ms.submit() - s_id = ms.get_pending_data(data_type = "id",item_name = i.item_name, s_date = "14-05-2021") + s_id = ms.get_pending_data(data_type = "id", item_name = i.item_name, s_date = expected_dates[1]) test = make_maintenance_visit(source_name = ms.name, item_name = "_Test Item", s_id = s_id) visit = frappe.new_doc('Maintenance Visit') visit = test visit.completion_status = "Partially Completed" - visit.set('purposes',[{ - 'item_code':i.item_code, - 'description':"test", - 'work_done':"test", - 'prevdoc_docname':ms.name, - 'prevdoc_doctype':ms.doctype, - 'prevdoc_detail_docname':s_id + visit.set('purposes', [{ + 'item_code': i.item_code, + 'description': "test", + 'work_done': "test", + 'prevdoc_docname' :ms.name, + 'prevdoc_doctype': ms.doctype, + 'prevdoc_detail_docname': s_id }]) visit.submit() - ms = frappe.get_doc('Maintenance Schedule',ms.name) - self.assertTrue(ms.schedules[1].completion_status,"Partially Completed") + ms = frappe.get_doc('Maintenance Schedule', ms.name) + + #checks if visit status is back updated in schedule + self.assertTrue(ms.schedules[1].completion_status, "Partially Completed") - - def get_events(ms): return frappe.get_all("Event Participants", filters={ "reference_doctype": ms.doctype, @@ -76,7 +80,6 @@ def get_events(ms): "parenttype": "Event" }) - def make_maintenance_schedule(): ms = frappe.new_doc("Maintenance Schedule") ms.company = "_Test Company" From 330353a5ced3d40dc2e699a4481234de205b1fd7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 22:07:45 +0530 Subject: [PATCH 025/180] refactor: use frappe.throw instread of recreating _msgprint was basically duplicating behvaiour of frappe.throw --- erpnext/stock/doctype/item/item.py | 25 ++++++------------- .../stock_reconciliation.py | 6 ++--- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index dbac79465e..174c87b48d 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1068,42 +1068,31 @@ def get_timeline_data(doctype, name): return out -def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1): +def validate_end_of_life(item_code, end_of_life=None, disabled=None): if (not end_of_life) or (disabled is None): end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"]) if end_of_life and end_of_life != "0000-00-00" and getdate(end_of_life) <= now_datetime().date(): - msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life)) - _msgprint(msg, verbose) + frappe.throw(_("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life))) if disabled: - _msgprint(_("Item {0} is disabled").format(item_code), verbose) + frappe.throw(_("Item {0} is disabled").format(item_code)) -def validate_is_stock_item(item_code, is_stock_item=None, verbose=1): +def validate_is_stock_item(item_code, is_stock_item=None): if not is_stock_item: is_stock_item = frappe.db.get_value("Item", item_code, "is_stock_item") if is_stock_item != 1: - msg = _("Item {0} is not a stock Item").format(item_code) - - _msgprint(msg, verbose) + frappe.throw(_("Item {0} is not a stock Item").format(item_code)) -def validate_cancelled_item(item_code, docstatus=None, verbose=1): +def validate_cancelled_item(item_code, docstatus=None): if docstatus is None: docstatus = frappe.db.get_value("Item", item_code, "docstatus") if docstatus == 2: - msg = _("Item {0} is cancelled").format(item_code) - _msgprint(msg, verbose) - -def _msgprint(msg, verbose): - if verbose: - msgprint(msg, raise_exception=True) - else: - raise frappe.ValidationError(msg) - + frappe.throw(_("Item {0} is cancelled").format(item_code)) def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): """returns last purchase details in stock uom""" diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 7e216d6181..96b1cadaaf 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -167,8 +167,8 @@ class StockReconciliation(StockController): item = frappe.get_doc("Item", item_code) # end of life and stock item - validate_end_of_life(item_code, item.end_of_life, item.disabled, verbose=0) - validate_is_stock_item(item_code, item.is_stock_item, verbose=0) + validate_end_of_life(item_code, item.end_of_life, item.disabled) + validate_is_stock_item(item_code, item.is_stock_item) # item should not be serialized if item.has_serial_no and not row.serial_no and not item.serial_no_series: @@ -179,7 +179,7 @@ class StockReconciliation(StockController): raise frappe.ValidationError(_("Batch no is required for batched item {0}").format(item_code)) # docstatus should be < 2 - validate_cancelled_item(item_code, item.docstatus, verbose=0) + validate_cancelled_item(item_code, item.docstatus) except Exception as e: self.validation_messages.append(_("Row # ") + ("%d: " % (row.idx)) + cstr(e)) From 4a2dbd4885777e435282df7afe8631f157f7a0a8 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 22:11:30 +0530 Subject: [PATCH 026/180] refactor: cleanup get_timeline_data, remove py2 --- erpnext/stock/doctype/item/item.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 174c87b48d..61d7e56d13 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -12,7 +12,7 @@ from erpnext.controllers.item_variant import (ItemVariantExistsError, copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes) from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for) from frappe import _, msgprint -from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate, +from frappe.utils import (cint, cstr, flt, formatdate, getdate, now_datetime, random_string, strip, get_link_to_form, nowtime) from frappe.utils.html_utils import clean_html from frappe.website.doctype.website_slideshow.website_slideshow import \ @@ -21,8 +21,6 @@ from frappe.website.doctype.website_slideshow.website_slideshow import \ from frappe.website.render import clear_cache from frappe.website.website_generator import WebsiteGenerator -from six import iteritems - class DuplicateReorderRows(frappe.ValidationError): pass @@ -1054,18 +1052,15 @@ def make_item_price(item, price_list_name, item_price): }).insert() def get_timeline_data(doctype, name): - '''returns timeline data based on stock ledger entry''' - out = {} - items = dict(frappe.db.sql('''select posting_date, count(*) - from `tabStock Ledger Entry` where item_code=%s - and posting_date > date_sub(curdate(), interval 1 year) - group by posting_date''', name)) + """get timeline data based on Stock Ledger Entry. This is displayed as heatmap on the item page.""" - for date, count in iteritems(items): - timestamp = get_timestamp(date) - out.update({timestamp: count}) + items = frappe.db.sql("""select unix_timestamp(posting_date), count(*) + from `tabStock Ledger Entry` + where item_code=%s and posting_date > date_sub(curdate(), interval 1 year) + group by posting_date""", name) + + return dict(items) - return out def validate_end_of_life(item_code, end_of_life=None, disabled=None): From ad58a8164aeabfe0c87c54052ec5ba3db4c1ca56 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 22:58:22 +0530 Subject: [PATCH 027/180] refactor: code cleanup minor fixes for improving code quality --- erpnext/stock/doctype/item/item.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 61d7e56d13..0b92e27152 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -201,7 +201,7 @@ class Item(WebsiteGenerator): def make_route(self): if not self.route: return cstr(frappe.db.get_value('Item Group', self.item_group, - 'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5)) + 'route')) + '/' + self.scrub((self.item_name or self.item_code) + '-' + random_string(5)) def validate_website_image(self): if frappe.flags.in_import: @@ -256,7 +256,6 @@ class Item(WebsiteGenerator): "attached_to_name": self.name }) except frappe.DoesNotExistError: - pass # cleanup frappe.local.message_log.pop() From 0b4858d8e5d84723d82544721784d60e8541e3c2 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 22:59:52 +0530 Subject: [PATCH 028/180] refactor: eliminate unnecessary loop, container casts --- erpnext/stock/doctype/item/item.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 0b92e27152..c41dd67727 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -539,10 +539,7 @@ class Item(WebsiteGenerator): def fill_customer_code(self): """ Append all the customer codes and insert into "customer_code" field of item table """ - cust_code = [] - for d in self.get('customer_items'): - cust_code.append(d.ref_code) - self.customer_code = ','.join(cust_code) + self.customer_code = ','.join(d.ref_code for d in self.get("customer_items", [])) def check_item_tax(self): """Check whether Tax Rate is not entered twice for same Tax Type""" @@ -755,7 +752,7 @@ class Item(WebsiteGenerator): template_item.save() def validate_item_defaults(self): - companies = list(set([row.company for row in self.item_defaults])) + companies = {row.company for row in self.item_defaults} if len(companies) != len(self.item_defaults): frappe.throw(_("Cannot set multiple Item Defaults for a company.")) From 83e6e2e68aec4ef9b6095652a83d19e44bf90e31 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:01:50 +0530 Subject: [PATCH 029/180] refactor: add guard clause for readability --- erpnext/stock/doctype/item/item.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index c41dd67727..b665eb8e46 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -953,20 +953,22 @@ class Item(WebsiteGenerator): d.variant_of = self.variant_of def cant_change(self): - if not self.get("__islocal"): - fields = ("has_serial_no", "is_stock_item", "valuation_method", "has_batch_no") + if self.get("__islocal"): + return - values = frappe.db.get_value("Item", self.name, fields, as_dict=True) - if not values.get('valuation_method') and self.get('valuation_method'): - values['valuation_method'] = frappe.db.get_single_value("Stock Settings", "valuation_method") or "FIFO" + fields = ("has_serial_no", "is_stock_item", "valuation_method", "has_batch_no") - if values: - for field in fields: - if cstr(self.get(field)) != cstr(values.get(field)): - if not self.check_if_linked_document_exists(field): - break # no linked document, allowed - else: - frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(field)))) + values = frappe.db.get_value("Item", self.name, fields, as_dict=True) + if not values.get('valuation_method') and self.get('valuation_method'): + values['valuation_method'] = frappe.db.get_single_value("Stock Settings", "valuation_method") or "FIFO" + + if values: + for field in fields: + if cstr(self.get(field)) != cstr(values.get(field)): + if not self.check_if_linked_document_exists(field): + break # no linked document, allowed + else: + frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(field)))) def check_if_linked_document_exists(self, field): linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Receipt Item", From 931c886f92c34453f87b54e315b8f3614a10df48 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:06:16 +0530 Subject: [PATCH 030/180] fix: not checking all fields `break` will break out of the loop without checking remaining fields. --- erpnext/stock/doctype/item/item.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index b665eb8e46..d09a4aa0dc 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -965,9 +965,7 @@ class Item(WebsiteGenerator): if values: for field in fields: if cstr(self.get(field)) != cstr(values.get(field)): - if not self.check_if_linked_document_exists(field): - break # no linked document, allowed - else: + if self.check_if_linked_document_exists(field): frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(field)))) def check_if_linked_document_exists(self, field): From 4b484d741d81834ad9749e9395b2510397b7ae09 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:10:54 +0530 Subject: [PATCH 031/180] refactor: use is_new() instead of __islocal Interface over implementation. --- erpnext/stock/doctype/item/item.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index d09a4aa0dc..7906923e6f 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -127,7 +127,7 @@ class Item(WebsiteGenerator): self.cant_change() self.update_show_in_website() - if not self.get("__islocal"): + if not self.is_new(): self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group") self.old_website_item_groups = frappe.db.sql_list("""select item_group from `tabWebsite Item Group` @@ -807,7 +807,7 @@ class Item(WebsiteGenerator): frappe.throw(_("Item has variants.")) def validate_attributes_in_variants(self): - if not self.has_variants or self.get("__islocal"): + if not self.has_variants or self.is_new(): return old_doc = self.get_doc_before_save() @@ -895,7 +895,7 @@ class Item(WebsiteGenerator): frappe.throw(_("Variant Based On cannot be changed")) def validate_uom(self): - if not self.get("__islocal"): + if not self.is_new(): check_stock_uom_with_bin(self.name, self.stock_uom) if self.has_variants: for d in frappe.db.get_all("Item", filters={"variant_of": self.name}): @@ -953,7 +953,7 @@ class Item(WebsiteGenerator): d.variant_of = self.variant_of def cant_change(self): - if self.get("__islocal"): + if self.is_new(): return fields = ("has_serial_no", "is_stock_item", "valuation_method", "has_batch_no") From c229ac932288189366ec6dd57f74db6f34248b1f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:15:32 +0530 Subject: [PATCH 032/180] refactor: add guard clause for readability Both functions only execute based on a condition. In such cases condition should immediately exit the function, this is called "guard clause" and helps in readability (less indent, and easy to "exit" when reading the code. --- erpnext/stock/doctype/item/item.py | 94 ++++++++++++++++-------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 7906923e6f..f7856be4ae 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -359,47 +359,49 @@ class Item(WebsiteGenerator): context.update(get_slideshow(self)) def set_attribute_context(self, context): - if self.has_variants: - attribute_values_available = {} - context.attribute_values = {} - context.selected_attributes = {} + if not self.has_variants: + return - # load attributes - for v in context.variants: - v.attributes = frappe.get_all("Item Variant Attribute", - fields=["attribute", "attribute_value"], - filters={"parent": v.name}) - # make a map for easier access in templates - v.attribute_map = frappe._dict({}) - for attr in v.attributes: - v.attribute_map[attr.attribute] = attr.attribute_value + attribute_values_available = {} + context.attribute_values = {} + context.selected_attributes = {} - for attr in v.attributes: - values = attribute_values_available.setdefault(attr.attribute, []) - if attr.attribute_value not in values: - values.append(attr.attribute_value) + # load attributes + for v in context.variants: + v.attributes = frappe.get_all("Item Variant Attribute", + fields=["attribute", "attribute_value"], + filters={"parent": v.name}) + # make a map for easier access in templates + v.attribute_map = frappe._dict({}) + for attr in v.attributes: + v.attribute_map[attr.attribute] = attr.attribute_value - if v.name == context.variant.name: - context.selected_attributes[attr.attribute] = attr.attribute_value + for attr in v.attributes: + values = attribute_values_available.setdefault(attr.attribute, []) + if attr.attribute_value not in values: + values.append(attr.attribute_value) - # filter attributes, order based on attribute table - for attr in self.attributes: - values = context.attribute_values.setdefault(attr.attribute, []) + if v.name == context.variant.name: + context.selected_attributes[attr.attribute] = attr.attribute_value - if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")): - for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt): - values.append(val) + # filter attributes, order based on attribute table + for attr in self.attributes: + values = context.attribute_values.setdefault(attr.attribute, []) - else: - # get list of values defined (for sequence) - for attr_value in frappe.db.get_all("Item Attribute Value", - fields=["attribute_value"], - filters={"parent": attr.attribute}, order_by="idx asc"): + if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")): + for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt): + values.append(val) - if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []): - values.append(attr_value.attribute_value) + else: + # get list of values defined (for sequence) + for attr_value in frappe.db.get_all("Item Attribute Value", + fields=["attribute_value"], + filters={"parent": attr.attribute}, order_by="idx asc"): - context.variant_info = json.dumps(context.variants) + if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []): + values.append(attr_value.attribute_value) + + context.variant_info = json.dumps(context.variants) def set_disabled_attributes(self, context): """Disable selection options of attribute combinations that do not result in a variant""" @@ -736,20 +738,22 @@ class Item(WebsiteGenerator): def update_template_item(self): """Set Show in Website for Template Item if True for its Variant""" - if self.variant_of: - if self.show_in_website: - self.show_variant_in_website = 1 - self.show_in_website = 0 + if not self.variant_of: + return - if self.show_variant_in_website: - # show template - template_item = frappe.get_doc("Item", self.variant_of) + if self.show_in_website: + self.show_variant_in_website = 1 + self.show_in_website = 0 - if not template_item.show_in_website: - template_item.show_in_website = 1 - template_item.flags.dont_update_variants = True - template_item.flags.ignore_permissions = True - template_item.save() + if self.show_variant_in_website: + # show template + template_item = frappe.get_doc("Item", self.variant_of) + + if not template_item.show_in_website: + template_item.show_in_website = 1 + template_item.flags.dont_update_variants = True + template_item.flags.ignore_permissions = True + template_item.save() def validate_item_defaults(self): companies = {row.company for row in self.item_defaults} From c12264f6bcded0c914885f9d238fa5c63d665282 Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 24 May 2021 13:20:22 +0530 Subject: [PATCH 033/180] chore: Cleanup Customer and Supplier Details section in Stock Entry - Changed depends on value to "Send to Subcontractor" for supplier fields - Removed Customer fields as they are not relevant to any Stock Entry purpose - Renamed section to "Supplier Details" visibe on subcontracting transfer --- .../doctype/stock_entry/stock_entry.json | 51 +++---------------- 1 file changed, 6 insertions(+), 45 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json index 98c047a09e..567b2ac3b0 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.json +++ b/erpnext/stock/doctype/stock_entry/stock_entry.json @@ -59,10 +59,6 @@ "supplier_name", "supplier_address", "address_display", - "column_break_39", - "customer", - "customer_name", - "customer_address", "accounting_dimensions_section", "project", "dimension_col_break", @@ -435,13 +431,13 @@ }, { "collapsible": 1, - "depends_on": "eval: in_list([\"Sales Return\", \"Purchase Return\", \"Send to Subcontractor\"], doc.purpose)", + "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "fieldname": "contact_section", "fieldtype": "Section Break", - "label": "Customer or Supplier Details" + "label": "Supplier Details" }, { - "depends_on": "eval:doc.purpose==\"Purchase Return\" || doc.purpose==\"Send to Subcontractor\"", + "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "fieldname": "supplier", "fieldtype": "Link", "label": "Supplier", @@ -453,7 +449,7 @@ }, { "bold": 1, - "depends_on": "eval:doc.purpose==\"Purchase Return\" || doc.purpose==\"Send to Subcontractor\"", + "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "fieldname": "supplier_name", "fieldtype": "Data", "label": "Supplier Name", @@ -463,7 +459,7 @@ "read_only": 1 }, { - "depends_on": "eval:doc.purpose==\"Purchase Return\" || doc.purpose==\"Send to Subcontractor\"", + "depends_on": "eval:doc.purpose === \"Send to Subcontractor\"", "fieldname": "supplier_address", "fieldtype": "Link", "label": "Supplier Address", @@ -477,41 +473,6 @@ "fieldtype": "Small Text", "label": "Address" }, - { - "fieldname": "column_break_39", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:doc.purpose==\"Sales Return\"", - "fieldname": "customer", - "fieldtype": "Link", - "label": "Customer", - "no_copy": 1, - "oldfieldname": "customer", - "oldfieldtype": "Link", - "options": "Customer", - "print_hide": 1 - }, - { - "bold": 1, - "depends_on": "eval:doc.purpose==\"Sales Return\"", - "fieldname": "customer_name", - "fieldtype": "Data", - "label": "Customer Name", - "no_copy": 1, - "oldfieldname": "customer_name", - "oldfieldtype": "Data", - "read_only": 1 - }, - { - "depends_on": "eval:doc.purpose==\"Sales Return\"", - "fieldname": "customer_address", - "fieldtype": "Small Text", - "label": "Customer Address", - "no_copy": 1, - "oldfieldname": "customer_address", - "oldfieldtype": "Small Text" - }, { "collapsible": 1, "fieldname": "printing_settings", @@ -655,7 +616,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2020-12-09 14:58:13.267321", + "modified": "2021-05-24 11:32:23.904307", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry", From bf1b3b89d1cb07481006a94d78112c110be74f70 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Mon, 24 May 2021 17:03:15 +0530 Subject: [PATCH 034/180] refactor: updated conditional visibility of check box --- .../manufacturing/doctype/production_plan/production_plan.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 3041507caf..1c0dde227c 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -322,6 +322,7 @@ }, { "default": "0", + "depends_on": "eval:doc.get_items_from == 'Sales Order'", "fieldname": "combine_items", "fieldtype": "Check", "label": "Consolidate Items" @@ -342,7 +343,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-05-07 16:56:00.255001", + "modified": "2021-05-24 16:59:03.643211", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", From 44c489223b855f837a279c65c989f30500ea70e8 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:43:28 +0530 Subject: [PATCH 035/180] chore: remove py2 compat code --- erpnext/stock/doctype/item/item.py | 4 +--- erpnext/stock/doctype/item/test_item.py | 9 ++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index f7856be4ae..a6f5160b5c 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1,8 +1,6 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals - import itertools import json import erpnext diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index e0b89d8e45..c300132ad0 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -14,7 +14,6 @@ from erpnext.stock.doctype.item.item import get_uom_conv_factor from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details -from six import iteritems test_ignore = ["BOM"] test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand"] @@ -98,7 +97,7 @@ class TestItem(unittest.TestCase): "ignore_pricing_rule": 1 }) - for key, value in iteritems(to_check): + for key, value in to_check.items(): self.assertEqual(value, details.get(key)) def test_item_tax_template(self): @@ -194,7 +193,7 @@ class TestItem(unittest.TestCase): "plc_conversion_rate": 1, "customer": "_Test Customer", }) - for key, value in iteritems(sales_item_check): + for key, value in sales_item_check.items(): self.assertEqual(value, sales_item_details.get(key)) purchase_item_check = { @@ -215,7 +214,7 @@ class TestItem(unittest.TestCase): "plc_conversion_rate": 1, "supplier": "_Test Supplier", }) - for key, value in iteritems(purchase_item_check): + for key, value in purchase_item_check.items(): self.assertEqual(value, purchase_item_details.get(key)) def test_item_attribute_change_after_variant(self): @@ -464,7 +463,7 @@ class TestItem(unittest.TestCase): self.assertEqual(len(matching_barcodes), 1) details = matching_barcodes[0] - for key, value in iteritems(barcode_properties): + for key, value in barcode_properties.items(): self.assertEqual(value, details.get(key)) # Add barcode again - should cause DuplicateEntryError From ccbde0efa07306710676d144fb7faf29635639db Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:52:00 +0530 Subject: [PATCH 036/180] refactor: use enumerate instead of trackign index also removed dead code --- erpnext/stock/doctype/item/item.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index a6f5160b5c..9a52fb4fc1 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -72,8 +72,6 @@ class Item(WebsiteGenerator): if not self.description: self.description = self.item_name - # if self.is_sales_item and not self.get('is_item_from_hub'): - # self.publish_in_hub = 1 def after_insert(self): '''set opening stock and item price''' @@ -1277,14 +1275,13 @@ def get_item_attribute(parent, attribute_value=''): filters = {'parent': parent, 'attribute_value': ("like", "%%%s%%" % attribute_value)}) def update_variants(variants, template, publish_progress=True): - count=0 - for d in variants: + total = len(variants) + for count, d in enumerate(variants, start=1): variant = frappe.get_doc("Item", d) copy_attributes_to_variant(template, variant) variant.save() - count+=1 if publish_progress: - frappe.publish_progress(count*100/len(variants), title = _("Updating Variants...")) + frappe.publish_progress(count / total * 100, title=_("Updating Variants...")) def on_doctype_update(): # since route is a Text column, it needs a length for indexing From 958d485ba49d47af46324395519d9683cbde4674 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 22 May 2021 23:58:38 +0530 Subject: [PATCH 037/180] refactor: msgprint(raise_exception)->frappe.throw --- erpnext/stock/doctype/item/item.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 9a52fb4fc1..e865bda5c1 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -516,7 +516,7 @@ class Item(WebsiteGenerator): def validate_item_type(self): if self.has_serial_no == 1 and self.is_stock_item == 0 and not self.is_fixed_asset: - msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1) + frappe.throw(_("'Has Serial No' can not be 'Yes' for non-stock item")) if self.has_serial_no == 0 and self.serial_no_series: self.serial_no_series = None @@ -1269,7 +1269,7 @@ def get_uom_conv_factor(uom, stock_uom): @frappe.whitelist() def get_item_attribute(parent, attribute_value=''): if not frappe.has_permission("Item"): - frappe.msgprint(_("No Permission"), raise_exception=1) + frappe.throw(_("No Permission")) return frappe.get_all("Item Attribute Value", fields = ["attribute_value"], filters = {'parent': parent, 'attribute_value': ("like", "%%%s%%" % attribute_value)}) From 297dc5e345b494c6f9cdba12653cdf45721a2af3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 00:17:08 +0530 Subject: [PATCH 038/180] perf: add basic optimisation for uom conversion --- erpnext/stock/doctype/item/item.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index e865bda5c1..2c862dcfb7 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1244,6 +1244,9 @@ def get_item_details(item_code, company=None): @frappe.whitelist() def get_uom_conv_factor(uom, stock_uom): + if uom == stock_uom: + return 1.0 + uoms = [uom, stock_uom] value = "" uom_details = frappe.db.sql("""select to_uom, from_uom, value from `tabUOM Conversion Factor`\ From 0d7f54c6c22578797f1e55eb4c29fbc452c591ce Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 00:30:27 +0530 Subject: [PATCH 039/180] refactor: simplify UOM conversion logic - Remove unnecessary sql query - Remove convoluted matching logic and be explcitiy while querying. - better variable names for understanding matching cases --- erpnext/stock/doctype/item/item.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 2c862dcfb7..ef855c7db5 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1247,27 +1247,22 @@ def get_uom_conv_factor(uom, stock_uom): if uom == stock_uom: return 1.0 - uoms = [uom, stock_uom] - value = "" - uom_details = frappe.db.sql("""select to_uom, from_uom, value from `tabUOM Conversion Factor`\ - where to_uom in ({0}) - """.format(', '.join([frappe.db.escape(i, percent=False) for i in uoms])), as_dict=True) + exact_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": stock_uom, "from_uom": uom}, ["value"], as_dict=1) + if exact_match: + return exact_match.value - for d in uom_details: - if d.from_uom == stock_uom and d.to_uom == uom: - value = 1/flt(d.value) - elif d.from_uom == uom and d.to_uom == stock_uom: - value = d.value + inverse_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": uom, "from_uom": stock_uom}, ["value"], as_dict=1) + if inverse_match: + return 1 / inverse_match.value - if not value: - uom_stock = frappe.db.get_value("UOM Conversion Factor", {"to_uom": stock_uom}, ["from_uom", "value"], as_dict=1) - uom_row = frappe.db.get_value("UOM Conversion Factor", {"to_uom": uom}, ["from_uom", "value"], as_dict=1) + # This attempts to try and get conversion from intermediate UOM. E.g. mg <=> g <=> kg + uom_stock = frappe.db.get_value("UOM Conversion Factor", {"to_uom": stock_uom}, ["from_uom", "value"], as_dict=1) + uom_row = frappe.db.get_value("UOM Conversion Factor", {"to_uom": uom}, ["from_uom", "value"], as_dict=1) - if uom_stock and uom_row: - if uom_stock.from_uom == uom_row.from_uom: - value = flt(uom_stock.value) * 1/flt(uom_row.value) + if uom_stock and uom_row: + if uom_stock.from_uom == uom_row.from_uom: + return flt(uom_stock.value) * 1/flt(uom_row.value) - return value @frappe.whitelist() def get_item_attribute(parent, attribute_value=''): From 019be66b7b1d137e686ca9b8189f638abdd5f47d Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 01:12:47 +0530 Subject: [PATCH 040/180] fix: consider all UOMs for intermediate conversion - Using `get_value` will restrict intermediate UOM to first UOM that is found. - A self join is required to truly capture the required behaviour. - Add explanation and examples. --- erpnext/stock/doctype/item/item.py | 32 ++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index ef855c7db5..a5bc492422 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1244,24 +1244,40 @@ def get_item_details(item_code, company=None): @frappe.whitelist() def get_uom_conv_factor(uom, stock_uom): + """ Get UOM conversion factor from uom to stock_uom + e.g. uom = "Kg", stock_uom = "Gram" then returns 1000.0 + """ if uom == stock_uom: return 1.0 - exact_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": stock_uom, "from_uom": uom}, ["value"], as_dict=1) + from_uom, to_uom = uom, stock_uom # renaming for readability + + exact_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": to_uom, "from_uom": from_uom}, ["value"], as_dict=1) if exact_match: return exact_match.value - inverse_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": uom, "from_uom": stock_uom}, ["value"], as_dict=1) + inverse_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": from_uom, "from_uom": to_uom}, ["value"], as_dict=1) if inverse_match: return 1 / inverse_match.value - # This attempts to try and get conversion from intermediate UOM. E.g. mg <=> g <=> kg - uom_stock = frappe.db.get_value("UOM Conversion Factor", {"to_uom": stock_uom}, ["from_uom", "value"], as_dict=1) - uom_row = frappe.db.get_value("UOM Conversion Factor", {"to_uom": uom}, ["from_uom", "value"], as_dict=1) + # This attempts to try and get conversion from intermediate UOM. + # case: + # g -> mg = 1000 + # g -> kg = 0.001 + # therefore kg -> mg = 1000 / 0.001 = 1,000,000 + intermediate_match = frappe.db.sql(""" + select (first.value / second.value) as value + from `tabUOM Conversion Factor` first + join `tabUOM Conversion Factor` second + on first.from_uom = second.from_uom + where + first.to_uom = %(to_uom)s + and second.to_uom = %(from_uom)s + limit 1 + """, {"to_uom": to_uom, "from_uom": from_uom}, as_dict=1) - if uom_stock and uom_row: - if uom_stock.from_uom == uom_row.from_uom: - return flt(uom_stock.value) * 1/flt(uom_row.value) + if intermediate_match: + return intermediate_match[0].value @frappe.whitelist() From b9fa12d5721dddd00291fca1e9ef157527fb5905 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 12:26:01 +0530 Subject: [PATCH 041/180] test: add tests for uom conversion function --- erpnext/stock/doctype/item/test_item.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index c300132ad0..2366f06f6d 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -374,6 +374,14 @@ class TestItem(unittest.TestCase): self.assertEqual(item_doc.uoms[1].uom, "Kg") self.assertEqual(item_doc.uoms[1].conversion_factor, 1000) + def test_uom_conv_intermediate(self): + factor = get_uom_conv_factor("Pound", "Gram") + self.assertAlmostEqual(factor, 453.592, 3) + + def test_uom_conv_base_case(self): + factor = get_uom_conv_factor("m", "m") + self.assertEqual(factor, 1.0) + def test_item_variant_by_manufacturer(self): fields = [{'field_name': 'description'}, {'field_name': 'variant_based_on'}] set_item_variant_settings(fields) From f5a937bc45e2fe8dd4a18a3b804a86e3caa84cad Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 12:38:15 +0530 Subject: [PATCH 042/180] test: check index creation on item table --- erpnext/stock/doctype/item/test_item.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 2366f06f6d..d9d1e5a44d 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -487,6 +487,20 @@ class TestItem(unittest.TestCase): new_barcode.barcode_type = 'EAN' self.assertRaises(InvalidBarcode, item_doc.save) + def test_index_creation(self): + "check if index is getting created in db" + from erpnext.stock.doctype.item.item import on_doctype_update + on_doctype_update() + + indices = frappe.db.sql("show index from tabItem", as_dict=1) + expected_columns = {"item_code", "item_name", "item_group", "route"} + for index in indices: + expected_columns.discard(index.get("Column_name")) + + if expected_columns: + self.fail(f"Expected db index on these columns: {', '.join(expected_columns)}") + + def set_item_variant_settings(fields): doc = frappe.get_doc('Item Variant Settings') doc.set('fields', fields) From eb177328767c940857f46ca2345e972e9915eda2 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 13:12:16 +0530 Subject: [PATCH 043/180] test: add test for item attribute completion --- erpnext/stock/doctype/item/item.py | 5 +++-- erpnext/stock/doctype/item/test_item.py | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index a5bc492422..ec46f60f2b 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1281,12 +1281,13 @@ def get_uom_conv_factor(uom, stock_uom): @frappe.whitelist() -def get_item_attribute(parent, attribute_value=''): +def get_item_attribute(parent, attribute_value=""): + """Used for providing auto-completions in child table.""" if not frappe.has_permission("Item"): frappe.throw(_("No Permission")) return frappe.get_all("Item Attribute Value", fields = ["attribute_value"], - filters = {'parent': parent, 'attribute_value': ("like", "%%%s%%" % attribute_value)}) + filters = {'parent': parent, 'attribute_value': ("like", f"%{attribute_value}%")}) def update_variants(variants, template, publish_progress=True): total = len(variants) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index d9d1e5a44d..7cd6050c02 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -10,13 +10,13 @@ from frappe.test_runner import make_test_objects from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError, InvalidItemAttributeValueError, get_variant) from erpnext.stock.doctype.item.item import StockExistsForTemplate, InvalidBarcode -from erpnext.stock.doctype.item.item import get_uom_conv_factor +from erpnext.stock.doctype.item.item import get_uom_conv_factor, get_item_attribute from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details test_ignore = ["BOM"] -test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand"] +test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"] def make_item(item_code, properties=None): if frappe.db.exists("Item", item_code): @@ -500,6 +500,21 @@ class TestItem(unittest.TestCase): if expected_columns: self.fail(f"Expected db index on these columns: {', '.join(expected_columns)}") + def test_attribute_completions(self): + expected_attrs = [{'attribute_value': 'Small'}, + {'attribute_value': 'Extra Small'}, + {'attribute_value': 'Extra Large'}, + {'attribute_value': 'Large'}, + {'attribute_value': '2XL'}, + {'attribute_value': 'Medium'}] + + attrs = get_item_attribute("Test Size") + self.assertEqual(attrs, expected_attrs) + + attrs = get_item_attribute("Test Size", attribute_value="extra") + self.assertEqual(attrs, [{'attribute_value': 'Extra Small'}, {'attribute_value': 'Extra Large'}]) + + def set_item_variant_settings(fields): doc = frappe.get_doc('Item Variant Settings') From a11a8e8ab2e30eaa9f3b1cd80c27dc9ad8f13aeb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 13:19:22 +0530 Subject: [PATCH 044/180] chore: add blame ignore file --- .git-blame-ignore-revs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..be425ec2d9 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,12 @@ +# Since version 2.23 (released in August 2019), git-blame has a feature +# to ignore or bypass certain commits. +# +# This file contains a list of commits that are not likely what you +# are looking for in a blame, such as mass reformatting or renaming. +# You can set this file as a default ignore file for blame by running +# the following command. +# +# $ git config blame.ignoreRevsFile .git-blame-ignore-revs + +# This commit just changes spaces to tabs for indentation in some files +5f473611bd6ed57703716244a054d3fb5ba9cd23 From 4e360f805f5cb4f7ed500316aa97ca7e52b2f9bf Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 14:48:03 +0530 Subject: [PATCH 045/180] test: hoist defaults to function signature --- erpnext/stock/doctype/item/test_item.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 7cd6050c02..9694927914 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -530,23 +530,24 @@ def make_item_variant(): test_records = frappe.get_test_records('Item') -def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, is_customer_provided_item=None, - customer=None, is_purchase_item=None, opening_stock=None, company=None): +def create_item(item_code, is_stock_item=1, valuation_rate=0, warehouse="_Test Warehouse - _TC", + is_customer_provided_item=None, customer=None, is_purchase_item=None, opening_stock=0, + company="_Test Company"): if not frappe.db.exists("Item", item_code): item = frappe.new_doc("Item") item.item_code = item_code item.item_name = item_code item.description = item_code item.item_group = "All Item Groups" - item.is_stock_item = is_stock_item or 1 - item.opening_stock = opening_stock or 0 - item.valuation_rate = valuation_rate or 0.0 + item.is_stock_item = is_stock_item + item.opening_stock = opening_stock + item.valuation_rate = valuation_rate item.is_purchase_item = is_purchase_item item.is_customer_provided_item = is_customer_provided_item item.customer = customer or '' item.append("item_defaults", { - "default_warehouse": warehouse or '_Test Warehouse - _TC', - "company": company or "_Test Company" + "default_warehouse": warehouse, + "company": company }) item.save() else: From fc54cf68ac33b213dd44821c10e01f84a6c4727a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 15:04:41 +0530 Subject: [PATCH 046/180] test: add tests for checking stock_uom with bin --- erpnext/stock/doctype/item/test_item.py | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 9694927914..8df12a3f16 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -514,6 +514,35 @@ class TestItem(unittest.TestCase): attrs = get_item_attribute("Test Size", attribute_value="extra") self.assertEqual(attrs, [{'attribute_value': 'Extra Small'}, {'attribute_value': 'Extra Large'}]) + def test_check_stock_uom_with_bin(self): + # this item has opening stock and stock_uom set in test_records. + item = frappe.get_doc("Item", "_Test Item") + item.stock_uom = "Gram" + self.assertRaises(frappe.ValidationError, item.save) + + def test_check_stock_uom_with_bin_no_sle(self): + from erpnext.stock.stock_balance import update_bin_qty + item = create_item("_Item with bin qty") + item.stock_uom = "Gram" + item.save() + + update_bin_qty(item.item_code, "_Test Warehouse - _TC", { + "reserved_qty": 10 + }) + + item.stock_uom = "Kilometer" + self.assertRaises(frappe.ValidationError, item.save) + + update_bin_qty(item.item_code, "_Test Warehouse - _TC", { + "reserved_qty": 0 + }) + + item.load_from_db() + item.stock_uom = "Kilometer" + try: + item.save() + except frappe.ValidationError as e: + self.fail(f"UoM change not allowed even though no SLE / BIN with positive qty exists: {e}") def set_item_variant_settings(fields): From 57266a7343edd1fb963d20db28593bed3f80ae50 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 14:21:24 +0530 Subject: [PATCH 047/180] refactor: check_stock_uom_with_bin --- erpnext/stock/doctype/item/item.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index ec46f60f2b..a0bd49543e 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -1183,27 +1183,25 @@ def check_stock_uom_with_bin(item, stock_uom): if stock_uom == frappe.db.get_value("Item", item, "stock_uom"): return - matched = True ref_uom = frappe.db.get_value("Stock Ledger Entry", {"item_code": item}, "stock_uom") if ref_uom: if cstr(ref_uom) != cstr(stock_uom): - matched = False - else: - bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1) - for bin in bin_list: - if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 - or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom): - matched = False - break + frappe.throw(_("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.").format(item)) - if matched and bin_list: - frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", (stock_uom, item)) + bin_list = frappe.db.sql(""" + select * from tabBin where item_code = %s + and (reserved_qty > 0 or ordered_qty > 0 or indented_qty > 0 or planned_qty > 0) + and stock_uom != %s + """, (item, stock_uom), as_dict=1) + + if bin_list: + frappe.throw(_("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You need to either cancel the linked documents or create a new Item.").format(item)) + + # No SLE or documents against item. Bin UOM can be changed safely. + frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", (stock_uom, item)) - if not matched: - frappe.throw( - _("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.").format(item)) def get_item_defaults(item_code, company): item = frappe.get_cached_doc('Item', item_code) From e971b4592e3bb1894294f561a522f2b06336908b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 15:33:06 +0530 Subject: [PATCH 048/180] test: add test for is_stock_item --- erpnext/stock/doctype/item/test_item.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 8df12a3f16..d9c77efc24 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -10,7 +10,8 @@ from frappe.test_runner import make_test_objects from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError, InvalidItemAttributeValueError, get_variant) from erpnext.stock.doctype.item.item import StockExistsForTemplate, InvalidBarcode -from erpnext.stock.doctype.item.item import get_uom_conv_factor, get_item_attribute +from erpnext.stock.doctype.item.item import (get_uom_conv_factor, get_item_attribute, + validate_is_stock_item) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details @@ -544,6 +545,13 @@ class TestItem(unittest.TestCase): except frappe.ValidationError as e: self.fail(f"UoM change not allowed even though no SLE / BIN with positive qty exists: {e}") + def test_validate_stock_item(self): + self.assertRaises(frappe.ValidationError, validate_is_stock_item, "_Test Non Stock Item") + + try: + validate_is_stock_item("_Test Item") + except frappe.ValidationError as e: + self.fail(f"stock item considered non-stock item: {e}") def set_item_variant_settings(fields): doc = frappe.get_doc('Item Variant Settings') From 42e057d079c1807393d376d347762e97100b6883 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 15:45:25 +0530 Subject: [PATCH 049/180] test: add test for get_timeline_data in item --- erpnext/stock/doctype/item/test_item.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index d9c77efc24..234a9132c2 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -11,7 +11,7 @@ from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsE InvalidItemAttributeValueError, get_variant) from erpnext.stock.doctype.item.item import StockExistsForTemplate, InvalidBarcode from erpnext.stock.doctype.item.item import (get_uom_conv_factor, get_item_attribute, - validate_is_stock_item) + validate_is_stock_item, get_timeline_data) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details @@ -488,6 +488,20 @@ class TestItem(unittest.TestCase): new_barcode.barcode_type = 'EAN' self.assertRaises(InvalidBarcode, item_doc.save) + def test_heatmap_data(self): + import time + data = get_timeline_data("Item", "_Test Item") + self.assertTrue(isinstance(data, dict)) + + now = time.time() + one_year_ago = now - 366 * 24 * 60 * 60 + + for timestamp, count in data.items(): + self.assertIsInstance(timestamp, int) + self.assertTrue(one_year_ago <= timestamp <= now) + self.assertIsInstance(count, int) + self.assertTrue(count >= 0) + def test_index_creation(self): "check if index is getting created in db" from erpnext.stock.doctype.item.item import on_doctype_update From 76dd6e904682a1bec1ff21d66c45e164fd26a47b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 16:19:48 +0530 Subject: [PATCH 050/180] test: contextmanager to change settings --- erpnext/tests/utils.py | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py index 16ecd5180b..11eb6afc1f 100644 --- a/erpnext/tests/utils.py +++ b/erpnext/tests/utils.py @@ -1,7 +1,8 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals +import copy +from contextlib import contextmanager import frappe @@ -41,3 +42,38 @@ def create_test_contact_and_address(): contact.add_email("test_contact_customer@example.com", is_primary=True) contact.add_phone("+91 0000000000", is_primary_phone=True) contact.insert() + + +@contextmanager +def change_settings(doctype, settings_dict): + """ A context manager to ensure that settings are changed before running + function and restored after running it regardless of exceptions occured. + This is useful in tests where you want to make changes in a function but + don't retain those changes. + import and use as decorator to cover full function or using `with` statement. + + example: + @change_settings("Stock Settings", {"item_naming_by": "Naming Series"}) + def test_case(self): + ... + """ + + try: + settings = frappe.get_doc(doctype) + # remember setting + previous_settings = copy.deepcopy(settings_dict) + for key in previous_settings: + previous_settings[key] = getattr(settings, key) + + # change setting + for key, value in settings_dict.items(): + setattr(settings, key, value) + settings.save() + yield # yield control to calling function + + finally: + # restore settings + settings = frappe.get_doc(doctype) + for key, value in previous_settings.items(): + setattr(settings, key, value) + settings.save() From c15fef571fda7fa6bf2ae7f43380b29098775d87 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 16:26:37 +0530 Subject: [PATCH 051/180] test: item naming series behaviour --- erpnext/stock/doctype/item/test_item.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 234a9132c2..9adacdfb78 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -14,6 +14,7 @@ from erpnext.stock.doctype.item.item import (get_uom_conv_factor, get_item_attri validate_is_stock_item, get_timeline_data) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.get_item_details import get_item_details +from erpnext.tests.utils import change_settings test_ignore = ["BOM"] @@ -567,6 +568,13 @@ class TestItem(unittest.TestCase): except frappe.ValidationError as e: self.fail(f"stock item considered non-stock item: {e}") + @change_settings("Stock Settings", {"item_naming_by": "Naming Series"}) + def test_autoname_series(self): + item = frappe.new_doc("Item") + item.item_group = "All Item Groups" + item.save() # if item code saved without item_code then series worked + + def set_item_variant_settings(fields): doc = frappe.get_doc('Item Variant Settings') doc.set('fields', fields) From 3aed662f4690ad6fb5fda680aad4246103eded81 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 16:41:03 +0530 Subject: [PATCH 052/180] chore: translation / semgrep / sider fixes --- erpnext/stock/doctype/item/item.py | 6 +++--- erpnext/stock/doctype/item/test_item.py | 10 +++++----- .../stock_reconciliation/stock_reconciliation.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index a0bd49543e..dd815404fa 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -365,8 +365,8 @@ class Item(WebsiteGenerator): # load attributes for v in context.variants: v.attributes = frappe.get_all("Item Variant Attribute", - fields=["attribute", "attribute_value"], - filters={"parent": v.name}) + fields=["attribute", "attribute_value"], + filters={"parent": v.name}) # make a map for easier access in templates v.attribute_map = frappe._dict({}) for attr in v.attributes: @@ -1256,7 +1256,7 @@ def get_uom_conv_factor(uom, stock_uom): inverse_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": from_uom, "from_uom": to_uom}, ["value"], as_dict=1) if inverse_match: - return 1 / inverse_match.value + return 1 / inverse_match.value # This attempts to try and get conversion from intermediate UOM. # case: diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 9adacdfb78..406039dc58 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -518,11 +518,11 @@ class TestItem(unittest.TestCase): def test_attribute_completions(self): expected_attrs = [{'attribute_value': 'Small'}, - {'attribute_value': 'Extra Small'}, - {'attribute_value': 'Extra Large'}, - {'attribute_value': 'Large'}, - {'attribute_value': '2XL'}, - {'attribute_value': 'Medium'}] + {'attribute_value': 'Extra Small'}, + {'attribute_value': 'Extra Large'}, + {'attribute_value': 'Large'}, + {'attribute_value': '2XL'}, + {'attribute_value': 'Medium'}] attrs = get_item_attribute("Test Size") self.assertEqual(attrs, expected_attrs) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 96b1cadaaf..b9f91906c6 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -96,7 +96,7 @@ class StockReconciliation(StockController): def validate_data(self): def _get_msg(row_num, msg): - return _("Row # {0}: ").format(row_num+1) + msg + return _("Row # {0}:").format(row_num+1) + " " + msg self.validation_messages = [] item_warehouse_combinations = [] @@ -182,7 +182,7 @@ class StockReconciliation(StockController): validate_cancelled_item(item_code, item.docstatus) except Exception as e: - self.validation_messages.append(_("Row # ") + ("%d: " % (row.idx)) + cstr(e)) + self.validation_messages.append(_("Row #") + " " + ("%d: " % (row.idx)) + cstr(e)) def update_stock_ledger(self): """ find difference between current and expected entries From 15f8a0fb22addd730b1ebfb43635cfb29f1ddb90 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 23 May 2021 18:10:21 +0530 Subject: [PATCH 053/180] test: fix flaky test --- erpnext/stock/doctype/item/test_item.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 406039dc58..c7467a5a0f 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -517,18 +517,15 @@ class TestItem(unittest.TestCase): self.fail(f"Expected db index on these columns: {', '.join(expected_columns)}") def test_attribute_completions(self): - expected_attrs = [{'attribute_value': 'Small'}, - {'attribute_value': 'Extra Small'}, - {'attribute_value': 'Extra Large'}, - {'attribute_value': 'Large'}, - {'attribute_value': '2XL'}, - {'attribute_value': 'Medium'}] + expected_attrs = {"Small", "Extra Small", "Extra Large", "Large", "2XL", "Medium"} attrs = get_item_attribute("Test Size") - self.assertEqual(attrs, expected_attrs) + received_attrs = {attr.attribute_value for attr in attrs} + self.assertEqual(received_attrs, expected_attrs) attrs = get_item_attribute("Test Size", attribute_value="extra") - self.assertEqual(attrs, [{'attribute_value': 'Extra Small'}, {'attribute_value': 'Extra Large'}]) + received_attrs = {attr.attribute_value for attr in attrs} + self.assertEqual(received_attrs, {"Extra Small", "Extra Large"}) def test_check_stock_uom_with_bin(self): # this item has opening stock and stock_uom set in test_records. From 3efd411ddb6ddb9b4f655e48d50cd7d8efa62fd6 Mon Sep 17 00:00:00 2001 From: Anuja P Date: Tue, 25 May 2021 16:24:01 +0530 Subject: [PATCH 054/180] fix: Hold status is added in the report --- .../report/issue_summary/issue_summary.js | 1 + .../report/issue_summary/issue_summary.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/erpnext/support/report/issue_summary/issue_summary.js b/erpnext/support/report/issue_summary/issue_summary.js index eb0e06cd08..a5e1de627e 100644 --- a/erpnext/support/report/issue_summary/issue_summary.js +++ b/erpnext/support/report/issue_summary/issue_summary.js @@ -42,6 +42,7 @@ frappe.query_reports["Issue Summary"] = { "", {label: __('Open'), value: 'Open'}, {label: __('Replied'), value: 'Replied'}, + {label: __('Hold'), value: 'Hold'}, {label: __('Resolved'), value: 'Resolved'}, {label: __('Closed'), value: 'Closed'} ] diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py index 7861e30d25..d93790d593 100644 --- a/erpnext/support/report/issue_summary/issue_summary.py +++ b/erpnext/support/report/issue_summary/issue_summary.py @@ -62,7 +62,7 @@ class IssueSummary(object): 'width': 200 }) - self.statuses = ['Open', 'Replied', 'Resolved', 'Closed'] + self.statuses = ['Open', 'Replied', 'Hold', 'Resolved', 'Closed'] for status in self.statuses: self.columns.append({ 'label': _(status), @@ -265,6 +265,7 @@ class IssueSummary(object): labels = [] open_issues = [] replied_issues = [] + hold_issues = [] resolved_issues = [] closed_issues = [] @@ -277,6 +278,7 @@ class IssueSummary(object): labels.append(entry.get(entity_field)) open_issues.append(entry.get('open')) replied_issues.append(entry.get('replied')) + hold_issues.append(entry.get('hold')) resolved_issues.append(entry.get('resolved')) closed_issues.append(entry.get('closed')) @@ -292,6 +294,10 @@ class IssueSummary(object): 'name': 'Replied', 'values': replied_issues[:30] }, + { + 'name': 'Hold', + 'values': hold_issues[:30] + }, { 'name': 'Resolved', 'values': resolved_issues[:30] @@ -313,12 +319,14 @@ class IssueSummary(object): open_issues = 0 replied = 0 + hold = 0 resolved = 0 closed = 0 for entry in self.data: open_issues += entry.get('open') replied += entry.get('replied') + hold += entry.get('hold') resolved += entry.get('resolved') closed += entry.get('closed') @@ -335,6 +343,12 @@ class IssueSummary(object): 'label': _('Replied'), 'datatype': 'Int', }, + { + 'value': hold, + 'indicator': 'Grey', + 'label': _('Hold'), + 'datatype': 'Int', + }, { 'value': resolved, 'indicator': 'Green', From 73e41c0bd6e7984c468ca5c3feaac0d5920110d2 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Tue, 25 May 2021 18:01:47 +0530 Subject: [PATCH 055/180] refactor: suggested changes --- erpnext/manufacturing/doctype/work_order/work_order.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index a154464a8b..2600790a59 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -383,7 +383,7 @@ class WorkOrder(Document): work_order_qty = 0.0 if plan_reference.item_reference == item_reference: if self.docstatus == 1: - work_order_qty = cint(plan_reference.qty) / total_bundle_qty + work_order_qty = flt(plan_reference.qty) / total_bundle_qty frappe.db.set_value('Sales Order Item', plan_reference.sales_order_item, 'work_order_qty', work_order_qty) From ff96bdf0c19525b1baec6d647a4ce7a389699958 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 25 May 2021 19:54:40 +0530 Subject: [PATCH 056/180] fix(ux): fix unstranslated text in msgprint/throw --- .../accounting_dimension/accounting_dimension.py | 2 +- .../doctype/accounts_settings/accounts_settings.py | 3 ++- .../chart_of_accounts_importer.py | 4 ++-- .../process_statement_of_accounts.js | 8 ++++---- erpnext/crm/doctype/appointment/appointment.py | 10 +++++----- .../course_scheduling_tool/course_scheduling_tool.py | 2 +- erpnext/loan_management/doctype/loan/loan.py | 2 +- erpnext/non_profit/doctype/member/member.py | 2 +- erpnext/public/js/controllers/transaction.js | 6 +++--- erpnext/setup/install.py | 2 +- erpnext/www/book_appointment/index.js | 4 ++-- 11 files changed, 23 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index 0ebf0eb541..7cd1e7736c 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -27,7 +27,7 @@ class AccountingDimension(Document): exists = frappe.db.get_value("Accounting Dimension", {'document_type': self.document_type}, ['name']) if exists and self.is_new(): - frappe.throw("Document Type already used as a dimension") + frappe.throw(_("Document Type already used as a dimension")) if not self.is_new(): self.validate_document_type_change() diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 4d3388090d..ac4a2d6f16 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.utils import cint from frappe.model.document import Document from frappe.custom.doctype.property_setter.property_setter import make_property_setter @@ -24,7 +25,7 @@ class AccountsSettings(Document): def validate_stale_days(self): if not self.allow_stale and cint(self.stale_days) <= 0: frappe.msgprint( - "Stale Days should start from 1.", title='Error', indicator='red', + _("Stale Days should start from 1."), title='Error', indicator='red', raise_exception=1) def enable_payment_schedule_in_print(self): diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py index f96f59169e..ef44626b37 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py @@ -22,7 +22,7 @@ def validate_company(company): 'allow_account_creation_against_child_company']) if parent_company and (not allow_account_creation_against_child_company): - msg = _("{} is a child company. ").format(frappe.bold(company)) + msg = _("{} is a child company.").format(frappe.bold(company)) + " " msg += _("Please import accounts against parent company or enable {} in company master.").format( frappe.bold('Allow Account Creation Against Child Company')) frappe.throw(msg, title=_('Wrong Company')) @@ -56,7 +56,7 @@ def get_file(file_name): extension = extension.lstrip(".") if extension not in ('csv', 'xlsx', 'xls'): - frappe.throw("Only CSV and Excel files can be used to for importing data. Please check the file format you are trying to upload") + frappe.throw(_("Only CSV and Excel files can be used to for importing data. Please check the file format you are trying to upload")) return file_doc, extension diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js index 6dc46430e0..088c190f45 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js @@ -19,7 +19,7 @@ frappe.ui.form.on('Process Statement Of Accounts', { frappe.show_alert({message: __('Emails Queued'), indicator: 'blue'}); } else{ - frappe.msgprint('No Records for these settings.') + frappe.msgprint(__('No Records for these settings.')) } } }); @@ -33,7 +33,7 @@ frappe.ui.form.on('Process Statement Of Accounts', { type: 'GET', success: function(result) { if(jQuery.isEmptyObject(result)){ - frappe.msgprint('No Records for these settings.'); + frappe.msgprint(__('No Records for these settings.')); } else{ window.location = url; @@ -92,7 +92,7 @@ frappe.ui.form.on('Process Statement Of Accounts', { frm.refresh_field('customers'); } else{ - frappe.throw('No Customers found with selected options.'); + frappe.throw(__('No Customers found with selected options.')); } } } @@ -129,4 +129,4 @@ frappe.ui.form.on('Process Statement Of Accounts Customer', { } }) } -}); \ No newline at end of file +}); diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py index 2009ebf7cb..df73f09c49 100644 --- a/erpnext/crm/doctype/appointment/appointment.py +++ b/erpnext/crm/doctype/appointment/appointment.py @@ -38,7 +38,7 @@ class Appointment(Document): number_of_agents = frappe.db.get_single_value('Appointment Booking Settings', 'number_of_agents') if not number_of_agents == 0: if (number_of_appointments_in_same_slot >= number_of_agents): - frappe.throw('Time slot is not available') + frappe.throw(_('Time slot is not available')) # Link lead if not self.party: lead = self.find_lead_by_email() @@ -75,10 +75,10 @@ class Appointment(Document): subject=_('Appointment Confirmation')) if frappe.session.user == "Guest": frappe.msgprint( - 'Please check your email to confirm the appointment') + _('Please check your email to confirm the appointment')) else : frappe.msgprint( - 'Appointment was created. But no lead was found. Please check the email to confirm') + _('Appointment was created. But no lead was found. Please check the email to confirm')) def on_change(self): # Sync Calendar @@ -91,7 +91,7 @@ class Appointment(Document): def set_verified(self, email): if not email == self.customer_email: - frappe.throw('Email verification failed.') + frappe.throw(_('Email verification failed.')) # Create new lead self.create_lead_and_link() # Remove unverified status @@ -184,7 +184,7 @@ class Appointment(Document): appointment_event.insert(ignore_permissions=True) self.calendar_event = appointment_event.name self.save(ignore_permissions=True) - + def _get_verify_url(self): verify_route = '/book_appointment/verify' params = { diff --git a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py index 6a0dcf460a..0f2ea96a58 100644 --- a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py +++ b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py @@ -75,7 +75,7 @@ class CourseSchedulingTool(Document): """Validates if Course Start Date is greater than Course End Date""" if self.course_start_date > self.course_end_date: frappe.throw( - "Course Start Date cannot be greater than Course End Date.") + _("Course Start Date cannot be greater than Course End Date.")) def delete_course_schedule(self, rescheduled, reschedule_errors): """Delete all course schedule within the Date range and specified filters""" diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py index 230475f2d1..69d11a8653 100644 --- a/erpnext/loan_management/doctype/loan/loan.py +++ b/erpnext/loan_management/doctype/loan/loan.py @@ -264,7 +264,7 @@ def make_loan_write_off(loan, company=None, posting_date=None, amount=0, as_dict pending_amount = amounts['pending_principal_amount'] if amount and (amount > pending_amount): - frappe.throw('Write Off amount cannot be greater than pending loan amount') + frappe.throw(_('Write Off amount cannot be greater than pending loan amount')) if not amount: amount = pending_amount diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py index efc072ee97..30be585e9a 100644 --- a/erpnext/non_profit/doctype/member/member.py +++ b/erpnext/non_profit/doctype/member/member.py @@ -28,7 +28,7 @@ class Member(Document): def setup_subscription(self): non_profit_settings = frappe.get_doc('Non Profit Settings') if not non_profit_settings.enable_razorpay_for_memberships: - frappe.throw('Please check Enable Razorpay for Memberships in {0} to setup subscription').format( + frappe.throw(_('Please check Enable Razorpay for Memberships in {0} to setup subscription')).format( get_link_to_form('Non Profit Settings', 'Non Profit Settings')) controller = get_payment_gateway_controller("Razorpay") diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index e153e6ccbc..ad1976d2d2 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -953,15 +953,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ (this.frm.doc.payment_schedule && this.frm.doc.payment_schedule.length)) { var message1 = ""; var message2 = ""; - var final_message = "Please clear the "; + var final_message = __("Please clear the") + " "; if (this.frm.doc.payment_terms_template) { - message1 = "selected Payment Terms Template"; + message1 = __("selected Payment Terms Template"); final_message = final_message + message1; } if ((this.frm.doc.payment_schedule || []).length) { - message2 = "Payment Schedule Table"; + message2 = __("Payment Schedule Table"); if (message1.length !== 0) message2 = " and " + message2; final_message = final_message + message2; } diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index c7220cbc07..bbee74cafb 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -39,7 +39,7 @@ def check_setup_wizard_not_completed(): if cint(frappe.db.get_single_value('System Settings', 'setup_complete') or 0): message = """ERPNext can only be installed on a fresh site where the setup wizard is not completed. You can reinstall this site (after saving your data) using: bench --site [sitename] reinstall""" - frappe.throw(message) + frappe.throw(message) # nosemgrep def set_single_defaults(): diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js index 377a3cc097..5562cbd471 100644 --- a/erpnext/www/book_appointment/index.js +++ b/erpnext/www/book_appointment/index.js @@ -48,7 +48,7 @@ function setup_date_picker() { function hide_next_button() { let next_button = document.getElementById('next-button'); next_button.disabled = true; - next_button.onclick = () => frappe.msgprint("Please select a date and time"); + next_button.onclick = () => frappe.msgprint(__("Please select a date and time")); } function show_next_button() { @@ -63,7 +63,7 @@ function on_date_or_timezone_select() { if (date_picker.value === '') { clear_time_slots(); hide_next_button(); - frappe.throw('Please select a date'); + frappe.throw(__('Please select a date')); } window.selected_date = date_picker.value; window.selected_timezone = timezone.value; From 0e804e292a65edca819ecd8d7b77ca88ab970151 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 26 May 2021 10:54:16 +0530 Subject: [PATCH 057/180] fix(gstr-1): incorrect gstin fetched incase of branch company address --- erpnext/regional/report/gstr_1/gstr_1.py | 36 ++++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index 1e28a40f81..b7c096248f 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -574,7 +574,7 @@ class Gstr1Report(object): def get_json(filters, report_name, data): filters = json.loads(filters) report_data = json.loads(data) - gstin = get_company_gstin_number(filters["company"]) + gstin = get_company_gstin_number(filters["company"], filters["company_address"]) fp = "%02d%s" % (getdate(filters["to_date"]).month, getdate(filters["to_date"]).year) @@ -810,23 +810,29 @@ def get_rate_and_tax_details(row, gstin): return {"num": int(num), "itm_det": itm_det} -def get_company_gstin_number(company): - filters = [ - ["is_your_company_address", "=", 1], - ["Dynamic Link", "link_doctype", "=", "Company"], - ["Dynamic Link", "link_name", "=", company], - ["Dynamic Link", "parenttype", "=", "Address"], - ] +def get_company_gstin_number(company, address=None): + if address: + gstin = frappe.db.get_value("Address", address, "gstin") - gstin = frappe.get_all("Address", filters=filters, fields=["gstin"]) - - if gstin: - return gstin[0]["gstin"] - else: - frappe.throw(_("Please set valid GSTIN No. in Company Address for company {0}").format( - frappe.bold(company) + if not gstin: + filters = [ + ["is_your_company_address", "=", 1], + ["Dynamic Link", "link_doctype", "=", "Company"], + ["Dynamic Link", "link_name", "=", company], + ["Dynamic Link", "parenttype", "=", "Address"], + ] + gstin = frappe.get_all("Address", filters=filters, pluck="gstin") + if gstin: + gstin[0] + + if not gstin: + address = frappe.bold(address) if address else "" + frappe.throw(_("Please set valid GSTIN No. in Company Address {} for company {}").format( + address, frappe.bold(company) )) + return gstin + @frappe.whitelist() def download_json_file(): ''' download json content in a file ''' From db5217e48e23a5bfbfa6c8127a99b1fd4fb8feab Mon Sep 17 00:00:00 2001 From: Anuja P Date: Wed, 26 May 2021 11:09:48 +0530 Subject: [PATCH 058/180] fix: renaming hold to on hold --- erpnext/support/doctype/issue/issue.json | 4 ++-- .../report/issue_summary/issue_summary.js | 2 +- .../report/issue_summary/issue_summary.py | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json index a43381c5c6..bc29821ee2 100644 --- a/erpnext/support/doctype/issue/issue.json +++ b/erpnext/support/doctype/issue/issue.json @@ -119,7 +119,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "Open\nReplied\nHold\nResolved\nClosed", + "options": "Open\nReplied\nOn Hold\nResolved\nClosed", "search_index": 1 }, { @@ -410,7 +410,7 @@ "icon": "fa fa-ticket", "idx": 7, "links": [], - "modified": "2020-08-11 18:49:07.574769", + "modified": "2021-05-26 10:49:07.574769", "modified_by": "Administrator", "module": "Support", "name": "Issue", diff --git a/erpnext/support/report/issue_summary/issue_summary.js b/erpnext/support/report/issue_summary/issue_summary.js index a5e1de627e..a5122d03ad 100644 --- a/erpnext/support/report/issue_summary/issue_summary.js +++ b/erpnext/support/report/issue_summary/issue_summary.js @@ -42,7 +42,7 @@ frappe.query_reports["Issue Summary"] = { "", {label: __('Open'), value: 'Open'}, {label: __('Replied'), value: 'Replied'}, - {label: __('Hold'), value: 'Hold'}, + {label: __('On Hold'), value: 'On Hold'}, {label: __('Resolved'), value: 'Resolved'}, {label: __('Closed'), value: 'Closed'} ] diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py index d93790d593..bba25b8bed 100644 --- a/erpnext/support/report/issue_summary/issue_summary.py +++ b/erpnext/support/report/issue_summary/issue_summary.py @@ -62,7 +62,7 @@ class IssueSummary(object): 'width': 200 }) - self.statuses = ['Open', 'Replied', 'Hold', 'Resolved', 'Closed'] + self.statuses = ['Open', 'Replied', 'On Hold', 'Resolved', 'Closed'] for status in self.statuses: self.columns.append({ 'label': _(status), @@ -265,7 +265,7 @@ class IssueSummary(object): labels = [] open_issues = [] replied_issues = [] - hold_issues = [] + on_hold_issues = [] resolved_issues = [] closed_issues = [] @@ -278,7 +278,7 @@ class IssueSummary(object): labels.append(entry.get(entity_field)) open_issues.append(entry.get('open')) replied_issues.append(entry.get('replied')) - hold_issues.append(entry.get('hold')) + on_hold_issues.append(entry.get('on_hold')) resolved_issues.append(entry.get('resolved')) closed_issues.append(entry.get('closed')) @@ -295,8 +295,8 @@ class IssueSummary(object): 'values': replied_issues[:30] }, { - 'name': 'Hold', - 'values': hold_issues[:30] + 'name': 'On Hold', + 'values': on_hold_issues[:30] }, { 'name': 'Resolved', @@ -319,14 +319,14 @@ class IssueSummary(object): open_issues = 0 replied = 0 - hold = 0 + on_hold = 0 resolved = 0 closed = 0 for entry in self.data: open_issues += entry.get('open') replied += entry.get('replied') - hold += entry.get('hold') + on_hold += entry.get('on_hold') resolved += entry.get('resolved') closed += entry.get('closed') @@ -344,9 +344,9 @@ class IssueSummary(object): 'datatype': 'Int', }, { - 'value': hold, + 'value': on_hold, 'indicator': 'Grey', - 'label': _('Hold'), + 'label': _('On Hold'), 'datatype': 'Int', }, { From 2e0e4a7861ddc800589a788198c0df32a6e9ccb7 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Wed, 26 May 2021 11:13:19 +0530 Subject: [PATCH 059/180] refactor: Additional Salary form clean up (#25785) * feat: additional salary clean up * fix: Label and description * fix: labels Co-authored-by: Rucha Mahabal --- .../additional_salary/additional_salary.json | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.json b/erpnext/payroll/doctype/additional_salary/additional_salary.json index 5e17a5cbb7..d9efe458dc 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.json +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.json @@ -7,25 +7,30 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "employee_details_section", "naming_series", "employee", "employee_name", - "salary_component", - "type", - "amount", - "ref_doctype", - "ref_docname", - "amended_from", "column_break_5", "company", "department", + "salary_details_section", + "salary_component", + "type", "currency", + "amount", + "column_break_13", + "is_recurring", + "payroll_date", "from_date", "to_date", - "payroll_date", - "is_recurring", + "properties_and_references_section", + "deduct_full_tax_on_selected_payroll_date", + "ref_doctype", + "ref_docname", + "column_break_22", "overwrite_salary_structure_amount", - "deduct_full_tax_on_selected_payroll_date" + "amended_from" ], "fields": [ { @@ -81,7 +86,7 @@ }, { "depends_on": "eval:(doc.is_recurring==0)", - "description": "Date on which this component is applied", + "description": "The date on which Salary Component with Amount will contribute for Earnings/Deduction in Salary Slip. ", "fieldname": "payroll_date", "fieldtype": "Date", "in_list_view": 1, @@ -159,6 +164,7 @@ "fieldname": "ref_docname", "fieldtype": "Dynamic Link", "label": "Reference Document", + "no_copy": 1, "options": "ref_doctype", "read_only": 1 }, @@ -171,11 +177,34 @@ "print_hide": 1, "read_only": 1, "reqd": 1 + }, + { + "fieldname": "employee_details_section", + "fieldtype": "Section Break", + "label": "Employee Details" + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_22", + "fieldtype": "Column Break" + }, + { + "fieldname": "salary_details_section", + "fieldtype": "Section Break", + "label": "Salary Details" + }, + { + "fieldname": "properties_and_references_section", + "fieldtype": "Section Break", + "label": "Properties and References" } ], "is_submittable": 1, "links": [], - "modified": "2021-03-31 22:33:59.098532", + "modified": "2021-05-26 11:10:00.812698", "modified_by": "Administrator", "module": "Payroll", "name": "Additional Salary", From 349ef8274beee540626635ba46987c4a7b21d9d8 Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Wed, 26 May 2021 12:14:02 +0530 Subject: [PATCH 060/180] fix: student invalid password reset link (#25826) --- erpnext/education/doctype/student/student.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py index 2dc0f634f0..6be9e7104b 100644 --- a/erpnext/education/doctype/student/student.py +++ b/erpnext/education/doctype/student/student.py @@ -74,7 +74,6 @@ class Student(Document): student_user.flags.ignore_permissions = True student_user.add_roles("Student") student_user.save() - update_password_link = student_user.reset_password() def update_applicant_status(self): """Updates Student Applicant status to Admitted""" From 1cdf5a0dbad7eea6111839bfc14e4b59f8970f59 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 26 May 2021 14:42:15 +0530 Subject: [PATCH 061/180] fix: add requested changes --- erpnext/controllers/stock_controller.py | 8 +- erpnext/public/js/controllers/transaction.js | 15 +- .../stock/doctype/stock_entry/stock_entry.js | 130 ++++++++++++++++++ 3 files changed, 144 insertions(+), 9 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 6f97743b60..abc966a477 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -508,7 +508,7 @@ def make_quality_inspections(doctype, docname, items): inspections = [] for item in items: - if item.get("sample_size") > item.get("qty"): + if flt(item.get("sample_size")) > flt(item.get("qty")): frappe.throw(_("{item_name}'s Sample Size ({sample_size}) cannot be greater than the Accepted Quantity ({accepted_quantity})").format( item_name=item.get("item_name"), sample_size=item.get("sample_size"), @@ -523,14 +523,14 @@ def make_quality_inspections(doctype, docname, items): "reference_name": docname, "item_code": item.get("item_code"), "description": item.get("description"), - "sample_size": item.get("sample_size"), + "sample_size": flt(item.get("sample_size")), "item_serial_no": item.get("serial_no").split("\n")[0] if item.get("serial_no") else None, "batch_no": item.get("batch_no") }).insert() quality_inspection.save() - inspections.append(quality_inspection) + inspections.append(quality_inspection.name) - return [get_link_to_form("Quality Inspection", inspection.name) for inspection in inspections] + return inspections def is_reposting_pending(): diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 8738957166..95562baa8e 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -2039,11 +2039,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, freeze: true, callback: function (r) { - if (r.message) { - frappe.msgprint({ - message: __("Quality Inspections Created: {0}", [r.message.join(", ")]), - indicator: "green" - }); + if (r.message.length > 0) { + if (r.message.length === 1) { + frappe.set_route("Form", "Quality Inspection", r.message[0]); + } else { + frappe.route_options = { + "reference_type": me.frm.doc.doctype, + "reference_name": me.frm.doc.name + }; + frappe.set_route("List", "Quality Inspection"); + } } dialog.hide(); } diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index de23e769f8..3524c41720 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -115,6 +115,13 @@ frappe.ui.form.on('Stock Entry', { return; } + if (!frm.is_new() && frm.doc.docstatus === 0) { + frm.add_custom_button(__("Quality Inspection(s)"), () => { + frm.trigger("make_quality_inspection"); + }, __("Create")); + frm.page.set_inner_btn_group_as_primary(__('Create')); + } + let quality_inspection_field = frm.get_docfield("items", "quality_inspection"); quality_inspection_field.get_route_options_for_new_doc = function(row) { if (frm.is_new()) return; @@ -142,6 +149,129 @@ frappe.ui.form.on('Stock Entry', { }); }, + make_quality_inspection: function (frm) { + let data = []; + const fields = [ + { + label: "Items", + fieldtype: "Table", + fieldname: "items", + cannot_add_rows: true, + in_place_edit: true, + data: data, + get_data: () => { + return data; + }, + fields: [ + { + fieldtype: "Data", + fieldname: "docname", + hidden: true + }, + { + fieldtype: "Read Only", + fieldname: "item_code", + label: __("Item Code"), + in_list_view: true + }, + { + fieldtype: "Read Only", + fieldname: "item_name", + label: __("Item Name"), + in_list_view: true + }, + { + fieldtype: "Float", + fieldname: "qty", + label: __("Accepted Quantity"), + in_list_view: true, + read_only: true + }, + { + fieldtype: "Float", + fieldname: "sample_size", + label: __("Sample Size"), + reqd: true, + in_list_view: true + }, + { + fieldtype: "Data", + fieldname: "description", + label: __("Description"), + hidden: true + }, + { + fieldtype: "Data", + fieldname: "serial_no", + label: __("Serial No"), + hidden: true + }, + { + fieldtype: "Data", + fieldname: "batch_no", + label: __("Batch No"), + hidden: true + } + ] + } + ]; + + const dialog = new frappe.ui.Dialog({ + title: __("Select Items for Quality Inspection"), + fields: fields, + primary_action: function () { + const data = dialog.get_values(); + frappe.call({ + method: "erpnext.controllers.stock_controller.make_quality_inspections", + args: { + doctype: frm.doc.doctype, + docname: frm.doc.name, + items: data + }, + freeze: true, + callback: function (r) { + if (r.message.length > 0) { + if (r.message.length === 1) { + frappe.set_route("Form", "Quality Inspection", r.message[0]); + } else { + frappe.route_options = { + "reference_type": frm.doc.doctype, + "reference_name": frm.doc.name + }; + frappe.set_route("List", "Quality Inspection"); + } + } + dialog.hide(); + } + }); + }, + primary_action_label: __("Create") + }); + + frm.doc.items.forEach(item => { + if (!item.quality_inspection) { + let dialog_items = dialog.fields_dict.items; + dialog_items.df.data.push({ + "docname": item.name, + "item_code": item.item_code, + "item_name": item.item_name, + "qty": item.qty, + "description": item.description, + "serial_no": item.serial_no, + "batch_no": item.batch_no + }); + dialog_items.grid.refresh(); + } + }); + + data = dialog.fields_dict.items.df.data; + if (!data.length) { + frappe.msgprint(__("All items in this document already have a linked Quality Inspection.")); + } else { + dialog.show(); + } + }, + outgoing_stock_entry: function(frm) { frappe.call({ doc: frm.doc, From 1e3a3b27c6e4f66aa38c9adaf86b5bde39293a00 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 26 May 2021 15:18:10 +0530 Subject: [PATCH 062/180] style: semgrep issues --- erpnext/controllers/accounts_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 2c3519b04a..c77ea55775 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -225,7 +225,7 @@ class AccountsController(TransactionBase): def validate_date_with_fiscal_year(self): if self.meta.get_field("fiscal_year"): - date_field = "" + date_field = None if self.meta.get_field("posting_date"): date_field = "posting_date" elif self.meta.get_field("transaction_date"): From 9857d63523d3bffc1377622cbca2ff1c4c0815d0 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 26 May 2021 15:41:36 +0530 Subject: [PATCH 063/180] fix: add requested changes --- .../stock/doctype/stock_entry/stock_entry.js | 130 +----------------- 1 file changed, 4 insertions(+), 126 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 3524c41720..93a6fc0e0a 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -117,7 +117,8 @@ frappe.ui.form.on('Stock Entry', { if (!frm.is_new() && frm.doc.docstatus === 0) { frm.add_custom_button(__("Quality Inspection(s)"), () => { - frm.trigger("make_quality_inspection"); + let transaction_controller = new erpnext.TransactionController({ frm: frm }); + transaction_controller.make_quality_inspection(); }, __("Create")); frm.page.set_inner_btn_group_as_primary(__('Create')); } @@ -149,129 +150,6 @@ frappe.ui.form.on('Stock Entry', { }); }, - make_quality_inspection: function (frm) { - let data = []; - const fields = [ - { - label: "Items", - fieldtype: "Table", - fieldname: "items", - cannot_add_rows: true, - in_place_edit: true, - data: data, - get_data: () => { - return data; - }, - fields: [ - { - fieldtype: "Data", - fieldname: "docname", - hidden: true - }, - { - fieldtype: "Read Only", - fieldname: "item_code", - label: __("Item Code"), - in_list_view: true - }, - { - fieldtype: "Read Only", - fieldname: "item_name", - label: __("Item Name"), - in_list_view: true - }, - { - fieldtype: "Float", - fieldname: "qty", - label: __("Accepted Quantity"), - in_list_view: true, - read_only: true - }, - { - fieldtype: "Float", - fieldname: "sample_size", - label: __("Sample Size"), - reqd: true, - in_list_view: true - }, - { - fieldtype: "Data", - fieldname: "description", - label: __("Description"), - hidden: true - }, - { - fieldtype: "Data", - fieldname: "serial_no", - label: __("Serial No"), - hidden: true - }, - { - fieldtype: "Data", - fieldname: "batch_no", - label: __("Batch No"), - hidden: true - } - ] - } - ]; - - const dialog = new frappe.ui.Dialog({ - title: __("Select Items for Quality Inspection"), - fields: fields, - primary_action: function () { - const data = dialog.get_values(); - frappe.call({ - method: "erpnext.controllers.stock_controller.make_quality_inspections", - args: { - doctype: frm.doc.doctype, - docname: frm.doc.name, - items: data - }, - freeze: true, - callback: function (r) { - if (r.message.length > 0) { - if (r.message.length === 1) { - frappe.set_route("Form", "Quality Inspection", r.message[0]); - } else { - frappe.route_options = { - "reference_type": frm.doc.doctype, - "reference_name": frm.doc.name - }; - frappe.set_route("List", "Quality Inspection"); - } - } - dialog.hide(); - } - }); - }, - primary_action_label: __("Create") - }); - - frm.doc.items.forEach(item => { - if (!item.quality_inspection) { - let dialog_items = dialog.fields_dict.items; - dialog_items.df.data.push({ - "docname": item.name, - "item_code": item.item_code, - "item_name": item.item_name, - "qty": item.qty, - "description": item.description, - "serial_no": item.serial_no, - "batch_no": item.batch_no - }); - dialog_items.grid.refresh(); - } - }); - - data = dialog.fields_dict.items.df.data; - if (!data.length) { - frappe.msgprint(__("All items in this document already have a linked Quality Inspection.")); - } else { - dialog.show(); - } - }, - outgoing_stock_entry: function(frm) { frappe.call({ doc: frm.doc, @@ -285,7 +163,7 @@ frappe.ui.form.on('Stock Entry', { refresh: function(frm) { if(!frm.doc.docstatus) { frm.trigger('validate_purpose_consumption'); - frm.add_custom_button(__('Create Material Request'), function() { + frm.add_custom_button(__('Material Request'), function() { frappe.model.with_doctype('Material Request', function() { var mr = frappe.model.get_new_doc('Material Request'); var items = frm.get_field('items').grid.get_selected_children(); @@ -308,7 +186,7 @@ frappe.ui.form.on('Stock Entry', { }); frappe.set_route('Form', 'Material Request', mr.name); }); - }); + }, __("Create")); } if(frm.doc.items) { From dc513886668aa595bf73ebecd7312935c82284b5 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Wed, 26 May 2021 18:28:24 +0530 Subject: [PATCH 064/180] style: fixed indentations and formatting --- .../maintenance_schedule.js | 4 +- .../maintenance_schedule.py | 70 +++++++++---------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index 1e5773c8bc..e2de941963 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -70,7 +70,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ this.frm.add_custom_button(__('Create Maintenance Visit'), function () { let options = ""; - me.frm.call('get_pending_data', {data_type: "items"}).then(r =>{ + me.frm.call('get_pending_data', {data_type: "items"}).then(r => { options = r.message; let schedule_id = ""; @@ -108,7 +108,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ item_name: field.value, s_date: this.value, data_type: "id" - }).then(r =>{ + }).then(r => { schedule_id = r.message; }); } diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 5d573c5524..ea76e91b3f 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -140,7 +140,7 @@ class MaintenanceSchedule(TransactionBase): if employee: holiday_list = get_holiday_list_for_employee(employee) else: - holiday_list = frappe.get_cached_value('Company', self.company, "default_holiday_list") + holiday_list = frappe.get_cached_value('Company', self.company, "default_holiday_list") holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday` where parent=%s''', holiday_list) @@ -161,16 +161,16 @@ class MaintenanceSchedule(TransactionBase): if d.start_date and d.end_date and d.periodicity and d.periodicity!="Random": date_diff = (getdate(d.end_date) - getdate(d.start_date)).days + 1 days_in_period = { - "Weekly": 7, - "Monthly": 30, - "Quarterly": 90, - "Half Yearly": 180, - "Yearly": 365 + "Weekly": 7, + "Monthly": 30, + "Quarterly": 90, + "Half Yearly": 180, + "Yearly": 365 } if date_diff < days_in_period[d.periodicity]: throw(_("Row {0}: To set {1} periodicity, difference between from and to date must be greater than or equal to {2}") - .format(d.idx, d.periodicity, days_in_period[d.periodicity])) + .format(d.idx, d.periodicity, days_in_period[d.periodicity])) def validate_maintenance_detail(self): if not self.get('items'): @@ -217,28 +217,28 @@ class MaintenanceSchedule(TransactionBase): def validate_serial_no(self, item_code, serial_nos, amc_start_date): for serial_no in serial_nos: sr_details = frappe.db.get_value("Serial No", serial_no, - ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date", "item_code"], as_dict=1) + ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date", "item_code"], as_dict=1) if not sr_details: frappe.throw(_("Serial No {0} not found").format(serial_no)) if sr_details.get("item_code") != item_code: frappe.throw(_("Serial No {0} does not belong to Item {1}") - .format(frappe.bold(serial_no), frappe.bold(item_code)), title="Invalid") + .format(frappe.bold(serial_no), frappe.bold(item_code)), title="Invalid") if sr_details.warranty_expiry_date \ - and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date): + and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date): throw(_("Serial No {0} is under warranty upto {1}") - .format(serial_no, sr_details.warranty_expiry_date)) + .format(serial_no, sr_details.warranty_expiry_date)) if sr_details.amc_expiry_date and getdate(sr_details.amc_expiry_date) >= getdate(amc_start_date): throw(_("Serial No {0} is under maintenance contract upto {1}") - .format(serial_no, sr_details.amc_expiry_date)) + .format(serial_no, sr_details.amc_expiry_date)) if not sr_details.warehouse and sr_details.delivery_date and \ - getdate(sr_details.delivery_date) >= getdate(amc_start_date): + getdate(sr_details.delivery_date) >= getdate(amc_start_date): throw(_("Maintenance start date can not be before delivery date for Serial No {0}") - .format(serial_no)) + .format(serial_no)) def validate_schedule(self): item_lst1 =[] @@ -281,7 +281,7 @@ class MaintenanceSchedule(TransactionBase): delete_events(self.doctype, self.name) @frappe.whitelist() - def get_pending_data(self,data_type,s_date = None, item_name = None): + def get_pending_data(self, data_type, s_date=None, item_name=None): if data_type == "date": dates = "" for schedule in self.schedules: @@ -298,7 +298,7 @@ class MaintenanceSchedule(TransactionBase): return items elif data_type == "id": for schedule in self.schedules: - if schedule.item_name == item_name and s_date == formatdate(schedule.scheduled_date,"dd-mm-yyyy"): + if schedule.item_name == item_name and s_date == formatdate(schedule.scheduled_date, "dd-mm-yyyy"): return schedule.name @frappe.whitelist() @@ -324,27 +324,25 @@ def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=No target.serial_no = '' doclist = get_mapped_doc("Maintenance Schedule", source_name, { - "Maintenance Schedule": { - "doctype": "Maintenance Visit", - "field_map": { - "name": "maintenance_schedule" - }, - "validation": { - "docstatus": ["=", 1] - }, - "postprocess": update_status + "Maintenance Schedule": { + "doctype": "Maintenance Visit", + "field_map": { + "name": "maintenance_schedule" }, - "Maintenance Schedule Item": { - "doctype": "Maintenance Visit Purpose", - "field_map": { - "parent": "prevdoc_docname", - "parenttype": "prevdoc_doctype", - }, - "condition": lambda doc: doc.item_name == item_name, - - "postprocess": update_sid - - } + "validation": { + "docstatus": ["=", 1] + }, + "postprocess": update_status + }, + "Maintenance Schedule Item": { + "doctype": "Maintenance Visit Purpose", + "field_map": { + "parent": "prevdoc_docname", + "parenttype": "prevdoc_doctype", + }, + "condition": lambda doc: doc.item_name == item_name, + "postprocess": update_sid + } }, target_doc) return doclist From 5e4128e70ca2d851b199a1fb1419c01c9d16a5df Mon Sep 17 00:00:00 2001 From: Anuja P Date: Wed, 26 May 2021 20:03:14 +0530 Subject: [PATCH 065/180] fix: patch for existing issues --- erpnext/patches.txt | 1 + .../rename_issue_status_hold_to_on_hold.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1e8ce3c658..3a7aa1bce3 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -781,3 +781,4 @@ erpnext.patches.v13_0.germany_fill_debtor_creditor_number erpnext.patches.v13_0.set_pos_closing_as_failed erpnext.patches.v13_0.update_timesheet_changes erpnext.patches.v13_0.set_training_event_attendance +erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py new file mode 100644 index 0000000000..b466678095 --- /dev/null +++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py @@ -0,0 +1,20 @@ +# Copyright (c) 2020, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + if frappe.db.exists('DocType', 'Issue'): + frappe.reload_doc("support", "doctype", "issue") + rename_status() + +def rename_status(): + frappe.db.sql(""" + UPDATE + `tabIssue` + SET + status = 'On Hold' + WHERE + status = 'Hold' + """) \ No newline at end of file From e2059fb9f65a854d2b8ed9f52d51eb40a4c0ad32 Mon Sep 17 00:00:00 2001 From: Anuja P Date: Wed, 26 May 2021 20:07:53 +0530 Subject: [PATCH 066/180] fix: spaces to tabs --- .../v13_0/rename_issue_status_hold_to_on_hold.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py index b466678095..48325fc2d4 100644 --- a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py +++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py @@ -6,15 +6,15 @@ import frappe def execute(): if frappe.db.exists('DocType', 'Issue'): - frappe.reload_doc("support", "doctype", "issue") - rename_status() + frappe.reload_doc("support", "doctype", "issue") + rename_status() def rename_status(): frappe.db.sql(""" UPDATE - `tabIssue` + `tabIssue` SET - status = 'On Hold' - WHERE - status = 'Hold' + status = 'On Hold' + WHERE + status = 'Hold' """) \ No newline at end of file From 45a89a7c6747b7708fa9b7cc77c2691365d81c20 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 27 May 2021 13:49:45 +0530 Subject: [PATCH 067/180] fix(pos): cannot add same item with different rates --- .../page/point_of_sale/pos_controller.js | 34 ++++++++++++------- .../page/point_of_sale/pos_item_cart.js | 25 +++++++++----- .../page/point_of_sale/pos_item_details.js | 28 ++++++++++----- .../page/point_of_sale/pos_item_selector.js | 9 +++-- 4 files changed, 62 insertions(+), 34 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 4f4f1b2240..0921f010e7 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -241,10 +241,8 @@ erpnext.PointOfSale.Controller = class { events: { get_frm: () => this.frm, - cart_item_clicked: (item_code, batch_no, uom) => { - const search_field = batch_no ? 'batch_no' : 'item_code'; - const search_value = batch_no || item_code; - const item_row = this.frm.doc.items.find(i => i[search_field] === search_value && i.uom === uom); + cart_item_clicked: (item_code, batch_no, uom, rate) => { + const item_row = this.get_item_from_frm(item_code, batch_no, uom, rate) this.item_details.toggle_item_details_section(item_row); }, @@ -275,18 +273,25 @@ erpnext.PointOfSale.Controller = class { this.cart.toggle_numpad(minimize); }, - form_updated: async (cdt, cdn, fieldname, value) => { + form_updated: (cdt, cdn, fieldname, value) => { const item_row = frappe.model.get_doc(cdt, cdn); if (item_row && item_row[fieldname] != value) { - const { item_code, batch_no, uom } = this.item_details.current_item; + const { item_code, batch_no, uom, rate } = this.item_details.current_item; const event = { field: fieldname, value, - item: { item_code, batch_no, uom } + item: { item_code, batch_no, uom, rate } } return this.on_cart_update(event) } + + return Promise.resolve(); + }, + + highlight_cart_item: (item) => { + const cart_item = this.cart.get_cart_item(item); + this.cart.toggle_item_highlight(cart_item); }, item_field_focused: (fieldname) => { @@ -501,8 +506,8 @@ erpnext.PointOfSale.Controller = class { let item_row = undefined; try { let { field, value, item } = args; - const { item_code, batch_no, serial_no, uom } = item; - item_row = this.get_item_from_frm(item_code, batch_no, uom); + const { item_code, batch_no, serial_no, uom, rate } = item; + item_row = this.get_item_from_frm(item_code, batch_no, uom, rate); const item_selected_from_selector = field === 'qty' && value === "+1" @@ -535,7 +540,7 @@ erpnext.PointOfSale.Controller = class { item_selected_from_selector && (value = flt(value)) - const args = { item_code, batch_no, [field]: value }; + const args = { item_code, batch_no, rate, [field]: value }; if (serial_no) { await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no); @@ -550,9 +555,11 @@ erpnext.PointOfSale.Controller = class { await this.check_stock_availability(item_row, value, this.frm.doc.set_warehouse); await this.trigger_new_item_events(item_row); - - this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row); + this.update_cart_html(item_row); + + this.item_details.$component.is(':visible') && this.edit_item_details_of(item_row); + this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row); } } catch (error) { @@ -563,12 +570,13 @@ erpnext.PointOfSale.Controller = class { } } - get_item_from_frm(item_code, batch_no, uom) { + get_item_from_frm(item_code, batch_no, uom, rate) { const has_batch_no = batch_no; return this.frm.doc.items.find( i => i.item_code === item_code && (!has_batch_no || (has_batch_no && i.batch_no === batch_no)) && (i.uom === uom) + && (i.rate == rate) ); } diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js index 11a63b3d4a..f7db9d4349 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_cart.js +++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js @@ -184,7 +184,8 @@ erpnext.PointOfSale.ItemCart = class { const item_code = unescape($cart_item.attr('data-item-code')); const batch_no = unescape($cart_item.attr('data-batch-no')); const uom = unescape($cart_item.attr('data-uom')); - me.events.cart_item_clicked(item_code, batch_no, uom); + const rate = unescape($cart_item.attr('data-rate')); + me.events.cart_item_clicked(item_code, batch_no, uom, rate); this.numpad_value = ''; }); @@ -520,28 +521,34 @@ erpnext.PointOfSale.ItemCart = class { } } - get_cart_item({ item_code, batch_no, uom }) { + get_cart_item({ item_code, batch_no, uom, rate }) { const batch_attr = `[data-batch-no="${escape(batch_no)}"]`; const item_code_attr = `[data-item-code="${escape(item_code)}"]`; const uom_attr = `[data-uom="${escape(uom)}"]`; + const rate_attr = `[data-rate="${escape(rate)}"]`; const item_selector = batch_no ? - `.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`; + `.cart-item-wrapper${batch_attr}${uom_attr}${rate_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}${rate_attr}`; return this.$cart_items_wrapper.find(item_selector); } + get_item_from_frm(item) { + const doc = this.events.get_frm().doc; + const { item_code, batch_no, uom, rate } = item; + const search_field = batch_no ? 'batch_no' : 'item_code'; + const search_value = batch_no || item_code; + + return doc.items.find(i => i[search_field] === search_value && i.uom === uom && i.rate === rate); + } + update_item_html(item, remove_item) { const $item = this.get_cart_item(item); if (remove_item) { $item && $item.next().remove() && $item.remove(); } else { - const { item_code, batch_no, uom } = item; - const search_field = batch_no ? 'batch_no' : 'item_code'; - const search_value = batch_no || item_code; - const item_row = this.events.get_frm().doc.items.find(i => i[search_field] === search_value && i.uom === uom); - + const item_row = this.get_item_from_frm(item); this.render_cart_item(item_row, $item); } @@ -559,7 +566,7 @@ erpnext.PointOfSale.ItemCart = class { this.$cart_items_wrapper.append( `
+ data-batch-no="${escape(item_data.batch_no || '')}" data-rate="${escape(item_data.rate)}">
` ) diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index 32a4556766..1afce32018 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -54,13 +54,24 @@ erpnext.PointOfSale.ItemDetails = class { this.$dicount_section = this.$component.find('.discount-section'); } - toggle_item_details_section(item) { - const { item_code, batch_no, uom } = this.current_item; + has_item_has_changed(item) { + const { item_code, batch_no, uom, rate } = this.current_item; const item_code_is_same = item && item_code === item.item_code; const batch_is_same = item && batch_no == item.batch_no; const uom_is_same = item && uom === item.uom; + const rate_is_same = item && rate === item.rate; + + if (!item) + return false - this.item_has_changed = !item ? false : item_code_is_same && batch_is_same && uom_is_same ? false : true; + if (item_code_is_same && batch_is_same && uom_is_same && rate_is_same) + return false + + return true; + } + + toggle_item_details_section(item) { + this.item_has_changed = this.has_item_has_changed(item) this.events.toggle_item_selector(this.item_has_changed); this.toggle_component(this.item_has_changed); @@ -72,11 +83,12 @@ erpnext.PointOfSale.ItemDetails = class { this.item_row = item; this.currency = this.events.get_frm().doc.currency; - this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom }; + this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom, rate: item.rate }; this.render_dom(item); this.render_discount_dom(item); this.render_form(item); + this.events.highlight_cart_item(item); } else { this.validate_serial_batch_item(); this.current_item = {}; @@ -198,12 +210,14 @@ erpnext.PointOfSale.ItemDetails = class { if (this.allow_rate_change) { this.rate_control.df.onchange = function() { if (this.value || flt(this.value) === 0) { + me.events.set_value_in_current_cart_item('rate', this.value); me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => { const item_row = frappe.get_doc(me.doctype, me.name); const doc = me.events.get_frm().doc; me.$item_price.html(format_currency(item_row.rate, doc.currency)); me.render_discount_dom(item_row); }); + me.current_item.rate = this.value; } }; } else { @@ -292,11 +306,7 @@ erpnext.PointOfSale.ItemDetails = class { frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => { const field_control = this[`${fieldname}_control`]; - const { item_code, batch_no, uom } = this.current_item; - const item_code_is_same = item_code === item_row.item_code; - const batch_is_same = batch_no == item_row.batch_no; - const uom_is_same = uom === item_row.uom; - const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false; + const item_is_same = !this.has_item_has_changed(item_row); if (item_is_same && field_control && field_control.get_value() !== value) { field_control.set_value(value); diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js index b8a82a9eda..55b07e71cb 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_selector.js +++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js @@ -78,7 +78,7 @@ erpnext.PointOfSale.ItemSelector = class { get_item_html(item) { const me = this; // eslint-disable-next-line no-unused-vars - const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item; + const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item; const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange"; let qty_to_display = actual_qty; @@ -108,6 +108,7 @@ erpnext.PointOfSale.ItemSelector = class { `
${get_item_image_html()} @@ -116,7 +117,7 @@ erpnext.PointOfSale.ItemSelector = class {
${frappe.ellipsis(item.item_name, 18)}
-
${format_currency(item.price_list_rate, item.currency, 0) || 0}
+
${format_currency(price_list_rate, item.currency, 0) || 0}
` ); @@ -213,13 +214,15 @@ erpnext.PointOfSale.ItemSelector = class { let batch_no = unescape($item.attr('data-batch-no')); let serial_no = unescape($item.attr('data-serial-no')); let uom = unescape($item.attr('data-uom')); + let rate = unescape($item.attr('data-rate')); // escape(undefined) returns "undefined" then unescape returns "undefined" batch_no = batch_no === "undefined" ? undefined : batch_no; serial_no = serial_no === "undefined" ? undefined : serial_no; uom = uom === "undefined" ? undefined : uom; + rate = rate === "undefined" ? undefined : rate; - me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom }}); + me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom, rate }}); me.set_search_value(''); }); From 3382655b5eb7f0e6477c63ab91ef2792735ef601 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 27 May 2021 14:27:38 +0530 Subject: [PATCH 068/180] fix: sider issues --- erpnext/selling/page/point_of_sale/pos_controller.js | 2 +- erpnext/selling/page/point_of_sale/pos_item_details.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 0921f010e7..ae3f9e3c9d 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -242,7 +242,7 @@ erpnext.PointOfSale.Controller = class { get_frm: () => this.frm, cart_item_clicked: (item_code, batch_no, uom, rate) => { - const item_row = this.get_item_from_frm(item_code, batch_no, uom, rate) + const item_row = this.get_item_from_frm(item_code, batch_no, uom, rate); this.item_details.toggle_item_details_section(item_row); }, diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index 1afce32018..df62696c4b 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -62,16 +62,16 @@ erpnext.PointOfSale.ItemDetails = class { const rate_is_same = item && rate === item.rate; if (!item) - return false + return false; if (item_code_is_same && batch_is_same && uom_is_same && rate_is_same) - return false + return false; return true; } toggle_item_details_section(item) { - this.item_has_changed = this.has_item_has_changed(item) + this.item_has_changed = this.has_item_has_changed(item); this.events.toggle_item_selector(this.item_has_changed); this.toggle_component(this.item_has_changed); From bb0a40b99572b4a3b278cb7ef0d0f1beeef9648b Mon Sep 17 00:00:00 2001 From: Anuja P Date: Thu, 27 May 2021 17:15:47 +0530 Subject: [PATCH 069/180] fix: ageing error in PSOA --- .../process_statement_of_accounts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index 2ad455c48f..0b0ee904ff 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -94,7 +94,7 @@ def get_report_pdf(doc, consolidated=True): continue html = frappe.render_template(template_path, \ - {"filters": filters, "data": res, "ageing": ageing[0] if doc.include_ageing else None, + {"filters": filters, "data": res, "ageing": ageing[0] if (doc.include_ageing and ageing) else None, "letter_head": letter_head if doc.letter_head else None, "terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms') if doc.terms_and_conditions else None}) From 9e4c28852e10848feda7bad57235a35fad807792 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 27 May 2021 17:25:50 +0530 Subject: [PATCH 070/180] refactor: added maintenance visit to maintenance schedule dashboard --- .../doctype/maintenance_schedule/maintenance_schedule.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json index 4df0c6c0f7..4f89a679c8 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json @@ -231,11 +231,12 @@ "is_submittable": 1, "links": [ { - "link_doctype": "Maintenance Visit Purpose", - "link_fieldname": "prevdoc_docname" + "group": "Visits", + "link_doctype": "Maintenance Visit", + "link_fieldname": "maintenance_schedule" } ], - "modified": "2021-04-21 11:27:05.744109", + "modified": "2021-05-27 16:05:10.746465", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule", From bd783e8072c8d4dcae4b9249b5a88363bb0a2d1b Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 27 May 2021 17:34:16 +0530 Subject: [PATCH 071/180] refactor: renamed item_ref to item_reference --- .../maintenance_schedule_detail.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json index 76acefbf61..8ccef6a817 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json @@ -18,7 +18,7 @@ "completion_status", "section_break_10", "serial_no", - "item_ref" + "item_reference" ], "fields": [ { @@ -97,14 +97,6 @@ "options": "Pending\nPartially Completed\nFully Completed", "read_only": 1 }, - { - "fieldname": "item_ref", - "fieldtype": "Link", - "hidden": 1, - "label": "Item Reference", - "options": "Maintenance Schedule Item", - "read_only": 1 - }, { "fieldname": "column_break_3", "fieldtype": "Column Break" @@ -120,12 +112,20 @@ { "fieldname": "section_break_10", "fieldtype": "Section Break" + }, + { + "fieldname": "item_reference", + "fieldtype": "Link", + "hidden": 1, + "label": "Item Reference", + "options": "Maintenance Schedule Item", + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-21 11:07:29.524071", + "modified": "2021-05-27 16:07:25.905015", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule Detail", From fbc86942911035f29a85fc9302e81e091b990657 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 27 May 2021 17:37:57 +0530 Subject: [PATCH 072/180] refactor: added maintenance schedule links to parent form --- .../maintenance_visit/maintenance_visit.json | 1286 ++++------------- 1 file changed, 284 insertions(+), 1002 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json index 32bfa0e324..ec32239518 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json @@ -1,1042 +1,324 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2013-01-10 16:34:31", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, + "actions": [], + "autoname": "naming_series:", + "creation": "2013-01-10 16:34:31", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "customer_details", + "column_break0", + "naming_series", + "customer", + "customer_name", + "address_display", + "contact_display", + "contact_mobile", + "contact_email", + "maintenance_schedule", + "maintenance_schedule_detail", + "column_break1", + "mntc_date", + "mntc_time", + "maintenance_details", + "completion_status", + "column_break_14", + "maintenance_type", + "section_break0", + "purposes", + "more_info", + "customer_feedback", + "col_break3", + "status", + "amended_from", + "company", + "contact_info_section", + "customer_address", + "contact_person", + "col_break4", + "territory", + "customer_group" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_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": "", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-user", - "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": "customer_details", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-user" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break0", - "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, - "oldfieldtype": "Column Break", - "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": "column_break0", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "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": "Series", - "length": 0, - "no_copy": 1, - "options": "MAT-MVS-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "MAT-MVS-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Customer", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer", - "oldfieldtype": "Link", - "options": "Customer", - "permlevel": 0, - "print_hide": 1, - "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": "customer", + "fieldtype": "Link", + "in_global_search": 1, + "label": "Customer", + "oldfieldname": "customer", + "oldfieldtype": "Link", + "options": "Customer", + "print_hide": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_name", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Customer Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "fieldname": "customer_name", + "fieldtype": "Data", + "hidden": 1, + "in_global_search": 1, + "label": "Customer Name", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "address_display", - "fieldtype": "Small Text", - "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": "Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "address_display", + "fieldtype": "Small Text", + "hidden": 1, + "label": "Address", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_display", - "fieldtype": "Small Text", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_display", + "fieldtype": "Small Text", + "hidden": 1, + "in_global_search": 1, + "label": "Contact", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_mobile", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Mobile No", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_mobile", + "fieldtype": "Data", + "hidden": 1, + "label": "Mobile No", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_email", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contact Email", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_email", + "fieldtype": "Data", + "hidden": 1, + "label": "Contact Email", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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, - "oldfieldtype": "Column Break", - "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": "column_break1", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break", "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "mntc_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": "Maintenance Date", - "length": 0, - "no_copy": 1, - "oldfieldname": "mntc_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "mntc_date", + "fieldtype": "Date", + "label": "Maintenance Date", + "no_copy": 1, + "oldfieldname": "mntc_date", + "oldfieldtype": "Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "mntc_time", - "fieldtype": "Time", - "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": "Maintenance Time", - "length": 0, - "no_copy": 1, - "oldfieldname": "mntc_time", - "oldfieldtype": "Time", - "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": "mntc_time", + "fieldtype": "Time", + "label": "Maintenance Time", + "no_copy": 1, + "oldfieldname": "mntc_time", + "oldfieldtype": "Time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "maintenance_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": "", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-wrench", - "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": "maintenance_details", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-wrench" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "completion_status", - "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": 1, - "label": "Completion Status", - "length": 0, - "no_copy": 0, - "oldfieldname": "completion_status", - "oldfieldtype": "Select", - "options": "\nPartially Completed\nFully Completed", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "completion_status", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Completion Status", + "oldfieldname": "completion_status", + "oldfieldtype": "Select", + "options": "\nPartially Completed\nFully Completed", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_14", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Unscheduled", - "fieldname": "maintenance_type", - "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": 1, - "label": "Maintenance Type", - "length": 0, - "no_copy": 0, - "oldfieldname": "maintenance_type", - "oldfieldtype": "Select", - "options": "\nScheduled\nUnscheduled\nBreakdown", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Unscheduled", + "fieldname": "maintenance_type", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Maintenance Type", + "oldfieldname": "maintenance_type", + "oldfieldtype": "Select", + "options": "\nScheduled\nUnscheduled\nBreakdown", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break0", - "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, - "oldfieldtype": "Section Break", - "options": "fa fa-wrench", - "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": "section_break0", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-wrench" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "purposes", - "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": "Purposes", - "length": 0, - "no_copy": 0, - "oldfieldname": "maintenance_visit_details", - "oldfieldtype": "Table", - "options": "Maintenance Visit Purpose", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "purposes", + "fieldtype": "Table", + "label": "Purposes", + "oldfieldname": "maintenance_visit_details", + "oldfieldtype": "Table", + "options": "Maintenance Visit Purpose", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "more_info", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "More Information", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-file-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": "more_info", + "fieldtype": "Section Break", + "label": "More Information", + "oldfieldtype": "Section Break", + "options": "fa fa-file-text" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_feedback", - "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": "Customer Feedback", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer_feedback", - "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": "customer_feedback", + "fieldtype": "Small Text", + "label": "Customer Feedback", + "oldfieldname": "customer_feedback", + "oldfieldtype": "Small Text" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "col_break3", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Draft", - "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, - "oldfieldname": "status", - "oldfieldtype": "Data", - "options": "\nDraft\nCancelled\nSubmitted", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "no_copy": 1, + "oldfieldname": "status", + "oldfieldtype": "Data", + "options": "\nDraft\nCancelled\nSubmitted", + "read_only": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "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, - "oldfieldname": "amended_from", - "oldfieldtype": "Data", - "options": "Maintenance Visit", - "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", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "oldfieldname": "amended_from", + "oldfieldtype": "Data", + "options": "Maintenance Visit", + "print_hide": 1, + "read_only": 1, "width": "150px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "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": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "oldfieldname": "company", - "oldfieldtype": "Select", - "options": "Company", - "permlevel": 0, - "print_hide": 1, - "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, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Select", + "options": "Company", + "print_hide": 1, + "remember_last_selected_value": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "customer", - "fieldname": "contact_info_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": "Contact Info", - "length": 0, - "no_copy": 0, - "options": "fa fa-bullhorn", - "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 - }, + "depends_on": "customer", + "fieldname": "contact_info_section", + "fieldtype": "Section Break", + "label": "Contact Info", + "options": "fa fa-bullhorn" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_address", - "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": "Customer Address", - "length": 0, - "no_copy": 0, - "options": "Address", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "customer_address", + "fieldtype": "Link", + "label": "Customer Address", + "options": "Address", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_person", - "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": "Contact Person", - "length": 0, - "no_copy": 0, - "options": "Contact", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "contact_person", + "fieldtype": "Link", + "label": "Contact Person", + "options": "Contact", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "col_break4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "territory", - "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": "Territory", - "length": 0, - "no_copy": 0, - "options": "Territory", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "territory", + "fieldtype": "Link", + "label": "Territory", + "options": "Territory", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "customer_group", - "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": "Customer Group", - "length": 0, - "no_copy": 0, - "options": "Customer Group", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "customer_group", + "fieldtype": "Link", + "label": "Customer Group", + "options": "Customer Group", + "print_hide": 1 + }, + { + "fieldname": "maintenance_schedule", + "fieldtype": "Link", + "label": "Maintenance Schedule", + "options": "Maintenance Schedule", + "read_only": 1 + }, + { + "fieldname": "maintenance_schedule_detail", + "fieldtype": "Link", + "hidden": 1, + "label": "Maintenance Schedule Detail", + "options": "Maintenance Schedule Detail" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-file-text", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Maintenance", - "name": "Maintenance Visit", - "owner": "Administrator", + ], + "icon": "fa fa-file-text", + "idx": 1, + "is_submittable": 1, + "links": [], + "modified": "2021-05-27 16:06:17.352572", + "modified_by": "Administrator", + "module": "Maintenance", + "name": "Maintenance Visit", + "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": 1, - "role": "Maintenance User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Maintenance User", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "status,maintenance_type,customer,customer_name,mntc_date,company", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "timeline_field": "customer", - "title_field": "customer_name", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "search_fields": "status,maintenance_type,customer,customer_name,mntc_date,company", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "timeline_field": "customer", + "title_field": "customer_name" } \ No newline at end of file From 04dfaf3b2afceeabafdc62ebb9eb15b8927fff15 Mon Sep 17 00:00:00 2001 From: anushka19 Date: Mon, 24 May 2021 20:49:46 +0530 Subject: [PATCH 073/180] fix: Broken help links fixed --- erpnext/public/js/help_links.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/erpnext/public/js/help_links.js b/erpnext/public/js/help_links.js index e78992302f..aa9bba17c7 100644 --- a/erpnext/public/js/help_links.js +++ b/erpnext/public/js/help_links.js @@ -644,14 +644,14 @@ frappe.help.help_links["List/Payment Request"] = [ frappe.help.help_links["List/Asset"] = [ { label: "Managing Fixed Assets", - url: docsUrl + "user/manual/en/accounts/managing-fixed-assets", + url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets", }, ]; frappe.help.help_links["List/Asset Category"] = [ { label: "Asset Category", - url: docsUrl + "user/manual/en/accounts/managing-fixed-assets", + url: docsUrl + "user/manual/en/asset/asset-category", }, ]; @@ -663,7 +663,7 @@ frappe.help.help_links["List/Item"] = [ { label: "Item", url: docsUrl + "user/manual/en/stock/item" }, { label: "Item Price", - url: docsUrl + "user/manual/en/stock/item/item-price", + url: docsUrl + "user/manual/en/stock/item-price", }, { label: "Barcode", @@ -672,25 +672,25 @@ frappe.help.help_links["List/Item"] = [ }, { label: "Item Wise Taxation", - url: docsUrl + "user/manual/en/accounts/item-wise-taxation", + url: docsUrl + "user/manual/en/accounts/item-tax-template", }, { label: "Managing Fixed Assets", - url: docsUrl + "user/manual/en/accounts/managing-fixed-assets", + url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets", }, { label: "Item Codification", - url: docsUrl + "user/manual/en/stock/item/item-codification", + url: docsUrl + "user/manual/en/stock/articles/item-codification", }, { label: "Item Variants", - url: docsUrl + "user/manual/en/stock/item/item-variants", + url: docsUrl + "user/manual/en/stock/item-variants", }, { label: "Item Valuation", url: docsUrl + - "user/manual/en/stock/item/item-valuation-fifo-and-moving-average", + "user/manual/en/stock/articles/item-valuation-fifo-and-moving-average", }, ]; @@ -698,7 +698,7 @@ frappe.help.help_links["Form/Item"] = [ { label: "Item", url: docsUrl + "user/manual/en/stock/item" }, { label: "Item Price", - url: docsUrl + "user/manual/en/stock/item/item-price", + url: docsUrl + "user/manual/en/stock/item-price", }, { label: "Barcode", @@ -707,19 +707,19 @@ frappe.help.help_links["Form/Item"] = [ }, { label: "Item Wise Taxation", - url: docsUrl + "user/manual/en/accounts/item-wise-taxation", + url: docsUrl + "user/manual/en/accounts/item-tax-template", }, { label: "Managing Fixed Assets", - url: docsUrl + "user/manual/en/accounts/managing-fixed-assets", + url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets", }, { label: "Item Codification", - url: docsUrl + "user/manual/en/stock/item/item-codification", + url: docsUrl + "user/manual/en/stock/articles/item-codification", }, { label: "Item Variants", - url: docsUrl + "user/manual/en/stock/item/item-variants", + url: docsUrl + "user/manual/en/stock/item-variants", }, { label: "Item Valuation", From 46d39d27aaea10eda484cf41dda0b3bb6392f67f Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 27 May 2021 14:16:01 +0200 Subject: [PATCH 074/180] fix: validate company in taxes setup --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 429a558c58..dd0ebd1517 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -11,6 +11,9 @@ from frappe import _ def setup_taxes_and_charges(company_name: str, country: str): + if not frappe.db.exists('Company', company_name): + frappe.throw(_('Company {} does not exist yet. Taxes setup aborted.').format(company_name)) + file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'country_wise_tax.json') with open(file_path, 'r') as json_file: tax_data = json.load(json_file) From 86ee3ebb09ea11e971a48e1718822a2e998fba10 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 27 May 2021 14:16:26 +0200 Subject: [PATCH 075/180] feat: create tax category during taxes setup --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index dd0ebd1517..672caf2606 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -102,6 +102,9 @@ def make_taxes_and_charges_template(company_name, doctype, template): if frappe.db.exists(doctype, {'title': template.get('title'), 'company': company_name}): return + if template.get('tax_category'): + ensure_tax_category_exists(template.get('tax_category')) + for tax_row in template.get('taxes'): account_data = tax_row.get('account_head') tax_row_defaults = { @@ -233,3 +236,10 @@ def get_or_create_tax_group(company_name, root_type): tax_group_name = tax_group_account.name return tax_group_name + + +def ensure_tax_category_exists(name): + if not frappe.db.exists('Tax Category', name): + doc = frappe.new_doc('Tax Category') + doc.title = name + doc.save() From 50794407b49469682a53b6f91dd3257ca7b25f9d Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 27 May 2021 14:17:53 +0200 Subject: [PATCH 076/180] feat: Item Tax Templates for Germany --- .../setup_wizard/data/country_wise_tax.json | 307 +++++++++++++----- 1 file changed, 232 insertions(+), 75 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 5876488033..2e2a0ca726 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -485,33 +485,32 @@ "SKR04 mit Kontonummern": { "sales_tax_templates": [ { - "title": "Umsatzsteuer 19%", + "title": "Umsatzsteuer", + "tax_category": "Umsatzsteuer", "taxes": [ { "account_head": { "account_name": "Umsatzsteuer 19%", "account_number": "3806", "tax_rate": 19.00 - } - } - ] - }, - { - "title": "Umsatzsteuer 7%", - "taxes": [ + }, + "rate": 0.00 + }, { "account_head": { "account_name": "Umsatzsteuer 7%", "account_number": "3801", "tax_rate": 7.00 - } + }, + "rate": 0.00 } ] } ], "purchase_tax_templates": [ { - "title": "Abziehbare Vorsteuer 19%", + "title": "Vorsteuer", + "tax_category": "Vorsteuer", "taxes": [ { "account_head": { @@ -519,25 +518,23 @@ "account_number": "1406", "root_type": "Asset", "tax_rate": 19.00 - } - } - ] - }, - { - "title": "Abziehbare Vorsteuer 7%", - "taxes": [ + }, + "rate": 0.00 + }, { "account_head": { "account_name": "Abziehbare Vorsteuer 7%", "account_number": "1401", "root_type": "Asset", "tax_rate": 7.00 - } + }, + "rate": 0.00 } ] }, { "title": "Innergemeinschaftlicher Erwerb 19% Umsatzsteuer und 19% Vorsteuer", + "tax_category": "Innergemeinschaftlicher Erwerb 19%", "taxes": [ { "account_head": { @@ -564,33 +561,32 @@ "SKR03 mit Kontonummern": { "sales_tax_templates": [ { - "title": "Umsatzsteuer 19%", + "title": "Umsatzsteuer", + "tax_category": "Umsatzsteuer", "taxes": [ { "account_head": { "account_name": "Umsatzsteuer 19%", "account_number": "1776", "tax_rate": 19.00 - } - } - ] - }, - { - "title": "Umsatzsteuer 7%", - "taxes": [ + }, + "rate": 0.00 + }, { "account_head": { "account_name": "Umsatzsteuer 7%", "account_number": "1771", "tax_rate": 7.00 - } + }, + "rate": 0.00 } ] } ], "purchase_tax_templates": [ { - "title": "Abziehbare Vorsteuer 19%", + "title": "Vorsteuer", + "tax_category": "Vorsteuer", "taxes": [ { "account_head": { @@ -598,20 +594,17 @@ "account_number": "1576", "root_type": "Asset", "tax_rate": 19.00 - } - } - ] - }, - { - "title": "Abziehbare Vorsteuer 7%", - "taxes": [ + }, + "rate": 0.00 + }, { "account_head": { "account_name": "Abziehbare Vorsteuer 7%", "account_number": "1571", "root_type": "Asset", "tax_rate": 7.00 - } + }, + "rate": 0.00 } ] } @@ -620,33 +613,32 @@ "Standard with Numbers": { "sales_tax_templates": [ { - "title": "Umsatzsteuer 19%", + "title": "Umsatzsteuer", + "tax_category": "Umsatzsteuer", "taxes": [ { "account_head": { "account_name": "Umsatzsteuer 19%", "account_number": "2301", "tax_rate": 19.00 - } - } - ] - }, - { - "title": "Umsatzsteuer 7%", - "taxes": [ + }, + "rate": 0.00 + }, { "account_head": { "account_name": "Umsatzsteuer 7%", "account_number": "2302", "tax_rate": 7.00 - } + }, + "rate": 0.00 } ] } ], "purchase_tax_templates": [ { - "title": "Abziehbare Vorsteuer 19%", + "title": "Vorsteuer", + "tax_category": "Vorsteuer", "taxes": [ { "account_head": { @@ -654,20 +646,107 @@ "account_number": "1501", "root_type": "Asset", "tax_rate": 19.00 - } - } - ] - }, - { - "title": "Abziehbare Vorsteuer 7%", - "taxes": [ + }, + "rate": 0.00 + }, { "account_head": { "account_name": "Abziehbare Vorsteuer 7%", "account_number": "1502", "root_type": "Asset", "tax_rate": 7.00 - } + }, + "rate": 0.00 + } + ] + } + ], + "item_tax_templates": [ + { + "title": "Umsatzsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "account_number": "2301", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "account_number": "2302", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Umsatzsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "account_number": "2301", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "account_number": "2302", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 + } + ] + }, + { + "title": "Vorsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "account_number": "1501", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "account_number": "1502", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Vorsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "account_number": "1501", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "account_number": "1502", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 } ] } @@ -676,13 +755,67 @@ "*": { "sales_tax_templates": [ { - "title": "Umsatzsteuer 19%", + "title": "Umsatzsteuer", + "tax_category": "Umsatzsteuer", "taxes": [ { "account_head": { "account_name": "Umsatzsteuer 19%", "tax_rate": 19.00 - } + }, + "rate": 0.00 + }, + { + "account_head": { + "account_name": "Umsatzsteuer 7%", + "tax_rate": 7.00 + }, + "rate": 0.00 + } + ] + } + ], + "purchase_tax_templates": [ + { + "title": "Vorsteuer 19%", + "tax_category": "Vorsteuer", + "taxes": [ + { + "account_head": { + "account_name": "Abziehbare Vorsteuer 19%", + "tax_rate": 19.00, + "root_type": "Asset" + }, + "rate": 0.00 + }, + { + "account_head": { + "account_name": "Abziehbare Vorsteuer 7%", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "rate": 0.00 + } + ] + } + ], + "item_tax_templates": [ + { + "title": "Umsatzsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 } ] }, @@ -690,36 +823,60 @@ "title": "Umsatzsteuer 7%", "taxes": [ { - "account_head": { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { "account_name": "Umsatzsteuer 7%", "tax_rate": 7.00 - } - } - ] - } - ], - "purchase_tax_templates": [ - { - "title": "Abziehbare Vorsteuer 19%", - "taxes": [ - { - "account_head": { - "account_name": "Abziehbare Vorsteuer 19%", - "tax_rate": 19.00, - "root_type": "Asset" - } + }, + "tax_rate": 7.00 } ] }, { - "title": "Abziehbare Vorsteuer 7%", + "title": "Vorsteuer 19%", "taxes": [ { - "account_head": { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { "account_name": "Abziehbare Vorsteuer 7%", "root_type": "Asset", "tax_rate": 7.00 - } + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Vorsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 } ] } From 591f3f0bb9ec944757a482db40e34162b3eb2fbe Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 4 May 2021 18:36:45 +0530 Subject: [PATCH 077/180] ci: Try Parallel tests --- .github/helper/install.sh | 2 +- .github/workflows/ci-tests.yml | 55 ++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/.github/helper/install.sh b/.github/helper/install.sh index 7b0f944c66..fd32624c2d 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -12,7 +12,7 @@ sudo apt install npm pip install frappe-bench -git clone https://github.com/frappe/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1 +git clone https://github.com/surajshetty3416/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1 bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench mkdir ~/frappe-bench/sites/test_site diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 84ecfb1457..de8d7ac503 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -13,7 +13,10 @@ jobs: include: - TYPE: "server" JOB_NAME: "Server" - RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-tests --app erpnext --coverage + RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext + - TYPE: "server" + JOB_NAME: "Server" + RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - TYPE: "patch" JOB_NAME: "Patch" RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate @@ -80,29 +83,29 @@ jobs: env: TYPE: ${{ matrix.TYPE }} - - name: Coverage - Pull Request - if: matrix.TYPE == 'server' && github.event_name == 'pull_request' - run: | - cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} - cd ${GITHUB_WORKSPACE} - pip install coveralls==2.2.0 - pip install coverage==4.5.4 - coveralls --service=github - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} - COVERALLS_SERVICE_NAME: github - - - name: Coverage - Push - if: matrix.TYPE == 'server' && github.event_name == 'push' - run: | - cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} - cd ${GITHUB_WORKSPACE} - pip install coveralls==2.2.0 - pip install coverage==4.5.4 - coveralls --service=github-actions - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} - COVERALLS_SERVICE_NAME: github-actions + # - name: Coverage - Pull Request + # if: matrix.TYPE == 'server' && github.event_name == 'pull_request' + # run: | + # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} + # cd ${GITHUB_WORKSPACE} + # pip install coveralls==2.2.0 + # pip install coverage==4.5.4 + # coveralls --service=github + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} + # COVERALLS_SERVICE_NAME: github + + # - name: Coverage - Push + # if: matrix.TYPE == 'server' && github.event_name == 'push' + # run: | + # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} + # cd ${GITHUB_WORKSPACE} + # pip install coveralls==2.2.0 + # pip install coverage==4.5.4 + # coveralls --service=github-actions + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} + # COVERALLS_SERVICE_NAME: github-actions From dd1530492104759f28df37e5b0235ab19551cff5 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 4 May 2021 18:58:20 +0530 Subject: [PATCH 078/180] fix: Frappe branch --- .github/helper/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/helper/install.sh b/.github/helper/install.sh index fd32624c2d..44659f22fa 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -12,7 +12,7 @@ sudo apt install npm pip install frappe-bench -git clone https://github.com/surajshetty3416/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1 +git clone https://github.com/surajshetty3416/frappe --branch "python-distributed-testing" --depth 1 bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench mkdir ~/frappe-bench/sites/test_site From 34e620fb5b50b6198544ae16b9480b345933ab70 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 6 May 2021 13:04:12 +0530 Subject: [PATCH 079/180] test: Fix dependency --- erpnext/tests/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py index e69de29bb2..dcc4f5336d 100644 --- a/erpnext/tests/__init__.py +++ b/erpnext/tests/__init__.py @@ -0,0 +1 @@ +global_test_dependencies = ['User', 'Company'] From 85dd5d2252d5d2539bec0cabb364c87df22d8660 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 6 May 2021 13:05:03 +0530 Subject: [PATCH 080/180] chore: Debug --- .github/workflows/ci-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index de8d7ac503..7373c1efa6 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -1,6 +1,6 @@ name: CI -on: [pull_request, workflow_dispatch, push] +on: [pull_request, workflow_dispatch] jobs: test: From 0f3d862ba993e56b1312e67334ae138ee52b663c Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 6 May 2021 15:13:09 +0530 Subject: [PATCH 081/180] chore: Debug --- .github/workflows/ci-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 7373c1efa6..b03aad794b 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -17,6 +17,9 @@ jobs: - TYPE: "server" JOB_NAME: "Server" RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext + - TYPE: "server" + JOB_NAME: "Server" + RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - TYPE: "patch" JOB_NAME: "Patch" RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate From 7b74985a548aaf80778555b84fe10104ee2b90e6 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 6 May 2021 17:44:26 +0530 Subject: [PATCH 082/180] test: Fix test_dependencies --- erpnext/accounts/doctype/budget/test_budget.py | 2 ++ erpnext/education/doctype/fees/test_fees.py | 3 +-- erpnext/tests/__init__.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py index c5ec23c829..603e21ea24 100644 --- a/erpnext/accounts/doctype/budget/test_budget.py +++ b/erpnext/accounts/doctype/budget/test_budget.py @@ -11,6 +11,8 @@ from erpnext.buying.doctype.purchase_order.test_purchase_order import create_pur from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry +test_dependencies = ['Monthly Distribution'] + class TestBudget(unittest.TestCase): def test_monthly_budget_crossed_ignore(self): set_total_expense_zero(nowdate(), "cost_center") diff --git a/erpnext/education/doctype/fees/test_fees.py b/erpnext/education/doctype/fees/test_fees.py index eedc2ae730..c6bb704b41 100644 --- a/erpnext/education/doctype/fees/test_fees.py +++ b/erpnext/education/doctype/fees/test_fees.py @@ -9,8 +9,7 @@ from frappe.utils import nowdate from frappe.utils.make_random import get_random from erpnext.education.doctype.program.test_program import make_program_and_linked_courses -# test_records = frappe.get_test_records('Fees') - +test_dependencies = ['Company'] class TestFees(unittest.TestCase): def test_fees(self): diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py index dcc4f5336d..593bc7c71b 100644 --- a/erpnext/tests/__init__.py +++ b/erpnext/tests/__init__.py @@ -1 +1 @@ -global_test_dependencies = ['User', 'Company'] +global_test_dependencies = ['User', 'Company', 'Cost Center', 'Account', 'Warehouse', 'Item'] From 232cd28d67921096ce10fb206894790264ef9e54 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 6 May 2021 18:37:14 +0530 Subject: [PATCH 083/180] test: Fix dependencies --- .../doctype/accounting_dimension/test_accounting_dimension.py | 3 ++- .../test_accounting_dimension_filter.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py index fc1d7e344a..6fb661eb54 100644 --- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py @@ -7,7 +7,8 @@ import frappe import unittest from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import delete_accounting_dimension + +test_dependencies = ['Location'] class TestAccountingDimension(unittest.TestCase): def setUp(self): diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py index 7877abd026..78a88eb48c 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py +++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py @@ -9,6 +9,8 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError +test_dependencies = ['Location'] + class TestAccountingDimensionFilter(unittest.TestCase): def setUp(self): create_dimension() From c26d41acf98216fbd31a3b97344e9865ec25d8f5 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 6 May 2021 18:37:45 +0530 Subject: [PATCH 084/180] chore: Remove unnecessary print statements --- erpnext/controllers/accounts_controller.py | 1 - erpnext/setup/doctype/email_digest/email_digest.py | 3 +-- erpnext/stock/stock_balance.py | 5 +---- erpnext/utilities/__init__.py | 1 - 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 544e624725..f88e8df728 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1011,7 +1011,6 @@ class AccountsController(TransactionBase): else: grand_total -= self.get("total_advance") base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total")) - if total != flt(grand_total, self.precision("grand_total")) or \ base_total != flt(base_grand_total, self.precision("base_grand_total")): frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total")) diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index 8c97322a71..5db54eeee1 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -808,7 +808,6 @@ def get_incomes_expenses_for_period(account, from_date, to_date): val = balance_on_to_date - balance_before_from_date else: last_year_closing_balance = get_balance_on(account, date=fy_start_date - timedelta(days=1)) - print(fy_start_date - timedelta(days=1), last_year_closing_balance) val = balance_on_to_date + (last_year_closing_balance - balance_before_from_date) return val @@ -837,4 +836,4 @@ def get_future_date_for_calendaer_event(frequency): elif frequency == "Monthly": to_date = add_to_date(from_date, months=1) - return from_date, to_date \ No newline at end of file + return from_date, to_date diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index 8ba1f1ca5c..8917bfeae4 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -194,9 +194,6 @@ def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, postin serial_nos = frappe.db.sql("""select count(name) from `tabSerial No` where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1])) - if serial_nos and flt(serial_nos[0][0]) != flt(d[2]): - print(d[0], d[1], d[2], serial_nos[0][0]) - sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry` where item_code = %s and warehouse = %s and is_cancelled = 0 order by posting_date desc limit 1""", (d[0], d[1])) @@ -230,7 +227,7 @@ def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, postin }) update_bin(args) - + create_repost_item_valuation_entry({ "item_code": d[0], "warehouse": d[1], diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py index 618cc985ae..0a5aa3c49b 100644 --- a/erpnext/utilities/__init__.py +++ b/erpnext/utilities/__init__.py @@ -12,7 +12,6 @@ def update_doctypes(): for f in dt.fields: if f.fieldname == d.fieldname and f.fieldtype in ("Text", "Small Text"): - print(f.parent, f.fieldname) f.fieldtype = "Text Editor" dt.save() break From 3b69aa80fcd0d4abf270076762bc451141af29ac Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 7 May 2021 00:32:00 +0530 Subject: [PATCH 085/180] ci: Enable coveralls --- .github/workflows/ci-tests.yml | 62 +++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index b03aad794b..4d955190be 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -12,13 +12,13 @@ jobs: matrix: include: - TYPE: "server" - JOB_NAME: "Server" + JOB_NAME: "Server.1" RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - TYPE: "server" - JOB_NAME: "Server" + JOB_NAME: "Server.2" RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - TYPE: "server" - JOB_NAME: "Server" + JOB_NAME: "Server.3" RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - TYPE: "patch" JOB_NAME: "Patch" @@ -86,29 +86,37 @@ jobs: env: TYPE: ${{ matrix.TYPE }} - # - name: Coverage - Pull Request - # if: matrix.TYPE == 'server' && github.event_name == 'pull_request' - # run: | - # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} - # cd ${GITHUB_WORKSPACE} - # pip install coveralls==2.2.0 - # pip install coverage==4.5.4 - # coveralls --service=github - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} - # COVERALLS_SERVICE_NAME: github + - name: Upload Coverage Data + if: matrix.TYPE == 'server' + run: | + cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} + cd ${GITHUB_WORKSPACE} + pip3 install coverage==5.5 + pip3 install coveralls==3.0.1 + coveralls --service=github-actions + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} + COVERALLS_FLAG_NAME: run-${{ matrix.container }} + COVERALLS_SERVICE_NAME: github-actions + COVERALLS_PARALLEL: true - # - name: Coverage - Push - # if: matrix.TYPE == 'server' && github.event_name == 'push' - # run: | - # cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} - # cd ${GITHUB_WORKSPACE} - # pip install coveralls==2.2.0 - # pip install coverage==4.5.4 - # coveralls --service=github-actions - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} - # COVERALLS_SERVICE_NAME: github-actions + coveralls: + name: Coverage Wrap Up + needs: test + container: python:3-slim + runs-on: ubuntu-18.04 + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Coveralls Finished + run: | + cd ${GITHUB_WORKSPACE} + ls -al + pip3 install coverage==5.5 + pip3 install coveralls==3.0.1 + coveralls --finish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b4c958caf05c2605c615e07fb82ab1d9df0419c0 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 8 May 2021 00:04:34 +0530 Subject: [PATCH 086/180] chore: Debug --- .github/workflows/patch.yml | 69 +++++++++++++++++++ .../{ci-tests.yml => server-tests.yml} | 31 +++------ 2 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/patch.yml rename .github/workflows/{ci-tests.yml => server-tests.yml} (70%) diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml new file mode 100644 index 0000000000..7c9e0272c9 --- /dev/null +++ b/.github/workflows/patch.yml @@ -0,0 +1,69 @@ +name: Patch + +on: [pull_request, workflow_dispatch] + +jobs: + test: + runs-on: ubuntu-18.04 + + name: Patch Test + + services: + mysql: + image: mariadb:10.3 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: YES + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 + + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.6 + + - name: Add to Hosts + run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node-modules + with: + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install + run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh + + - name: Run Patch Tests + run: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/server-tests.yml similarity index 70% rename from .github/workflows/ci-tests.yml rename to .github/workflows/server-tests.yml index 4d955190be..4042a407e7 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/server-tests.yml @@ -1,4 +1,4 @@ -name: CI +name: Server on: [pull_request, workflow_dispatch] @@ -7,24 +7,12 @@ jobs: runs-on: ubuntu-18.04 strategy: - fail-fast: false + fail-fast: true matrix: - include: - - TYPE: "server" - JOB_NAME: "Server.1" - RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - - TYPE: "server" - JOB_NAME: "Server.2" - RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - - TYPE: "server" - JOB_NAME: "Server.3" - RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --with-coverage --ci-build-id $GITHUB_RUN_ID --app erpnext - - TYPE: "patch" - JOB_NAME: "Patch" - RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate + container: [1, 2] - name: ${{ matrix.JOB_NAME }} + name: Server Tests services: mysql: @@ -42,7 +30,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.7 - name: Add to Hosts run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts @@ -55,6 +43,7 @@ jobs: restore-keys: | ${{ runner.os }}-pip- ${{ runner.os }}- + - name: Cache node modules uses: actions/cache@v2 env: @@ -66,6 +55,7 @@ jobs: ${{ runner.os }}-build-${{ env.cache-name }}- ${{ runner.os }}-build- ${{ runner.os }}- + - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" @@ -82,12 +72,11 @@ jobs: run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh - name: Run Tests - run: ${{ matrix.RUN_COMMAND }} + run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 2 --with-coverage env: - TYPE: ${{ matrix.TYPE }} + TYPE: server - name: Upload Coverage Data - if: matrix.TYPE == 'server' run: | cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} cd ${GITHUB_WORKSPACE} @@ -113,10 +102,8 @@ jobs: - name: Coveralls Finished run: | cd ${GITHUB_WORKSPACE} - ls -al pip3 install coverage==5.5 pip3 install coveralls==3.0.1 coveralls --finish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - From 5e88b14a01e790fd324c537f9f7a71928b4bffea Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 8 May 2021 00:05:48 +0530 Subject: [PATCH 087/180] chore: Debug --- .github/workflows/server-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 4042a407e7..1e9196119e 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -10,7 +10,7 @@ jobs: fail-fast: true matrix: - container: [1, 2] + container: [1, 2, 3] name: Server Tests @@ -72,7 +72,7 @@ jobs: run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh - name: Run Tests - run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 2 --with-coverage + run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 3 --with-coverage env: TYPE: server From 6ca8989013656aa749b89c8afadd173ce1406ec8 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 8 May 2021 13:51:34 +0530 Subject: [PATCH 088/180] ci: Disble failfast temporarily --- .github/workflows/server-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 1e9196119e..0d5a3ba61a 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-18.04 strategy: - fail-fast: true + fail-fast: false matrix: container: [1, 2, 3] From 8696580254f35c6145063a34de54b0a811068c04 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 8 May 2021 16:02:40 +0530 Subject: [PATCH 089/180] ci: Fix coveralls --- .github/workflows/server-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 0d5a3ba61a..e5fb72538d 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -82,12 +82,12 @@ jobs: cd ${GITHUB_WORKSPACE} pip3 install coverage==5.5 pip3 install coveralls==3.0.1 - coveralls --service=github-actions + coveralls env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} COVERALLS_FLAG_NAME: run-${{ matrix.container }} - COVERALLS_SERVICE_NAME: github-actions + COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }} COVERALLS_PARALLEL: true coveralls: From 175cb27bcbdd23ef41e256bbf09748229135feeb Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 8 May 2021 19:03:53 +0530 Subject: [PATCH 090/180] test: Pass ConflictingTaxRule during tax rule test --- erpnext/shopping_cart/test_shopping_cart.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/shopping_cart/test_shopping_cart.py b/erpnext/shopping_cart/test_shopping_cart.py index d857bf5f5c..ac61aebc56 100644 --- a/erpnext/shopping_cart/test_shopping_cart.py +++ b/erpnext/shopping_cart/test_shopping_cart.py @@ -7,7 +7,7 @@ import frappe from frappe.utils import nowdate, add_months from erpnext.shopping_cart.cart import _get_cart_quotation, update_cart, get_party from erpnext.tests.utils import create_test_contact_and_address - +from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule # test_dependencies = ['Payment Terms Template'] @@ -125,7 +125,7 @@ class TestShoppingCart(unittest.TestCase): tax_rule = frappe.get_test_records("Tax Rule")[0] try: frappe.get_doc(tax_rule).insert() - except frappe.DuplicateEntryError: + except (frappe.DuplicateEntryError, ConflictingTaxRule): pass def create_quotation(self): From c79f5d7514e73fb64f4e868dc672d6fd33a27ad3 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 9 May 2021 11:29:00 +0530 Subject: [PATCH 091/180] ci: Try parallel testing with orchestrator --- .github/workflows/server-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index e5fb72538d..0e638104c8 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -72,9 +72,10 @@ jobs: run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh - name: Run Tests - run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --build-number ${{ matrix.container }} --total-builds 3 --with-coverage + run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --use-orchestrator --with-coverage env: TYPE: server + CI_BUILD_ID: ${{ github.run_id }} - name: Upload Coverage Data run: | From ab8816e11da22887e413b53b1a11bb916f21127e Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 9 May 2021 14:38:28 +0530 Subject: [PATCH 092/180] test: Fix test dependency --- .../doctype/accounting_dimension/test_accounting_dimension.py | 2 +- .../test_accounting_dimension_filter.py | 2 +- .../doctype/accounting_period/test_accounting_period.py | 4 +++- erpnext/tests/__init__.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py index 6fb661eb54..e657a9ae34 100644 --- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py @@ -8,7 +8,7 @@ import unittest from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry -test_dependencies = ['Location'] +test_dependencies = ['Cost Center', 'Location', 'Warehouse', 'Department'] class TestAccountingDimension(unittest.TestCase): def setUp(self): diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py index 78a88eb48c..7f6254f99f 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py +++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py @@ -9,7 +9,7 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError -test_dependencies = ['Location'] +test_dependencies = ['Location', 'Cost Center', 'Department'] class TestAccountingDimensionFilter(unittest.TestCase): def setUp(self): diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py index 10cd939894..3b4f138495 100644 --- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py @@ -10,6 +10,8 @@ from erpnext.accounts.general_ledger import ClosedAccountingPeriod from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +test_dependencies = ['Item'] + class TestAccountingPeriod(unittest.TestCase): def test_overlap(self): ap1 = create_accounting_period(start_date = "2018-04-01", @@ -38,7 +40,7 @@ def create_accounting_period(**args): accounting_period.start_date = args.start_date or nowdate() accounting_period.end_date = args.end_date or add_months(nowdate(), 1) accounting_period.company = args.company or "_Test Company" - accounting_period.period_name =args.period_name or "_Test_Period_Name_1" + accounting_period.period_name = args.period_name or "_Test_Period_Name_1" accounting_period.append("closed_documents", { "document_type": 'Sales Invoice', "closed": 1 }) diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py index 593bc7c71b..a504340d40 100644 --- a/erpnext/tests/__init__.py +++ b/erpnext/tests/__init__.py @@ -1 +1 @@ -global_test_dependencies = ['User', 'Company', 'Cost Center', 'Account', 'Warehouse', 'Item'] +global_test_dependencies = ['User', 'Company', 'Item'] From a70e11450e9e17cc81ff47ffba967a6b76c1fb61 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 9 May 2021 14:38:54 +0530 Subject: [PATCH 093/180] ci: Check limits --- .github/workflows/server-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 0e638104c8..e7830c07f6 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -10,7 +10,7 @@ jobs: fail-fast: false matrix: - container: [1, 2, 3] + container: [1, 2, 3, 4] name: Server Tests @@ -30,7 +30,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v2 with: - python-version: 3.7 + python-version: 3.6 - name: Add to Hosts run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts From 19c5fd72d65e92da553c58c4712ab200bd3174aa Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 09:18:25 +0530 Subject: [PATCH 094/180] refactor: Rename assertEquals to assertEqual to avoid deprecation warnings --- erpnext/accounts/doctype/dunning/test_dunning.py | 2 +- erpnext/accounts/doctype/pricing_rule/pricing_rule.py | 2 +- erpnext/assets/doctype/asset/test_asset.py | 2 +- .../doctype/mpesa_settings/test_mpesa_settings.py | 4 ++-- erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py | 2 +- erpnext/regional/india/utils.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/dunning/test_dunning.py b/erpnext/accounts/doctype/dunning/test_dunning.py index c5ce514cdd..e2d4d82e41 100644 --- a/erpnext/accounts/doctype/dunning/test_dunning.py +++ b/erpnext/accounts/doctype/dunning/test_dunning.py @@ -29,7 +29,7 @@ class TestDunning(unittest.TestCase): self.assertEqual(round(amounts.get('interest_amount'), 2), 0.44) self.assertEqual(round(amounts.get('dunning_amount'), 2), 20.44) self.assertEqual(round(amounts.get('grand_total'), 2), 120.44) - + def test_gl_entries(self): dunning = create_dunning() dunning.submit() diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index aedf1c6f1a..556f49d34c 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -152,7 +152,7 @@ class PricingRule(Document): frappe.throw(_("Valid from date must be less than valid upto date")) def validate_condition(self): - if self.condition and ("=" in self.condition) and re.match("""[\w\.:_]+\s*={1}\s*[\w\.@'"]+""", self.condition): + if self.condition and ("=" in self.condition) and re.match(r'[\w\.:_]+\s*={1}\s*[\w\.@\'"]+', self.condition): frappe.throw(_("Invalid condition expression")) #-------------------------------------------------------------------------------- diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 30a270c204..3cd4b802c1 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -566,7 +566,7 @@ class TestAsset(unittest.TestCase): doc = make_invoice(pr.name) self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account) - + def test_asset_cwip_toggling_cases(self): cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting") name = frappe.db.get_value("Asset Category Account", filters={"parent": "Computers"}, fieldname=["name"]) diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py index d370fbcda7..3c2e59ab82 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py @@ -81,7 +81,7 @@ class TestMpesaSettings(unittest.TestCase): integration_request.reload() self.assertEqual(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R") self.assertEqual(integration_request.status, "Completed") - + frappe.db.set_value("Customer", "_Test Customer", "default_currency", "") integration_request.delete() pr.reload() @@ -139,7 +139,7 @@ class TestMpesaSettings(unittest.TestCase): pr.cancel() pr.delete() pos_invoice.delete() - + def test_processing_of_only_one_succes_callback_payload(self): create_mpesa_settings(payment_gateway_name="Payment") mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account") diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py index d079bedb42..113fa513f9 100644 --- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py +++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py @@ -29,7 +29,7 @@ class TestTherapyPlan(unittest.TestCase): self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed') patient, medical_department, practitioner = create_healthcare_docs() - appointment = create_appointment(patient, practitioner, nowdate()) + appointment = create_appointment(patient, practitioner, nowdate()) session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name) session = frappe.get_doc(session) session.submit() diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index fc227defbf..075c698fea 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -500,7 +500,7 @@ def download_ewb_json(): if not isinstance(docname, list): # removes characters not allowed in a filename (https://stackoverflow.com/a/38766141/4767738) - filename_prefix = re.sub('[^\w_.)( -]', '', docname) + filename_prefix = re.sub(r'[^\w_.)( -]', '', docname) frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(filename_prefix, frappe.utils.random_string(5)) From b3e647fecace96eb3c817c5dcf9241a5ebc3a3a4 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 16:13:43 +0530 Subject: [PATCH 095/180] fix: Pass ORCHESTRATOR_URL via secrets --- .github/workflows/server-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index e7830c07f6..0acafcab43 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -76,6 +76,7 @@ jobs: env: TYPE: server CI_BUILD_ID: ${{ github.run_id }} + ORCHESTRATOR_URL: ${{ secrets.ORCHESTRATOR_URL }} - name: Upload Coverage Data run: | From a891d6eed2894c776d91a9a3995d8a3d8de11fe5 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 17:25:21 +0530 Subject: [PATCH 096/180] fix: allow_zero_valuation_rate for rejected qty --- .../doctype/purchase_invoice/test_purchase_invoice.py | 7 ++++--- .../doctype/stock_ledger_entry/test_stock_ledger_entry.py | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 66be11ff23..53db689c84 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -636,8 +636,8 @@ class TestPurchaseInvoice(unittest.TestCase): def test_rejected_serial_no(self): pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1, - rejected_qty=1, rate=500, update_stock=1, - rejected_warehouse = "_Test Rejected Warehouse - _TC") + rejected_qty=1, rate=500, update_stock=1, rejected_warehouse = "_Test Rejected Warehouse - _TC", + allow_zero_valuation_rate=1) self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].serial_no, "warehouse"), pi.get("items")[0].warehouse) @@ -994,7 +994,8 @@ def make_purchase_invoice(**args): "project": args.project, "rejected_warehouse": args.rejected_warehouse or "", "rejected_serial_no": args.rejected_serial_no or "", - "asset_location": args.location or "" + "asset_location": args.location or "", + "allow_zero_valuation_rate": args.get("allow_zero_valuation_rate") or 0 }) if args.get_taxes_and_charges: diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index 3296f5ba4a..a1f1897041 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -15,10 +15,12 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import create_landed_cost_voucher from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import BackDatedStockTransaction +from frappe.core.page.permission_manager.permission_manager import reset class TestStockLedgerEntry(unittest.TestCase): def setUp(self): items = create_items() + reset('Stock Entry') # delete SLE and BINs for all items frappe.db.sql("delete from `tabStock Ledger Entry` where item_code in (%s)" % (', '.join(['%s']*len(items))), items) From d1a13ec0504e39edfb7de193539ba2c94f5b52b9 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 17:37:44 +0530 Subject: [PATCH 097/180] test: Fix valuation rate for raw materials --- .../stock/doctype/purchase_receipt/test_purchase_receipt.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index e5ef978ca3..5095a80214 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -297,6 +297,8 @@ class TestPurchaseReceipt(unittest.TestCase): item_code = "Test Extra Item 1", qty=10, basic_rate=100) se2 = make_stock_entry(target="_Test Warehouse - _TC", item_code = "_Test FG Item", qty=1, basic_rate=100) + se3 = make_stock_entry(target="_Test Warehouse - _TC", + item_code = "Test Extra Item 2", qty=1, basic_rate=100) rm_items = [ { "item_code": item_code, @@ -331,6 +333,7 @@ class TestPurchaseReceipt(unittest.TestCase): se.cancel() se1.cancel() se2.cancel() + se3.cancel() po.reload() po.cancel() From d48ea663d9c458a20b30f7a8f3dc6f639406c4b7 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 18:01:53 +0530 Subject: [PATCH 098/180] test: Fix test name - Rename TestSubcontractedItemToBeReceived > TestSubcontractedItemToBeTransferred --- ...t_subcontracted_raw_materials_to_be_transferred.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py index 6900938236..c1fc6fb82f 100644 --- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py +++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py @@ -9,12 +9,12 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcontracted_raw_materials_to_be_transferred import execute import json, frappe, unittest -class TestSubcontractedItemToBeReceived(unittest.TestCase): +class TestSubcontractedItemToBeTransferred(unittest.TestCase): - def test_pending_and_received_qty(self): + def test_pending_and_transferred_qty(self): po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes') - make_stock_entry(item_code='_Test Item', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100) - make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100) + make_stock_entry(item_code='_Test Item', target='_Test Warehouse - _TC', qty=100, basic_rate=100) + make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse - _TC', qty=100, basic_rate=100) transfer_subcontracted_raw_materials(po.name) col, data = execute(filters=frappe._dict({'supplier': po.supplier, 'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)), @@ -38,7 +38,8 @@ def transfer_subcontracted_raw_materials(po): 'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 200, 'stock_uom': 'Nos'}] rm_item_string = json.dumps(rm_item) se = frappe.get_doc(make_rm_stock_entry(po, rm_item_string)) + se.from_warehouse = '_Test Warehouse 1 - _TC' se.to_warehouse = '_Test Warehouse 1 - _TC' se.stock_entry_type = 'Send to Subcontractor' se.save() - se.submit() \ No newline at end of file + se.submit() From 54354a84e1c15c8fadf836865d8bc0b5405321c9 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 18:39:09 +0530 Subject: [PATCH 099/180] test: Fix permission error --- .../doctype/stock_ledger_entry/test_stock_ledger_entry.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index a1f1897041..ba31ad7b06 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -316,10 +316,11 @@ class TestStockLedgerEntry(unittest.TestCase): # Set User with Stock User role but not Stock Manager try: user = frappe.get_doc("User", "test@example.com") - frappe.set_user(user.name) user.add_roles("Stock User") user.remove_roles("Stock Manager") + frappe.set_user(user.name) + stock_entry_on_today = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100) back_dated_se_1 = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100, posting_date=add_days(today(), -1), do_not_submit=True) From 273589e835342ea364c3d096a1fd327769df98c8 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 20:33:47 +0530 Subject: [PATCH 100/180] test: Fix a case where test used to fail due to holiday list - fixes: "Please set a default Holiday List for Employee EMP-00009 or Company Wind Power LLC" error --- .../hr/doctype/upload_attendance/test_upload_attendance.py | 7 +++++++ .../payroll/doctype/payroll_entry/test_payroll_entry.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py index 6e151d0e3c..03b0cf3da2 100644 --- a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py +++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py @@ -5,11 +5,18 @@ from __future__ import unicode_literals import frappe import unittest +import erpnext from frappe.utils import getdate from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data from erpnext.hr.doctype.employee.test_employee import make_employee +test_dependencies = ['Holiday List'] + class TestUploadAttendance(unittest.TestCase): + @classmethod + def setUpClass(cls): + frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", '_Test Holiday List') + def test_date_range(self): employee = make_employee("test_employee@company.com") employee_doc = frappe.get_doc("Employee", employee) diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py index 7528bf7a7f..b80b32061f 100644 --- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py +++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py @@ -15,7 +15,13 @@ from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_ from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry, create_loan_type, create_loan_accounts from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans +test_dependencies = ['Holiday List'] + class TestPayrollEntry(unittest.TestCase): + @classmethod + def setUpClass(cls): + frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", '_Test Holiday List') + def setUp(self): for dt in ["Salary Slip", "Salary Component", "Salary Component Account", "Payroll Entry", "Salary Structure", "Salary Structure Assignment", "Payroll Employee Detail", "Additional Salary"]: From 96542c3d043a2865af4f77ab6da754eb62bebdc4 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 20:49:07 +0530 Subject: [PATCH 101/180] style: Fix sider issues --- .../doctype/accounting_period/test_accounting_period.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py index 3b4f138495..dc472c7695 100644 --- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py @@ -40,7 +40,7 @@ def create_accounting_period(**args): accounting_period.start_date = args.start_date or nowdate() accounting_period.end_date = args.end_date or add_months(nowdate(), 1) accounting_period.company = args.company or "_Test Company" - accounting_period.period_name = args.period_name or "_Test_Period_Name_1" + accounting_period.period_name = args.period_name or "_Test_Period_Name_1" accounting_period.append("closed_documents", { "document_type": 'Sales Invoice', "closed": 1 }) From b9a8afc234b2a1647bc66e647d136b87d684f22a Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 10 May 2021 23:48:37 +0530 Subject: [PATCH 102/180] ci: Add test orchestrator URL --- .github/workflows/server-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 0acafcab43..bd60081064 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -76,7 +76,7 @@ jobs: env: TYPE: server CI_BUILD_ID: ${{ github.run_id }} - ORCHESTRATOR_URL: ${{ secrets.ORCHESTRATOR_URL }} + ORCHESTRATOR_URL: http://test-orchestrator.frappe.io - name: Upload Coverage Data run: | @@ -87,7 +87,6 @@ jobs: coveralls env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} COVERALLS_FLAG_NAME: run-${{ matrix.container }} COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }} COVERALLS_PARALLEL: true From 77f2686142568b12dcbea50db03928f6b8ec5673 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 11 May 2021 10:09:06 +0530 Subject: [PATCH 103/180] ci: Use only 3 containers for now --- .github/workflows/server-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index bd60081064..6597048bc7 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -10,7 +10,7 @@ jobs: fail-fast: false matrix: - container: [1, 2, 3, 4] + container: [1, 2, 3] name: Server Tests From 113a6f3d80b95fd249dbe95224f0be197d533c86 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 11 May 2021 10:59:16 +0530 Subject: [PATCH 104/180] fix: Use frappe.safe_eval instead of eval --- erpnext/setup/doctype/email_digest/email_digest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index 5db54eeee1..340d89bdf8 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -249,7 +249,7 @@ class EmailDigest(Document): card = cache.get(cache_key) if card: - card = eval(card) + card = frappe.safe_eval(card) else: card = frappe._dict(getattr(self, "get_" + key)()) From 6da2212e2d4f1eba80a4a5d845d515f62a1eaf62 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 12 May 2021 18:14:22 +0530 Subject: [PATCH 105/180] ci: Update frappe branch --- .github/helper/install.sh | 2 +- .github/workflows/server-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/helper/install.sh b/.github/helper/install.sh index 44659f22fa..7b0f944c66 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -12,7 +12,7 @@ sudo apt install npm pip install frappe-bench -git clone https://github.com/surajshetty3416/frappe --branch "python-distributed-testing" --depth 1 +git clone https://github.com/frappe/frappe --branch "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" --depth 1 bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench mkdir ~/frappe-bench/sites/test_site diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 6597048bc7..6f831ac3d1 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -12,7 +12,7 @@ jobs: matrix: container: [1, 2, 3] - name: Server Tests + name: Python Unit Tests services: mysql: From 85aeca14432ecbec86c88549358eac338298eaa4 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 12 May 2021 23:13:11 +0530 Subject: [PATCH 106/180] ci: Update Python version to 3.7 --- .github/workflows/server-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 6f831ac3d1..92685e2177 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.7 - name: Add to Hosts run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts From bcf116422a2d7ed1a4ea33eda1a894b055bbf5b0 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 28 May 2021 09:12:24 +0530 Subject: [PATCH 107/180] ci: Do not generate coverage report for hotfix branch --- .github/workflows/server-tests.yml | 31 ------------------------------ 1 file changed, 31 deletions(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 92685e2177..de5cc61d1e 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -77,34 +77,3 @@ jobs: TYPE: server CI_BUILD_ID: ${{ github.run_id }} ORCHESTRATOR_URL: http://test-orchestrator.frappe.io - - - name: Upload Coverage Data - run: | - cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} - cd ${GITHUB_WORKSPACE} - pip3 install coverage==5.5 - pip3 install coveralls==3.0.1 - coveralls - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_FLAG_NAME: run-${{ matrix.container }} - COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }} - COVERALLS_PARALLEL: true - - coveralls: - name: Coverage Wrap Up - needs: test - container: python:3-slim - runs-on: ubuntu-18.04 - steps: - - name: Clone - uses: actions/checkout@v2 - - - name: Coveralls Finished - run: | - cd ${GITHUB_WORKSPACE} - pip3 install coverage==5.5 - pip3 install coveralls==3.0.1 - coveralls --finish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c4d4be3265d216b48aaabeffa777984f47626dbc Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 18 May 2021 15:42:13 +0530 Subject: [PATCH 108/180] fix: ensure website theme is applied correctly --- erpnext/public/scss/shopping_cart.scss | 18 +++++++++--------- erpnext/public/scss/website.scss | 9 ++++----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss index 159a8a47cd..92e5d32219 100644 --- a/erpnext/public/scss/shopping_cart.scss +++ b/erpnext/public/scss/shopping_cart.scss @@ -1,4 +1,3 @@ -@import "frappe/public/scss/desk/variables"; @import "frappe/public/scss/common/mixins"; body.product-page { @@ -217,12 +216,12 @@ body.product-page { border-color: var(--table-border-color) !important; padding: 15px; - @include media-breakpoint-between(xs, md) { + @media (max-width: 840px) { height: 300px; width: 300px; } - @include media-breakpoint-up(lg) { + @media (min-width: 1090px) { height: 350px; width: 350px; } @@ -233,11 +232,12 @@ body.product-page { } .item-slideshow { - @include media-breakpoint-between(xs, md) { + + @media (max-width: 840px) { max-height: 320px; } - @include media-breakpoint-up(lg) { + @media (min-width: 1090px) { max-height: 430px; } @@ -254,7 +254,7 @@ body.product-page { cursor: pointer; &:hover, &.active { - border-color: $primary; + border-color: var(--primary); } } @@ -316,12 +316,12 @@ body.product-page { } .item-group-slideshow { - .item-group-description { + // .item-group-description { // max-width: 900px; - } + // } .carousel-inner.rounded-carousel { - border-radius: $card-border-radius; + border-radius: var(--card-border-radius); } } diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss index 56b717c424..f4325c03f5 100644 --- a/erpnext/public/scss/website.scss +++ b/erpnext/public/scss/website.scss @@ -1,4 +1,3 @@ -@import "frappe/public/scss/website/variables"; .filter-options { max-height: 300px; @@ -14,7 +13,7 @@ } &.active { - border-color: $primary; + border-color: var(--primary); .check { display: inline-flex; @@ -25,7 +24,7 @@ .check { display: inline-flex; padding: 0.25rem; - background: $primary; + background: var(--primary); color: white; border-radius: 50%; font-size: 12px; @@ -38,12 +37,12 @@ } .result { - border-bottom: 1px solid $border-color; + border-bottom: 1px solid var(--border-color); } .transaction-list-item { padding: 1rem 0; - border-top: 1px solid $border-color; + border-top: 1px solid var(--border-color); position: relative; a.transaction-item-link { From f4db3139b7fb0b1f00b3b55fe3ed5005f3ee2d14 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 28 May 2021 08:55:38 +0530 Subject: [PATCH 109/180] refactor: Use css variables for breakpoint value --- erpnext/public/scss/shopping_cart.scss | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss index 92e5d32219..9402cf9ea4 100644 --- a/erpnext/public/scss/shopping_cart.scss +++ b/erpnext/public/scss/shopping_cart.scss @@ -73,15 +73,6 @@ body.product-page { } } - // .card-body { - // text-align: center; - // } - - // .featured-item { - // .card-body { - // text-align: left; - // } - // } .card-img-container { height: 210px; width: 100%; @@ -216,12 +207,12 @@ body.product-page { border-color: var(--table-border-color) !important; padding: 15px; - @media (max-width: 840px) { + @media (max-width: var(--md-width)) { height: 300px; width: 300px; } - @media (min-width: 1090px) { + @media (min-width: var(--lg-width)) { height: 350px; width: 350px; } @@ -233,11 +224,11 @@ body.product-page { .item-slideshow { - @media (max-width: 840px) { + @media (max-width: var(--md-width)) { max-height: 320px; } - @media (min-width: 1090px) { + @media (min-width: var(--lg-width)) { max-height: 430px; } @@ -316,9 +307,6 @@ body.product-page { } .item-group-slideshow { - // .item-group-description { - // max-width: 900px; - // } .carousel-inner.rounded-carousel { border-radius: var(--card-border-radius); From 8a776a63cd8884bce7ea4f2dcb4173c630055157 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 28 May 2021 09:56:30 +0530 Subject: [PATCH 110/180] fix(POS): Add Product Bundles to POS item search (#25860) --- erpnext/selling/page/point_of_sale/point_of_sale.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index 750a1a6071..09a3efc491 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -62,7 +62,6 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va `tabItem` item {bin_join_selection} WHERE item.disabled = 0 - AND item.is_stock_item = 1 AND item.has_variants = 0 AND item.is_sales_item = 1 AND item.is_fixed_asset = 0 @@ -84,6 +83,7 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va ), {'warehouse': warehouse}, as_dict=1) if items_data: + items_data = filter_service_items(items_data) items = [d.item_code for d in items_data] item_prices_data = frappe.get_all("Item Price", fields = ["item_code", "price_list_rate", "currency"], @@ -135,6 +135,14 @@ def search_serial_or_batch_or_barcode_number(search_value): return {} +def filter_service_items(items): + for item in items: + if not item['is_stock_item']: + if not frappe.db.exists('Product Bundle', item['item_code']): + items.remove(item) + + return items + def get_conditions(item_code, serial_no, batch_no, barcode): if serial_no or batch_no or barcode: return "item.name = {0}".format(frappe.db.escape(item_code)) From 17736afab555307bb95d743667f22be2c4592535 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 28 May 2021 10:03:41 +0530 Subject: [PATCH 111/180] fix(POS): Fix stock availability calculation if negative_stock_allowed is checked (#25859) --- erpnext/selling/page/point_of_sale/point_of_sale.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index 09a3efc491..cb811df8e8 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -15,7 +15,6 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va data = dict() result = [] - allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock') warehouse, hide_unavailable_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items']) if not frappe.db.exists('Item Group', item_group): @@ -96,10 +95,7 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va for item in items_data: item_code = item.item_code item_price = item_prices.get(item_code) or {} - if allow_negative_stock: - item_stock_qty = frappe.db.sql("""select ifnull(sum(actual_qty), 0) from `tabBin` where item_code = %s""", item_code)[0][0] - else: - item_stock_qty = get_stock_availability(item_code, warehouse) + item_stock_qty = get_stock_availability(item_code, warehouse) row = {} row.update(item) From 3bca90dbe6b6b9335765e41345b2902b512171f7 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 27 May 2021 17:42:31 +0530 Subject: [PATCH 112/180] refactor: updated mapping for maintenance schedule links in maintenance visit --- .../maintenance_schedule.py | 17 +++++++---------- .../test_maintenance_schedule.py | 6 ++++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index ea76e91b3f..d6e42f3ee1 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -34,7 +34,7 @@ class MaintenanceSchedule(TransactionBase): count = count + 1 child.sales_person = d.sales_person child.completion_status = "Pending" - child.item_ref = d.name + child.item_reference = d.name @frappe.whitelist() def validate_end_date_visits(self): @@ -314,11 +314,12 @@ def update_serial_nos(s_id): def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None): from frappe.model.mapper import get_mapped_doc - def update_status(source, target, parent): + def update_status_and_detail(source, target, parent): target.maintenance_type = "Scheduled" + target.maintenance_schedule = source.name + target.maintenance_schedule_detail = s_id - def update_sid(source, target, parent): - target.prevdoc_detail_docname = s_id + def update_sales(source, target, parent): sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person') target.service_person = sales_person target.serial_no = '' @@ -332,16 +333,12 @@ def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=No "validation": { "docstatus": ["=", 1] }, - "postprocess": update_status + "postprocess": update_status_and_detail }, "Maintenance Schedule Item": { "doctype": "Maintenance Visit Purpose", - "field_map": { - "parent": "prevdoc_docname", - "parenttype": "prevdoc_doctype", - }, "condition": lambda doc: doc.item_name == item_name, - "postprocess": update_sid + "postprocess": update_sales } }, target_doc) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py index 58ee964fb5..08282b4c3d 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py @@ -57,16 +57,18 @@ class TestMaintenanceSchedule(unittest.TestCase): test = make_maintenance_visit(source_name = ms.name, item_name = "_Test Item", s_id = s_id) visit = frappe.new_doc('Maintenance Visit') visit = test + visit.maintenance_schedule = ms.name + visit.maintenance_schedule_detail = s_id visit.completion_status = "Partially Completed" - visit.set('purposes', [{ 'item_code': i.item_code, 'description': "test", 'work_done': "test", + 'service_person': "Sales Team", 'prevdoc_docname' :ms.name, 'prevdoc_doctype': ms.doctype, - 'prevdoc_detail_docname': s_id }]) + visit.save() visit.submit() ms = frappe.get_doc('Maintenance Schedule', ms.name) From 7fa045c1c9142fa4a3d26790fe999e2f455dcef6 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 27 May 2021 17:44:28 +0530 Subject: [PATCH 113/180] refactor: using parent form links of maintenance schedule --- .../maintenance_visit/maintenance_visit.py | 91 +++++++++---------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index 8a3094cb36..79d65c921a 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -17,70 +17,61 @@ class MaintenanceVisit(TransactionBase): if d.serial_no and not frappe.db.exists("Serial No", d.serial_no): frappe.throw(_("Serial No {0} does not exist").format(d.serial_no)) - def validate_mntc_date(self): - if self.maintenance_type == "Scheduled": - p = self.purposes - for i in p: - detail_ref = i.prevdoc_detail_docname - item_ref = frappe.db.get_value('Maintenance Schedule Detail', detail_ref , 'item_ref') + def validate_maintenance_date(self): + if self.maintenance_type == "Scheduled" and self.maintenance_schedule_detail: + item_ref = frappe.db.get_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'item_reference') start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date']) if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date): - frappe.throw(_("Date must be between {0} and {1}").format(start_date,end_date)) + frappe.throw(_("Date must be between {0} and {1}").format(start_date, end_date)) def validate(self): self.validate_serial_no() - self.validate_mntc_date() + self.validate_maintenance_date() - def get_schedule_datail_ref(self): - if self.maintenance_type == "Scheduled": - p = self.purposes - for i in p: - detail_ref = i.prevdoc_detail_docname - return detail_ref - def update_completion_status(self): - detail_ref = self.get_schedule_datail_ref() - frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'completion_status', self.completion_status) + if self.maintenance_schedule_detail: + frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'completion_status', self.completion_status) def update_actual_date(self): - detail_ref = self.get_schedule_datail_ref() - frappe.db.set_value('Maintenance Schedule Detail', detail_ref, 'actual_date', self.mntc_date) + if self.maintenance_schedule_detail: + frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'actual_date', self.mntc_date) def update_customer_issue(self, flag): - for d in self.get('purposes'): - if d.prevdoc_docname and d.prevdoc_doctype == 'Warranty Claim' : - if flag==1: - mntc_date = self.mntc_date - service_person = d.service_person - work_done = d.work_done - status = "Open" - if self.completion_status == 'Fully Completed': - status = 'Closed' - elif self.completion_status == 'Partially Completed': - status = 'Work In Progress' - else: - nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name)) - - if nm: - status = 'Work In Progress' - mntc_date = nm and nm[0][1] or '' - service_person = nm and nm[0][2] or '' - work_done = nm and nm[0][3] or '' + if not self.maintenance_schedule: + for d in self.get('purposes'): + if d.prevdoc_docname and d.prevdoc_doctype == 'Warranty Claim' : + if flag==1: + mntc_date = self.mntc_date + service_person = d.service_person + work_done = d.work_done + status = "Open" + if self.completion_status == 'Fully Completed': + status = 'Closed' + elif self.completion_status == 'Partially Completed': + status = 'Work In Progress' else: - status = 'Open' - mntc_date = None - service_person = None - work_done = None + nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name)) - wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname) - wc_doc.update({ - 'resolution_date': mntc_date, - 'resolved_by': service_person, - 'resolution_details': work_done, - 'status': status - }) + if nm: + status = 'Work In Progress' + mntc_date = nm and nm[0][1] or '' + service_person = nm and nm[0][2] or '' + work_done = nm and nm[0][3] or '' + else: + status = 'Open' + mntc_date = None + service_person = None + work_done = None - wc_doc.db_update() + wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname) + wc_doc.update({ + 'resolution_date': mntc_date, + 'resolved_by': service_person, + 'resolution_details': work_done, + 'status': status + }) + + wc_doc.db_update() def check_if_last_visit(self): """check if last maintenance visit against same sales order/ Warranty Claim""" From d071586589bb24162e268ec0fb4e295334ac4067 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Thu, 27 May 2021 17:48:43 +0530 Subject: [PATCH 114/180] refactor: removed maintenance schedule detail link --- .../maintenance_visit_purpose.json | 41 +++---------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json index 0d19d708d9..158f143ae8 100644 --- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json +++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json @@ -17,8 +17,7 @@ "work_details", "work_done", "prevdoc_doctype", - "prevdoc_docname", - "prevdoc_detail_docname" + "prevdoc_docname" ], "fields": [ { @@ -90,44 +89,14 @@ "fieldtype": "Link", "hidden": 1, "label": "Document Type", - "no_copy": 1, - "oldfieldname": "prevdoc_doctype", - "oldfieldtype": "Data", - "options": "DocType", - "print_hide": 1, - "print_width": "150px", - "read_only": 1, - "report_hide": 1, - "width": "150px" + "options": "DocType" }, { "fieldname": "prevdoc_docname", "fieldtype": "Dynamic Link", - "label": "Against Document No", - "no_copy": 1, - "oldfieldname": "prevdoc_docname", - "oldfieldtype": "Data", - "options": "prevdoc_doctype", - "print_hide": 1, - "print_width": "160px", - "read_only": 1, - "report_hide": 1, - "width": "160px" - }, - { - "fieldname": "prevdoc_detail_docname", - "fieldtype": "Link", "hidden": 1, - "label": "Against Document Detail No", - "no_copy": 1, - "oldfieldname": "prevdoc_detail_docname", - "oldfieldtype": "Data", - "options": "Maintenance Schedule Detail", - "print_hide": 1, - "print_width": "160px", - "read_only": 1, - "report_hide": 1, - "width": "160px" + "label": "Against Document No", + "options": "prevdoc_doctype" }, { "fieldname": "column_break_3", @@ -141,7 +110,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-04-21 11:16:52.025914", + "modified": "2021-05-27 17:47:21.474282", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Visit Purpose", From 0b02f1335f136a00066dd62b4d06f29cfe157d25 Mon Sep 17 00:00:00 2001 From: noahjacob Date: Fri, 28 May 2021 11:04:34 +0530 Subject: [PATCH 115/180] refactor: removed redundant links in test case --- .../doctype/maintenance_schedule/test_maintenance_schedule.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py index 08282b4c3d..09981bad05 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py @@ -65,8 +65,6 @@ class TestMaintenanceSchedule(unittest.TestCase): 'description': "test", 'work_done': "test", 'service_person': "Sales Team", - 'prevdoc_docname' :ms.name, - 'prevdoc_doctype': ms.doctype, }]) visit.save() visit.submit() From faa25166a91022dbb969f0753fef8f07a0d01eef Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Fri, 28 May 2021 11:23:18 +0530 Subject: [PATCH 116/180] revert: "ci: Do not generate coverage report for hotfix branch" Reverts: https://github.com/frappe/erpnext/commit/bcf116422a2d7ed1a4ea33eda1a894b055bbf5b0 --- .github/workflows/server-tests.yml | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index de5cc61d1e..92685e2177 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -77,3 +77,34 @@ jobs: TYPE: server CI_BUILD_ID: ${{ github.run_id }} ORCHESTRATOR_URL: http://test-orchestrator.frappe.io + + - name: Upload Coverage Data + run: | + cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} + cd ${GITHUB_WORKSPACE} + pip3 install coverage==5.5 + pip3 install coveralls==3.0.1 + coveralls + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_FLAG_NAME: run-${{ matrix.container }} + COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }} + COVERALLS_PARALLEL: true + + coveralls: + name: Coverage Wrap Up + needs: test + container: python:3-slim + runs-on: ubuntu-18.04 + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Coveralls Finished + run: | + cd ${GITHUB_WORKSPACE} + pip3 install coverage==5.5 + pip3 install coveralls==3.0.1 + coveralls --finish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From d24eccd623a60d99bc6981f484fc5b9439cd8dd0 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 28 May 2021 11:36:24 +0530 Subject: [PATCH 117/180] fix(plaid): cannot reset plaid link for a bank account --- erpnext/accounts/doctype/bank/bank.js | 102 ++++++++++++++++++ .../doctype/plaid_settings/plaid_connector.py | 2 + .../doctype/plaid_settings/plaid_settings.py | 42 ++++++-- 3 files changed, 140 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js index 059e1d3158..337c93ef61 100644 --- a/erpnext/accounts/doctype/bank/bank.js +++ b/erpnext/accounts/doctype/bank/bank.js @@ -25,6 +25,10 @@ frappe.ui.form.on('Bank', { frm.add_custom_button(__('Refresh Plaid Link'), () => { new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token); }); + + frm.add_custom_button(__('Reset Plaid Link'), () => { + new erpnext.integrations.plaidLink(frm); + }); } } }); @@ -121,3 +125,101 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink { frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' }); } }; + +erpnext.integrations.plaidLink = class plaidLink { + constructor(parent) { + this.frm = parent; + this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js'; + this.init_config(); + } + + async init_config() { + this.product = ["auth", "transactions"]; + this.plaid_env = this.frm.doc.plaid_env; + this.client_name = frappe.boot.sitename; + this.token = await this.get_link_token(); + this.init_plaid(); + } + + async get_link_token() { + const token = await this.frm.call("get_link_token").then(resp => resp.message); + if (!token) { + frappe.throw(__('Cannot retrieve link token. Check Error Log for more information')); + } + return token; + } + + init_plaid() { + const me = this; + me.loadScript(me.plaidUrl) + .then(() => { + me.onScriptLoaded(me); + }) + .then(() => { + if (me.linkHandler) { + me.linkHandler.open(); + } + }) + .catch((error) => { + me.onScriptError(error); + }); + } + + loadScript(src) { + return new Promise(function (resolve, reject) { + if (document.querySelector('script[src="' + src + '"]')) { + resolve(); + return; + } + const el = document.createElement('script'); + el.type = 'text/javascript'; + el.async = true; + el.src = src; + el.addEventListener('load', resolve); + el.addEventListener('error', reject); + el.addEventListener('abort', reject); + document.head.appendChild(el); + }); + } + + onScriptLoaded(me) { + me.linkHandler = Plaid.create({ + clientName: me.client_name, + product: me.product, + env: me.plaid_env, + token: me.token, + onSuccess: me.plaid_success + }); + } + + onScriptError(error) { + frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information")); + console.log(error); + } + + plaid_success(token, response) { + const me = this; + + frappe.prompt({ + fieldtype: "Link", + options: "Company", + label: __("Company"), + fieldname: "company", + reqd: 1 + }, (data) => { + me.company = data.company; + frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', { + token: token, + response: response + }).then((result) => { + frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', { + response: response, + bank: result, + company: me.company + }); + }).then(() => { + frappe.show_alert({ message: __("Bank accounts added"), indicator: 'green' }); + }); + }, __("Select a company"), __("Continue")); + } +}; diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py index 5f990cdd03..42d4b9b2b4 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py @@ -99,5 +99,7 @@ class PlaidConnector(): response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions)) transactions.extend(response["transactions"]) return transactions + except ItemError as e: + raise e except Exception: frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error")) diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py index ce15e47c5e..3ef069b5e2 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py @@ -12,6 +12,7 @@ from frappe.desk.doctype.tag.tag import add_tag from frappe.model.document import Document from frappe.utils import add_months, formatdate, getdate, today +from plaid.errors import ItemError class PlaidSettings(Document): @staticmethod @@ -51,7 +52,7 @@ def add_institution(token, response): }) bank.insert() except Exception: - frappe.throw(frappe.get_traceback()) + frappe.log_error(frappe.get_traceback(), title=_('Plaid Link Error')) else: bank = frappe.get_doc("Bank", response["institution"]["name"]) bank.plaid_access_token = access_token @@ -83,7 +84,12 @@ def add_bank_accounts(response, bank, company): if not acc_subtype: add_account_subtype(account["subtype"]) - if not frappe.db.exists("Bank Account", dict(integration_id=account["id"])): + existing_bank_account = frappe.db.exists("Bank Account", { + 'account_name': account["name"], + 'bank': bank["bank_name"] + }) + + if not existing_bank_account: try: new_account = frappe.get_doc({ "doctype": "Bank Account", @@ -103,10 +109,27 @@ def add_bank_accounts(response, bank, company): except frappe.UniqueValidationError: frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"])) except Exception: - frappe.throw(frappe.get_traceback()) + frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error")) + frappe.throw(_("There was an error creating Bank Account while linking with Plaid."), + title=_("Plaid Link Failed")) else: - result.append(frappe.db.get_value("Bank Account", dict(integration_id=account["id"]), "name")) + try: + existing_account = frappe.get_doc('Bank Account', existing_bank_account) + existing_account.update({ + "bank": bank["bank_name"], + "account_name": account["name"], + "account_type": account.get("type", ""), + "account_subtype": account.get("subtype", ""), + "mask": account.get("mask", ""), + "integration_id": account["id"] + }) + existing_account.save() + result.append(existing_bank_account) + except Exception: + frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error")) + frappe.throw(_("There was an error updating Bank Account {} while linking with Plaid.").format( + existing_bank_account), title=_("Plaid Link Failed")) return result @@ -172,9 +195,16 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None): account_id = None plaid = PlaidConnector(access_token) - transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id) - return transactions + try: + transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id) + except ItemError as e: + if e.code == "ITEM_LOGIN_REQUIRED": + msg = _("There was an error syncing transactions.") + " " + msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " " + frappe.log_error(msg, title=_("Plaid Link Refresh Required")) + + return transactions or [] def new_bank_transaction(transaction): From bbce2e91a375feef3b1dd7e26c2239769e11a730 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 28 May 2021 11:56:47 +0530 Subject: [PATCH 118/180] fix: reset plaid link button --- erpnext/accounts/doctype/bank/bank.js | 4 ---- .../doctype/plaid_settings/plaid_settings.js | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js index 337c93ef61..f2c599c5c1 100644 --- a/erpnext/accounts/doctype/bank/bank.js +++ b/erpnext/accounts/doctype/bank/bank.js @@ -25,10 +25,6 @@ frappe.ui.form.on('Bank', { frm.add_custom_button(__('Refresh Plaid Link'), () => { new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token); }); - - frm.add_custom_button(__('Reset Plaid Link'), () => { - new erpnext.integrations.plaidLink(frm); - }); } } }); diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js index bbc2ca8846..37bf282450 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js @@ -16,6 +16,10 @@ frappe.ui.form.on('Plaid Settings', { new erpnext.integrations.plaidLink(frm); }); + frm.add_custom_button(__('Reset Plaid Link'), () => { + new erpnext.integrations.plaidLink(frm); + }); + frm.add_custom_button(__("Sync Now"), () => { frappe.call({ method: "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.enqueue_synchronization", From 20be7fb93dbe7db28920c44fd1815607fe9da249 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 28 May 2021 11:57:38 +0530 Subject: [PATCH 119/180] fix(India): Show only company addresses for ITC reversal entry --- .../doctype/journal_entry/regional/india.js | 17 +++++++++++++++++ .../doctype/gstr_3b_report/gstr_3b_report.py | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 erpnext/accounts/doctype/journal_entry/regional/india.js diff --git a/erpnext/accounts/doctype/journal_entry/regional/india.js b/erpnext/accounts/doctype/journal_entry/regional/india.js new file mode 100644 index 0000000000..75a69ac0cf --- /dev/null +++ b/erpnext/accounts/doctype/journal_entry/regional/india.js @@ -0,0 +1,17 @@ +frappe.ui.form.on("Journal Entry", { + refresh: function(frm) { + frm.set_query('company_address', function(doc) { + if(!doc.company) { + frappe.throw(__('Please set Company')); + } + + return { + query: 'frappe.contacts.doctype.address.address.address_query', + filters: { + link_doctype: 'Company', + link_name: doc.company + } + }; + }); + } +}); \ No newline at end of file diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py index 3ddcc58867..641520437f 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py @@ -310,7 +310,7 @@ class GSTR3BReport(Document): self.report_dict['sup_details']['osup_det']['txval'] += taxable_value gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category') - place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply', '00-Other Territory') + place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory' if gst_category in ['Unregistered', 'Registered Composition', 'UIN Holders'] and \ self.gst_details.get("gst_state") != place_of_supply.split("-")[1]: From 05386ff12f22ac672bb0b87c10257a185dc1db78 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 28 May 2021 12:58:18 +0530 Subject: [PATCH 120/180] chore: remove unwanted method --- erpnext/accounts/doctype/bank/bank.js | 100 +------------------------- 1 file changed, 1 insertion(+), 99 deletions(-) diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js index f2c599c5c1..19041a3f73 100644 --- a/erpnext/accounts/doctype/bank/bank.js +++ b/erpnext/accounts/doctype/bank/bank.js @@ -120,102 +120,4 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink { plaid_success(token, response) { frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' }); } -}; - -erpnext.integrations.plaidLink = class plaidLink { - constructor(parent) { - this.frm = parent; - this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js'; - this.init_config(); - } - - async init_config() { - this.product = ["auth", "transactions"]; - this.plaid_env = this.frm.doc.plaid_env; - this.client_name = frappe.boot.sitename; - this.token = await this.get_link_token(); - this.init_plaid(); - } - - async get_link_token() { - const token = await this.frm.call("get_link_token").then(resp => resp.message); - if (!token) { - frappe.throw(__('Cannot retrieve link token. Check Error Log for more information')); - } - return token; - } - - init_plaid() { - const me = this; - me.loadScript(me.plaidUrl) - .then(() => { - me.onScriptLoaded(me); - }) - .then(() => { - if (me.linkHandler) { - me.linkHandler.open(); - } - }) - .catch((error) => { - me.onScriptError(error); - }); - } - - loadScript(src) { - return new Promise(function (resolve, reject) { - if (document.querySelector('script[src="' + src + '"]')) { - resolve(); - return; - } - const el = document.createElement('script'); - el.type = 'text/javascript'; - el.async = true; - el.src = src; - el.addEventListener('load', resolve); - el.addEventListener('error', reject); - el.addEventListener('abort', reject); - document.head.appendChild(el); - }); - } - - onScriptLoaded(me) { - me.linkHandler = Plaid.create({ - clientName: me.client_name, - product: me.product, - env: me.plaid_env, - token: me.token, - onSuccess: me.plaid_success - }); - } - - onScriptError(error) { - frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information")); - console.log(error); - } - - plaid_success(token, response) { - const me = this; - - frappe.prompt({ - fieldtype: "Link", - options: "Company", - label: __("Company"), - fieldname: "company", - reqd: 1 - }, (data) => { - me.company = data.company; - frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', { - token: token, - response: response - }).then((result) => { - frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', { - response: response, - bank: result, - company: me.company - }); - }).then(() => { - frappe.show_alert({ message: __("Bank accounts added"), indicator: 'green' }); - }); - }, __("Select a company"), __("Continue")); - } -}; +}; \ No newline at end of file From 6fb218e03344ec00a8af0a8d8df57beacf89cf4b Mon Sep 17 00:00:00 2001 From: Noah Jacob Date: Fri, 28 May 2021 16:15:50 +0530 Subject: [PATCH 121/180] refactor: suggested changes --- .../doctype/maintenance_schedule/maintenance_schedule.js | 2 +- .../doctype/maintenance_visit/maintenance_visit.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index e2de941963..44712d543b 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -67,7 +67,7 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({ let schedules = me.frm.doc.schedules; let flag = schedules.some(schedule => schedule.completion_status === "Pending"); if (flag) { - this.frm.add_custom_button(__('Create Maintenance Visit'), function () { + this.frm.add_custom_button(__('Maintenance Visit'), function () { let options = ""; me.frm.call('get_pending_data', {data_type: "items"}).then(r => { diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index 79d65c921a..7fffc942a0 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -20,9 +20,10 @@ class MaintenanceVisit(TransactionBase): def validate_maintenance_date(self): if self.maintenance_type == "Scheduled" and self.maintenance_schedule_detail: item_ref = frappe.db.get_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'item_reference') - start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date']) - if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date): - frappe.throw(_("Date must be between {0} and {1}").format(start_date, end_date)) + if item_ref: + start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date']) + if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date): + frappe.throw(_("Date must be between {0} and {1}").format(start_date, end_date)) def validate(self): self.validate_serial_no() From b72b4c0bf9f2f19d80456407cddc4062a7174198 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 28 May 2021 17:38:01 +0530 Subject: [PATCH 122/180] fix(pos): rendering of broken image on pos --- erpnext/selling/page/point_of_sale/pos_item_cart.js | 12 +++++++++++- .../selling/page/point_of_sale/pos_item_selector.js | 11 ++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js index 11a63b3d4a..8a989731cc 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_cart.js +++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js @@ -636,13 +636,23 @@ erpnext.PointOfSale.ItemCart = class { function get_item_image_html() { const { image, item_name } = item_data; if (image) { - return `
${image}
`; + return ` +
+ ${frappe.get_abbr(item_name)} +
`; } else { return `
${frappe.get_abbr(item_name)}
`; } } } + handle_broken_image($img) { + const item_abbr = $($img).attr('alt'); + $($img).parent().replaceWith(`
${item_abbr}
`); + } + scroll_to_item($item) { if ($item.length === 0) return; const scrollTop = $item.offset().top - this.$cart_items_wrapper.offset().top + this.$cart_items_wrapper.scrollTop(); diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js index b8a82a9eda..b6109acc57 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_selector.js +++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js @@ -94,7 +94,11 @@ erpnext.PointOfSale.ItemSelector = class { ${qty_to_display}
- ${frappe.get_abbr(item.item_name)} + ${frappe.get_abbr(item.item_name)}
`; } else { return `
@@ -122,6 +126,11 @@ erpnext.PointOfSale.ItemSelector = class { ); } + handle_broken_image($img) { + const item_abbr = $($img).attr('alt'); + $($img).parent().replaceWith(`
${item_abbr}
`); + } + make_search_bar() { const me = this; const doc = me.events.get_frm().doc; From 431d3295b444d46b4bc44b5e882de507be006b42 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 28 May 2021 21:12:25 +0530 Subject: [PATCH 123/180] fix: use dictionary filter instead of list (#25874) Item query doesn't support list filter anymore. --- erpnext/manufacturing/doctype/work_order/work_order.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index a6086fb88d..3e5a72db9a 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -76,9 +76,9 @@ frappe.ui.form.on("Work Order", { frm.set_query("production_item", function() { return { query: "erpnext.controllers.queries.item_query", - filters:[ - ['is_stock_item', '=',1] - ] + filters: { + "is_stock_item": 1, + } }; }); From 3be28054de5e6d917af9608d53c48604e3285450 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 31 May 2021 09:11:42 +0530 Subject: [PATCH 124/180] refactor: Vehicle Expenses Report (#25727) * refactor: Vehicle Expense Report * test: Vehicle Expenses Report * feat: Added Employee filter to report - fix Vehicle Log form view * fix: set currency fieldtype for chart data - added filters for employee and vehicle * fix: service expenses not getting set --- .../doctype/vehicle_log/test_vehicle_log.py | 81 +++--- .../hr/doctype/vehicle_log/vehicle_log.json | 12 +- .../vehicle_expenses/test_vehicle_expenses.py | 73 ++++++ .../vehicle_expenses/vehicle_expenses.js | 77 +++--- .../vehicle_expenses/vehicle_expenses.json | 35 +-- .../vehicle_expenses/vehicle_expenses.py | 231 ++++++++++++++---- 6 files changed, 374 insertions(+), 135 deletions(-) create mode 100644 erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py index cf0048c1a7..ed52c4e122 100644 --- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe import unittest -from frappe.utils import nowdate,flt, cstr,random_string +from frappe.utils import nowdate, flt, cstr, random_string from erpnext.hr.doctype.employee.test_employee import make_employee from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim @@ -18,23 +18,13 @@ class TestVehicleLog(unittest.TestCase): self.employee_id = make_employee("testdriver@example.com", company="_Test Company") self.license_plate = get_vehicle(self.employee_id) - + def tearDown(self): frappe.delete_doc("Vehicle", self.license_plate, force=1) frappe.delete_doc("Employee", self.employee_id, force=1) def test_make_vehicle_log_and_syncing_of_odometer_value(self): - vehicle_log = frappe.get_doc({ - "doctype": "Vehicle Log", - "license_plate": cstr(self.license_plate), - "employee": self.employee_id, - "date":frappe.utils.nowdate(), - "odometer":5010, - "fuel_qty":frappe.utils.flt(50), - "price": frappe.utils.flt(500) - }) - vehicle_log.save() - vehicle_log.submit() + vehicle_log = make_vehicle_log(self.license_plate, self.employee_id) #checking value of vehicle odometer value on submit. vehicle = frappe.get_doc("Vehicle", self.license_plate) @@ -51,19 +41,9 @@ class TestVehicleLog(unittest.TestCase): self.assertEqual(vehicle.last_odometer, current_odometer - distance_travelled) vehicle_log.delete() - + def test_vehicle_log_fuel_expense(self): - vehicle_log = frappe.get_doc({ - "doctype": "Vehicle Log", - "license_plate": cstr(self.license_plate), - "employee": self.employee_id, - "date": frappe.utils.nowdate(), - "odometer":5010, - "fuel_qty":frappe.utils.flt(50), - "price": frappe.utils.flt(500) - }) - vehicle_log.save() - vehicle_log.submit() + vehicle_log = make_vehicle_log(self.license_plate, self.employee_id) expense_claim = make_expense_claim(vehicle_log.name) fuel_expense = expense_claim.expenses[0].amount @@ -73,6 +53,18 @@ class TestVehicleLog(unittest.TestCase): frappe.delete_doc("Expense Claim", expense_claim.name) frappe.delete_doc("Vehicle Log", vehicle_log.name) + def test_vehicle_log_with_service_expenses(self): + vehicle_log = make_vehicle_log(self.license_plate, self.employee_id, with_services=True) + + expense_claim = make_expense_claim(vehicle_log.name) + expenses = expense_claim.expenses[0].amount + self.assertEqual(expenses, 27000) + + vehicle_log.cancel() + frappe.delete_doc("Expense Claim", expense_claim.name) + frappe.delete_doc("Vehicle Log", vehicle_log.name) + + def get_vehicle(employee_id): license_plate=random_string(10).upper() vehicle = frappe.get_doc({ @@ -81,15 +73,46 @@ def get_vehicle(employee_id): "make": "Maruti", "model": "PCM", "employee": employee_id, - "last_odometer":5000, - "acquisition_date":frappe.utils.nowdate(), + "last_odometer": 5000, + "acquisition_date": nowdate(), "location": "Mumbai", "chassis_no": "1234ABCD", "uom": "Litre", - "vehicle_value":frappe.utils.flt(500000) + "vehicle_value": flt(500000) }) try: vehicle.insert() except frappe.DuplicateEntryError: pass - return license_plate \ No newline at end of file + return license_plate + + +def make_vehicle_log(license_plate, employee_id, with_services=False): + vehicle_log = frappe.get_doc({ + "doctype": "Vehicle Log", + "license_plate": cstr(license_plate), + "employee": employee_id, + "date": nowdate(), + "odometer": 5010, + "fuel_qty": flt(50), + "price": flt(500) + }) + + if with_services: + vehicle_log.append("service_detail", { + "service_item": "Oil Change", + "type": "Inspection", + "frequency": "Mileage", + "expense_amount": flt(500) + }) + vehicle_log.append("service_detail", { + "service_item": "Wheels", + "type": "Change", + "frequency": "Half Yearly", + "expense_amount": flt(1500) + }) + + vehicle_log.save() + vehicle_log.submit() + + return vehicle_log \ No newline at end of file diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.json b/erpnext/hr/doctype/vehicle_log/vehicle_log.json index 619e295ebe..4ea904542d 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.json +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "naming_series:", "creation": "2016-09-03 14:14:51.788550", "doctype": "DocType", @@ -10,7 +11,6 @@ "naming_series", "license_plate", "employee", - "column_break_4", "column_break_7", "model", "make", @@ -65,10 +65,6 @@ "options": "Employee", "reqd": 1 }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, { "fieldname": "column_break_7", "fieldtype": "Column Break" @@ -142,7 +138,6 @@ { "fieldname": "service_detail", "fieldtype": "Table", - "label": "Service Detail", "options": "Vehicle Service" }, { @@ -158,7 +153,7 @@ "fetch_from": "license_plate.last_odometer", "fieldname": "last_odometer", "fieldtype": "Int", - "label": "last Odometer Value ", + "label": "Last Odometer Value ", "read_only": 1, "reqd": 1 }, @@ -168,7 +163,8 @@ } ], "is_submittable": 1, - "modified": "2020-03-18 16:45:45.060761", + "links": [], + "modified": "2021-05-17 00:10:21.188352", "modified_by": "Administrator", "module": "HR", "name": "Vehicle Log", diff --git a/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py new file mode 100644 index 0000000000..26e0f26392 --- /dev/null +++ b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py @@ -0,0 +1,73 @@ +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import unittest +import frappe +from frappe.utils import getdate +from erpnext.hr.doctype.employee.test_employee import make_employee +from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim +from erpnext.hr.doctype.vehicle_log.test_vehicle_log import get_vehicle, make_vehicle_log +from erpnext.hr.report.vehicle_expenses.vehicle_expenses import execute +from erpnext.accounts.utils import get_fiscal_year + +class TestVehicleExpenses(unittest.TestCase): + @classmethod + def setUpClass(self): + frappe.db.sql('delete from `tabVehicle Log`') + + employee_id = frappe.db.sql('''select name from `tabEmployee` where name="testdriver@example.com"''') + self.employee_id = employee_id[0][0] if employee_id else None + if not self.employee_id: + self.employee_id = make_employee('testdriver@example.com', company='_Test Company') + + self.license_plate = get_vehicle(self.employee_id) + + def test_vehicle_expenses_based_on_fiscal_year(self): + vehicle_log = make_vehicle_log(self.license_plate, self.employee_id, with_services=True) + expense_claim = make_expense_claim(vehicle_log.name) + + # Based on Fiscal Year + filters = { + 'filter_based_on': 'Fiscal Year', + 'fiscal_year': get_fiscal_year(getdate())[0] + } + + report = execute(filters) + + expected_data = [{ + 'vehicle': self.license_plate, + 'make': 'Maruti', + 'model': 'PCM', + 'location': 'Mumbai', + 'log_name': vehicle_log.name, + 'odometer': 5010, + 'date': getdate(), + 'fuel_qty': 50.0, + 'fuel_price': 500.0, + 'fuel_expense': 25000.0, + 'service_expense': 2000.0, + 'employee': self.employee_id + }] + + self.assertEqual(report[1], expected_data) + + # Based on Date Range + fiscal_year = get_fiscal_year(getdate(), as_dict=True) + filters = { + 'filter_based_on': 'Date Range', + 'from_date': fiscal_year.year_start_date, + 'to_date': fiscal_year.year_end_date + } + + report = execute(filters) + self.assertEqual(report[1], expected_data) + + # clean up + vehicle_log.cancel() + frappe.delete_doc('Expense Claim', expense_claim.name) + frappe.delete_doc('Vehicle Log', vehicle_log.name) + + def tearDown(self): + frappe.delete_doc('Vehicle', self.license_plate, force=1) + frappe.delete_doc('Employee', self.employee_id, force=1) diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js index b66bebbec1..879acd18ef 100644 --- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js +++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js @@ -1,31 +1,52 @@ // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.require("assets/erpnext/js/financial_statements.js", function() { - frappe.query_reports["Vehicle Expenses"] = { - "filters": [ - { - "fieldname": "fiscal_year", - "label": __("Fiscal Year"), - "fieldtype": "Link", - "options": "Fiscal Year", - "default": frappe.defaults.get_user_default("fiscal_year"), - "reqd": 1, - "on_change": function(query_report) { - var fiscal_year = query_report.get_values().fiscal_year; - if (!fiscal_year) { - return; - } - frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) { - var fy = frappe.model.get_doc("Fiscal Year", fiscal_year); - - frappe.query_report.set_filter({ - from_date: fy.year_start_date, - to_date: fy.year_end_date - }); - }); - } - } - ] - } -}); +frappe.query_reports["Vehicle Expenses"] = { + "filters": [ + { + "fieldname": "filter_based_on", + "label": __("Filter Based On"), + "fieldtype": "Select", + "options": ["Fiscal Year", "Date Range"], + "default": ["Fiscal Year"], + "reqd": 1 + }, + { + "fieldname": "fiscal_year", + "label": __("Fiscal Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "depends_on": "eval: doc.filter_based_on == 'Fiscal Year'", + "reqd": 1 + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "reqd": 1, + "depends_on": "eval: doc.filter_based_on == 'Date Range'", + "default": frappe.datetime.add_months(frappe.datetime.nowdate(), -12) + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "reqd": 1, + "depends_on": "eval: doc.filter_based_on == 'Date Range'", + "default": frappe.datetime.nowdate() + }, + { + "fieldname": "vehicle", + "label": __("Vehicle"), + "fieldtype": "Link", + "options": "Vehicle" + }, + { + "fieldname": "employee", + "label": __("Employee"), + "fieldtype": "Link", + "options": "Employee" + } + ] +}; diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json index 2ab0c143b8..1a3e5a93bb 100644 --- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json +++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json @@ -1,20 +1,23 @@ { - "add_total_row": 0, - "apply_user_permissions": 1, - "creation": "2016-09-09 03:33:40.605734", - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 2, - "is_standard": "Yes", - "modified": "2017-02-24 19:59:18.641284", - "modified_by": "Administrator", - "module": "HR", - "name": "Vehicle Expenses", - "owner": "Administrator", - "ref_doctype": "Vehicle", - "report_name": "Vehicle Expenses", - "report_type": "Script Report", + "add_total_row": 1, + "columns": [], + "creation": "2016-09-09 03:33:40.605734", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 2, + "is_standard": "Yes", + "modified": "2021-05-16 22:48:22.767535", + "modified_by": "Administrator", + "module": "HR", + "name": "Vehicle Expenses", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Vehicle", + "report_name": "Vehicle Expenses", + "report_type": "Script Report", "roles": [ { "role": "Fleet Manager" diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py index eab58ffbbc..d847cbb5c9 100644 --- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py +++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py @@ -5,86 +5,209 @@ from __future__ import unicode_literals import frappe import erpnext from frappe import _ -from frappe.utils import flt,cstr +from frappe.utils import flt from erpnext.accounts.report.financial_statements import get_period_list def execute(filters=None): - columns, data, chart = [], [], [] - if filters.get('fiscal_year'): - company = erpnext.get_default_company() - period_list = get_period_list(filters.get('fiscal_year'), filters.get('fiscal_year'), - '', '', 'Fiscal Year', 'Monthly', company=company) - columns=get_columns() - data=get_log_data(filters) - chart=get_chart_data(data,period_list) + filters = frappe._dict(filters or {}) + + columns = get_columns() + data = get_vehicle_log_data(filters) + chart = get_chart_data(data, filters) + return columns, data, None, chart def get_columns(): - columns = [_("License") + ":Link/Vehicle:100", _('Create') + ":data:50", - _("Model") + ":data:50", _("Location") + ":data:100", - _("Log") + ":Link/Vehicle Log:100", _("Odometer") + ":Int:80", - _("Date") + ":Date:100", _("Fuel Qty") + ":Float:80", - _("Fuel Price") + ":Float:100",_("Fuel Expense") + ":Float:100", - _("Service Expense") + ":Float:100" + return [ + { + 'fieldname': 'vehicle', + 'fieldtype': 'Link', + 'label': _('Vehicle'), + 'options': 'Vehicle', + 'width': 150 + }, + { + 'fieldname': 'make', + 'fieldtype': 'Data', + 'label': _('Make'), + 'width': 100 + }, + { + 'fieldname': 'model', + 'fieldtype': 'Data', + 'label': _('Model'), + 'width': 80 + }, + { + 'fieldname': 'location', + 'fieldtype': 'Data', + 'label': _('Location'), + 'width': 100 + }, + { + 'fieldname': 'log_name', + 'fieldtype': 'Link', + 'label': _('Vehicle Log'), + 'options': 'Vehicle Log', + 'width': 100 + }, + { + 'fieldname': 'odometer', + 'fieldtype': 'Int', + 'label': _('Odometer Value'), + 'width': 120 + }, + { + 'fieldname': 'date', + 'fieldtype': 'Date', + 'label': _('Date'), + 'width': 100 + }, + { + 'fieldname': 'fuel_qty', + 'fieldtype': 'Float', + 'label': _('Fuel Qty'), + 'width': 80 + }, + { + 'fieldname': 'fuel_price', + 'fieldtype': 'Float', + 'label': _('Fuel Price'), + 'width': 100 + }, + { + 'fieldname': 'fuel_expense', + 'fieldtype': 'Currency', + 'label': _('Fuel Expense'), + 'width': 150 + }, + { + 'fieldname': 'service_expense', + 'fieldtype': 'Currency', + 'label': _('Service Expense'), + 'width': 150 + }, + { + 'fieldname': 'employee', + 'fieldtype': 'Link', + 'label': _('Employee'), + 'options': 'Employee', + 'width': 150 + } ] + return columns -def get_log_data(filters): - fy = frappe.db.get_value('Fiscal Year', filters.get('fiscal_year'), ['year_start_date', 'year_end_date'], as_dict=True) - data = frappe.db.sql("""select - vhcl.license_plate as "License", vhcl.make as "Make", vhcl.model as "Model", - vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer", - log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price", - log.fuel_qty * log.price as "Fuel Expense" - from + +def get_vehicle_log_data(filters): + start_date, end_date = get_period_dates(filters) + conditions, values = get_conditions(filters) + + data = frappe.db.sql(""" + SELECT + vhcl.license_plate as vehicle, vhcl.make, vhcl.model, + vhcl.location, log.name as log_name, log.odometer, + log.date, log.employee, log.fuel_qty, + log.price as fuel_price, + log.fuel_qty * log.price as fuel_expense + FROM `tabVehicle` vhcl,`tabVehicle Log` log - where - vhcl.license_plate = log.license_plate and log.docstatus = 1 and date between %s and %s - order by date""" ,(fy.year_start_date, fy.year_end_date), as_dict=1) - dl=list(data) - for row in dl: - row["Service Expense"]= get_service_expense(row["Log"]) - return dl + WHERE + vhcl.license_plate = log.license_plate + and log.docstatus = 1 + and date between %(start_date)s and %(end_date)s + {0} + ORDER BY date""".format(conditions), values, as_dict=1) + + for row in data: + row['service_expense'] = get_service_expense(row.log_name) + + return data + + +def get_conditions(filters): + conditions = '' + + start_date, end_date = get_period_dates(filters) + values = { + 'start_date': start_date, + 'end_date': end_date + } + + if filters.employee: + conditions += ' and log.employee = %(employee)s' + values['employee'] = filters.employee + + if filters.vehicle: + conditions += ' and vhcl.license_plate = %(vehicle)s' + values['vehicle'] = filters.vehicle + + return conditions, values + + +def get_period_dates(filters): + if filters.filter_based_on == 'Fiscal Year' and filters.fiscal_year: + fy = frappe.db.get_value('Fiscal Year', filters.fiscal_year, + ['year_start_date', 'year_end_date'], as_dict=True) + return fy.year_start_date, fy.year_end_date + else: + return filters.from_date, filters.to_date + def get_service_expense(logname): - expense_amount = frappe.db.sql("""select sum(expense_amount) - from `tabVehicle Log` log,`tabVehicle Service` ser - where ser.parent=log.name and log.name=%s""",logname) - return flt(expense_amount[0][0]) if expense_amount else 0 + expense_amount = frappe.db.sql(""" + SELECT sum(expense_amount) + FROM + `tabVehicle Log` log, `tabVehicle Service` service + WHERE + service.parent=log.name and log.name=%s + """, logname) + + return flt(expense_amount[0][0]) if expense_amount else 0.0 + + +def get_chart_data(data, filters): + period_list = get_period_list(filters.fiscal_year, filters.fiscal_year, + filters.from_date, filters.to_date, filters.filter_based_on, 'Monthly') + + fuel_data, service_data = [], [] -def get_chart_data(data,period_list): - fuel_exp_data,service_exp_data,fueldata,servicedata = [],[],[],[] - service_exp_data = [] - fueldata = [] for period in period_list: - total_fuel_exp=0 - total_ser_exp=0 - for row in data: - if row["Date"] <= period.to_date and row["Date"] >= period.from_date: - total_fuel_exp+=flt(row["Fuel Expense"]) - total_ser_exp+=flt(row["Service Expense"]) - fueldata.append([period.key,total_fuel_exp]) - servicedata.append([period.key,total_ser_exp]) + total_fuel_exp = 0 + total_service_exp = 0 + + for row in data: + if row.date <= period.to_date and row.date >= period.from_date: + total_fuel_exp += flt(row.fuel_expense) + total_service_exp += flt(row.service_expense) + + fuel_data.append([period.key, total_fuel_exp]) + service_data.append([period.key, total_service_exp]) + + labels = [period.label for period in period_list] + fuel_exp_data= [row[1] for row in fuel_data] + service_exp_data= [row[1] for row in service_data] - labels = [period.key for period in period_list] - fuel_exp_data= [row[1] for row in fueldata] - service_exp_data= [row[1] for row in servicedata] datasets = [] if fuel_exp_data: datasets.append({ - 'name': 'Fuel Expenses', + 'name': _('Fuel Expenses'), 'values': fuel_exp_data }) + if service_exp_data: datasets.append({ - 'name': 'Service Expenses', + 'name': _('Service Expenses'), 'values': service_exp_data }) + chart = { - "data": { + 'data': { 'labels': labels, 'datasets': datasets - } + }, + 'type': 'line', + 'fieldtype': 'Currency' } - chart["type"] = "line" + return chart From 89f621baa465942efb98487684c7d4feff1db2ca Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 31 May 2021 09:56:49 +0530 Subject: [PATCH 125/180] fix(pos): closing entry shows incorrect expected amount (#25868) --- .../accounts/doctype/pos_closing_entry/pos_closing_entry.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js index 8c5a34a0d8..6418d73090 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js @@ -107,7 +107,7 @@ frappe.ui.form.on('POS Closing Entry', { frm.set_value("taxes", []); for (let row of frm.doc.payment_reconciliation) { - row.expected_amount = 0; + row.expected_amount = row.opening_amount; } for (let row of frm.doc.pos_transactions) { @@ -154,6 +154,9 @@ function add_to_pos_transaction(d, frm) { function refresh_payments(d, frm) { d.payments.forEach(p => { const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment); + if (p.account == d.account_for_change_amount) { + p.amount -= flt(d.change_amount); + } if (payment) { payment.expected_amount += flt(p.amount); payment.difference = payment.closing_amount - payment.expected_amount; From 80540d38ba5c17ec12eab15531bc63be09eeb609 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Mon, 31 May 2021 12:06:20 +0200 Subject: [PATCH 126/180] fix: add_deduct_tax in Purchase Taxes setup (#25871) --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 429a558c58..5019837441 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -106,6 +106,9 @@ def make_taxes_and_charges_template(company_name, doctype, template): 'charge_type': 'On Net Total' } + if doctype == 'Purchase Taxes and Charges Template': + tax_row_defaults['add_deduct_tax'] = 'Add' + # if account_head is a dict, search or create the account and get it's name if isinstance(account_data, dict): tax_row_defaults['description'] = '{0} @ {1}'.format(account_data.get('account_name'), account_data.get('tax_rate')) From 0358b6474368462690211a0191138b644c3bd3be Mon Sep 17 00:00:00 2001 From: Anupam Date: Mon, 31 May 2021 15:59:32 +0530 Subject: [PATCH 127/180] fix: featching serialized items --- .../stock_reconciliation/stock_reconciliation.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 7e216d6181..32e0ccb93f 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -477,19 +477,19 @@ class StockReconciliation(StockController): def get_items(warehouse, posting_date, posting_time, company): lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"]) items = frappe.db.sql(""" - select i.name, i.item_name, bin.warehouse + select i.name, i.item_name, bin.warehouse, i.has_serial_no from tabBin bin, tabItem i where i.name=bin.item_code and i.disabled=0 and i.is_stock_item = 1 - and i.has_variants = 0 and i.has_serial_no = 0 and i.has_batch_no = 0 + and i.has_variants = 0 and i.has_batch_no = 0 and exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=bin.warehouse) """, (lft, rgt)) items += frappe.db.sql(""" - select i.name, i.item_name, id.default_warehouse + select i.name, i.item_name, id.default_warehouse, i.has_serial_no from tabItem i, `tabItem Default` id where i.name = id.parent and exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=id.default_warehouse) - and i.is_stock_item = 1 and i.has_serial_no = 0 and i.has_batch_no = 0 + and i.is_stock_item = 1 and i.has_batch_no = 0 and i.has_variants = 0 and i.disabled = 0 and id.company=%s group by i.name """, (lft, rgt, company)) @@ -497,7 +497,7 @@ def get_items(warehouse, posting_date, posting_time, company): res = [] for d in set(items): stock_bal = get_stock_balance(d[0], d[2], posting_date, posting_time, - with_valuation_rate=True) + with_valuation_rate=True , with_serial_no=cint(d[3])) if frappe.db.get_value("Item", d[0], "disabled") == 0: res.append({ @@ -507,7 +507,9 @@ def get_items(warehouse, posting_date, posting_time, company): "item_name": d[1], "valuation_rate": stock_bal[1], "current_qty": stock_bal[0], - "current_valuation_rate": stock_bal[1] + "current_valuation_rate": stock_bal[1], + "current_serial_no": stock_bal[2] if cint(d[3]) else '', + "serial_no": stock_bal[2] if cint(d[3]) else '' }) return res From 0ea6725baaf61637aa1625098ccc5e3365c40730 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 31 May 2021 19:48:31 +0530 Subject: [PATCH 128/180] fix: Rename Loan Management workspace to Loans (#25856) --- .../workspace/loan_management/loan_management.json | 6 +++--- erpnext/patches.txt | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/loan_management/workspace/loan_management/loan_management.json b/erpnext/loan_management/workspace/loan_management/loan_management.json index 18559dceef..d0b67f7c64 100644 --- a/erpnext/loan_management/workspace/loan_management/loan_management.json +++ b/erpnext/loan_management/workspace/loan_management/loan_management.json @@ -12,7 +12,7 @@ "idx": 0, "is_default": 0, "is_standard": 1, - "label": "Loan Management", + "label": "Loans", "links": [ { "hidden": 0, @@ -220,10 +220,10 @@ "type": "Link" } ], - "modified": "2021-02-18 17:31:53.586508", + "modified": "2021-05-25 17:31:53.586508", "modified_by": "Administrator", "module": "Loan Management", - "name": "Loan Management", + "name": "Loans", "owner": "Administrator", "pin_to_bottom": 0, "pin_to_top": 0, diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 3a7aa1bce3..93689a0ef3 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -779,6 +779,7 @@ erpnext.patches.v12_0.add_ewaybill_validity_field erpnext.patches.v13_0.germany_make_custom_fields erpnext.patches.v13_0.germany_fill_debtor_creditor_number erpnext.patches.v13_0.set_pos_closing_as_failed +execute:frappe.rename_doc("Workspace", "Loan Management", "Loans", force=True) erpnext.patches.v13_0.update_timesheet_changes erpnext.patches.v13_0.set_training_event_attendance erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold From 908b0090e967cd2503d69e4df99878c048ab35ba Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Mon, 31 May 2021 19:49:03 +0530 Subject: [PATCH 129/180] fix: Create POS Invoice for Product Bundles (#25847) Co-authored-by: Saqib --- .../doctype/pos_invoice/pos_invoice.py | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index f55fdab21c..8ec4ef224c 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -140,6 +140,7 @@ class POSInvoice(SalesInvoice): return available_stock = get_stock_availability(d.item_code, d.warehouse) + item_code, warehouse, qty = frappe.bold(d.item_code), frappe.bold(d.warehouse), frappe.bold(d.qty) if flt(available_stock) <= 0: frappe.throw(_('Row #{}: Item Code: {} is not available under warehouse {}.') @@ -213,8 +214,9 @@ class POSInvoice(SalesInvoice): for d in self.get("items"): is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item") if not is_stock_item: - frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice. ") - .format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item")) + if not frappe.db.exists('Product Bundle', d.item_code): + frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice.") + .format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item")) def validate_mode_of_payment(self): if len(self.payments) == 0: @@ -455,15 +457,36 @@ class POSInvoice(SalesInvoice): @frappe.whitelist() def get_stock_availability(item_code, warehouse): + if frappe.db.get_value('Item', item_code, 'is_stock_item'): + bin_qty = get_bin_qty(item_code, warehouse) + pos_sales_qty = get_pos_reserved_qty(item_code, warehouse) + return bin_qty - pos_sales_qty + else: + if frappe.db.exists('Product Bundle', item_code): + return get_bundle_availability(item_code, warehouse) + +def get_bundle_availability(bundle_item_code, warehouse): + product_bundle = frappe.get_doc('Product Bundle', bundle_item_code) + + bundle_bin_qty = 1000000 + for item in product_bundle.items: + item_bin_qty = get_bin_qty(item.item_code, warehouse) + item_pos_reserved_qty = get_pos_reserved_qty(item.item_code, warehouse) + available_qty = item_bin_qty - item_pos_reserved_qty + + max_available_bundles = available_qty / item.qty + if bundle_bin_qty > max_available_bundles: + bundle_bin_qty = max_available_bundles + + pos_sales_qty = get_pos_reserved_qty(bundle_item_code, warehouse) + return bundle_bin_qty - pos_sales_qty + +def get_bin_qty(item_code, warehouse): bin_qty = frappe.db.sql("""select actual_qty from `tabBin` where item_code = %s and warehouse = %s limit 1""", (item_code, warehouse), as_dict=1) - pos_sales_qty = get_pos_reserved_qty(item_code, warehouse) - - bin_qty = bin_qty[0].actual_qty or 0 if bin_qty else 0 - - return bin_qty - pos_sales_qty + return bin_qty[0].actual_qty or 0 if bin_qty else 0 def get_pos_reserved_qty(item_code, warehouse): reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty @@ -522,4 +545,4 @@ def add_return_modes(doc, pos_profile): mode_of_payment = pos_payment_method.mode_of_payment if pos_payment_method.allow_in_returns and not [d for d in doc.get('payments') if d.mode_of_payment == mode_of_payment]: payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company) - append_payment(payment_mode[0]) \ No newline at end of file + append_payment(payment_mode[0]) From 022b5c973a6fced4271bb4b77360dbd4c1425d03 Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Mon, 31 May 2021 19:49:53 +0530 Subject: [PATCH 130/180] fix: wrap dates in getdate for leave application (#25899) * fix: wrap dates in getdate for leave application * fix: translation issue * fix: replaced today with getdate --- .../leave_application/leave_application.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 0bf551e178..cee6f374fd 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -4,8 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \ - comma_or, get_fullname, add_days, nowdate, get_datetime_str +from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, get_fullname, add_days, nowdate from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee @@ -85,7 +84,7 @@ class LeaveApplication(Document): def validate_dates(self): if frappe.db.get_single_value("HR Settings", "restrict_backdated_leave_application"): - if self.from_date and self.from_date < frappe.utils.today(): + if self.from_date and getdate(self.from_date) < getdate(): allowed_role = frappe.db.get_single_value("HR Settings", "role_allowed_to_create_backdated_leave_application") if allowed_role not in frappe.get_roles(): frappe.throw(_("Only users with the {0} role can create backdated leave applications").format(allowed_role)) @@ -248,9 +247,9 @@ class LeaveApplication(Document): self.throw_overlap_error(d) def throw_overlap_error(self, d): - msg = _("Employee {0} has already applied for {1} between {2} and {3} : ").format(self.employee, - d['leave_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \ - + """ {0}""".format(d["name"]) + form_link = get_link_to_form("Leave Application", d.name) + msg = _("Employee {0} has already applied for {1} between {2} and {3} : {4}").format(self.employee, + d['leave_type'], formatdate(d['from_date']), formatdate(d['to_date']), form_link) frappe.throw(msg, OverlapError) def get_total_leaves_on_half_day(self): @@ -356,7 +355,7 @@ class LeaveApplication(Document): sender = dict() sender['email'] = frappe.get_doc('User', frappe.session.user).email - sender['full_name'] = frappe.utils.get_fullname(sender['email']) + sender['full_name'] = get_fullname(sender['email']) try: frappe.sendmail( @@ -823,4 +822,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 \ No newline at end of file + return leave_approver From c8b34798feadff95d38f7d5961d7b8aa83730a8e Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Tue, 1 Jun 2021 10:44:26 +0530 Subject: [PATCH 131/180] fix(Delivery Note): Assign Product Bundle's conversion_factor to Packed Items (#25840) --- erpnext/stock/doctype/packed_item/packed_item.json | 8 +++++++- erpnext/stock/doctype/packed_item/packed_item.py | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index f1d7f8c8c9..bb396e806f 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -13,6 +13,7 @@ "section_break_6", "warehouse", "target_warehouse", + "conversion_factor", "column_break_9", "qty", "uom", @@ -209,13 +210,18 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "fieldname": "conversion_factor", + "fieldtype": "Float", + "label": "Conversion Factor" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-09-24 09:25:13.050151", + "modified": "2021-05-26 07:08:05.111385", "modified_by": "Administrator", "module": "Stock", "name": "Packed Item", diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py index 5341f29853..4ab71bdf62 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -53,6 +53,7 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip pi.parent_detail_docname = main_item_row.name pi.uom = item.stock_uom pi.qty = flt(qty) + pi.conversion_factor = main_item_row.conversion_factor if description and not pi.description: pi.description = description if not pi.warehouse and not doc.amended_from: From 1175e0686bd920356264522200c40769f76bf658 Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Tue, 1 Jun 2021 10:53:00 +0530 Subject: [PATCH 132/180] refactor: leave balance report (#25771) * refactor: leave balance report * refactor: sql to orm --- .../employee_leave_balance.js | 19 +++- .../employee_leave_balance.py | 88 ++++++++++++++----- erpnext/hr/utils.py | 1 + 3 files changed, 85 insertions(+), 23 deletions(-) diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js index 05728a297b..8bb3457190 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js @@ -37,5 +37,22 @@ frappe.query_reports["Employee Leave Balance"] = { "fieldtype": "Link", "options": "Employee", } - ] + ], + + onload: () => { + frappe.call({ + type: "GET", + method: "erpnext.hr.utils.get_leave_period", + args: { + "from_date": frappe.defaults.get_default("year_start_date"), + "to_date": frappe.defaults.get_default("year_end_date"), + "company": frappe.defaults.get_user_default("Company") + }, + freeze: true, + callback: (data) => { + frappe.query_report.set_filter_value("from_date", data.message[0].from_date); + frappe.query_report.set_filter_value("to_date", data.message[0].to_date); + } + }); + } } diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index 06f9160363..4dd4570e8c 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -6,15 +6,16 @@ import frappe from frappe.utils import flt, add_days from frappe import _ from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on +from itertools import groupby def execute(filters=None): if filters.to_date <= filters.from_date: - frappe.throw(_('"From date" can not be greater than or equal to "To date"')) + frappe.throw(_('"From Date" can not be greater than or equal to "To Date"')) columns = get_columns() data = get_data(filters) - - return columns, data + charts = get_chart_data(data) + return columns, data, None, charts def get_columns(): columns = [{ @@ -31,9 +32,10 @@ def get_columns(): 'options': 'Employee' }, { 'label': _('Employee Name'), - 'fieldtype': 'Data', + 'fieldtype': 'Dynamic Link', 'fieldname': 'employee_name', 'width': 100, + 'options': 'employee' }, { 'label': _('Opening Balance'), 'fieldtype': 'float', @@ -64,8 +66,7 @@ def get_columns(): return columns def get_data(filters): - leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC") - + leave_types = frappe.db.get_list('Leave Type', pluck='name', order_by='name') conditions = get_conditions(filters) user = frappe.session.user @@ -113,12 +114,8 @@ def get_data(filters): # not be shown on the basis of days left it create in user mind for carry_forward leave row.closing_balance = (new_allocation + opening - (row.leaves_expired + leaves_taken)) - - row.indent = 1 data.append(row) - new_leaves_allocated = 0 - return data @@ -129,27 +126,37 @@ def get_conditions(filters): if filters.get('employee'): conditions['name'] = filters.get('employee') - if filters.get('employee'): - conditions['name'] = filters.get('employee') - if filters.get('company'): conditions['company'] = filters.get('company') + if filters.get('department'): + conditions['department'] = filters.get('department') + return conditions def get_department_leave_approver_map(department=None): - conditions='' - if department: - conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department} # get current department and all its child - department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec - + department_list = frappe.get_list('Department', + filters={ + 'disabled': 0 + }, + or_filters={ + 'name': department, + 'parent_department': department + }, + fields=['name'], + pluck='name' + ) # retrieve approvers list from current department and from its subsequent child departments - approver_list = frappe.get_all('Department Approver', filters={ - 'parentfield': 'leave_approvers', - 'parent': ('in', department_list) - }, fields=['parent', 'approver'], as_list=1) + approver_list = frappe.get_all('Department Approver', + filters={ + 'parentfield': 'leave_approvers', + 'parent': ('in', department_list) + }, + fields=['parent', 'approver'], + as_list=1 + ) approvers = {} @@ -190,3 +197,40 @@ def get_allocated_and_expired_leaves(from_date, to_date, employee, leave_type): new_allocation += record.leaves return new_allocation, expired_leaves + +def get_chart_data(data): + labels = [] + datasets = [] + employee_data = data + + if data and data[0].get('employee_name'): + get_dataset_for_chart(employee_data, datasets, labels) + + chart = { + 'data': { + 'labels': labels, + 'datasets': datasets + }, + 'type': 'bar', + 'colors': ['#456789', '#EE8888', '#7E77BF'] + } + + return chart + +def get_dataset_for_chart(employee_data, datasets, labels): + leaves = [] + employee_data = sorted(employee_data, key=lambda k: k['employee_name']) + + for key, group in groupby(employee_data, lambda x: x['employee_name']): + for grp in group: + if grp.closing_balance: + leaves.append(frappe._dict({ + 'leave_type': grp.leave_type, + 'closing_balance': grp.closing_balance + })) + + if leaves: + labels.append(key) + + for leave in leaves: + datasets.append({'name': leave.leave_type, 'values': [leave.closing_balance]}) diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 80189e87b7..ebb1734347 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -269,6 +269,7 @@ def get_total_exemption_amount(declarations): total_exemption_amount = sum([flt(d.total_exemption_amount) for d in exemptions.values()]) return total_exemption_amount +@frappe.whitelist() def get_leave_period(from_date, to_date, company): leave_period = frappe.db.sql(""" select name, from_date, to_date From 2c7fac0e7689b1eba05cc18abeee535fd52726b0 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 1 Jun 2021 11:56:00 +0530 Subject: [PATCH 133/180] fix: reload doc for possible future schema changes (#25904) --- erpnext/patches/v12_0/purchase_receipt_status.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/patches/v12_0/purchase_receipt_status.py b/erpnext/patches/v12_0/purchase_receipt_status.py index 1a99b3163b..459221e769 100644 --- a/erpnext/patches/v12_0/purchase_receipt_status.py +++ b/erpnext/patches/v12_0/purchase_receipt_status.py @@ -19,6 +19,9 @@ def execute(): logger.info("purchase_receipt_status: begin patch, PR count: {}" .format(len(affected_purchase_receipts))) + frappe.reload_doc("stock", "doctype", "Purchase Receipt") + frappe.reload_doc("stock", "doctype", "Purchase Receipt Item") + for pr in affected_purchase_receipts: pr_name = pr[0] From 865663857c30de89f5b0a7808421ecf05c53224e Mon Sep 17 00:00:00 2001 From: Fisher Yu <12823863+szufisher@users.noreply.github.com> Date: Tue, 1 Jun 2021 14:45:58 +0800 Subject: [PATCH 134/180] fix: chart of accounts importer always error (#25882) * fix: chart of accounts importer always error chart of accounts importer always error Parent Account Missing * Update chart_of_accounts_importer.py --- .../chart_of_accounts_importer/chart_of_accounts_importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py index ef44626b37..3b764aab10 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py @@ -293,7 +293,7 @@ def validate_accounts(file_name): accounts_dict = {} for account in accounts: accounts_dict.setdefault(account["account_name"], account) - if not hasattr(account, "parent_account"): + if "parent_account" not in account: msg = _("Please make sure the file you are using has 'Parent Account' column present in the header.") msg += "

" msg += _("Alternatively, you can download the template and fill your data in.") From 721b4130db37e0219843b0fbca9acd1a36ee816b Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 2 Jun 2021 14:13:09 +0530 Subject: [PATCH 135/180] fix: not able to select the item code in work order --- erpnext/controllers/queries.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 46301b7587..638503edfa 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -204,7 +204,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals if "description" in searchfields: searchfields.remove("description") - + columns = '' extra_searchfields = [field for field in searchfields if not field in ["name", "item_group", "description"]] @@ -216,9 +216,10 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals if not field in searchfields] searchfields = " or ".join([field + " like %(txt)s" for field in searchfields]) - if filters.get('supplier'): - item_group_list = frappe.get_all('Supplier Item Group', filters = {'supplier': filters.get('supplier')}, fields = ['item_group']) - + if filters and isinstance(filters, dict) and filters.get('supplier'): + item_group_list = frappe.get_all('Supplier Item Group', + filters = {'supplier': filters.get('supplier')}, fields = ['item_group']) + item_groups = [] for i in item_group_list: item_groups.append(i.item_group) @@ -227,7 +228,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals if item_groups: filters['item_group'] = ['in', item_groups] - + description_cond = '' if frappe.db.count('Item', cache=True) < 50000: # scan description only if items are less than 50000 From a06ec03efcaedeeffaf9b8f9818bfb866f44e2d1 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Wed, 2 Jun 2021 14:55:31 +0530 Subject: [PATCH 136/180] test: add test for new QI function --- erpnext/controllers/stock_controller.py | 5 +- erpnext/public/js/controllers/transaction.js | 2 +- .../test_quality_inspection.py | 152 ++++++++++++------ 3 files changed, 103 insertions(+), 56 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index abc966a477..0da723d56e 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -504,9 +504,10 @@ class StockController(AccountsController): @frappe.whitelist() def make_quality_inspections(doctype, docname, items): - items = json.loads(items).get('items') - inspections = [] + if isinstance(items, str): + items = json.loads(items) + inspections = [] for item in items: if flt(item.get("sample_size")) > flt(item.get("qty")): frappe.throw(_("{item_name}'s Sample Size ({sample_size}) cannot be greater than the Accepted Quantity ({accepted_quantity})").format( diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 95562baa8e..982b1fe1eb 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -2035,7 +2035,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ args: { doctype: me.frm.doc.doctype, docname: me.frm.doc.name, - items: data + items: data.items }, freeze: true, callback: function (r) { diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py index 56b046a92e..7f3d701034 100644 --- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py @@ -1,29 +1,45 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals -import frappe import unittest + +import frappe from frappe.utils import nowdate -from erpnext.stock.doctype.item.test_item import create_item + +from erpnext.controllers.stock_controller import ( + QualityInspectionNotSubmittedError, + QualityInspectionRejectedError, + QualityInspectionRequiredError, + make_quality_inspections, +) from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note +from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry -from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError, QualityInspectionNotSubmittedError # test_records = frappe.get_test_records('Quality Inspection') + class TestQualityInspection(unittest.TestCase): def setUp(self): create_item("_Test Item with QA") - frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1) + frappe.db.set_value( + "Item", "_Test Item with QA", "inspection_required_before_delivery", 1 + ) def test_qa_for_delivery(self): - make_stock_entry(item_code="_Test Item with QA", target="_Test Warehouse - _TC", qty=1, basic_rate=100) + make_stock_entry( + item_code="_Test Item with QA", + target="_Test Warehouse - _TC", + qty=1, + basic_rate=100 + ) dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) self.assertRaises(QualityInspectionRequiredError, dn.submit) - qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected") + qa = create_quality_inspection( + reference_type="Delivery Note", reference_name=dn.name, status="Rejected" + ) dn.reload() self.assertRaises(QualityInspectionRejectedError, dn.submit) @@ -38,7 +54,9 @@ class TestQualityInspection(unittest.TestCase): def test_qa_not_submit(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) - qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, do_not_submit=True) + qa = create_quality_inspection( + reference_type="Delivery Note", reference_name=dn.name, do_not_submit=True + ) dn.items[0].quality_inspection = qa.name self.assertRaises(QualityInspectionNotSubmittedError, dn.submit) @@ -48,21 +66,28 @@ class TestQualityInspection(unittest.TestCase): def test_value_based_qi_readings(self): # Test QI based on acceptance values (Non formula) dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) - readings = [{ - "specification": "Iron Content", # numeric reading - "min_value": 0.1, - "max_value": 0.9, - "reading_1": "0.4" - }, - { - "specification": "Particle Inspection Needed", # non-numeric reading - "numeric": 0, - "value": "Yes", - "reading_value": "Yes" - }] + readings = [ + { + "specification": "Iron Content", # numeric reading + "min_value": 0.1, + "max_value": 0.9, + "reading_1": "0.4" + }, + { + "specification": "Particle Inspection Needed", # non-numeric reading + "numeric": 0, + "value": "Yes", + "reading_value": "Yes" + } + ] + + qa = create_quality_inspection( + reference_type="Delivery Note", + reference_name=dn.name, + readings=readings, + do_not_save=True + ) - qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, - readings=readings, do_not_save=True) qa.save() # status must be auto set as per formula @@ -74,36 +99,43 @@ class TestQualityInspection(unittest.TestCase): def test_formula_based_qi_readings(self): dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) - readings = [{ - "specification": "Iron Content", # numeric reading - "formula_based_criteria": 1, - "acceptance_formula": "reading_1 > 0.35 and reading_1 < 0.50", - "reading_1": "0.4" - }, - { - "specification": "Calcium Content", # numeric reading - "formula_based_criteria": 1, - "acceptance_formula": "reading_1 > 0.20 and reading_1 < 0.50", - "reading_1": "0.7" - }, - { - "specification": "Mg Content", # numeric reading - "formula_based_criteria": 1, - "acceptance_formula": "mean < 0.9", - "reading_1": "0.5", - "reading_2": "0.7", - "reading_3": "random text" # check if random string input causes issues - }, - { - "specification": "Calcium Content", # non-numeric reading - "formula_based_criteria": 1, - "numeric": 0, - "acceptance_formula": "reading_value in ('Grade A', 'Grade B', 'Grade C')", - "reading_value": "Grade B" - }] + readings = [ + { + "specification": "Iron Content", # numeric reading + "formula_based_criteria": 1, + "acceptance_formula": "reading_1 > 0.35 and reading_1 < 0.50", + "reading_1": "0.4" + }, + { + "specification": "Calcium Content", # numeric reading + "formula_based_criteria": 1, + "acceptance_formula": "reading_1 > 0.20 and reading_1 < 0.50", + "reading_1": "0.7" + }, + { + "specification": "Mg Content", # numeric reading + "formula_based_criteria": 1, + "acceptance_formula": "mean < 0.9", + "reading_1": "0.5", + "reading_2": "0.7", + "reading_3": "random text" # check if random string input causes issues + }, + { + "specification": "Calcium Content", # non-numeric reading + "formula_based_criteria": 1, + "numeric": 0, + "acceptance_formula": "reading_value in ('Grade A', 'Grade B', 'Grade C')", + "reading_value": "Grade B" + } + ] + + qa = create_quality_inspection( + reference_type="Delivery Note", + reference_name=dn.name, + readings=readings, + do_not_save=True + ) - qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, - readings=readings, do_not_save=True) qa.save() # status must be auto set as per formula @@ -115,6 +147,19 @@ class TestQualityInspection(unittest.TestCase): qa.delete() dn.delete() + def test_make_quality_inspections_from_linked_document(self): + dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) + for item in dn.items: + item.sample_size = item.qty + quality_inspections = make_quality_inspections(dn.doctype, dn.name, dn.items) + self.assertEqual(len(dn.items), len(quality_inspections)) + + # cleanup + for qi in quality_inspections: + frappe.delete_doc("Quality Inspection", qi) + dn.delete() + + def create_quality_inspection(**args): args = frappe._dict(args) qa = frappe.new_doc("Quality Inspection") @@ -134,7 +179,7 @@ def create_quality_inspection(**args): readings = args.readings if args.status == "Rejected": - readings["reading_1"] = "12" # status is auto set in child on save + readings["reading_1"] = "12" # status is auto set in child on save if isinstance(readings, list): for entry in readings: @@ -150,10 +195,11 @@ def create_quality_inspection(**args): return qa + def create_quality_inspection_parameter(parameter): if not frappe.db.exists("Quality Inspection Parameter", parameter): frappe.get_doc({ "doctype": "Quality Inspection Parameter", "parameter": parameter, "description": parameter - }).insert() \ No newline at end of file + }).insert() From f259bf48aaa40630b0a7b08b6d323a14ffc8aa03 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 2 Jun 2021 13:20:03 +0200 Subject: [PATCH 137/180] refactor: make tax category --- .../setup_wizard/data/country_wise_tax.json | 4 +++ .../setup_wizard/operations/taxes_setup.py | 33 +++++++++++-------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 2e2a0ca726..5ed8ab92bf 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -481,6 +481,10 @@ }, "Germany": { + "tax_categories": [ + "Umsatzsteuer", + "Vorsteuer" + ], "chart_of_accounts": { "SKR04 mit Kontonummern": { "sales_tax_templates": [ diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 4a3de957b9..f4fe18e116 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -26,7 +26,7 @@ def setup_taxes_and_charges(company_name: str, country: str): if 'chart_of_accounts' not in country_wise_tax: country_wise_tax = simple_to_detailed(country_wise_tax) - from_detailed_data(company_name, country_wise_tax.get('chart_of_accounts')) + from_detailed_data(company_name, country_wise_tax) def simple_to_detailed(templates): @@ -77,10 +77,16 @@ def simple_to_detailed(templates): def from_detailed_data(company_name, data): """Create Taxes and Charges Templates from detailed data.""" coa_name = frappe.db.get_value('Company', company_name, 'chart_of_accounts') - tax_templates = data.get(coa_name) or data.get('*') - sales_tax_templates = tax_templates.get('sales_tax_templates') or tax_templates.get('*') - purchase_tax_templates = tax_templates.get('purchase_tax_templates') or tax_templates.get('*') - item_tax_templates = tax_templates.get('item_tax_templates') or tax_templates.get('*') + coa_data = data.get('chart_of_accounts', {}) + tax_templates = coa_data.get(coa_name) or coa_data.get('*', {}) + tax_categories = data.get('tax_categories') + sales_tax_templates = tax_templates.get('sales_tax_templates') or tax_templates.get('*', {}) + purchase_tax_templates = tax_templates.get('purchase_tax_templates') or tax_templates.get('*', {}) + item_tax_templates = tax_templates.get('item_tax_templates') or tax_templates.get('*', {}) + + if tax_categories: + for tax_category in tax_categories: + make_tax_catgory(tax_category) if sales_tax_templates: for template in sales_tax_templates: @@ -102,9 +108,6 @@ def make_taxes_and_charges_template(company_name, doctype, template): if frappe.db.exists(doctype, {'title': template.get('title'), 'company': company_name}): return - if template.get('tax_category'): - ensure_tax_category_exists(template.get('tax_category')) - for tax_row in template.get('taxes'): account_data = tax_row.get('account_head') tax_row_defaults = { @@ -241,8 +244,12 @@ def get_or_create_tax_group(company_name, root_type): return tax_group_name -def ensure_tax_category_exists(name): - if not frappe.db.exists('Tax Category', name): - doc = frappe.new_doc('Tax Category') - doc.title = name - doc.save() +def make_tax_catgory(tax_category): + doctype = 'Tax Category' + if isinstance(tax_category, str): + tax_category = {'title': tax_category} + + tax_category['doctype'] = doctype + if not frappe.db.exists(doctype, tax_category['title']): + doc = frappe.get_doc(tax_category) + doc.insert(ignore_permissions=True) From b6f27a4caef1fd479762579fd6f612fdc78fa69d Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 2 Jun 2021 13:20:33 +0200 Subject: [PATCH 138/180] feat: set is_default for german tax templates --- erpnext/setup/setup_wizard/data/country_wise_tax.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 5ed8ab92bf..f4728ef398 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -491,6 +491,7 @@ { "title": "Umsatzsteuer", "tax_category": "Umsatzsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -515,6 +516,7 @@ { "title": "Vorsteuer", "tax_category": "Vorsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -567,6 +569,7 @@ { "title": "Umsatzsteuer", "tax_category": "Umsatzsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -591,6 +594,7 @@ { "title": "Vorsteuer", "tax_category": "Vorsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -619,6 +623,7 @@ { "title": "Umsatzsteuer", "tax_category": "Umsatzsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -643,6 +648,7 @@ { "title": "Vorsteuer", "tax_category": "Vorsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -761,6 +767,7 @@ { "title": "Umsatzsteuer", "tax_category": "Umsatzsteuer", + "is_default": 1, "taxes": [ { "account_head": { @@ -783,6 +790,7 @@ { "title": "Vorsteuer 19%", "tax_category": "Vorsteuer", + "is_default": 1, "taxes": [ { "account_head": { From 3c748efae3cfc78a88447ac9edeccfea860f1358 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 2 Jun 2021 13:27:15 +0200 Subject: [PATCH 139/180] feat: add Item Tax Templates for german COAs "SKR03" and "SKR04" --- .../setup_wizard/data/country_wise_tax.json | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index f4728ef398..8305cae73e 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -562,6 +562,96 @@ } ] } + ], + "item_tax_templates": [ + { + "title": "Umsatzsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "account_number": "3806", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "account_number": "3801", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Umsatzsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "account_number": "3806", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "account_number": "3801", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 + } + ] + }, + { + "title": "Vorsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "account_number": "1406", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "account_number": "1401", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Vorsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "account_number": "1406", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "account_number": "1401", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 + } + ] + } ] }, "SKR03 mit Kontonummern": { @@ -616,6 +706,96 @@ } ] } + ], + "item_tax_templates": [ + { + "title": "Umsatzsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "account_number": "1776", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "account_number": "1771", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Umsatzsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Umsatzsteuer 19%", + "account_number": "1776", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Umsatzsteuer 7%", + "account_number": "1771", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 + } + ] + }, + { + "title": "Vorsteuer 19%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "account_number": "1576", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 19.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "account_number": "1571", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 0.00 + } + ] + }, + { + "title": "Vorsteuer 7%", + "taxes": [ + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 19%", + "account_number": "1576", + "root_type": "Asset", + "tax_rate": 19.00 + }, + "tax_rate": 0.00 + }, + { + "tax_type": { + "account_name": "Abziehbare Vorsteuer 7%", + "account_number": "1571", + "root_type": "Asset", + "tax_rate": 7.00 + }, + "tax_rate": 7.00 + } + ] + } ] }, "Standard with Numbers": { From f6627550d11ea95170ce5f208a257bb31218585f Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Wed, 2 Jun 2021 15:17:00 +0200 Subject: [PATCH 140/180] fix: remove wrong tax_category --- erpnext/setup/setup_wizard/data/country_wise_tax.json | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 8305cae73e..ec9a6d6b70 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -540,7 +540,6 @@ }, { "title": "Innergemeinschaftlicher Erwerb 19% Umsatzsteuer und 19% Vorsteuer", - "tax_category": "Innergemeinschaftlicher Erwerb 19%", "taxes": [ { "account_head": { From 311b378328ec3d8ea774749f69188210eef237cd Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 3 Jun 2021 12:58:53 +0530 Subject: [PATCH 141/180] fix(pos): searching items with barcode or serial no --- .../page/point_of_sale/point_of_sale.py | 88 ++++++++++--------- .../page/point_of_sale/pos_item_selector.js | 6 +- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index cb811df8e8..7742f24385 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -8,38 +8,52 @@ from frappe.utils import cint from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_stock_availability -from six import string_types +def search_by_term(search_term, warehouse, price_list): + result = search_for_serial_or_batch_or_barcode_number(search_term) + + item_code = result.get("item_code") or search_term + serial_no = result.get("serial_no") or "" + batch_no = result.get("batch_no") or "" + barcode = result.get("barcode") or "" + + if result: + item_info = frappe.db.get_value("Item", item_code, + ["name as item_code", "item_name", "description", "stock_uom", "image as item_image", "is_stock_item"], + as_dict=1) + + item_stock_qty = get_stock_availability(item_code, warehouse) + price_list_rate, currency = frappe.db.get_value('Item Price', { + 'price_list': price_list, + 'item_code': item_code + }, ["price_list_rate", "currency"]) + + item_info.update({ + 'serial_no': serial_no, + 'batch_no': batch_no, + 'barcode': barcode, + 'price_list_rate': price_list_rate, + 'currency': currency, + 'actual_qty': item_stock_qty + }) + + return {'items': [item_info]} @frappe.whitelist() -def get_items(start, page_length, price_list, item_group, pos_profile, search_value=""): - data = dict() +def get_items(start, page_length, price_list, item_group, pos_profile, search_term=""): + warehouse, hide_unavailable_items = frappe.db.get_value( + 'POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items']) + result = [] - warehouse, hide_unavailable_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items']) + if search_term: + result = search_by_term(search_term, warehouse, price_list) + if result: + return result if not frappe.db.exists('Item Group', item_group): item_group = get_root_of('Item Group') - if search_value: - data = search_serial_or_batch_or_barcode_number(search_value) - - item_code = data.get("item_code") if data.get("item_code") else search_value - serial_no = data.get("serial_no") if data.get("serial_no") else "" - batch_no = data.get("batch_no") if data.get("batch_no") else "" - barcode = data.get("barcode") if data.get("barcode") else "" - - if data: - item_info = frappe.db.get_value( - "Item", data.get("item_code"), - ["name as item_code", "item_name", "description", "stock_uom", "image as item_image", "is_stock_item"] - , as_dict=1) - item_info.setdefault('serial_no', serial_no) - item_info.setdefault('batch_no', batch_no) - item_info.setdefault('barcode', barcode) - - return { 'items': [item_info] } - - condition = get_conditions(item_code, serial_no, batch_no, barcode) + condition = get_conditions(search_term) condition += get_item_group_condition(pos_profile) lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt']) @@ -106,14 +120,10 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va }) result.append(row) - res = { - 'items': result - } - - return res + return {'items': result} @frappe.whitelist() -def search_serial_or_batch_or_barcode_number(search_value): +def search_for_serial_or_batch_or_barcode_number(search_value): # search barcode no barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['barcode', 'parent as item_code'], as_dict=True) if barcode_data: @@ -139,27 +149,21 @@ def filter_service_items(items): return items -def get_conditions(item_code, serial_no, batch_no, barcode): - if serial_no or batch_no or barcode: - return "item.name = {0}".format(frappe.db.escape(item_code)) - - return make_condition(item_code) - -def make_condition(item_code): +def get_conditions(search_term): condition = "(" - condition += """item.name like {item_code} - or item.item_name like {item_code}""".format(item_code = frappe.db.escape('%' + item_code + '%')) - condition += add_search_fields_condition(item_code) + condition += """item.name like {search_term} + or item.item_name like {search_term}""".format(search_term=frappe.db.escape('%' + search_term + '%')) + condition += add_search_fields_condition(search_term) condition += ")" return condition -def add_search_fields_condition(item_code): +def add_search_fields_condition(search_term): condition = '' search_fields = frappe.get_all('POS Search Fields', fields = ['fieldname']) if search_fields: for field in search_fields: - condition += " or item.{0} like {1}".format(field['fieldname'], frappe.db.escape('%' + item_code + '%')) + condition += " or item.`{0}` like {1}".format(field['fieldname'], frappe.db.escape('%' + search_term + '%')) return condition def get_item_group_condition(pos_profile): diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js index 5b48725d9c..3e3377e5dc 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_selector.js +++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js @@ -51,7 +51,7 @@ erpnext.PointOfSale.ItemSelector = class { }); } - get_items({start = 0, page_length = 40, search_value=''}) { + get_items({start = 0, page_length = 40, search_term=''}) { const doc = this.events.get_frm().doc; const price_list = (doc && doc.selling_price_list) || this.price_list; let { item_group, pos_profile } = this; @@ -61,7 +61,7 @@ erpnext.PointOfSale.ItemSelector = class { return frappe.call({ method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items", freeze: true, - args: { start, page_length, price_list, item_group, search_value, pos_profile }, + args: { start, page_length, price_list, item_group, search_term, pos_profile }, }); } @@ -302,7 +302,7 @@ erpnext.PointOfSale.ItemSelector = class { } } - this.get_items({ search_value: search_term }) + this.get_items({ search_term }) .then(({ message }) => { // eslint-disable-next-line no-unused-vars const { items, serial_no, batch_no, barcode } = message; From 81b9a5ee4776613ad8720e7004267a82037715f4 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 3 Jun 2021 12:59:09 +0530 Subject: [PATCH 142/180] fix(pos): cannot cancel consolidated sales invoice --- erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 1808005f62..f813425e6b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -17,7 +17,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte var me = this; this._super(); - this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet']; + this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log', 'POS Closing Entry']; if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) { // show debit_to in print format this.frm.set_df_property("debit_to", "print_hide", 0); From 10558344b0fa25b12f71fda9ca21bb8c5170cb83 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 27 May 2021 17:05:36 +0530 Subject: [PATCH 143/180] fix: timeout error in the repost item valuation --- erpnext/hooks.py | 4 +++- .../repost_item_valuation/repost_item_valuation.py | 13 ++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 55169dffba..8ad77a1524 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -332,7 +332,9 @@ scheduler_events = { "erpnext.projects.doctype.project.project.collect_project_status", "erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts", "erpnext.support.doctype.issue.issue.set_service_level_agreement_variance", - "erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders", + "erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders" + ], + "hourly_long": [ "erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries" ], "daily": [ diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index 5b626ea345..55f2ebb224 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -37,6 +37,9 @@ class RepostItemValuation(Document): self.db_set('status', status) def on_submit(self): + if not frappe.flags.in_test: + return + frappe.enqueue(repost, timeout=1800, queue='long', job_name='repost_sle', now=frappe.flags.in_test, doc=self) @@ -115,12 +118,6 @@ def notify_error_to_stock_managers(doc, traceback): frappe.sendmail(recipients=recipients, subject=subject, message=message) def repost_entries(): - job_log = frappe.get_all('Scheduled Job Log', fields = ['status', 'creation'], - filters = {'scheduled_job_type': 'repost_item_valuation.repost_entries'}, order_by='creation desc', limit=1) - - if job_log and job_log[0]['status'] == 'Start' and time_diff_in_hours(now(), job_log[0]['creation']) < 2: - return - riv_entries = get_repost_item_valuation_entries() for row in riv_entries: @@ -135,9 +132,7 @@ def repost_entries(): check_if_stock_and_account_balance_synced(today(), d.name) def get_repost_item_valuation_entries(): - date = add_to_date(now(), hours=-3) - return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation` WHERE status != 'Completed' and creation <= %s and docstatus = 1 ORDER BY timestamp(posting_date, posting_time) asc, creation asc - """, date, as_dict=1) + """, now(), as_dict=1) From c59371ab0c500d9d863db334931d527e8face6eb Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 3 Jun 2021 20:02:58 +0530 Subject: [PATCH 144/180] fix: filter type for item query (#25942) --- erpnext/controllers/queries.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 638503edfa..81ac234e70 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe import erpnext +import json from frappe.desk.reportview import get_match_cond, get_filters_cond from frappe.utils import nowdate, getdate from collections import defaultdict @@ -198,6 +199,9 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters): def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): conditions = [] + if isinstance(filters, str): + filters = json.loads(filters) + #Get searchfields from meta and use in Item Link field query meta = frappe.get_meta("Item", cached=True) searchfields = meta.get_search_fields() From c6e016e5452950f393348710f6872febc9f9fb04 Mon Sep 17 00:00:00 2001 From: Saqib Date: Fri, 4 Jun 2021 10:08:22 +0530 Subject: [PATCH 145/180] fix: wrong round off gl entry posted in case of purchase invoice (#25775) --- erpnext/accounts/general_ledger.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index f1717c50d8..d4b249429b 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -185,10 +185,10 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision): for d in gl_map: if d.account == round_off_account: round_off_gle = d - if d.debit_in_account_currency: - debit_credit_diff -= flt(d.debit_in_account_currency) + if d.debit: + debit_credit_diff -= flt(d.debit) else: - debit_credit_diff += flt(d.credit_in_account_currency) + debit_credit_diff += flt(d.credit) round_off_account_exists = True if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)): From af4794b2d13b9499bff8333e1cb0b479e8405032 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 4 Jun 2021 10:53:44 +0530 Subject: [PATCH 146/180] fix: custom conversion factor field not mapped from job card to stock entry --- erpnext/manufacturing/doctype/job_card/job_card.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index fb26062566..d764db33f8 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -433,7 +433,8 @@ def make_material_request(source_name, target_doc=None): def make_stock_entry(source_name, target_doc=None): def update_item(obj, target, source_parent): target.t_warehouse = source_parent.wip_warehouse - target.conversion_factor = 1 + if not target.conversion_factor: + target.conversion_factor = 1 def set_missing_values(source, target): target.purpose = "Material Transfer for Manufacture" From 3f45901f257f69d9e3155507da020c18c5155cdc Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 4 Jun 2021 11:16:38 +0530 Subject: [PATCH 147/180] fix: invalid 'depends_on' expression in opportunity (#25955) --- erpnext/crm/doctype/opportunity/opportunity.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 2e09a76c0f..4ba4140244 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -280,7 +280,6 @@ "read_only": 1 }, { - "depends_on": "eval:", "fieldname": "territory", "fieldtype": "Link", "label": "Territory", @@ -431,7 +430,7 @@ "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2021-01-06 19:42:46.190051", + "modified": "2021-06-04 10:11:22.831139", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", From 215516f81940c5e743380d4f97a13eda7d9969be Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 4 Jun 2021 13:09:14 +0530 Subject: [PATCH 148/180] fix: AttributeError: 'PurchaseReceiptItem' object has no attribute 'purchase_invoice' (#25902) (#25957) * fix: AttributeError: 'PurchaseReceiptItem' object has no attribute 'purchase_invoice' This error occurs when upgrading from erpnext 13.0.1 to 13.4.0 after typing bench update --patch --reset * fix(minor): use .get instead of getattr Co-authored-by: D Tim Cummings --- erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index f1292d8cbd..83ba324495 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -497,7 +497,7 @@ class PurchaseReceipt(BuyingController): def update_billing_status(self, update_modified=True): updated_pr = [self.name] for d in self.get("items"): - if d.purchase_invoice and d.purchase_invoice_item: + if d.get("purchase_invoice") and d.get("purchase_invoice_item"): d.db_set('billed_amt', d.amount, update_modified=update_modified) elif d.purchase_order_item: updated_pr += update_billed_amount_based_on_po(d.purchase_order_item, update_modified) @@ -748,4 +748,3 @@ def get_item_account_wise_additional_cost(purchase_document): account.base_amount * item.get(based_on_field) / total_item_cost return item_account_wise_cost - From 8a7e283926d51626d9114eaa4f6647b920ad8c9f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 4 Jun 2021 22:53:26 +0530 Subject: [PATCH 149/180] feat: Item Taxes based on net rate --- erpnext/controllers/taxes_and_totals.py | 4 +- .../public/js/controllers/taxes_and_totals.js | 90 ++++++++++++++++--- erpnext/public/js/controllers/transaction.js | 66 +------------- erpnext/stock/doctype/item/item.py | 6 ++ erpnext/stock/doctype/item_tax/item_tax.json | 20 ++++- erpnext/stock/get_item_details.py | 34 +++++-- 6 files changed, 137 insertions(+), 83 deletions(-) diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 9fae49482d..8040435634 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -54,6 +54,7 @@ class calculate_taxes_and_totals(object): if item.item_code and item.get('item_tax_template'): item_doc = frappe.get_cached_doc("Item", item.item_code) args = { + 'net_rate': item.net_rate or item.rate, 'tax_category': self.doc.get('tax_category'), 'posting_date': self.doc.get('posting_date'), 'bill_date': self.doc.get('bill_date'), @@ -78,7 +79,8 @@ class calculate_taxes_and_totals(object): taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True) if item.item_tax_template not in taxes: - frappe.throw(_("Row {0}: Invalid Item Tax Template for item {1}").format( + item.item_tax_template = taxes[0] + frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format( item.idx, frappe.bold(item.item_code) )) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 2e133bed2e..ff4898eeff 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -12,7 +12,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) { effective_item_rate = item.blanket_order_rate; } - if(item.margin_type == "Percentage"){ + if(item.margin_type == "Percentage") { item.rate_with_margin = flt(effective_item_rate) + flt(effective_item_rate) * ( flt(item.margin_rate_or_amount) / 100); } else { @@ -73,15 +73,18 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ }, _calculate_taxes_and_totals: function() { - this.validate_conversion_rate(); - this.calculate_item_values(); - this.initialize_taxes(); - this.determine_exclusive_rate(); - this.calculate_net_total(); - this.calculate_taxes(); - this.manipulate_grand_total_for_inclusive_tax(); - this.calculate_totals(); - this._cleanup(); + frappe.run_serially([ + () => this.validate_conversion_rate(), + () => this.calculate_item_values(), + () => this.update_item_tax_map(), + () => this.initialize_taxes(), + () => this.determine_exclusive_rate(), + () => this.calculate_net_total(), + () => this.calculate_taxes(), + () => this.manipulate_grand_total_for_inclusive_tax(), + () => this.calculate_totals(), + () => this._cleanup() + ]); }, validate_conversion_rate: function() { @@ -263,6 +266,68 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]); }, + update_item_tax_map: function() { + let me = this; + let item_codes = []; + let item_rates = {}; + $.each(this.frm.doc.items || [], function(i, item) { + if(item.item_code) { + // Use combination of name and item code in case same item is added multiple times + item_codes.push([item.item_code, item.name]); + item_rates[item.name] = item.net_rate; + } + }); + + if(item_codes.length) { + return this.frm.call({ + method: "erpnext.stock.get_item_details.get_item_tax_info", + args: { + company: me.frm.doc.company, + tax_category: cstr(me.frm.doc.tax_category), + item_codes: item_codes, + item_rates: item_rates + }, + callback: function(r) { + if(!r.exc) { + $.each(me.frm.doc.items || [], function(i, item) { + if(item.name && r.message.hasOwnProperty(item.name)) { + item.item_tax_template = r.message[item.name].item_tax_template; + item.item_tax_rate = r.message[item.name].item_tax_rate; + me.add_taxes_from_item_tax_template(item.item_tax_rate); + } + else { + item.item_tax_template = ""; + item.item_tax_rate = "{}"; + } + }); + } + + this.frm.refresh_fields(); + } + }); + } + }, + + add_taxes_from_item_tax_template: function(item_tax_map) { + let me = this; + + if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { + if(typeof (item_tax_map) == "string") { + item_tax_map = JSON.parse(item_tax_map); + } + + $.each(item_tax_map, function(tax, rate) { + let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); + if(!found) { + let child = frappe.model.add_child(me.frm.doc, "taxes"); + child.charge_type = "On Net Total"; + child.account_head = tax; + child.rate = 0; + } + }); + } + }, + calculate_taxes: function() { var me = this; this.frm.doc.rounding_adjustment = 0; @@ -406,6 +471,11 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ let tax_detail = tax.item_wise_tax_detail; let key = item.item_code || item.item_name; + if(typeof (tax_detail) == "string") { + tax.item_wise_tax_detail = JSON.parse(tax.item_wise_tax_detail); + tax_detail = tax.item_wise_tax_detail; + } + let item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate; if (tax_detail && tax_detail[key]) item_wise_tax_amount += tax_detail[key][1]; diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ad1976d2d2..ee6696b7d1 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -6,6 +6,7 @@ frappe.provide('erpnext.accounts.dimensions'); erpnext.TransactionController = erpnext.taxes_and_totals.extend({ setup: function() { this._super(); + let me = this; frappe.flags.hide_serial_batch_dialog = true; frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); @@ -43,8 +44,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ cur_frm.cscript.calculate_stock_uom_rate(frm, cdt, cdn); }); - - frappe.ui.form.on(this.frm.cscript.tax_table, "rate", function(frm, cdt, cdn) { cur_frm.cscript.calculate_taxes_and_totals(); }); @@ -121,7 +120,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }); - var me = this; if(this.frm.fields_dict["items"].grid.get_field('batch_no')) { this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) { return me.set_query_for_batch(doc, cdt, cdn); @@ -556,6 +554,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ name: me.frm.doc.name, project: item.project || me.frm.doc.project, qty: item.qty || 1, + net_rate: item.rate, stock_qty: item.stock_qty, conversion_factor: item.conversion_factor, weight_per_unit: item.weight_per_unit, @@ -712,26 +711,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }); }, - add_taxes_from_item_tax_template: function(item_tax_map) { - let me = this; - - if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { - if(typeof (item_tax_map) == "string") { - item_tax_map = JSON.parse(item_tax_map); - } - - $.each(item_tax_map, function(tax, rate) { - let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); - if(!found) { - let child = frappe.model.add_child(me.frm.doc, "taxes"); - child.charge_type = "On Net Total"; - child.account_head = tax; - child.rate = 0; - } - }); - } - }, - serial_no: function(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); @@ -835,9 +814,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ frappe.run_serially([ () => me.frm.script_manager.trigger("currency"), - () => me.update_item_tax_map(), () => me.apply_default_taxes(), - () => me.apply_pricing_rule() + () => me.apply_pricing_rule(), + () => me.calculate_taxes_and_totals() ]); } } @@ -1816,7 +1795,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ callback: function(r) { if(!r.exc) { item.item_tax_rate = r.message; - me.add_taxes_from_item_tax_template(item.item_tax_rate); me.calculate_taxes_and_totals(); } } @@ -1827,43 +1805,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }, - update_item_tax_map: function() { - var me = this; - var item_codes = []; - $.each(this.frm.doc.items || [], function(i, item) { - if(item.item_code) { - item_codes.push(item.item_code); - } - }); - if(item_codes.length) { - return this.frm.call({ - method: "erpnext.stock.get_item_details.get_item_tax_info", - args: { - company: me.frm.doc.company, - tax_category: cstr(me.frm.doc.tax_category), - item_codes: item_codes - }, - callback: function(r) { - if(!r.exc) { - $.each(me.frm.doc.items || [], function(i, item) { - if(item.item_code && r.message.hasOwnProperty(item.item_code)) { - if (!item.item_tax_template) { - item.item_tax_template = r.message[item.item_code].item_tax_template; - item.item_tax_rate = r.message[item.item_code].item_tax_rate; - } - me.add_taxes_from_item_tax_template(item.item_tax_rate); - } else { - item.item_tax_template = ""; - item.item_tax_rate = "{}"; - } - }); - me.calculate_taxes_and_totals(); - } - } - }); - } - }, is_recurring: function() { // set default values for recurring documents diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index dbac79465e..60f468e82e 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -128,6 +128,7 @@ class Item(WebsiteGenerator): self.validate_auto_reorder_enabled_in_stock_settings() self.cant_change() self.update_show_in_website() + self.validate_item_tax_net_rate_range() if not self.get("__islocal"): self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group") @@ -490,6 +491,11 @@ class Item(WebsiteGenerator): if self.disabled: self.show_in_website = False + def validate_item_tax_net_rate_range(self): + for tax in self.get('taxes'): + if tax.maximum_net_rate < tax.minimum_net_rate: + frappe.throw(_("Row #{0}: Maximum Net Rate cannot be greater than Minimum Net Rate")) + def update_template_tables(self): template = frappe.get_doc("Item", self.variant_of) diff --git a/erpnext/stock/doctype/item_tax/item_tax.json b/erpnext/stock/doctype/item_tax/item_tax.json index ae36efc7e3..fb100967f3 100644 --- a/erpnext/stock/doctype/item_tax/item_tax.json +++ b/erpnext/stock/doctype/item_tax/item_tax.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2013-02-22 01:28:01", "doctype": "DocType", "editable_grid": 1, @@ -6,7 +7,9 @@ "field_order": [ "item_tax_template", "tax_category", - "valid_from" + "valid_from", + "minimum_net_rate", + "maximum_net_rate" ], "fields": [ { @@ -33,11 +36,24 @@ "fieldtype": "Date", "in_list_view": 1, "label": "Valid From" + }, + { + "fieldname": "maximum_net_rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Maximum Net Rate" + }, + { + "fieldname": "minimum_net_rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Minimum Net Rate" } ], "idx": 1, "istable": 1, - "modified": "2020-06-25 01:40:28.859752", + "links": [], + "modified": "2021-06-03 13:20:06.982303", "modified_by": "Administrator", "module": "Stock", "name": "Item Tax", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index d1dcdc21c8..6f510539a4 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -436,18 +436,22 @@ def get_barcode_data(items_list): return itemwise_barcode @frappe.whitelist() -def get_item_tax_info(company, tax_category, item_codes): +def get_item_tax_info(company, tax_category, item_codes, item_rates=None): out = {} if isinstance(item_codes, string_types): item_codes = json.loads(item_codes) + if isinstance(item_rates, string_types): + item_rates = json.loads(item_rates) + for item_code in item_codes: - if not item_code or item_code in out: + if not item_code or item_code[1] in out: continue - out[item_code] = {} - item = frappe.get_cached_doc("Item", item_code) - get_item_tax_template({"company": company, "tax_category": tax_category}, item, out[item_code]) - out[item_code]["item_tax_rate"] = get_item_tax_map(company, out[item_code].get("item_tax_template"), as_json=True) + out[item_code[1]] = {} + item = frappe.get_cached_doc("Item", item_code[0]) + args = {"company": company, "tax_category": tax_category, "net_rate": item_rates[item_code[1]]} + get_item_tax_template(args, item, out[item_code[1]]) + out[item_code[1]]["item_tax_rate"] = get_item_tax_map(company, out[item_code[1]].get("item_tax_template"), as_json=True) return out @@ -478,12 +482,13 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False): for tax in taxes: tax_company = frappe.get_value("Item Tax Template", tax.item_tax_template, 'company') - if tax.valid_from and tax_company == args['company']: + if (tax.valid_from or tax.maximum_net_rate) and tax_company == args['company']: # In purchase Invoice first preference will be given to supplier invoice date # if supplier date is not present then posting date validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date') - if getdate(tax.valid_from) <= getdate(validation_date): + if getdate(tax.valid_from) <= getdate(validation_date) \ + and is_within_valid_range(args, tax): taxes_with_validity.append(tax) else: if tax_company == args['company']: @@ -502,12 +507,25 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False): if not taxes_with_validity and (not taxes_with_no_validity): return None + # do not change if already a valid template + if args.get('item_tax_template') in taxes: + return arg.get('item_tax_template') + for tax in taxes: if cstr(tax.tax_category) == cstr(args.get("tax_category")): out["item_tax_template"] = tax.item_tax_template return tax.item_tax_template return None +def is_within_valid_range(args, tax): + if not flt(tax.maximum_net_rate): + # No range specified, just ignore + return True + elif flt(tax.minimum_net_rate) <= flt(args.get('net_rate')) <= flt(tax.maximum_net_rate): + return True + + return False + @frappe.whitelist() def get_item_tax_map(company, item_tax_template, as_json=True): item_tax_map = {} From e8a78bd43d027ea36ff2902ecf48835b76109038 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 5 Jun 2021 13:16:39 +0530 Subject: [PATCH 150/180] fix: Add test cases --- .../sales_invoice/test_sales_invoice.py | 69 +++++++++++++------ erpnext/stock/doctype/item/item.py | 2 +- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index df6d483904..1b1bb3b18f 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1963,6 +1963,54 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(value_details['TotInvVal'], si.base_grand_total) self.assertTrue(einvoice['EwbDtls']) + def test_item_tax_validity(self): + item = frappe.get_doc("Item", "_Test Item 2") + + if item.taxes: + item.taxes = [] + item.save() + + item.append("taxes", { + "item_tax_template": "_Test Item Tax Template 1 - _TC", + "valid_from": add_days(nowdate(), 1) + }) + + item.save() + + sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1) + sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC" + self.assertRaises(frappe.ValidationError, sales_invoice.save) + + item.taxes = [] + item.save() + + def test_item_tax_net_range(self): + item = create_item("T Shirt") + + item.set('taxes', []) + item.append("taxes", { + "item_tax_template": "_Test Account Excise Duty @ 10 - _TC", + "minimum_net_rate": 0, + "maximum_net_rate": 500 + }) + + item.append("taxes", { + "item_tax_template": "_Test Account Excise Duty @ 12 - _TC", + "minimum_net_rate": 501, + "maximum_net_rate": 1000 + }) + + item.save() + + sales_invoice = create_sales_invoice(item = "T Shirt", rate=700, do_not_submit=True) + self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC") + + # Apply discount + sales_invoice.apply_discount_on = 'Net Total' + sales_invoice.discount_amount = 300 + sales_invoice.save() + self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC") + def make_test_address_for_ewaybill(): if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'): address = frappe.get_doc({ @@ -2085,27 +2133,6 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date): doc.assertEqual(expected_gle[i][2], gle.credit) doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) - def test_item_tax_validity(self): - item = frappe.get_doc("Item", "_Test Item 2") - - if item.taxes: - item.taxes = [] - item.save() - - item.append("taxes", { - "item_tax_template": "_Test Item Tax Template 1 - _TC", - "valid_from": add_days(nowdate(), 1) - }) - - item.save() - - sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1) - sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC" - self.assertRaises(frappe.ValidationError, sales_invoice.save) - - item.taxes = [] - item.save() - def create_sales_invoice(**args): si = frappe.new_doc("Sales Invoice") args = frappe._dict(args) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 60f468e82e..0420ea7c54 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -493,7 +493,7 @@ class Item(WebsiteGenerator): def validate_item_tax_net_rate_range(self): for tax in self.get('taxes'): - if tax.maximum_net_rate < tax.minimum_net_rate: + if flt(tax.maximum_net_rate) < flt(tax.minimum_net_rate): frappe.throw(_("Row #{0}: Maximum Net Rate cannot be greater than Minimum Net Rate")) def update_template_tables(self): From 3646c301edc1380efcd0eedcd590e8124dfe90d8 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 5 Jun 2021 13:21:03 +0530 Subject: [PATCH 151/180] fix: Linting issues --- .../public/js/controllers/taxes_and_totals.js | 25 +++++++++---------- erpnext/stock/get_item_details.py | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index ff4898eeff..0b9d771119 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -12,7 +12,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) { effective_item_rate = item.blanket_order_rate; } - if(item.margin_type == "Percentage") { + if (item.margin_type == "Percentage") { item.rate_with_margin = flt(effective_item_rate) + flt(effective_item_rate) * ( flt(item.margin_rate_or_amount) / 100); } else { @@ -22,7 +22,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ item_rate = flt(item.rate_with_margin , precision("rate", item)); - if(item.discount_percentage){ + if (item.discount_percentage) { item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100; } @@ -271,14 +271,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ let item_codes = []; let item_rates = {}; $.each(this.frm.doc.items || [], function(i, item) { - if(item.item_code) { + if (item.item_code) { // Use combination of name and item code in case same item is added multiple times item_codes.push([item.item_code, item.name]); item_rates[item.name] = item.net_rate; } }); - if(item_codes.length) { + if (item_codes.length) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_item_tax_info", args: { @@ -288,21 +288,18 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ item_rates: item_rates }, callback: function(r) { - if(!r.exc) { + if (!r.exc) { $.each(me.frm.doc.items || [], function(i, item) { - if(item.name && r.message.hasOwnProperty(item.name)) { + if (item.name && r.message.hasOwnProperty(item.name)) { item.item_tax_template = r.message[item.name].item_tax_template; item.item_tax_rate = r.message[item.name].item_tax_rate; me.add_taxes_from_item_tax_template(item.item_tax_rate); - } - else { + } else { item.item_tax_template = ""; item.item_tax_rate = "{}"; } }); } - - this.frm.refresh_fields(); } }); } @@ -311,14 +308,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ add_taxes_from_item_tax_template: function(item_tax_map) { let me = this; - if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { - if(typeof (item_tax_map) == "string") { + if (item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { + if (typeof (item_tax_map) == "string") { item_tax_map = JSON.parse(item_tax_map); } $.each(item_tax_map, function(tax, rate) { let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); - if(!found) { + if (!found) { let child = frappe.model.add_child(me.frm.doc, "taxes"); child.charge_type = "On Net Total"; child.account_head = tax; @@ -632,6 +629,8 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail); }); } + + this.frm.refresh_fields(); }, set_discount_amount: function() { diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 6f510539a4..746cbbf601 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -509,7 +509,7 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False): # do not change if already a valid template if args.get('item_tax_template') in taxes: - return arg.get('item_tax_template') + return args.get('item_tax_template') for tax in taxes: if cstr(tax.tax_category) == cstr(args.get("tax_category")): From a85c2c16b42d0ba5bc5f0157eaf87a062052ab6b Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sun, 6 Jun 2021 11:07:20 +0530 Subject: [PATCH 152/180] fix(pos): item rate precision in item selector --- erpnext/selling/page/point_of_sale/pos_item_selector.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js index 3e3377e5dc..64c529ee4a 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_selector.js +++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js @@ -80,6 +80,7 @@ erpnext.PointOfSale.ItemSelector = class { // eslint-disable-next-line no-unused-vars const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item; const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange"; + const precision = flt(price_list_rate, 2) % 1 != 0 ? 2 : 0; let qty_to_display = actual_qty; @@ -121,7 +122,7 @@ erpnext.PointOfSale.ItemSelector = class {
${frappe.ellipsis(item.item_name, 18)}
-
${format_currency(price_list_rate, item.currency, 0) || 0}
+
${format_currency(price_list_rate, item.currency, precision) || 0}
` ); From bc46a9772d7daaa50d0ecdac301e604cb43b5878 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sun, 6 Jun 2021 11:11:07 +0530 Subject: [PATCH 153/180] fix(pos): cash shortcuts not working --- erpnext/selling/page/point_of_sale/pos_payment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js index 600f160490..156fb777fe 100644 --- a/erpnext/selling/page/point_of_sale/pos_payment.js +++ b/erpnext/selling/page/point_of_sale/pos_payment.js @@ -171,7 +171,7 @@ erpnext.PointOfSale.Payment = class { this.setup_listener_for_payments(); - this.$payment_modes.on('click', '.shortcut', () => { + this.$payment_modes.on('click', '.shortcut', function() { const value = $(this).attr('data-value'); me.selected_mode.set_value(value); }); From 3f32969bee847e9a3abfc89ae2c7c84c07a7e53e Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sun, 6 Jun 2021 11:18:20 +0530 Subject: [PATCH 154/180] fix(pos): broken image in item details section --- .../selling/page/point_of_sale/pos_item_details.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index df62696c4b..5e09df8efe 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -133,13 +133,24 @@ erpnext.PointOfSale.ItemDetails = class { this.$item_description.html(get_description_html()); this.$item_price.html(format_currency(price_list_rate, this.currency)); if (image) { - this.$item_image.html(`${image}`); + this.$item_image.html( + `${frappe.get_abbr(item_name)}` + ); } else { this.$item_image.html(`
${frappe.get_abbr(item_name)}
`); } } + handle_broken_image($img) { + const item_abbr = $($img).attr('alt'); + $($img).replaceWith(`
${item_abbr}
`); + } + render_discount_dom(item) { if (item.discount_percentage) { this.$dicount_section.html( From 18be767f75b9c858fa66294d037f1a9b9d2c6ace Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 6 Jun 2021 13:25:34 +0530 Subject: [PATCH 155/180] fix: Remove invalid test --- .../sales_invoice/test_sales_invoice.py | 21 ------------------- erpnext/controllers/taxes_and_totals.py | 11 +++++----- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 1b1bb3b18f..0d61f67e52 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1963,27 +1963,6 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(value_details['TotInvVal'], si.base_grand_total) self.assertTrue(einvoice['EwbDtls']) - def test_item_tax_validity(self): - item = frappe.get_doc("Item", "_Test Item 2") - - if item.taxes: - item.taxes = [] - item.save() - - item.append("taxes", { - "item_tax_template": "_Test Item Tax Template 1 - _TC", - "valid_from": add_days(nowdate(), 1) - }) - - item.save() - - sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1) - sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC" - self.assertRaises(frappe.ValidationError, sales_invoice.save) - - item.taxes = [] - item.save() - def test_item_tax_net_range(self): item = create_item("T Shirt") diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 8040435634..fb22a1d608 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -78,11 +78,12 @@ class calculate_taxes_and_totals(object): taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True) - if item.item_tax_template not in taxes: - item.item_tax_template = taxes[0] - frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format( - item.idx, frappe.bold(item.item_code) - )) + if taxes: + if item.item_tax_template not in taxes: + item.item_tax_template = taxes[0] + frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format( + item.idx, frappe.bold(item.item_code) + )) def validate_conversion_rate(self): # validate conversion rate From 7a20c3b92ae05395bf75703a1e6aaad31f537a79 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 6 Jun 2021 19:23:21 +0530 Subject: [PATCH 156/180] fix: Ignore internal transfer inoices from GST Reports --- erpnext/regional/report/gstr_1/gstr_1.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index b7c096248f..80e2d725a2 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -147,6 +147,13 @@ class Gstr1Report(object): def get_invoice_data(self): self.invoices = frappe._dict() conditions = self.get_conditions() + + company_gstins = get_company_gstin_number(self.filters.get('company'), all_gstins=True) + + self.filters.update({ + 'company_gstins': company_gstins + }) + invoice_data = frappe.db.sql(""" select {select_columns} @@ -193,6 +200,9 @@ class Gstr1Report(object): elif self.filters.get("type_of_business") == "EXPORT": conditions += """ AND is_return !=1 and gst_category = 'Overseas' """ + + conditions += " AND billing_address_gstin NOT IN %(company_gstins)s" + return conditions def get_invoice_items(self): @@ -810,7 +820,8 @@ def get_rate_and_tax_details(row, gstin): return {"num": int(num), "itm_det": itm_det} -def get_company_gstin_number(company, address=None): +def get_company_gstin_number(company, address=None, all_gstins=False): + gstin = '' if address: gstin = frappe.db.get_value("Address", address, "gstin") @@ -822,9 +833,9 @@ def get_company_gstin_number(company, address=None): ["Dynamic Link", "parenttype", "=", "Address"], ] gstin = frappe.get_all("Address", filters=filters, pluck="gstin") - if gstin: - gstin[0] - + if gstin and not all_gstins: + gstin = gstin[0] + if not gstin: address = frappe.bold(address) if address else "" frappe.throw(_("Please set valid GSTIN No. in Company Address {} for company {}").format( From d4398fd84aee28ef82c98ab44d42082550195c39 Mon Sep 17 00:00:00 2001 From: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com> Date: Mon, 7 Jun 2021 16:20:21 +0530 Subject: [PATCH 157/180] fix: update cost center from pos (#25971) --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 023f4b049c..f8b5179d2c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -531,7 +531,7 @@ class SalesInvoice(SellingController): # set pos values in items for item in self.get("items"): if item.get('item_code'): - profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos) + profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos, update_data=True) for fname, val in iteritems(profile_details): if (not for_validate) or (for_validate and not item.get(fname)): item.set(fname, val) From 447c978757ffeef8ebaeedc2dd34124ed9b45fff Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Fri, 28 May 2021 21:28:42 +0530 Subject: [PATCH 158/180] fix: choose correct Salary Structure Assignment when getting data for formula eval --- .../doctype/salary_slip/salary_slip.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index afdf081ac8..cc9e8d1043 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -493,8 +493,28 @@ class SalarySlip(TransactionBase): '''Returns data for evaluating formula''' data = frappe._dict() + salary_structure_assignment = frappe.get_value( + "Salary Structure Assignment", + { + "employee": self.employee, + "salary_structure": self.salary_structure, + "from_date": ("<=", self.start_date), + "docstatus": 1, + }, + order_by="from_date desc", + ) + + if not salary_structure_assignment: + frappe.throw( + _("Please assign a Salary Structure for Employee {0} " + "applicable from or before {1} first").format( + frappe.bold(self.employee_name), + frappe.bold(self.start_date) + ) + ) + data.update(frappe.get_doc("Salary Structure Assignment", - {"employee": self.employee, "salary_structure": self.salary_structure}).as_dict()) + salary_structure_assignment).as_dict()) data.update(frappe.get_doc("Employee", self.employee).as_dict()) data.update(self.as_dict()) From 74818c7b624534a39b647476587abb02f84b1e88 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Sat, 29 May 2021 00:04:26 +0530 Subject: [PATCH 159/180] fix: improve filter for `from_date`; validation for joining and relieving date --- .../doctype/salary_slip/salary_slip.py | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index cc9e8d1043..2b35d94dfc 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -115,10 +115,23 @@ class SalarySlip(TransactionBase): status = "Cancelled" return status - def validate_dates(self): + def validate_dates(self, joining_date=None, relieving_date=None): if date_diff(self.end_date, self.start_date) < 0: frappe.throw(_("To date cannot be before From date")) + if not joining_date: + joining_date, relieving_date = frappe.get_cached_value( + "Employee", + self.employee, + ("date_of_joining", "relieving_date") + ) + + if date_diff(self.end_date, joining_date) < 0: + frappe.throw(_("Cannot create Salary Slip for Employee joining after Payroll Period")) + + if relieving_date and date_diff(relieving_date, self.start_date) < 0: + frappe.throw(_("Cannot create Salary Slip for Employee who has left before Payroll Period")) + def is_rounding_total_disabled(self): return cint(frappe.db.get_single_value("Payroll Settings", "disable_rounded_total")) @@ -154,9 +167,14 @@ class SalarySlip(TransactionBase): if not self.salary_slip_based_on_timesheet: self.get_date_details() - self.validate_dates() - joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee, - ["date_of_joining", "relieving_date"]) + + joining_date, relieving_date = frappe.get_cached_value( + "Employee", + self.employee, + ("date_of_joining", "relieving_date") + ) + + self.validate_dates(joining_date, relieving_date) #getin leave details self.get_working_days_details(joining_date, relieving_date) @@ -492,13 +510,21 @@ class SalarySlip(TransactionBase): def get_data_for_eval(self): '''Returns data for evaluating formula''' data = frappe._dict() + employee = frappe.get_doc("Employee", self.employee).as_dict() + + start_date = getdate(self.start_date) + date_to_validate = ( + employee.date_of_joining + if employee.date_of_joining > start_date + else start_date + ) salary_structure_assignment = frappe.get_value( "Salary Structure Assignment", { "employee": self.employee, "salary_structure": self.salary_structure, - "from_date": ("<=", self.start_date), + "from_date": ("<=", date_to_validate), "docstatus": 1, }, order_by="from_date desc", @@ -509,14 +535,14 @@ class SalarySlip(TransactionBase): _("Please assign a Salary Structure for Employee {0} " "applicable from or before {1} first").format( frappe.bold(self.employee_name), - frappe.bold(self.start_date) + frappe.bold(formatdate(date_to_validate)), ) ) data.update(frappe.get_doc("Salary Structure Assignment", salary_structure_assignment).as_dict()) - data.update(frappe.get_doc("Employee", self.employee).as_dict()) + data.update(employee) data.update(self.as_dict()) # set values for components From 0e5e1350b241e9ac0b1c93b92da1d8999cd9723c Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Fri, 4 Jun 2021 13:51:45 +0530 Subject: [PATCH 160/180] perf: use frappe.get_value with wildcard instead of another frappe.get_doc call --- erpnext/payroll/doctype/salary_slip/salary_slip.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 2b35d94dfc..877503b41c 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -527,7 +527,9 @@ class SalarySlip(TransactionBase): "from_date": ("<=", date_to_validate), "docstatus": 1, }, + "*", order_by="from_date desc", + as_dict=True, ) if not salary_structure_assignment: @@ -539,9 +541,7 @@ class SalarySlip(TransactionBase): ) ) - data.update(frappe.get_doc("Salary Structure Assignment", - salary_structure_assignment).as_dict()) - + data.update(salary_structure_assignment) data.update(employee) data.update(self.as_dict()) From ca205be5ac62ff25815df81bde6e2a8a7852b26c Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 7 Jun 2021 18:40:54 +0530 Subject: [PATCH 161/180] fix: tests --- .../doctype/salary_slip/test_salary_slip.py | 51 +++++++++++-------- .../salary_structure/test_salary_structure.py | 39 +++++++++----- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 01e4170d31..9e7db977ab 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -8,7 +8,6 @@ import erpnext import calendar import random from erpnext.accounts.utils import get_fiscal_year -from frappe.utils.make_random import get_random from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day, cstr from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details @@ -155,12 +154,14 @@ class TestSalarySlip(unittest.TestCase): self.assertEqual(ss.gross_pay, 78000) def test_payment_days(self): + from erpnext.payroll.doctype.salary_structure.test_salary_structure import create_salary_structure_assignment + no_of_days = self.get_no_of_days() # Holidays not included in working days frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1) # set joinng date in the same month - make_employee("test_payment_days@salary.com") + employee = make_employee("test_payment_days@salary.com") if getdate(nowdate()).day >= 15: relieving_date = getdate(add_days(nowdate(),-10)) date_of_joining = getdate(add_days(nowdate(),-10)) @@ -174,25 +175,30 @@ class TestSalarySlip(unittest.TestCase): date_of_joining = getdate(nowdate()) relieving_date = getdate(nowdate()) - frappe.db.set_value("Employee", frappe.get_value("Employee", - {"employee_name":"test_payment_days@salary.com"}, "name"), "date_of_joining", date_of_joining) - frappe.db.set_value("Employee", frappe.get_value("Employee", - {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", None) - frappe.db.set_value("Employee", frappe.get_value("Employee", - {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Active") + frappe.db.set_value("Employee", employee, { + "date_of_joining": date_of_joining, + "relieving_date": None, + "status": "Active" + }) - ss = make_employee_salary_slip("test_payment_days@salary.com", "Monthly", "Test Payment Days") + salary_structure = "Test Payment Days" + ss = make_employee_salary_slip("test_payment_days@salary.com", "Monthly", salary_structure) self.assertEqual(ss.total_working_days, no_of_days[0]) self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1)) # set relieving date in the same month - frappe.db.set_value("Employee",frappe.get_value("Employee", - {"employee_name":"test_payment_days@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60))) - frappe.db.set_value("Employee", frappe.get_value("Employee", - {"employee_name":"test_payment_days@salary.com"}, "name"), "relieving_date", relieving_date) - frappe.db.set_value("Employee", frappe.get_value("Employee", - {"employee_name":"test_payment_days@salary.com"}, "name"), "status", "Left") + frappe.db.set_value("Employee", employee, { + "date_of_joining": add_days(nowdate(),-60), + "relieving_date": relieving_date, + "status": "Left" + }) + + if date_of_joining.day > 1: + self.assertRaises(frappe.ValidationError, ss.save) + + create_salary_structure_assignment(employee, salary_structure) + ss.reload() ss.save() self.assertEqual(ss.total_working_days, no_of_days[0]) @@ -285,6 +291,7 @@ class TestSalarySlip(unittest.TestCase): def test_multi_currency_salary_slip(self): from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + applicant = make_employee("test_multi_currency_salary_slip@salary.com", company="_Test Company") frappe.db.sql("""delete from `tabSalary Structure` where name='Test Multi Currency Salary Slip'""") salary_structure = make_salary_structure("Test Multi Currency Salary Slip", "Monthly", employee=applicant, company="_Test Company", currency='USD') @@ -325,7 +332,8 @@ class TestSalarySlip(unittest.TestCase): def test_component_wise_year_to_date_computation(self): from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure - applicant = make_employee("test_ytd@salary.com", company="_Test Company") + employee_name = "test_component_wise_ytd@salary.com" + applicant = make_employee(employee_name, company="_Test Company") payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company") @@ -336,13 +344,13 @@ class TestSalarySlip(unittest.TestCase): "Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period) # clear salary slip for this employee - frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'") + frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = '%s'" % employee_name) create_salary_slips_for_payroll_period(applicant, salary_structure.name, payroll_period, deduct_random=False, num=3) salary_slips = frappe.get_all("Salary Slip", fields=["name"], filters={"employee_name": - "test_ytd@salary.com"}, order_by = "posting_date") + employee_name}, order_by="posting_date") year_to_date = dict() for slip in salary_slips: @@ -380,10 +388,10 @@ class TestSalarySlip(unittest.TestCase): from erpnext.payroll.doctype.salary_structure.test_salary_structure import \ make_salary_structure, create_salary_structure_assignment + salary_structure = make_salary_structure("Stucture to test tax", "Monthly", - other_details={"max_benefits": 100000}, test_tax=True) - create_salary_structure_assignment(employee, salary_structure.name, - payroll_period.start_date) + other_details={"max_benefits": 100000}, test_tax=True, + employee=employee, payroll_period=payroll_period) # create salary slip for whole period deducting tax only on last period # to find the total tax amount paid @@ -469,6 +477,7 @@ class TestSalarySlip(unittest.TestCase): def make_employee_salary_slip(user, payroll_frequency, salary_structure=None): from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + if not salary_structure: salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip" diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index 36387f23df..26cd9922e4 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -6,7 +6,7 @@ import frappe import unittest import erpnext from frappe.utils.make_random import get_random -from frappe.utils import nowdate, add_days, add_years, getdate, add_months +from frappe.utils import nowdate, add_days, add_years, getdate, add_months, get_first_day, date_diff from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_earning_salary_component,\ make_deduction_salary_component, make_employee_salary_slip, create_tax_slab @@ -113,8 +113,9 @@ class TestSalaryStructure(unittest.TestCase): sal_struct = make_salary_structure("Salary Structure Multi Currency", "Monthly", currency='USD') self.assertEqual(sal_struct.currency, 'USD') -def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None, - test_tax=False, company=None, currency=erpnext.get_default_currency(), payroll_period=None): +def make_salary_structure(salary_structure, payroll_frequency, employee=None, + from_date=None, dont_submit=False, other_details=None,test_tax=False, + company=None, currency=erpnext.get_default_currency(), payroll_period=None): if test_tax: frappe.db.sql("""delete from `tabSalary Structure` where name=%s""",(salary_structure)) @@ -139,10 +140,23 @@ def make_salary_structure(salary_structure, payroll_frequency, employee=None, do else: salary_structure_doc = frappe.get_doc("Salary Structure", salary_structure) + filters = {'employee':employee, 'docstatus': 1} + if not from_date and payroll_period: + from_date = payroll_period.start_date + + if from_date: + filters['from_date'] = from_date + if employee and not frappe.db.get_value("Salary Structure Assignment", - {'employee':employee, 'docstatus': 1}) and salary_structure_doc.docstatus==1: - create_salary_structure_assignment(employee, salary_structure, company=company, currency=currency, - payroll_period=payroll_period) + filters) and salary_structure_doc.docstatus==1: + create_salary_structure_assignment( + employee, + salary_structure, + from_date=from_date, + company=company, + currency=currency, + payroll_period=payroll_period + ) return salary_structure_doc @@ -165,12 +179,13 @@ def create_salary_structure_assignment(employee, salary_structure, from_date=Non salary_structure_assignment.base = 50000 salary_structure_assignment.variable = 5000 - if getdate(nowdate()).day == 1: - date = from_date or nowdate() - else: - date = from_date or add_days(nowdate(), -1) + if not from_date: + from_date = get_first_day(nowdate()) + joining_date = frappe.get_cached_value("Employee", employee, "date_of_joining") + if date_diff(joining_date, from_date) > 0: + from_date = joining_date - salary_structure_assignment.from_date = date + salary_structure_assignment.from_date = from_date salary_structure_assignment.salary_structure = salary_structure salary_structure_assignment.currency = currency salary_structure_assignment.payroll_payable_account = get_payable_account(company) @@ -183,4 +198,4 @@ def create_salary_structure_assignment(employee, salary_structure, from_date=Non def get_payable_account(company=None): if not company: company = erpnext.get_default_company() - return frappe.db.get_value("Company", company, "default_payroll_payable_account") \ No newline at end of file + return frappe.db.get_value("Company", company, "default_payroll_payable_account") From 062e247353a2277727050c648a4633a2d24fb1b8 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 7 Jun 2021 19:34:02 +0530 Subject: [PATCH 162/180] test: remove unused imports --- .../payroll/doctype/salary_structure/test_salary_structure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index 26cd9922e4..dce6b7aa3d 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -6,7 +6,7 @@ import frappe import unittest import erpnext from frappe.utils.make_random import get_random -from frappe.utils import nowdate, add_days, add_years, getdate, add_months, get_first_day, date_diff +from frappe.utils import nowdate, add_years, get_first_day, date_diff from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_earning_salary_component,\ make_deduction_salary_component, make_employee_salary_slip, create_tax_slab From bbf07d9214bf86eb120a7ad14989b2bd21a5d9d7 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Tue, 8 Jun 2021 17:05:44 +0530 Subject: [PATCH 163/180] fix: quiz timer issues --- erpnext/education/utils.py | 13 +++++++------ erpnext/public/js/education/lms/quiz.js | 10 ++++------ erpnext/www/lms/content.html | 1 + 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/erpnext/education/utils.py b/erpnext/education/utils.py index 8f51fef847..9d5653c170 100644 --- a/erpnext/education/utils.py +++ b/erpnext/education/utils.py @@ -219,7 +219,6 @@ def get_quiz(quiz_name, course): try: quiz = frappe.get_doc("Quiz", quiz_name) questions = quiz.get_questions() - duration = quiz.duration except: frappe.throw(_("Quiz {0} does not exist").format(quiz_name), frappe.DoesNotExistError) return None @@ -236,15 +235,17 @@ def get_quiz(quiz_name, course): return { 'questions': questions, 'activity': None, - 'duration':duration + 'is_time_bound': quiz.is_time_bound, + 'duration': quiz.duration } student = get_current_student() course_enrollment = get_enrollment("course", course, student.name) status, score, result, time_taken = check_quiz_completion(quiz, course_enrollment) return { - 'questions': questions, + 'questions': questions, 'activity': {'is_complete': status, 'score': score, 'result': result, 'time_taken': time_taken}, + 'is_time_bound': quiz.is_time_bound, 'duration': quiz.duration } @@ -372,9 +373,9 @@ def check_content_completion(content_name, content_type, enrollment_name): def check_quiz_completion(quiz, enrollment_name): attempts = frappe.get_all("Quiz Activity", filters={ - 'enrollment': enrollment_name, + 'enrollment': enrollment_name, 'quiz': quiz.name - }, + }, fields=["name", "activity_date", "score", "status", "time_taken"] ) status = False if quiz.max_attempts == 0 else bool(len(attempts) >= quiz.max_attempts) @@ -389,4 +390,4 @@ def check_quiz_completion(quiz, enrollment_name): time_taken = attempts[0]['time_taken'] if result == 'Pass': status = True - return status, score, result, time_taken \ No newline at end of file + return status, score, result, time_taken diff --git a/erpnext/public/js/education/lms/quiz.js b/erpnext/public/js/education/lms/quiz.js index 32fa4ab1ec..5bb8425c85 100644 --- a/erpnext/public/js/education/lms/quiz.js +++ b/erpnext/public/js/education/lms/quiz.js @@ -20,10 +20,8 @@ class Quiz { } make(data) { - if (data.duration) { - const timer_display = document.createElement("div"); - timer_display.classList.add("lms-timer", "float-right", "font-weight-bold"); - document.getElementsByClassName("lms-title")[0].appendChild(timer_display); + if (data.is_time_bound) { + $(".lms-timer").removeClass("hide") if (!data.activity || (data.activity && !data.activity.is_complete)) { this.initialiseTimer(data.duration); this.is_time_bound = true; @@ -118,7 +116,7 @@ class Quiz { quiz_response: this.get_selected(), course: this.course, program: this.program, - time_taken: this.is_time_bound ? this.time_taken : "" + time_taken: this.is_time_bound ? this.time_taken : 0 }).then(res => { this.submit_btn.remove() if (!res.message) { @@ -237,4 +235,4 @@ class Question { this.options = option_list this.wrapper.appendChild(options_wrapper) } -} \ No newline at end of file +} diff --git a/erpnext/www/lms/content.html b/erpnext/www/lms/content.html index 15afb097b9..d22ef66d2a 100644 --- a/erpnext/www/lms/content.html +++ b/erpnext/www/lms/content.html @@ -64,6 +64,7 @@

{{ content.name }} ({{ position + 1 }}/{{length}})

+
{% endmacro %} From 0ea4d850e1c3870c750072e0ce89a6cd73605266 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Tue, 8 Jun 2021 17:23:44 +0530 Subject: [PATCH 164/180] fix: Allow all System Managers to delete company transactions (#25834) --- .../transaction_deletion_record.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py index 38f8de7a66..ece9fb5699 100644 --- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py +++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py @@ -12,10 +12,6 @@ from frappe.desk.notifications import clear_notifications class TransactionDeletionRecord(Document): def validate(self): frappe.only_for('System Manager') - company_obj = frappe.get_doc('Company', self.company) - if frappe.session.user != company_obj.owner and frappe.session.user != 'Administrator': - frappe.throw(_('Transactions can only be deleted by the creator of the Company or the Administrator.'), - frappe.PermissionError) doctypes_to_be_ignored_list = get_doctypes_to_be_ignored() for doctype in self.doctypes_to_be_ignored: if doctype.doctype_name not in doctypes_to_be_ignored_list: From 7ace06ac21c7d29d8470df139979c15f46a82ed1 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Tue, 8 Jun 2021 18:26:23 +0530 Subject: [PATCH 165/180] fix: sider --- erpnext/education/utils.py | 2 +- erpnext/public/js/education/lms/quiz.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/education/utils.py b/erpnext/education/utils.py index 9d5653c170..9db8a4a90d 100644 --- a/erpnext/education/utils.py +++ b/erpnext/education/utils.py @@ -245,7 +245,7 @@ def get_quiz(quiz_name, course): return { 'questions': questions, 'activity': {'is_complete': status, 'score': score, 'result': result, 'time_taken': time_taken}, - 'is_time_bound': quiz.is_time_bound, + 'is_time_bound': quiz.is_time_bound, 'duration': quiz.duration } diff --git a/erpnext/public/js/education/lms/quiz.js b/erpnext/public/js/education/lms/quiz.js index 5bb8425c85..66160a7610 100644 --- a/erpnext/public/js/education/lms/quiz.js +++ b/erpnext/public/js/education/lms/quiz.js @@ -21,7 +21,7 @@ class Quiz { make(data) { if (data.is_time_bound) { - $(".lms-timer").removeClass("hide") + $(".lms-timer").removeClass("hide"); if (!data.activity || (data.activity && !data.activity.is_complete)) { this.initialiseTimer(data.duration); this.is_time_bound = true; From 18eed58fc5afa1ef95037a1c297b308c34de58ee Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 8 Jun 2021 20:52:14 +0530 Subject: [PATCH 166/180] fix(e-invoicing): service item check --- erpnext/regional/india/e_invoice/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index 843fb012b9..a1179ff9b6 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -199,7 +199,7 @@ def get_item_list(invoice): item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None - item.is_service_item = 'N' if frappe.db.get_value('Item', d.item_code, 'is_stock_item') else 'Y' + item.is_service_item = 'Y' if item.gst_hsn_code[:2] == "99" else 'N' item.serial_no = "" item = update_item_taxes(invoice, item) From 99b583f688966cc89d069f8c5b7c4cf88108abb5 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 9 Jun 2021 00:06:35 +0530 Subject: [PATCH 167/180] fix: on click of duplicate button system copy the difference account from first row --- erpnext/stock/doctype/stock_entry/stock_entry.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 93a6fc0e0a..1a25994b24 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -986,7 +986,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ items_add: function(doc, cdt, cdn) { var row = frappe.get_doc(cdt, cdn); - this.frm.script_manager.copy_from_first_row("items", row, ["expense_account", "cost_center"]); + + if (!(row.expense_account && row.cost_center)) { + this.frm.script_manager.copy_from_first_row("items", row, ["expense_account", "cost_center"]); + } if(!row.s_warehouse) row.s_warehouse = this.frm.doc.from_warehouse; if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse; From 21b8e2f0d8f18972b05783eface42404cc104c30 Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Wed, 9 Jun 2021 12:57:21 +0530 Subject: [PATCH 168/180] fix: hiding Rounding Adjustment field (#25380) * fix: hiding Rounding Adjustment field * fix: updating purchase_invoice.json --- .../accounts/doctype/purchase_invoice/purchase_invoice.json | 4 +++- erpnext/buying/doctype/purchase_order/purchase_order.json | 4 +++- .../buying/doctype/supplier_quotation/supplier_quotation.json | 4 +++- erpnext/stock/doctype/purchase_receipt/purchase_receipt.json | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index d3d3ffa17f..9157821520 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -837,6 +837,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment (Company Currency)", @@ -883,6 +884,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment", @@ -1380,7 +1382,7 @@ "idx": 204, "is_submittable": 1, "links": [], - "modified": "2021-04-30 22:45:58.334107", + "modified": "2021-06-09 12:30:25.632109", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index ee2beea67f..8677c71bc5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -765,6 +765,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment (Company Currency)", @@ -810,6 +811,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment", @@ -1124,7 +1126,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-01-20 22:07:23.487138", + "modified": "2021-04-19 00:55:30.781375", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json index 40fbe2c26e..0a51a8e9a1 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json @@ -576,6 +576,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment (Company Currency", @@ -620,6 +621,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment", @@ -802,7 +804,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2020-12-03 15:18:29.073368", + "modified": "2021-04-19 00:58:20.995491", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index 32d349f303..ad350d344f 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -762,6 +762,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment (Company Currency)", @@ -805,6 +806,7 @@ "read_only": 1 }, { + "depends_on": "eval:!doc.disable_rounded_total", "fieldname": "rounding_adjustment", "fieldtype": "Currency", "label": "Rounding Adjustment", @@ -1147,7 +1149,7 @@ "idx": 261, "is_submittable": 1, "links": [], - "modified": "2020-12-26 20:49:39.106049", + "modified": "2021-04-19 01:01:00.754119", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", From b57ebba3fd8af3cb70b16a340d41961ba6eb7223 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Wed, 9 Jun 2021 17:56:41 +0530 Subject: [PATCH 169/180] fix: Validate negative allocated amount in Payment Entry (#25799) --- .../invoice_discounting/invoice_discounting.py | 7 +++++-- .../doctype/payment_entry/payment_entry.py | 14 ++++++++++---- .../doctype/payment_request/payment_request.py | 3 +-- .../accounts_receivable/accounts_receivable.py | 1 + 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index 7b62b617f9..95d2ee56d9 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -49,11 +49,11 @@ class InvoiceDiscounting(AccountsController): self.make_gl_entries() def on_cancel(self): - self.set_status() + self.set_status(cancel=1) self.update_sales_invoice() self.make_gl_entries() - def set_status(self, status=None): + def set_status(self, status=None, cancel=0): if status: self.status = status self.db_set("status", status) @@ -66,6 +66,9 @@ class InvoiceDiscounting(AccountsController): elif self.docstatus == 2: self.status = "Cancelled" + if cancel: + self.db_set('status', self.status, update_modified = True) + def update_sales_invoice(self): for d in self.invoices: if self.docstatus == 1: diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 62ab76c323..e01c651a93 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -65,7 +65,6 @@ class PaymentEntry(AccountsController): self.set_status() def on_submit(self): - self.setup_party_account_field() if self.difference_amount: frappe.throw(_("Difference Amount must be zero")) self.make_gl_entries() @@ -78,7 +77,6 @@ class PaymentEntry(AccountsController): def on_cancel(self): self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry') - self.setup_party_account_field() self.make_gl_entries(cancel=1) self.update_outstanding_amounts() self.update_advance_paid() @@ -122,6 +120,11 @@ class PaymentEntry(AccountsController): if flt(d.allocated_amount) > flt(d.outstanding_amount): frappe.throw(_("Row #{0}: Allocated Amount cannot be greater than outstanding amount.").format(d.idx)) + # Check for negative outstanding invoices as well + if flt(d.allocated_amount) < 0: + if flt(d.allocated_amount) < flt(d.outstanding_amount): + frappe.throw(_("Row #{0}: Allocated Amount cannot be greater than outstanding amount.").format(d.idx)) + def delink_advance_entry_references(self): for reference in self.references: if reference.reference_doctype in ("Sales Invoice", "Purchase Invoice"): @@ -177,7 +180,7 @@ class PaymentEntry(AccountsController): for field, value in iteritems(ref_details): if field == 'exchange_rate' or not d.get(field) or force: - d.set(field, value) + d.db_set(field, value) def validate_payment_type(self): if self.payment_type not in ("Receive", "Pay", "Internal Transfer"): @@ -386,6 +389,8 @@ class PaymentEntry(AccountsController): else: self.status = 'Draft' + self.db_set('status', self.status, update_modified = True) + def set_amounts(self): self.set_amounts_in_company_currency() self.set_total_allocated_amount() @@ -791,7 +796,7 @@ def split_invoices_based_on_payment_terms(outstanding_invoices): outstanding_invoices.pop(idx - 1) outstanding_invoices += invoice_ref_based_on_payment_terms[idx] - + return outstanding_invoices def get_orders_to_be_billed(posting_date, party_type, party, @@ -989,6 +994,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre outstanding_amount = ref_doc.get("outstanding_amount") elif reference_doctype == "Donation": total_amount = ref_doc.get("amount") + outstanding_amount = total_amount exchange_rate = 1 elif reference_doctype == "Dunning": total_amount = ref_doc.get("dunning_amount") diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 53ac996290..468978785b 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -101,7 +101,7 @@ class PaymentRequest(Document): controller.validate_transaction_currency(self.currency) controller.request_for_payment(**payment_record) - + def get_request_amount(self): data_of_completed_requests = frappe.get_all("Integration Request", filters={ 'reference_doctype': self.doctype, @@ -492,7 +492,6 @@ def update_payment_req_status(doc, method): status = 'Requested' pay_req_doc.db_set('status', status) - frappe.db.commit() def get_dummy_message(doc): return frappe.render_template("""{% if doc.contact_person -%} diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index db605f7285..a11b77a6f6 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -584,6 +584,7 @@ class ReceivablePayableReport(object): `tabGL Entry` where docstatus < 2 + and is_cancelled = 0 and party_type=%s and (party is not null and party != '') {1} {2} {3}""" From 26f06093903036bdb222e523d3dba12888869086 Mon Sep 17 00:00:00 2001 From: Saqib Date: Wed, 9 Jun 2021 19:47:28 +0530 Subject: [PATCH 170/180] feat: enable/disable gl entry posting for change given in pos (#25822) --- .../accounts_settings/accounts_settings.json | 9 +++- .../doctype/sales_invoice/sales_invoice.py | 12 ++++- .../sales_invoice/test_sales_invoice.py | 44 +++++++++++++++++-- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 781f94e203..2735b1ccee 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -18,6 +18,7 @@ "delete_linked_ledger_entries", "book_asset_depreciation_entry_automatically", "unlink_advance_payment_on_cancelation_of_order", + "post_change_gl_entries", "tax_settings_section", "determine_address_tax_category_from", "column_break_19", @@ -253,6 +254,12 @@ { "fieldname": "column_break_19", "fieldtype": "Column Break" + }, + { + "default": "1", + "fieldname": "post_change_gl_entries", + "fieldtype": "Check", + "label": "Post Ledger Entries for Given Change" } ], "icon": "icon-cog", @@ -260,7 +267,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-04-30 15:25:10.381008", + "modified": "2021-05-25 12:34:05.858669", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f8b5179d2c..0b8d28aef0 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -849,7 +849,6 @@ class SalesInvoice(SellingController): self.make_loyalty_point_redemption_gle(gl_entries) self.make_pos_gl_entries(gl_entries) - self.make_gle_for_change_amount(gl_entries) self.make_write_off_gl_entry(gl_entries) self.make_gle_for_rounding_adjustment(gl_entries) @@ -983,7 +982,13 @@ class SalesInvoice(SellingController): def make_pos_gl_entries(self, gl_entries): if cint(self.is_pos): + + skip_change_gl_entries = not cint(frappe.db.get_single_value('Accounts Settings', 'post_change_gl_entries')) + for payment_mode in self.payments: + if skip_change_gl_entries and payment_mode.account == self.account_for_change_amount: + payment_mode.base_amount -= self.change_amount + if payment_mode.amount: # POS, make payment entries gl_entries.append( @@ -1015,8 +1020,11 @@ class SalesInvoice(SellingController): }, payment_mode_account_currency, item=self) ) + if not skip_change_gl_entries: + self.make_gle_for_change_amount(gl_entries) + def make_gle_for_change_amount(self, gl_entries): - if cint(self.is_pos) and self.change_amount: + if self.change_amount: if self.account_for_change_amount: gl_entries.append( self.get_gl_dict({ diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index df6d483904..5409a6f192 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -713,7 +713,7 @@ class TestSalesInvoice(unittest.TestCase): si.submit() self.assertEqual(si.paid_amount, 100.0) - self.pos_gl_entry(si, pos, 50) + self.validate_pos_gl_entry(si, pos, 50) def test_pos_returns_with_repayment(self): from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return @@ -749,7 +749,7 @@ class TestSalesInvoice(unittest.TestCase): make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1") - pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", + make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1") pos = create_sales_invoice(company= "_Test Company with perpetual inventory", @@ -770,7 +770,45 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(pos.grand_total, 100.0) self.assertEqual(pos.write_off_amount, -5) - def pos_gl_entry(self, si, pos, cash_amount): + def test_pos_with_no_gl_entry_for_change_amount(self): + frappe.db.set_value('Accounts Settings', None, 'post_change_gl_entries', 0) + + make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1", + expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1") + + make_purchase_receipt(company= "_Test Company with perpetual inventory", + item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1") + + pos = create_sales_invoice(company= "_Test Company with perpetual inventory", + debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", + income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", + cost_center = "Main - TCP1", do_not_save=True) + + pos.is_pos = 1 + pos.update_stock = 1 + + taxes = get_taxes_and_charges() + pos.taxes = [] + for tax in taxes: + pos.append("taxes", tax) + + pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50}) + pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 60}) + + pos.insert() + pos.submit() + + self.assertEqual(pos.grand_total, 100.0) + self.assertEqual(pos.change_amount, 10) + + self.validate_pos_gl_entry(pos, pos, 60, validate_without_change_gle=True) + + frappe.db.set_value('Accounts Settings', None, 'post_change_gl_entries', 1) + + def validate_pos_gl_entry(self, si, pos, cash_amount, validate_without_change_gle=False): + if validate_without_change_gle: + cash_amount -= pos.change_amount + # check stock ledger entries sle = frappe.db.sql("""select * from `tabStock Ledger Entry` where voucher_type = 'Sales Invoice' and voucher_no = %s""", From 42557c4ad387db7ea4956ac80dfaea085614481d Mon Sep 17 00:00:00 2001 From: Saqib Date: Wed, 9 Jun 2021 19:48:31 +0530 Subject: [PATCH 171/180] feat: cost-center wise period closing entry (#25766) --- .../period_closing_voucher.json | 452 +++++------------- .../period_closing_voucher.py | 111 +++-- .../test_period_closing_voucher.py | 85 ++++ 3 files changed, 277 insertions(+), 371 deletions(-) diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json index 47546c07a4..84c941ecc1 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.json @@ -1,350 +1,138 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "ACC-PCV-.YYYY.-.#####", - "beta": 0, - "creation": "2013-01-10 16:34:07", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 0, - "engine": "InnoDB", + "actions": [], + "autoname": "ACC-PCV-.YYYY.-.#####", + "creation": "2013-01-10 16:34:07", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "transaction_date", + "posting_date", + "fiscal_year", + "amended_from", + "company", + "cost_center_wise_pnl", + "column_break1", + "closing_account_head", + "remarks" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "transaction_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": "Transaction Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "transaction_date", - "oldfieldtype": "Date", - "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": "transaction_date", + "fieldtype": "Date", + "label": "Transaction Date", + "oldfieldname": "transaction_date", + "oldfieldtype": "Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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": 0, - "in_standard_filter": 0, - "label": "Posting Date", - "length": 0, - "no_copy": 0, - "oldfieldname": "posting_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "posting_date", + "fieldtype": "Date", + "label": "Posting Date", + "oldfieldname": "posting_date", + "oldfieldtype": "Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "fiscal_year", - "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": 1, - "label": "Closing Fiscal Year", - "length": 0, - "no_copy": 0, - "oldfieldname": "fiscal_year", - "oldfieldtype": "Select", - "options": "Fiscal Year", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "fiscal_year", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Closing Fiscal Year", + "oldfieldname": "fiscal_year", + "oldfieldtype": "Select", + "options": "Fiscal Year", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "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, - "oldfieldname": "amended_from", - "oldfieldtype": "Data", - "options": "Period Closing Voucher", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "amended_from", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "oldfieldname": "amended_from", + "oldfieldtype": "Data", + "options": "Period Closing Voucher", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "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": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "oldfieldname": "company", - "oldfieldtype": "Select", - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Select", + "options": "Company", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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, - "oldfieldtype": "Column Break", - "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": "column_break1", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "The account head under Liability or Equity, in which Profit/Loss will be booked", - "fieldname": "closing_account_head", - "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": "Closing Account Head", - "length": 0, - "no_copy": 0, - "oldfieldname": "closing_account_head", - "oldfieldtype": "Link", - "options": "Account", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "description": "The account head under Liability or Equity, in which Profit/Loss will be booked", + "fieldname": "closing_account_head", + "fieldtype": "Link", + "label": "Closing Account Head", + "oldfieldname": "closing_account_head", + "oldfieldtype": "Link", + "options": "Account", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "remarks", - "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": "Remarks", - "length": 0, - "no_copy": 0, - "oldfieldname": "remarks", - "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": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "remarks", + "fieldtype": "Small Text", + "label": "Remarks", + "oldfieldname": "remarks", + "oldfieldtype": "Small Text", + "reqd": 1 + }, + { + "default": "0", + "fieldname": "cost_center_wise_pnl", + "fieldtype": "Check", + "label": "Book Cost Center Wise Profit/Loss" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-file-text", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Period Closing Voucher", - "owner": "Administrator", + ], + "icon": "fa fa-file-text", + "idx": 1, + "is_submittable": 1, + "links": [], + "modified": "2021-05-20 15:27:37.210458", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Period Closing Voucher", + "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": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "posting_date, fiscal_year", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "closing_account_head", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "search_fields": "posting_date, fiscal_year", + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "closing_account_head" } \ No newline at end of file diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index a74fa062b6..b0a5b04de6 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -51,63 +51,96 @@ class PeriodClosingVoucher(AccountsController): def make_gl_entries(self): gl_entries = [] - net_pl_balance = 0 - dimension_fields = ['t1.cost_center'] + net_pl_balance = 0 - accounting_dimensions = get_accounting_dimensions() - for dimension in accounting_dimensions: - dimension_fields.append('t1.{0}'.format(dimension)) - - dimension_filters, default_dimensions = get_dimensions() - - pl_accounts = self.get_pl_balances(dimension_fields) + pl_accounts = self.get_pl_balances() for acc in pl_accounts: - if flt(acc.balance_in_company_currency): + if flt(acc.bal_in_company_currency): gl_entries.append(self.get_gl_dict({ "account": acc.account, "cost_center": acc.cost_center, "account_currency": acc.account_currency, - "debit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \ - if flt(acc.balance_in_account_currency) < 0 else 0, - "debit": abs(flt(acc.balance_in_company_currency)) \ - if flt(acc.balance_in_company_currency) < 0 else 0, - "credit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \ - if flt(acc.balance_in_account_currency) > 0 else 0, - "credit": abs(flt(acc.balance_in_company_currency)) \ - if flt(acc.balance_in_company_currency) > 0 else 0 + "debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0, + "debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0, + "credit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0, + "credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0 }, item=acc)) - net_pl_balance += flt(acc.balance_in_company_currency) + net_pl_balance += flt(acc.bal_in_company_currency) if net_pl_balance: - cost_center = frappe.db.get_value("Company", self.company, "cost_center") - gl_entry = self.get_gl_dict({ - "account": self.closing_account_head, - "debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0, - "debit": abs(net_pl_balance) if net_pl_balance > 0 else 0, - "credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0, - "credit": abs(net_pl_balance) if net_pl_balance < 0 else 0, - "cost_center": cost_center - }) - - for dimension in accounting_dimensions: - gl_entry.update({ - dimension: default_dimensions.get(self.company, {}).get(dimension) - }) - - gl_entries.append(gl_entry) + if self.cost_center_wise_pnl: + costcenter_wise_gl_entries = self.get_costcenter_wise_pnl_gl_entries(pl_accounts) + gl_entries += costcenter_wise_gl_entries + else: + gl_entry = self.get_pnl_gl_entry(net_pl_balance) + gl_entries.append(gl_entry) from erpnext.accounts.general_ledger import make_gl_entries make_gl_entries(gl_entries) + + def get_pnl_gl_entry(self, net_pl_balance): + cost_center = frappe.db.get_value("Company", self.company, "cost_center") + gl_entry = self.get_gl_dict({ + "account": self.closing_account_head, + "debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0, + "debit": abs(net_pl_balance) if net_pl_balance > 0 else 0, + "credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0, + "credit": abs(net_pl_balance) if net_pl_balance < 0 else 0, + "cost_center": cost_center + }) + + self.update_default_dimensions(gl_entry) + + return gl_entry + + def get_costcenter_wise_pnl_gl_entries(self, pl_accounts): + company_cost_center = frappe.db.get_value("Company", self.company, "cost_center") + gl_entries = [] + + for acc in pl_accounts: + if flt(acc.bal_in_company_currency): + gl_entry = self.get_gl_dict({ + "account": self.closing_account_head, + "cost_center": acc.cost_center or company_cost_center, + "account_currency": acc.account_currency, + "debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0, + "debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0, + "credit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0, + "credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0 + }, item=acc) + + self.update_default_dimensions(gl_entry) + + gl_entries.append(gl_entry) + + return gl_entries + + def update_default_dimensions(self, gl_entry): + if not self.accounting_dimensions: + self.accounting_dimensions = get_accounting_dimensions() + + _, default_dimensions = get_dimensions() + for dimension in self.accounting_dimensions: + gl_entry.update({ + dimension: default_dimensions.get(self.company, {}).get(dimension) + }) + + def get_pl_balances(self): + """Get balance for dimension-wise pl accounts""" + + dimension_fields = ['t1.cost_center'] + + self.accounting_dimensions = get_accounting_dimensions() + for dimension in self.accounting_dimensions: + dimension_fields.append('t1.{0}'.format(dimension)) - def get_pl_balances(self, dimension_fields): - """Get balance for pl accounts""" return frappe.db.sql(""" select t1.account, t2.account_currency, {dimension_fields}, - sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as balance_in_account_currency, - sum(t1.debit) - sum(t1.credit) as balance_in_company_currency + sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as bal_in_account_currency, + sum(t1.debit) - sum(t1.credit) as bal_in_company_currency from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.report_type = 'Profit and Loss' and t2.docstatus < 2 and t2.company = %s diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py index eb02d97b78..2f29372b01 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py @@ -8,6 +8,7 @@ import frappe from frappe.utils import flt, today from erpnext.accounts.utils import get_fiscal_year, now from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice class TestPeriodClosingVoucher(unittest.TestCase): def test_closing_entry(self): @@ -65,6 +66,58 @@ class TestPeriodClosingVoucher(unittest.TestCase): self.assertEqual(gle_for_random_expense_account[0].amount_in_account_currency, -1*random_expense_account[0].balance_in_account_currency) + def test_cost_center_wise_posting(self): + frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'") + + company = create_company() + surplus_account = create_account() + + cost_center1 = create_cost_center("Test Cost Center 1") + cost_center2 = create_cost_center("Test Cost Center 2") + + create_sales_invoice( + company=company, + cost_center=cost_center1, + income_account="Sales - TPC", + expense_account="Cost of Goods Sold - TPC", + rate=400, + debit_to="Debtors - TPC" + ) + create_sales_invoice( + company=company, + cost_center=cost_center2, + income_account="Sales - TPC", + expense_account="Cost of Goods Sold - TPC", + rate=200, + debit_to="Debtors - TPC" + ) + + pcv = frappe.get_doc({ + "transaction_date": today(), + "posting_date": today(), + "fiscal_year": get_fiscal_year(today())[0], + "company": "Test PCV Company", + "cost_center_wise_pnl": 1, + "closing_account_head": surplus_account, + "remarks": "Test", + "doctype": "Period Closing Voucher" + }) + pcv.insert() + pcv.submit() + + expected_gle = ( + ('Sales - TPC', 200.0, 0.0, cost_center2), + (surplus_account, 0.0, 200.0, cost_center2), + ('Sales - TPC', 400.0, 0.0, cost_center1), + (surplus_account, 0.0, 400.0, cost_center1) + ) + + pcv_gle = frappe.db.sql(""" + select account, debit, credit, cost_center from `tabGL Entry` where voucher_no=%s + """, (pcv.name)) + + self.assertTrue(pcv_gle, expected_gle) + def make_period_closing_voucher(self): pcv = frappe.get_doc({ "doctype": "Period Closing Voucher", @@ -80,6 +133,38 @@ class TestPeriodClosingVoucher(unittest.TestCase): return pcv +def create_company(): + company = frappe.get_doc({ + 'doctype': 'Company', + 'company_name': "Test PCV Company", + 'country': 'United States', + 'default_currency': 'USD' + }) + company.insert(ignore_if_duplicate = True) + return company.name + +def create_account(): + account = frappe.get_doc({ + "account_name": "Reserve and Surplus", + "is_group": 0, + "company": "Test PCV Company", + "root_type": "Liability", + "report_type": "Balance Sheet", + "account_currency": "USD", + "parent_account": "Current Liabilities - TPC", + "doctype": "Account" + }).insert(ignore_if_duplicate = True) + return account.name + +def create_cost_center(cc_name): + costcenter = frappe.get_doc({ + "company": "Test PCV Company", + "cost_center_name": cc_name, + "doctype": "Cost Center", + "parent_cost_center": "Test PCV Company - TPC" + }) + costcenter.insert(ignore_if_duplicate = True) + return costcenter.name test_dependencies = ["Customer", "Cost Center"] test_records = frappe.get_test_records("Period Closing Voucher") From 076bd5eaab52c9ad7805ff511787f8de045743b3 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Thu, 10 Jun 2021 12:08:44 +0530 Subject: [PATCH 172/180] fix: Only display GST card in Accounting Workspace if it's in India --- .../workspace/accounting/accounting.json | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json index df68318052..10a4001502 100644 --- a/erpnext/accounts/workspace/accounting/accounting.json +++ b/erpnext/accounts/workspace/accounting/accounting.json @@ -445,15 +445,15 @@ "type": "Link" }, { - "dependencies": "GL Entry", - "hidden": 0, - "is_query_report": 1, - "label": "UAE VAT 201", - "link_to": "UAE VAT 201", - "link_type": "Report", - "onboard": 0, - "type": "Link" - }, + "dependencies": "GL Entry", + "hidden": 0, + "is_query_report": 1, + "label": "UAE VAT 201", + "link_to": "UAE VAT 201", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -684,6 +684,7 @@ "is_query_report": 0, "label": "Goods and Services Tax (GST India)", "onboard": 0, + "only_for": "India", "type": "Card Break" }, { @@ -694,6 +695,7 @@ "link_to": "GST Settings", "link_type": "DocType", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -704,6 +706,7 @@ "link_to": "GST HSN Code", "link_type": "DocType", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -714,6 +717,7 @@ "link_to": "GSTR-1", "link_type": "Report", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -724,6 +728,7 @@ "link_to": "GSTR-2", "link_type": "Report", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -734,6 +739,7 @@ "link_to": "GSTR 3B Report", "link_type": "DocType", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -744,6 +750,7 @@ "link_to": "GST Sales Register", "link_type": "Report", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -754,6 +761,7 @@ "link_to": "GST Purchase Register", "link_type": "Report", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -764,6 +772,7 @@ "link_to": "GST Itemised Sales Register", "link_type": "Report", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -774,6 +783,7 @@ "link_to": "GST Itemised Purchase Register", "link_type": "Report", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -784,6 +794,7 @@ "link_to": "C-Form", "link_type": "DocType", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -794,6 +805,7 @@ "link_to": "Lower Deduction Certificate", "link_type": "DocType", "onboard": 0, + "only_for": "India", "type": "Link" }, { @@ -1052,7 +1064,7 @@ "type": "Link" } ], - "modified": "2021-05-12 11:48:01.905144", + "modified": "2021-06-10 03:17:31.427945", "modified_by": "Administrator", "module": "Accounts", "name": "Accounting", @@ -1107,4 +1119,4 @@ "type": "Dashboard" } ] -} +} \ No newline at end of file From aedf25ba46d20d8a7d40b6c77f880cfdc426cf90 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 4 Jun 2021 11:44:40 +0530 Subject: [PATCH 173/180] chore: Drop old patches v7 backup was restored and upgraded to latest v10.x.x branch. The patches run uptil the upgrade are removed in this change. This means only existing v10 sites are allowed direct upgrade to v13 and newer --- erpnext/patches/repair_tools/__init__.py | 0 .../set_stock_balance_as_per_serial_no.py | 13 - erpnext/patches/v10_0/__init__.py | 0 .../patches/v10_0/add_agriculture_domain.py | 13 - .../add_guardian_role_for_parent_portal.py | 23 -- .../patches/v10_0/add_non_profit_domain.py | 20 -- .../allow_operators_in_supplier_scorecard.py | 23 -- .../v10_0/copy_projects_renamed_fields.py | 13 - ..._regional_print_format_based_on_country.py | 22 -- .../fix_reserved_qty_for_sub_contract.py | 31 --- .../recalculate_gross_margin_for_project.py | 14 - .../v10_0/rename_schools_to_education.py | 32 --- ...r_purchase_receipts_with_rejected_items.py | 32 --- ...t_requested_qty_for_non_stock_uom_items.py | 21 -- ...t_auto_created_serial_no_in_stock_entry.py | 56 ---- erpnext/patches/v10_0/set_b2c_limit.py | 12 - ..._default_payment_terms_based_on_company.py | 37 --- erpnext/patches/v10_0/set_discount_amount.py | 35 --- ...set_numeric_ranges_in_template_if_blank.py | 35 --- .../v10_0/set_primary_contact_for_customer.py | 21 -- ...n_transactions_based_on_serial_no_input.py | 21 -- .../patches/v10_0/set_student_party_type.py | 8 - .../setup_vat_for_uae_and_saudi_arabia.py | 13 - ...s_of_all_department_members_in_calendar.py | 6 - erpnext/patches/v10_0/taxes_issue_with_pos.py | 26 -- .../update_address_template_for_india.py | 12 - .../patches/v10_0/update_assessment_plan.py | 17 -- .../patches/v10_0/update_assessment_result.py | 20 -- .../update_asset_calculate_depreciation.py | 12 - .../v10_0/update_hub_connector_domain.py | 10 - .../v10_0/update_lft_rgt_for_employee.py | 9 - .../patches/v10_0/update_project_in_sle.py | 15 -- .../update_reserved_qty_for_purchase_order.py | 53 ---- ...date_sales_order_link_to_purchase_order.py | 18 -- ...update_status_for_multiple_source_in_po.py | 40 --- .../update_status_in_purchase_receipt.py | 8 - .../update_territory_and_customer_group.py | 29 --- .../v10_0/update_user_image_in_employee.py | 19 -- .../v10_0/update_warehouse_address_details.py | 37 --- erpnext/patches/v10_1/__init__.py | 0 erpnext/patches/v11_0/__init__.py | 1 - .../v11_0/remove_subscriber_doctype.py | 16 -- erpnext/patches/v11_1/__init__.py | 0 erpnext/patches/v12_0/__init__.py | 0 erpnext/patches/v13_0/__init__.py | 1 - erpnext/patches/v4_0/__init__.py | 0 .../patches/v4_0/apply_user_permissions.py | 50 ---- erpnext/patches/v4_0/countrywise_coa.py | 29 --- ...custom_fields_for_india_specific_fields.py | 63 ----- .../v4_0/create_price_list_if_missing.py | 35 --- .../v4_0/customer_discount_to_pricing_rule.py | 33 --- erpnext/patches/v4_0/fields_to_be_renamed.py | 109 -------- erpnext/patches/v4_0/fix_address_template.py | 12 - .../patches/v4_0/fix_case_of_hr_module_def.py | 13 - erpnext/patches/v4_0/fix_contact_address.py | 13 - erpnext/patches/v4_0/fix_employee_user_id.py | 23 -- .../global_defaults_to_system_settings.py | 39 --- erpnext/patches/v4_0/import_country_codes.py | 15 -- .../v4_0/map_charge_to_taxes_and_charges.py | 16 -- .../move_warehouse_user_to_restrictions.py | 13 - erpnext/patches/v4_0/new_address_template.py | 14 - .../patches/v4_0/reload_sales_print_format.py | 8 - .../remove_employee_role_if_no_employee.py | 18 -- .../patches/v4_0/remove_module_home_pages.py | 10 - .../patches/v4_0/rename_sitemap_to_route.py | 17 -- .../v4_0/reset_permissions_for_masters.py | 20 -- .../patches/v4_0/save_default_letterhead.py | 13 - .../set_pricing_rule_for_buying_or_selling.py | 13 - erpnext/patches/v4_0/split_email_settings.py | 67 ----- .../patches/v4_0/update_account_root_type.py | 34 --- ...custom_print_formats_for_renamed_fields.py | 36 --- ...to_sales_person_in_maintenance_schedule.py | 12 - ...harges_in_custom_purchase_print_formats.py | 12 - .../v4_0/update_tax_amount_after_discount.py | 20 -- .../patches/v4_0/update_user_properties.py | 51 ---- .../v4_0/update_users_report_view_settings.py | 12 - erpnext/patches/v4_0/validate_v3_patch.py | 11 - erpnext/patches/v4_1/__init__.py | 0 .../v4_1/fix_delivery_and_billing_status.py | 12 - erpnext/patches/v4_1/fix_jv_remarks.py | 21 -- .../v4_1/fix_sales_order_delivered_status.py | 15 -- .../patches/v4_1/set_outgoing_email_footer.py | 12 - erpnext/patches/v4_2/__init__.py | 0 .../patches/v4_2/add_currency_turkish_lira.py | 10 - erpnext/patches/v4_2/default_website_style.py | 11 - ...elete_gl_entries_for_cancelled_invoices.py | 14 - .../patches/v4_2/delete_old_print_formats.py | 23 -- erpnext/patches/v4_2/discount_amount.py | 12 - .../patches/v4_2/fix_account_master_type.py | 12 - .../fix_gl_entries_for_stock_transactions.py | 54 ---- erpnext/patches/v4_2/fix_recurring_orders.py | 41 --- erpnext/patches/v4_2/party_model.py | 117 --------- erpnext/patches/v4_2/recalculate_bom_cost.py | 16 -- .../repost_sle_for_si_with_no_warehouse.py | 34 --- .../v4_2/repost_stock_reconciliation.py | 31 --- erpnext/patches/v4_2/reset_bom_costs.py | 17 -- .../v4_2/seprate_manufacture_and_repack.py | 9 - erpnext/patches/v4_2/set_company_country.py | 15 -- erpnext/patches/v4_2/set_item_has_batch.py | 65 ----- erpnext/patches/v4_2/toggle_rounded_total.py | 9 - .../v4_2/update_landed_cost_voucher.py | 10 - .../patches/v4_2/update_project_milestones.py | 9 - .../update_sales_order_invoice_field_name.py | 7 - .../v4_2/update_stock_uom_for_dn_in_sle.py | 11 - erpnext/patches/v4_4/__init__.py | 0 erpnext/patches/v4_4/make_email_accounts.py | 96 ------- erpnext/patches/v5_0/__init__.py | 0 .../v5_0/convert_stock_reconciliation.py | 31 --- .../patches/v5_0/execute_on_doctype_update.py | 9 - .../fix_taxes_and_totals_in_party_currency.py | 66 ----- .../v5_0/index_on_account_and_gl_entry.py | 30 --- erpnext/patches/v5_0/is_group.py | 9 - erpnext/patches/v5_0/item_patches.py | 6 - .../v5_0/link_warehouse_with_account.py | 10 - erpnext/patches/v5_0/new_crm_module.py | 24 -- erpnext/patches/v5_0/newsletter.py | 38 --- .../v5_0/opportunity_not_submittable.py | 10 - erpnext/patches/v5_0/party_model_patch_fix.py | 18 -- erpnext/patches/v5_0/portal_fixes.py | 7 - erpnext/patches/v5_0/project_costing.py | 8 - .../v5_0/recalculate_total_amount_in_jv.py | 26 -- ...nned_operating_cost_in_production_order.py | 13 - .../patches/v5_0/remove_birthday_events.py | 7 - erpnext/patches/v5_0/rename_customer_issue.py | 6 - erpnext/patches/v5_0/rename_pos_setting.py | 6 - .../patches/v5_0/rename_table_fieldnames.py | 243 ------------------ .../v5_0/rename_taxes_and_charges_master.py | 14 - erpnext/patches/v5_0/rename_total_fields.py | 55 ---- ...lds_in_custom_scripts_and_print_formats.py | 65 ----- .../repost_gle_for_jv_with_multiple_party.py | 26 -- erpnext/patches/v5_0/repost_requested_qty.py | 21 -- erpnext/patches/v5_0/reset_values_in_tools.py | 12 - erpnext/patches/v5_0/set_appraisal_remarks.py | 9 - .../v5_0/set_default_company_in_bom.py | 10 - erpnext/patches/v5_0/set_footer_address.py | 9 - .../patches/v5_0/stock_entry_update_value.py | 8 - .../taxes_and_totals_in_party_currency.py | 80 ------ erpnext/patches/v5_0/update_account_types.py | 20 -- erpnext/patches/v5_0/update_advance_paid.py | 13 - .../update_companywise_payment_account.py | 21 -- .../v5_0/update_dn_against_doc_fields.py | 14 - erpnext/patches/v5_0/update_from_bom.py | 9 - .../update_frozen_accounts_permission_role.py | 13 - .../v5_0/update_item_and_description_again.py | 50 ---- .../v5_0/update_item_desc_in_invoice.py | 52 ---- .../v5_0/update_item_description_and_image.py | 54 ---- .../patches/v5_0/update_item_name_in_bom.py | 18 -- .../v5_0/update_journal_entry_title.py | 12 - ...pdate_material_transfer_for_manufacture.py | 6 - ..._material_transferred_for_manufacturing.py | 10 - ...ial_transferred_for_manufacturing_again.py | 19 -- .../v5_0/update_operation_description.py | 11 - erpnext/patches/v5_0/update_opportunity.py | 14 - erpnext/patches/v5_0/update_projects.py | 34 --- erpnext/patches/v5_0/update_sms_sender.py | 9 - ...amount_after_discount_in_purchase_cycle.py | 17 -- .../patches/v5_0/update_temporary_account.py | 9 - erpnext/patches/v5_0/update_time_log_title.py | 12 - erpnext/patches/v5_1/__init__.py | 0 erpnext/patches/v5_1/default_bom.py | 7 - erpnext/patches/v5_1/fix_against_account.py | 37 --- erpnext/patches/v5_1/rename_roles.py | 10 - erpnext/patches/v5_1/sales_bom_rename.py | 12 - erpnext/patches/v5_2/__init__.py | 1 - .../v5_2/change_item_selects_to_checks.py | 19 -- erpnext/patches/v5_4/__init__.py | 0 erpnext/patches/v5_4/cleanup_journal_entry.py | 21 -- .../patches/v5_4/fix_invoice_outstanding.py | 13 - .../patches/v5_4/fix_missing_item_images.py | 126 --------- ...x_reserved_qty_and_sle_for_packed_items.py | 22 -- ...anagers_regarding_wrong_tax_calculation.py | 41 --- .../patches/v5_4/set_root_and_report_type.py | 12 - .../v5_4/stock_entry_additional_costs.py | 53 ---- .../update_purchase_cost_against_project.py | 13 - erpnext/patches/v5_7/__init__.py | 1 - .../patches/v5_7/item_template_attributes.py | 124 --------- erpnext/patches/v5_8/__init__.py | 1 - .../v5_8/add_credit_note_print_heading.py | 14 - erpnext/patches/v5_8/tax_rule.py | 31 --- ...pdate_order_reference_in_return_entries.py | 92 ------- erpnext/patches/v6_0/__init__.py | 0 erpnext/patches/v6_0/default_activity_rate.py | 14 - .../patches/v6_0/fix_outstanding_amount.py | 16 -- erpnext/patches/v6_0/fix_planned_qty.py | 14 - erpnext/patches/v6_0/multi_currency.py | 65 ----- erpnext/patches/v6_0/set_default_title.py | 36 --- erpnext/patches/v6_10/__init__.py | 1 - .../v6_10/email_digest_default_quote.py | 6 - .../fix_billed_amount_in_drop_ship_po.py | 18 -- .../fix_delivery_status_of_drop_ship_item.py | 10 - erpnext/patches/v6_10/fix_jv_total_amount.py | 14 - .../v6_10/fix_ordered_received_billed.py | 17 -- erpnext/patches/v6_12/__init__.py | 0 .../repost_entries_with_target_warehouse.py | 175 ------------- erpnext/patches/v6_12/set_overdue_tasks.py | 8 - erpnext/patches/v6_16/__init__.py | 1 - .../v6_16/create_manufacturer_records.py | 19 -- .../update_billing_status_in_dn_and_pr.py | 42 --- erpnext/patches/v6_19/__init__.py | 1 - .../v6_19/comment_feed_communication.py | 7 - erpnext/patches/v6_2/__init__.py | 1 - .../fix_missing_default_taxes_and_lead.py | 25 -- .../v6_2/remove_newsletter_duplicates.py | 13 - erpnext/patches/v6_20/__init__.py | 0 .../set_party_account_currency_in_orders.py | 24 -- erpnext/patches/v6_20x/__init__.py | 1 - .../v6_20x/remove_customer_supplier_roles.py | 23 -- .../remove_fiscal_year_from_holiday_list.py | 19 -- .../v6_20x/rename_project_name_to_project.py | 17 -- ...t_valuation_rate_for_negative_inventory.py | 11 - erpnext/patches/v6_20x/set_compact_print.py | 8 - .../update_product_bundle_description.py | 11 - erpnext/patches/v6_21/__init__.py | 1 - erpnext/patches/v6_21/fix_reorder_level.py | 24 -- .../v6_21/rename_material_request_fields.py | 14 - erpnext/patches/v6_23/__init__.py | 0 .../v6_23/update_stopped_status_to_closed.py | 9 - erpnext/patches/v6_24/__init__.py | 0 ...tomer_address_to_shipping_address_on_po.py | 19 -- erpnext/patches/v6_24/set_recurring_id.py | 13 - erpnext/patches/v6_27/__init__.py | 1 - .../v6_27/fix_recurring_order_status.py | 54 ---- erpnext/patches/v6_3/__init__.py | 0 .../v6_3/convert_applicable_territory.py | 24 -- erpnext/patches/v6_4/__init__.py | 1 - erpnext/patches/v6_4/email_digest_update.py | 10 - erpnext/patches/v6_4/fix_duplicate_bins.py | 20 -- .../v6_4/fix_expense_included_in_valuation.py | 74 ------ ...x_journal_entries_due_to_reconciliation.py | 53 ---- ...ified_in_sales_order_and_purchase_order.py | 10 - .../fix_sales_order_maintenance_status.py | 8 - .../fix_status_in_sales_and_purchase_order.py | 8 - erpnext/patches/v6_4/make_image_thumbnail.py | 15 -- ...al_entries_where_reference_name_missing.py | 23 -- .../v6_4/round_status_updater_percentages.py | 14 - erpnext/patches/v6_4/set_user_in_contact.py | 7 - erpnext/patches/v6_5/__init__.py | 1 - .../v6_5/show_in_website_for_template_item.py | 15 -- erpnext/patches/v6_6/__init__.py | 1 - erpnext/patches/v6_6/fix_website_image.py | 32 --- ...emove_fiscal_year_from_leave_allocation.py | 17 -- erpnext/patches/v6_8/__init__.py | 0 erpnext/patches/v6_8/make_webform_standard.py | 14 - .../v6_8/move_drop_ship_to_po_items.py | 43 ---- erpnext/patches/v7_0/__init__.py | 0 .../v7_0/calculate_total_costing_amount.py | 18 -- .../v7_0/convert_timelog_to_timesheet.py | 69 ----- .../v7_0/convert_timelogbatch_to_timesheet.py | 32 --- erpnext/patches/v7_0/create_budget_record.py | 57 ---- .../v7_0/create_warehouse_nestedset.py | 128 --------- erpnext/patches/v7_0/fix_duplicate_icons.py | 27 -- ...ouse_ledger_gl_entries_for_transactions.py | 51 ---- erpnext/patches/v7_0/make_guardian.py | 37 --- .../v7_0/make_is_group_fieldtype_as_check.py | 18 -- ...count_type_stock_and_warehouse_to_stock.py | 10 - .../v7_0/migrate_mode_of_payments_v6_to_v7.py | 38 --- .../v7_0/migrate_schools_to_erpnext.py | 30 --- ...lesinvoiceitem_to_salesinvoicetimesheet.py | 17 -- .../v7_0/po_status_issue_for_pr_return.py | 40 --- erpnext/patches/v7_0/re_route.py | 5 - .../remove_administrator_role_in_doctypes.py | 9 - .../v7_0/remove_doctypes_and_reports.py | 27 -- erpnext/patches/v7_0/remove_features_setup.py | 29 --- .../remove_old_earning_deduction_doctypes.py | 16 -- .../v7_0/rename_advance_table_fields.py | 18 -- .../v7_0/rename_examination_to_assessment.py | 24 -- .../rename_fee_amount_to_fee_component.py | 16 -- erpnext/patches/v7_0/rename_prevdoc_fields.py | 76 ------ .../patches/v7_0/rename_salary_components.py | 149 ----------- .../patches/v7_0/rename_time_sheet_doctype.py | 14 - .../repost_bin_qty_and_item_projected_qty.py | 15 -- .../repost_gle_for_pi_with_update_stock.py | 20 -- .../v7_0/repost_gle_for_pos_sales_return.py | 25 -- ...et_base_amount_in_invoice_payment_table.py | 24 -- .../v7_0/set_is_group_for_warehouse.py | 7 - .../v7_0/set_material_request_type_in_item.py | 16 -- .../v7_0/set_naming_series_for_timesheet.py | 15 -- .../v7_0/set_party_name_in_payment_entry.py | 20 -- erpnext/patches/v7_0/set_portal_settings.py | 28 -- ..._table_for_expense_claim_type_if_exists.py | 20 -- .../v7_0/system_settings_setup_complete.py | 16 -- erpnext/patches/v7_0/update_autoname_field.py | 14 - .../v7_0/update_change_amount_account.py | 19 -- ...rsion_factor_in_supplier_quotation_item.py | 19 -- erpnext/patches/v7_0/update_home_page.py | 27 -- .../update_maintenance_module_in_doctype.py | 11 - .../v7_0/update_mins_to_first_response.py | 24 -- .../update_missing_employee_in_timesheet.py | 20 -- .../v7_0/update_mode_of_payment_type.py | 29 --- erpnext/patches/v7_0/update_party_status.py | 21 -- ...vdoc_values_for_supplier_quotation_item.py | 9 - .../v7_0/update_project_in_gl_entry.py | 21 -- .../update_refdoc_in_landed_cost_voucher.py | 15 -- .../v7_0/update_status_for_timesheet.py | 11 - .../patches/v7_0/update_status_of_po_so.py | 68 ----- ...pdate_status_of_zero_amount_sales_order.py | 7 - .../v7_0/update_timesheet_communications.py | 27 -- erpnext/patches/v7_1/__init__.py | 1 - .../add_account_user_role_for_timesheet.py | 31 --- .../v7_1/add_field_for_task_dependent.py | 10 - .../v7_1/fix_link_for_customer_from_lead.py | 7 - ..._invoice_from_parent_to_child_timesheet.py | 20 -- .../patches/v7_1/rename_field_timesheet.py | 11 - .../v7_1/rename_quality_inspection_field.py | 38 --- ...tock_for_deleted_bins_for_merging_items.py | 44 ---- erpnext/patches/v7_1/save_stock_settings.py | 15 -- .../v7_1/set_budget_against_as_cost_center.py | 11 - .../v7_1/set_currency_exchange_date.py | 10 - .../v7_1/set_prefered_contact_email.py | 17 -- .../patches/v7_1/set_sales_person_status.py | 8 - erpnext/patches/v7_1/set_student_guardian.py | 23 -- .../v7_1/set_total_amount_currency_in_je.py | 24 -- .../patches/v7_1/update_bom_base_currency.py | 20 -- erpnext/patches/v7_1/update_component_type.py | 15 -- erpnext/patches/v7_1/update_invoice_status.py | 34 --- erpnext/patches/v7_1/update_lead_source.py | 29 --- .../update_missing_salary_component_type.py | 50 ---- erpnext/patches/v7_1/update_portal_roles.py | 21 -- .../v7_1/update_total_billing_hours.py | 14 - erpnext/patches/v7_2/__init__.py | 1 - ...ar_leave_encashment_as_salary_component.py | 36 --- erpnext/patches/v7_2/contact_address_links.py | 32 --- .../delete_fleet_management_module_def.py | 10 - ...ty_supplied_items_for_non_subcontracted.py | 14 - .../patches/v7_2/make_all_assessment_group.py | 14 - erpnext/patches/v7_2/mark_students_active.py | 9 - .../v7_2/rename_att_date_attendance.py | 15 -- .../v7_2/rename_evaluation_criteria.py | 39 --- .../patches/v7_2/set_null_value_to_fields.py | 11 - .../patches/v7_2/setup_auto_close_settings.py | 18 -- erpnext/patches/v7_2/stock_uom_in_selling.py | 15 -- .../v7_2/update_abbr_in_salary_slips.py | 14 - .../patches/v7_2/update_assessment_modules.py | 51 ---- .../v7_2/update_attendance_docstatus.py | 10 - erpnext/patches/v7_2/update_doctype_status.py | 11 - .../update_guardian_name_in_student_master.py | 14 - erpnext/patches/v7_2/update_party_type.py | 16 -- erpnext/patches/v7_2/update_salary_slips.py | 22 -- .../v7_2/update_website_for_variant.py | 13 - erpnext/patches/v8_0/__init__.py | 1 - .../patches/v8_0/addresses_linked_to_lead.py | 5 - .../v8_0/change_in_words_varchar_length.py | 16 -- ...dress_doc_from_address_field_in_company.py | 33 --- erpnext/patches/v8_0/create_domain_docs.py | 53 ---- erpnext/patches/v8_0/delete_bin_indexes.py | 16 -- .../delete_schools_depricated_doctypes.py | 14 - .../patches/v8_0/disable_instructor_role.py | 18 -- ...ooking_asset_depreciation_automatically.py | 9 - ..._for_invoices_with_negative_outstanding.py | 23 -- ...ayments_table_blank_for_non_pos_invoice.py | 15 -- .../merge_student_batch_and_student_group.py | 73 ------ ...from_account_to_warehouse_for_inventory.py | 15 -- .../v8_0/move_perpetual_inventory_setting.py | 13 - ...ample_item_to_allow_zero_valuation_rate.py | 13 - ...ems_in_status_field_of_material_request.py | 25 -- ...rename_total_margin_to_rate_with_margin.py | 24 -- ...ost_reserved_qty_for_multiple_sales_uom.py | 19 -- .../revert_manufacturers_table_from_item.py | 22 -- erpnext/patches/v8_0/save_system_settings.py | 20 -- ..._serial_nos_for_disabled_sales_invoices.py | 14 - .../patches/v8_0/set_project_copied_from.py | 11 - ...nvoice_serial_number_from_delivery_note.py | 42 --- .../patches/v8_0/update_customer_pos_id.py | 9 - .../patches/v8_0/update_production_orders.py | 49 ---- .../v8_0/update_sales_cost_in_project.py | 11 - ...tus_as_paid_for_completed_expense_claim.py | 19 -- .../update_stock_qty_value_in_bom_item.py | 14 - ...ate_stock_qty_value_in_purchase_invoice.py | 9 - ...ate_student_groups_from_student_batches.py | 38 --- .../update_supplier_address_in_stock_entry.py | 22 -- erpnext/patches/v8_1/__init__.py | 0 erpnext/patches/v8_1/add_hsn_sac_codes.py | 11 - .../add_indexes_in_transaction_doctypes.py | 10 - ...allow_invoice_copy_to_edit_after_submit.py | 13 - .../patches/v8_1/delete_deprecated_reports.py | 33 --- erpnext/patches/v8_1/gst_fixes.py | 62 ----- ...e_sales_invoice_from_returned_serial_no.py | 18 -- .../v8_1/removed_report_support_hours.py | 14 - .../v8_1/set_delivery_date_in_so_item.py | 22 -- .../v8_1/update_expense_claim_status.py | 23 -- erpnext/patches/v8_1/update_gst_state.py | 15 -- erpnext/patches/v8_10/__init__.py | 0 .../change_default_customer_credit_days.py | 89 ------- erpnext/patches/v8_3/__init__.py | 0 .../set_restrict_to_domain_for_module_def.py | 9 - .../v8_3/update_company_total_sales.py | 15 -- erpnext/patches/v8_4/__init__.py | 1 - .../patches/v8_4/make_scorecard_records.py | 11 - erpnext/patches/v8_5/__init__.py | 0 .../fix_tax_breakup_for_non_invoice_docs.py | 48 ---- .../remove_project_type_property_setter.py | 18 -- .../remove_quotations_route_in_sidebar.py | 16 -- .../v8_5/set_default_mode_of_payment.py | 17 -- .../update_customer_group_in_POS_profile.py | 9 - .../update_existing_data_in_project_type.py | 19 -- erpnext/patches/v8_6/__init__.py | 0 ...point_sms_doctype_module_to_frappe_core.py | 9 - .../patches/v8_6/rename_bom_update_tool.py | 9 - ...mission_for_quotation_for_sales_manager.py | 11 - .../v8_6/update_timesheet_company_from_PO.py | 15 -- erpnext/patches/v8_7/__init__.py | 0 .../v8_7/fix_purchase_receipt_status.py | 13 - .../make_subscription_from_recurring_data.py | 58 ----- erpnext/patches/v8_8/__init__.py | 0 .../add_new_fields_in_accounts_settings.py | 9 - .../patches/v8_8/set_bom_rate_as_per_uom.py | 13 - erpnext/patches/v8_9/__init__.py | 1 - .../v8_9/add_setup_progress_actions.py | 47 ---- ...gst_doctypes_for_outside_india_accounts.py | 14 - ...e_employee_from_salary_structure_parent.py | 6 - .../v8_9/rename_company_sales_target_field.py | 8 - .../v8_9/set_default_customer_group.py | 8 - .../set_default_fields_in_variant_settings.py | 13 - erpnext/patches/v8_9/set_member_party_type.py | 9 - .../v8_9/set_print_zero_amount_taxes.py | 9 - ...update_billing_gstin_for_indian_account.py | 15 -- erpnext/patches/v9_0/__init__.py | 1 - erpnext/patches/v9_0/add_healthcare_domain.py | 13 - .../add_user_to_child_table_in_pos_profile.py | 38 --- .../patches/v9_0/copy_old_fees_field_data.py | 15 -- ..._existing_warehouse_from_stock_settings.py | 8 - .../v9_0/remove_subscription_module.py | 9 - .../v9_0/revert_manufacturing_user_role.py | 22 -- erpnext/patches/v9_0/set_pos_profile_name.py | 24 -- ...for_material_request_and_purchase_order.py | 24 -- ...ipping_type_for_existing_shipping_rules.py | 18 -- .../patches/v9_0/set_uoms_in_variant_field.py | 14 - .../v9_0/set_variant_item_description.py | 46 ---- .../student_admission_childtable_migrate.py | 31 --- .../v9_0/update_employee_loan_details.py | 24 -- ...te_multi_uom_fields_in_material_request.py | 12 - erpnext/patches/v9_1/__init__.py | 0 .../v9_1/create_issue_opportunity_type.py | 34 --- erpnext/patches/v9_2/__init__.py | 0 .../delete_healthcare_domain_default_items.py | 17 -- .../patches/v9_2/delete_process_payroll.py | 5 - .../v9_2/remove_company_from_patient.py | 7 - .../v9_2/rename_net_weight_in_item_master.py | 8 - .../v9_2/rename_translated_domains_in_en.py | 39 --- .../repost_reserved_qty_for_production.py | 9 - .../v9_2/set_item_name_in_production_order.py | 12 - 441 files changed, 9599 deletions(-) delete mode 100644 erpnext/patches/repair_tools/__init__.py delete mode 100644 erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py delete mode 100644 erpnext/patches/v10_0/__init__.py delete mode 100644 erpnext/patches/v10_0/add_agriculture_domain.py delete mode 100644 erpnext/patches/v10_0/add_guardian_role_for_parent_portal.py delete mode 100644 erpnext/patches/v10_0/add_non_profit_domain.py delete mode 100644 erpnext/patches/v10_0/allow_operators_in_supplier_scorecard.py delete mode 100644 erpnext/patches/v10_0/copy_projects_renamed_fields.py delete mode 100644 erpnext/patches/v10_0/enabled_regional_print_format_based_on_country.py delete mode 100644 erpnext/patches/v10_0/fix_reserved_qty_for_sub_contract.py delete mode 100644 erpnext/patches/v10_0/recalculate_gross_margin_for_project.py delete mode 100644 erpnext/patches/v10_0/rename_schools_to_education.py delete mode 100644 erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py delete mode 100644 erpnext/patches/v10_0/repost_requested_qty_for_non_stock_uom_items.py delete mode 100644 erpnext/patches/v10_0/set_auto_created_serial_no_in_stock_entry.py delete mode 100644 erpnext/patches/v10_0/set_b2c_limit.py delete mode 100644 erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py delete mode 100644 erpnext/patches/v10_0/set_discount_amount.py delete mode 100644 erpnext/patches/v10_0/set_numeric_ranges_in_template_if_blank.py delete mode 100644 erpnext/patches/v10_0/set_primary_contact_for_customer.py delete mode 100644 erpnext/patches/v10_0/set_qty_in_transactions_based_on_serial_no_input.py delete mode 100644 erpnext/patches/v10_0/set_student_party_type.py delete mode 100644 erpnext/patches/v10_0/setup_vat_for_uae_and_saudi_arabia.py delete mode 100644 erpnext/patches/v10_0/show_leaves_of_all_department_members_in_calendar.py delete mode 100644 erpnext/patches/v10_0/taxes_issue_with_pos.py delete mode 100644 erpnext/patches/v10_0/update_address_template_for_india.py delete mode 100644 erpnext/patches/v10_0/update_assessment_plan.py delete mode 100644 erpnext/patches/v10_0/update_assessment_result.py delete mode 100644 erpnext/patches/v10_0/update_asset_calculate_depreciation.py delete mode 100644 erpnext/patches/v10_0/update_hub_connector_domain.py delete mode 100644 erpnext/patches/v10_0/update_lft_rgt_for_employee.py delete mode 100644 erpnext/patches/v10_0/update_project_in_sle.py delete mode 100644 erpnext/patches/v10_0/update_reserved_qty_for_purchase_order.py delete mode 100644 erpnext/patches/v10_0/update_sales_order_link_to_purchase_order.py delete mode 100644 erpnext/patches/v10_0/update_status_for_multiple_source_in_po.py delete mode 100644 erpnext/patches/v10_0/update_status_in_purchase_receipt.py delete mode 100644 erpnext/patches/v10_0/update_territory_and_customer_group.py delete mode 100644 erpnext/patches/v10_0/update_user_image_in_employee.py delete mode 100644 erpnext/patches/v10_0/update_warehouse_address_details.py delete mode 100644 erpnext/patches/v10_1/__init__.py delete mode 100644 erpnext/patches/v11_0/__init__.py delete mode 100644 erpnext/patches/v11_0/remove_subscriber_doctype.py delete mode 100644 erpnext/patches/v11_1/__init__.py delete mode 100644 erpnext/patches/v12_0/__init__.py delete mode 100644 erpnext/patches/v13_0/__init__.py delete mode 100644 erpnext/patches/v4_0/__init__.py delete mode 100644 erpnext/patches/v4_0/apply_user_permissions.py delete mode 100644 erpnext/patches/v4_0/countrywise_coa.py delete mode 100644 erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py delete mode 100644 erpnext/patches/v4_0/create_price_list_if_missing.py delete mode 100644 erpnext/patches/v4_0/customer_discount_to_pricing_rule.py delete mode 100644 erpnext/patches/v4_0/fields_to_be_renamed.py delete mode 100644 erpnext/patches/v4_0/fix_address_template.py delete mode 100644 erpnext/patches/v4_0/fix_case_of_hr_module_def.py delete mode 100644 erpnext/patches/v4_0/fix_contact_address.py delete mode 100644 erpnext/patches/v4_0/fix_employee_user_id.py delete mode 100644 erpnext/patches/v4_0/global_defaults_to_system_settings.py delete mode 100644 erpnext/patches/v4_0/import_country_codes.py delete mode 100644 erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py delete mode 100644 erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py delete mode 100644 erpnext/patches/v4_0/new_address_template.py delete mode 100644 erpnext/patches/v4_0/reload_sales_print_format.py delete mode 100644 erpnext/patches/v4_0/remove_employee_role_if_no_employee.py delete mode 100644 erpnext/patches/v4_0/remove_module_home_pages.py delete mode 100644 erpnext/patches/v4_0/rename_sitemap_to_route.py delete mode 100644 erpnext/patches/v4_0/reset_permissions_for_masters.py delete mode 100644 erpnext/patches/v4_0/save_default_letterhead.py delete mode 100644 erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py delete mode 100644 erpnext/patches/v4_0/split_email_settings.py delete mode 100644 erpnext/patches/v4_0/update_account_root_type.py delete mode 100644 erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py delete mode 100644 erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py delete mode 100644 erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py delete mode 100644 erpnext/patches/v4_0/update_tax_amount_after_discount.py delete mode 100644 erpnext/patches/v4_0/update_user_properties.py delete mode 100644 erpnext/patches/v4_0/update_users_report_view_settings.py delete mode 100644 erpnext/patches/v4_0/validate_v3_patch.py delete mode 100644 erpnext/patches/v4_1/__init__.py delete mode 100644 erpnext/patches/v4_1/fix_delivery_and_billing_status.py delete mode 100644 erpnext/patches/v4_1/fix_jv_remarks.py delete mode 100644 erpnext/patches/v4_1/fix_sales_order_delivered_status.py delete mode 100644 erpnext/patches/v4_1/set_outgoing_email_footer.py delete mode 100644 erpnext/patches/v4_2/__init__.py delete mode 100644 erpnext/patches/v4_2/add_currency_turkish_lira.py delete mode 100644 erpnext/patches/v4_2/default_website_style.py delete mode 100644 erpnext/patches/v4_2/delete_gl_entries_for_cancelled_invoices.py delete mode 100644 erpnext/patches/v4_2/delete_old_print_formats.py delete mode 100644 erpnext/patches/v4_2/discount_amount.py delete mode 100644 erpnext/patches/v4_2/fix_account_master_type.py delete mode 100644 erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py delete mode 100644 erpnext/patches/v4_2/fix_recurring_orders.py delete mode 100644 erpnext/patches/v4_2/party_model.py delete mode 100644 erpnext/patches/v4_2/recalculate_bom_cost.py delete mode 100644 erpnext/patches/v4_2/repost_sle_for_si_with_no_warehouse.py delete mode 100644 erpnext/patches/v4_2/repost_stock_reconciliation.py delete mode 100644 erpnext/patches/v4_2/reset_bom_costs.py delete mode 100644 erpnext/patches/v4_2/seprate_manufacture_and_repack.py delete mode 100644 erpnext/patches/v4_2/set_company_country.py delete mode 100644 erpnext/patches/v4_2/set_item_has_batch.py delete mode 100644 erpnext/patches/v4_2/toggle_rounded_total.py delete mode 100644 erpnext/patches/v4_2/update_landed_cost_voucher.py delete mode 100644 erpnext/patches/v4_2/update_project_milestones.py delete mode 100644 erpnext/patches/v4_2/update_sales_order_invoice_field_name.py delete mode 100644 erpnext/patches/v4_2/update_stock_uom_for_dn_in_sle.py delete mode 100644 erpnext/patches/v4_4/__init__.py delete mode 100644 erpnext/patches/v4_4/make_email_accounts.py delete mode 100644 erpnext/patches/v5_0/__init__.py delete mode 100644 erpnext/patches/v5_0/convert_stock_reconciliation.py delete mode 100644 erpnext/patches/v5_0/execute_on_doctype_update.py delete mode 100644 erpnext/patches/v5_0/fix_taxes_and_totals_in_party_currency.py delete mode 100644 erpnext/patches/v5_0/index_on_account_and_gl_entry.py delete mode 100644 erpnext/patches/v5_0/is_group.py delete mode 100644 erpnext/patches/v5_0/item_patches.py delete mode 100644 erpnext/patches/v5_0/link_warehouse_with_account.py delete mode 100644 erpnext/patches/v5_0/new_crm_module.py delete mode 100644 erpnext/patches/v5_0/newsletter.py delete mode 100644 erpnext/patches/v5_0/opportunity_not_submittable.py delete mode 100644 erpnext/patches/v5_0/party_model_patch_fix.py delete mode 100644 erpnext/patches/v5_0/portal_fixes.py delete mode 100644 erpnext/patches/v5_0/project_costing.py delete mode 100644 erpnext/patches/v5_0/recalculate_total_amount_in_jv.py delete mode 100644 erpnext/patches/v5_0/reclculate_planned_operating_cost_in_production_order.py delete mode 100644 erpnext/patches/v5_0/remove_birthday_events.py delete mode 100644 erpnext/patches/v5_0/rename_customer_issue.py delete mode 100644 erpnext/patches/v5_0/rename_pos_setting.py delete mode 100644 erpnext/patches/v5_0/rename_table_fieldnames.py delete mode 100644 erpnext/patches/v5_0/rename_taxes_and_charges_master.py delete mode 100644 erpnext/patches/v5_0/rename_total_fields.py delete mode 100644 erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py delete mode 100644 erpnext/patches/v5_0/repost_gle_for_jv_with_multiple_party.py delete mode 100644 erpnext/patches/v5_0/repost_requested_qty.py delete mode 100644 erpnext/patches/v5_0/reset_values_in_tools.py delete mode 100644 erpnext/patches/v5_0/set_appraisal_remarks.py delete mode 100644 erpnext/patches/v5_0/set_default_company_in_bom.py delete mode 100644 erpnext/patches/v5_0/set_footer_address.py delete mode 100644 erpnext/patches/v5_0/stock_entry_update_value.py delete mode 100644 erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py delete mode 100644 erpnext/patches/v5_0/update_account_types.py delete mode 100644 erpnext/patches/v5_0/update_advance_paid.py delete mode 100644 erpnext/patches/v5_0/update_companywise_payment_account.py delete mode 100644 erpnext/patches/v5_0/update_dn_against_doc_fields.py delete mode 100644 erpnext/patches/v5_0/update_from_bom.py delete mode 100644 erpnext/patches/v5_0/update_frozen_accounts_permission_role.py delete mode 100644 erpnext/patches/v5_0/update_item_and_description_again.py delete mode 100644 erpnext/patches/v5_0/update_item_desc_in_invoice.py delete mode 100644 erpnext/patches/v5_0/update_item_description_and_image.py delete mode 100644 erpnext/patches/v5_0/update_item_name_in_bom.py delete mode 100644 erpnext/patches/v5_0/update_journal_entry_title.py delete mode 100644 erpnext/patches/v5_0/update_material_transfer_for_manufacture.py delete mode 100644 erpnext/patches/v5_0/update_material_transferred_for_manufacturing.py delete mode 100644 erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py delete mode 100644 erpnext/patches/v5_0/update_operation_description.py delete mode 100644 erpnext/patches/v5_0/update_opportunity.py delete mode 100644 erpnext/patches/v5_0/update_projects.py delete mode 100644 erpnext/patches/v5_0/update_sms_sender.py delete mode 100644 erpnext/patches/v5_0/update_tax_amount_after_discount_in_purchase_cycle.py delete mode 100644 erpnext/patches/v5_0/update_temporary_account.py delete mode 100644 erpnext/patches/v5_0/update_time_log_title.py delete mode 100644 erpnext/patches/v5_1/__init__.py delete mode 100644 erpnext/patches/v5_1/default_bom.py delete mode 100644 erpnext/patches/v5_1/fix_against_account.py delete mode 100644 erpnext/patches/v5_1/rename_roles.py delete mode 100644 erpnext/patches/v5_1/sales_bom_rename.py delete mode 100644 erpnext/patches/v5_2/__init__.py delete mode 100644 erpnext/patches/v5_2/change_item_selects_to_checks.py delete mode 100644 erpnext/patches/v5_4/__init__.py delete mode 100644 erpnext/patches/v5_4/cleanup_journal_entry.py delete mode 100644 erpnext/patches/v5_4/fix_invoice_outstanding.py delete mode 100644 erpnext/patches/v5_4/fix_missing_item_images.py delete mode 100644 erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py delete mode 100644 erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py delete mode 100644 erpnext/patches/v5_4/set_root_and_report_type.py delete mode 100644 erpnext/patches/v5_4/stock_entry_additional_costs.py delete mode 100644 erpnext/patches/v5_4/update_purchase_cost_against_project.py delete mode 100644 erpnext/patches/v5_7/__init__.py delete mode 100644 erpnext/patches/v5_7/item_template_attributes.py delete mode 100644 erpnext/patches/v5_8/__init__.py delete mode 100644 erpnext/patches/v5_8/add_credit_note_print_heading.py delete mode 100644 erpnext/patches/v5_8/tax_rule.py delete mode 100644 erpnext/patches/v5_8/update_order_reference_in_return_entries.py delete mode 100644 erpnext/patches/v6_0/__init__.py delete mode 100644 erpnext/patches/v6_0/default_activity_rate.py delete mode 100644 erpnext/patches/v6_0/fix_outstanding_amount.py delete mode 100644 erpnext/patches/v6_0/fix_planned_qty.py delete mode 100644 erpnext/patches/v6_0/multi_currency.py delete mode 100644 erpnext/patches/v6_0/set_default_title.py delete mode 100644 erpnext/patches/v6_10/__init__.py delete mode 100644 erpnext/patches/v6_10/email_digest_default_quote.py delete mode 100644 erpnext/patches/v6_10/fix_billed_amount_in_drop_ship_po.py delete mode 100644 erpnext/patches/v6_10/fix_delivery_status_of_drop_ship_item.py delete mode 100644 erpnext/patches/v6_10/fix_jv_total_amount.py delete mode 100644 erpnext/patches/v6_10/fix_ordered_received_billed.py delete mode 100644 erpnext/patches/v6_12/__init__.py delete mode 100644 erpnext/patches/v6_12/repost_entries_with_target_warehouse.py delete mode 100644 erpnext/patches/v6_12/set_overdue_tasks.py delete mode 100644 erpnext/patches/v6_16/__init__.py delete mode 100644 erpnext/patches/v6_16/create_manufacturer_records.py delete mode 100644 erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py delete mode 100644 erpnext/patches/v6_19/__init__.py delete mode 100644 erpnext/patches/v6_19/comment_feed_communication.py delete mode 100644 erpnext/patches/v6_2/__init__.py delete mode 100644 erpnext/patches/v6_2/fix_missing_default_taxes_and_lead.py delete mode 100644 erpnext/patches/v6_2/remove_newsletter_duplicates.py delete mode 100644 erpnext/patches/v6_20/__init__.py delete mode 100644 erpnext/patches/v6_20/set_party_account_currency_in_orders.py delete mode 100644 erpnext/patches/v6_20x/__init__.py delete mode 100644 erpnext/patches/v6_20x/remove_customer_supplier_roles.py delete mode 100644 erpnext/patches/v6_20x/remove_fiscal_year_from_holiday_list.py delete mode 100644 erpnext/patches/v6_20x/rename_project_name_to_project.py delete mode 100644 erpnext/patches/v6_20x/repost_valuation_rate_for_negative_inventory.py delete mode 100644 erpnext/patches/v6_20x/set_compact_print.py delete mode 100644 erpnext/patches/v6_20x/update_product_bundle_description.py delete mode 100644 erpnext/patches/v6_21/__init__.py delete mode 100644 erpnext/patches/v6_21/fix_reorder_level.py delete mode 100644 erpnext/patches/v6_21/rename_material_request_fields.py delete mode 100644 erpnext/patches/v6_23/__init__.py delete mode 100644 erpnext/patches/v6_23/update_stopped_status_to_closed.py delete mode 100644 erpnext/patches/v6_24/__init__.py delete mode 100644 erpnext/patches/v6_24/map_customer_address_to_shipping_address_on_po.py delete mode 100644 erpnext/patches/v6_24/set_recurring_id.py delete mode 100644 erpnext/patches/v6_27/__init__.py delete mode 100644 erpnext/patches/v6_27/fix_recurring_order_status.py delete mode 100644 erpnext/patches/v6_3/__init__.py delete mode 100644 erpnext/patches/v6_3/convert_applicable_territory.py delete mode 100644 erpnext/patches/v6_4/__init__.py delete mode 100644 erpnext/patches/v6_4/email_digest_update.py delete mode 100644 erpnext/patches/v6_4/fix_duplicate_bins.py delete mode 100644 erpnext/patches/v6_4/fix_expense_included_in_valuation.py delete mode 100644 erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py delete mode 100644 erpnext/patches/v6_4/fix_modified_in_sales_order_and_purchase_order.py delete mode 100644 erpnext/patches/v6_4/fix_sales_order_maintenance_status.py delete mode 100644 erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py delete mode 100644 erpnext/patches/v6_4/make_image_thumbnail.py delete mode 100644 erpnext/patches/v6_4/repost_gle_for_journal_entries_where_reference_name_missing.py delete mode 100644 erpnext/patches/v6_4/round_status_updater_percentages.py delete mode 100644 erpnext/patches/v6_4/set_user_in_contact.py delete mode 100644 erpnext/patches/v6_5/__init__.py delete mode 100644 erpnext/patches/v6_5/show_in_website_for_template_item.py delete mode 100644 erpnext/patches/v6_6/__init__.py delete mode 100644 erpnext/patches/v6_6/fix_website_image.py delete mode 100644 erpnext/patches/v6_6/remove_fiscal_year_from_leave_allocation.py delete mode 100644 erpnext/patches/v6_8/__init__.py delete mode 100644 erpnext/patches/v6_8/make_webform_standard.py delete mode 100644 erpnext/patches/v6_8/move_drop_ship_to_po_items.py delete mode 100644 erpnext/patches/v7_0/__init__.py delete mode 100644 erpnext/patches/v7_0/calculate_total_costing_amount.py delete mode 100644 erpnext/patches/v7_0/convert_timelog_to_timesheet.py delete mode 100644 erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py delete mode 100644 erpnext/patches/v7_0/create_budget_record.py delete mode 100644 erpnext/patches/v7_0/create_warehouse_nestedset.py delete mode 100644 erpnext/patches/v7_0/fix_duplicate_icons.py delete mode 100644 erpnext/patches/v7_0/fix_nonwarehouse_ledger_gl_entries_for_transactions.py delete mode 100644 erpnext/patches/v7_0/make_guardian.py delete mode 100644 erpnext/patches/v7_0/make_is_group_fieldtype_as_check.py delete mode 100644 erpnext/patches/v7_0/merge_account_type_stock_and_warehouse_to_stock.py delete mode 100644 erpnext/patches/v7_0/migrate_mode_of_payments_v6_to_v7.py delete mode 100644 erpnext/patches/v7_0/migrate_schools_to_erpnext.py delete mode 100644 erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py delete mode 100644 erpnext/patches/v7_0/po_status_issue_for_pr_return.py delete mode 100644 erpnext/patches/v7_0/re_route.py delete mode 100644 erpnext/patches/v7_0/remove_administrator_role_in_doctypes.py delete mode 100644 erpnext/patches/v7_0/remove_doctypes_and_reports.py delete mode 100644 erpnext/patches/v7_0/remove_features_setup.py delete mode 100644 erpnext/patches/v7_0/remove_old_earning_deduction_doctypes.py delete mode 100644 erpnext/patches/v7_0/rename_advance_table_fields.py delete mode 100644 erpnext/patches/v7_0/rename_examination_to_assessment.py delete mode 100644 erpnext/patches/v7_0/rename_fee_amount_to_fee_component.py delete mode 100644 erpnext/patches/v7_0/rename_prevdoc_fields.py delete mode 100644 erpnext/patches/v7_0/rename_salary_components.py delete mode 100644 erpnext/patches/v7_0/rename_time_sheet_doctype.py delete mode 100644 erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py delete mode 100644 erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py delete mode 100644 erpnext/patches/v7_0/repost_gle_for_pos_sales_return.py delete mode 100644 erpnext/patches/v7_0/set_base_amount_in_invoice_payment_table.py delete mode 100644 erpnext/patches/v7_0/set_is_group_for_warehouse.py delete mode 100644 erpnext/patches/v7_0/set_material_request_type_in_item.py delete mode 100644 erpnext/patches/v7_0/set_naming_series_for_timesheet.py delete mode 100644 erpnext/patches/v7_0/set_party_name_in_payment_entry.py delete mode 100644 erpnext/patches/v7_0/set_portal_settings.py delete mode 100644 erpnext/patches/v7_0/setup_account_table_for_expense_claim_type_if_exists.py delete mode 100644 erpnext/patches/v7_0/system_settings_setup_complete.py delete mode 100644 erpnext/patches/v7_0/update_autoname_field.py delete mode 100644 erpnext/patches/v7_0/update_change_amount_account.py delete mode 100644 erpnext/patches/v7_0/update_conversion_factor_in_supplier_quotation_item.py delete mode 100644 erpnext/patches/v7_0/update_home_page.py delete mode 100644 erpnext/patches/v7_0/update_maintenance_module_in_doctype.py delete mode 100644 erpnext/patches/v7_0/update_mins_to_first_response.py delete mode 100644 erpnext/patches/v7_0/update_missing_employee_in_timesheet.py delete mode 100644 erpnext/patches/v7_0/update_mode_of_payment_type.py delete mode 100644 erpnext/patches/v7_0/update_party_status.py delete mode 100644 erpnext/patches/v7_0/update_prevdoc_values_for_supplier_quotation_item.py delete mode 100644 erpnext/patches/v7_0/update_project_in_gl_entry.py delete mode 100644 erpnext/patches/v7_0/update_refdoc_in_landed_cost_voucher.py delete mode 100644 erpnext/patches/v7_0/update_status_for_timesheet.py delete mode 100644 erpnext/patches/v7_0/update_status_of_po_so.py delete mode 100644 erpnext/patches/v7_0/update_status_of_zero_amount_sales_order.py delete mode 100644 erpnext/patches/v7_0/update_timesheet_communications.py delete mode 100644 erpnext/patches/v7_1/__init__.py delete mode 100644 erpnext/patches/v7_1/add_account_user_role_for_timesheet.py delete mode 100644 erpnext/patches/v7_1/add_field_for_task_dependent.py delete mode 100644 erpnext/patches/v7_1/fix_link_for_customer_from_lead.py delete mode 100644 erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py delete mode 100644 erpnext/patches/v7_1/rename_field_timesheet.py delete mode 100644 erpnext/patches/v7_1/rename_quality_inspection_field.py delete mode 100644 erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py delete mode 100644 erpnext/patches/v7_1/save_stock_settings.py delete mode 100644 erpnext/patches/v7_1/set_budget_against_as_cost_center.py delete mode 100644 erpnext/patches/v7_1/set_currency_exchange_date.py delete mode 100644 erpnext/patches/v7_1/set_prefered_contact_email.py delete mode 100644 erpnext/patches/v7_1/set_sales_person_status.py delete mode 100644 erpnext/patches/v7_1/set_student_guardian.py delete mode 100644 erpnext/patches/v7_1/set_total_amount_currency_in_je.py delete mode 100644 erpnext/patches/v7_1/update_bom_base_currency.py delete mode 100644 erpnext/patches/v7_1/update_component_type.py delete mode 100644 erpnext/patches/v7_1/update_invoice_status.py delete mode 100644 erpnext/patches/v7_1/update_lead_source.py delete mode 100644 erpnext/patches/v7_1/update_missing_salary_component_type.py delete mode 100644 erpnext/patches/v7_1/update_portal_roles.py delete mode 100644 erpnext/patches/v7_1/update_total_billing_hours.py delete mode 100644 erpnext/patches/v7_2/__init__.py delete mode 100644 erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py delete mode 100644 erpnext/patches/v7_2/contact_address_links.py delete mode 100644 erpnext/patches/v7_2/delete_fleet_management_module_def.py delete mode 100644 erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py delete mode 100644 erpnext/patches/v7_2/make_all_assessment_group.py delete mode 100644 erpnext/patches/v7_2/mark_students_active.py delete mode 100644 erpnext/patches/v7_2/rename_att_date_attendance.py delete mode 100644 erpnext/patches/v7_2/rename_evaluation_criteria.py delete mode 100644 erpnext/patches/v7_2/set_null_value_to_fields.py delete mode 100644 erpnext/patches/v7_2/setup_auto_close_settings.py delete mode 100644 erpnext/patches/v7_2/stock_uom_in_selling.py delete mode 100644 erpnext/patches/v7_2/update_abbr_in_salary_slips.py delete mode 100644 erpnext/patches/v7_2/update_assessment_modules.py delete mode 100644 erpnext/patches/v7_2/update_attendance_docstatus.py delete mode 100644 erpnext/patches/v7_2/update_doctype_status.py delete mode 100644 erpnext/patches/v7_2/update_guardian_name_in_student_master.py delete mode 100644 erpnext/patches/v7_2/update_party_type.py delete mode 100644 erpnext/patches/v7_2/update_salary_slips.py delete mode 100644 erpnext/patches/v7_2/update_website_for_variant.py delete mode 100644 erpnext/patches/v8_0/__init__.py delete mode 100644 erpnext/patches/v8_0/addresses_linked_to_lead.py delete mode 100644 erpnext/patches/v8_0/change_in_words_varchar_length.py delete mode 100644 erpnext/patches/v8_0/create_address_doc_from_address_field_in_company.py delete mode 100644 erpnext/patches/v8_0/create_domain_docs.py delete mode 100644 erpnext/patches/v8_0/delete_bin_indexes.py delete mode 100644 erpnext/patches/v8_0/delete_schools_depricated_doctypes.py delete mode 100644 erpnext/patches/v8_0/disable_instructor_role.py delete mode 100644 erpnext/patches/v8_0/enable_booking_asset_depreciation_automatically.py delete mode 100644 erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py delete mode 100644 erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py delete mode 100644 erpnext/patches/v8_0/merge_student_batch_and_student_group.py delete mode 100644 erpnext/patches/v8_0/move_account_head_from_account_to_warehouse_for_inventory.py delete mode 100644 erpnext/patches/v8_0/move_perpetual_inventory_setting.py delete mode 100644 erpnext/patches/v8_0/rename_is_sample_item_to_allow_zero_valuation_rate.py delete mode 100644 erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py delete mode 100644 erpnext/patches/v8_0/rename_total_margin_to_rate_with_margin.py delete mode 100644 erpnext/patches/v8_0/repost_reserved_qty_for_multiple_sales_uom.py delete mode 100644 erpnext/patches/v8_0/revert_manufacturers_table_from_item.py delete mode 100644 erpnext/patches/v8_0/save_system_settings.py delete mode 100644 erpnext/patches/v8_0/set_null_to_serial_nos_for_disabled_sales_invoices.py delete mode 100644 erpnext/patches/v8_0/set_project_copied_from.py delete mode 100644 erpnext/patches/v8_0/set_sales_invoice_serial_number_from_delivery_note.py delete mode 100644 erpnext/patches/v8_0/update_customer_pos_id.py delete mode 100644 erpnext/patches/v8_0/update_production_orders.py delete mode 100644 erpnext/patches/v8_0/update_sales_cost_in_project.py delete mode 100644 erpnext/patches/v8_0/update_status_as_paid_for_completed_expense_claim.py delete mode 100644 erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py delete mode 100644 erpnext/patches/v8_0/update_stock_qty_value_in_purchase_invoice.py delete mode 100644 erpnext/patches/v8_0/update_student_groups_from_student_batches.py delete mode 100644 erpnext/patches/v8_0/update_supplier_address_in_stock_entry.py delete mode 100644 erpnext/patches/v8_1/__init__.py delete mode 100644 erpnext/patches/v8_1/add_hsn_sac_codes.py delete mode 100644 erpnext/patches/v8_1/add_indexes_in_transaction_doctypes.py delete mode 100644 erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py delete mode 100644 erpnext/patches/v8_1/delete_deprecated_reports.py delete mode 100644 erpnext/patches/v8_1/gst_fixes.py delete mode 100644 erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py delete mode 100644 erpnext/patches/v8_1/removed_report_support_hours.py delete mode 100644 erpnext/patches/v8_1/set_delivery_date_in_so_item.py delete mode 100644 erpnext/patches/v8_1/update_expense_claim_status.py delete mode 100644 erpnext/patches/v8_1/update_gst_state.py delete mode 100644 erpnext/patches/v8_10/__init__.py delete mode 100644 erpnext/patches/v8_10/change_default_customer_credit_days.py delete mode 100644 erpnext/patches/v8_3/__init__.py delete mode 100644 erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py delete mode 100644 erpnext/patches/v8_3/update_company_total_sales.py delete mode 100644 erpnext/patches/v8_4/__init__.py delete mode 100644 erpnext/patches/v8_4/make_scorecard_records.py delete mode 100644 erpnext/patches/v8_5/__init__.py delete mode 100644 erpnext/patches/v8_5/fix_tax_breakup_for_non_invoice_docs.py delete mode 100644 erpnext/patches/v8_5/remove_project_type_property_setter.py delete mode 100644 erpnext/patches/v8_5/remove_quotations_route_in_sidebar.py delete mode 100644 erpnext/patches/v8_5/set_default_mode_of_payment.py delete mode 100644 erpnext/patches/v8_5/update_customer_group_in_POS_profile.py delete mode 100644 erpnext/patches/v8_5/update_existing_data_in_project_type.py delete mode 100644 erpnext/patches/v8_6/__init__.py delete mode 100644 erpnext/patches/v8_6/point_sms_doctype_module_to_frappe_core.py delete mode 100644 erpnext/patches/v8_6/rename_bom_update_tool.py delete mode 100644 erpnext/patches/v8_6/set_write_permission_for_quotation_for_sales_manager.py delete mode 100644 erpnext/patches/v8_6/update_timesheet_company_from_PO.py delete mode 100644 erpnext/patches/v8_7/__init__.py delete mode 100644 erpnext/patches/v8_7/fix_purchase_receipt_status.py delete mode 100644 erpnext/patches/v8_7/make_subscription_from_recurring_data.py delete mode 100644 erpnext/patches/v8_8/__init__.py delete mode 100644 erpnext/patches/v8_8/add_new_fields_in_accounts_settings.py delete mode 100644 erpnext/patches/v8_8/set_bom_rate_as_per_uom.py delete mode 100644 erpnext/patches/v8_9/__init__.py delete mode 100644 erpnext/patches/v8_9/add_setup_progress_actions.py delete mode 100644 erpnext/patches/v8_9/delete_gst_doctypes_for_outside_india_accounts.py delete mode 100644 erpnext/patches/v8_9/remove_employee_from_salary_structure_parent.py delete mode 100644 erpnext/patches/v8_9/rename_company_sales_target_field.py delete mode 100644 erpnext/patches/v8_9/set_default_customer_group.py delete mode 100644 erpnext/patches/v8_9/set_default_fields_in_variant_settings.py delete mode 100644 erpnext/patches/v8_9/set_member_party_type.py delete mode 100644 erpnext/patches/v8_9/set_print_zero_amount_taxes.py delete mode 100644 erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py delete mode 100644 erpnext/patches/v9_0/__init__.py delete mode 100644 erpnext/patches/v9_0/add_healthcare_domain.py delete mode 100644 erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py delete mode 100644 erpnext/patches/v9_0/copy_old_fees_field_data.py delete mode 100644 erpnext/patches/v9_0/remove_non_existing_warehouse_from_stock_settings.py delete mode 100644 erpnext/patches/v9_0/remove_subscription_module.py delete mode 100644 erpnext/patches/v9_0/revert_manufacturing_user_role.py delete mode 100644 erpnext/patches/v9_0/set_pos_profile_name.py delete mode 100644 erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py delete mode 100644 erpnext/patches/v9_0/set_shipping_type_for_existing_shipping_rules.py delete mode 100644 erpnext/patches/v9_0/set_uoms_in_variant_field.py delete mode 100644 erpnext/patches/v9_0/set_variant_item_description.py delete mode 100644 erpnext/patches/v9_0/student_admission_childtable_migrate.py delete mode 100644 erpnext/patches/v9_0/update_employee_loan_details.py delete mode 100644 erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py delete mode 100644 erpnext/patches/v9_1/__init__.py delete mode 100644 erpnext/patches/v9_1/create_issue_opportunity_type.py delete mode 100644 erpnext/patches/v9_2/__init__.py delete mode 100644 erpnext/patches/v9_2/delete_healthcare_domain_default_items.py delete mode 100644 erpnext/patches/v9_2/delete_process_payroll.py delete mode 100644 erpnext/patches/v9_2/remove_company_from_patient.py delete mode 100644 erpnext/patches/v9_2/rename_net_weight_in_item_master.py delete mode 100644 erpnext/patches/v9_2/rename_translated_domains_in_en.py delete mode 100644 erpnext/patches/v9_2/repost_reserved_qty_for_production.py delete mode 100644 erpnext/patches/v9_2/set_item_name_in_production_order.py diff --git a/erpnext/patches/repair_tools/__init__.py b/erpnext/patches/repair_tools/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py b/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py deleted file mode 100644 index 5a421d146f..0000000000 --- a/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - from erpnext.stock.stock_balance import set_stock_balance_as_per_serial_no - frappe.db.auto_commit_on_many_writes = 1 - - set_stock_balance_as_per_serial_no() - - frappe.db.auto_commit_on_many_writes = 0 diff --git a/erpnext/patches/v10_0/__init__.py b/erpnext/patches/v10_0/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v10_0/add_agriculture_domain.py b/erpnext/patches/v10_0/add_agriculture_domain.py deleted file mode 100644 index c18e69f3e6..0000000000 --- a/erpnext/patches/v10_0/add_agriculture_domain.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - domain = 'Agriculture' - if not frappe.db.exists('Domain', domain): - frappe.get_doc({ - 'doctype': 'Domain', - 'domain': domain - }).insert(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v10_0/add_guardian_role_for_parent_portal.py b/erpnext/patches/v10_0/add_guardian_role_for_parent_portal.py deleted file mode 100644 index 0b891f21f4..0000000000 --- a/erpnext/patches/v10_0/add_guardian_role_for_parent_portal.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # create guardian role - if not frappe.get_value('Role', dict(role_name='Guardian')): - frappe.get_doc({ - 'doctype': 'Role', - 'role_name': 'Guardian', - 'desk_access': 0, - 'restrict_to_domain': 'Education' - }).insert(ignore_permissions=True) - - # set guardian roles in already created users - if frappe.db.exists("Doctype", "Guardian"): - for user in frappe.db.sql_list("""select u.name from `tabUser` u , `tabGuardian` g where g.email_address = u.name"""): - user = frappe.get_doc('User', user) - user.flags.ignore_validate = True - user.flags.ignore_mandatory = True - user.save() diff --git a/erpnext/patches/v10_0/add_non_profit_domain.py b/erpnext/patches/v10_0/add_non_profit_domain.py deleted file mode 100644 index b03d669515..0000000000 --- a/erpnext/patches/v10_0/add_non_profit_domain.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - domain = 'Non Profit' - if not frappe.db.exists('Domain', domain): - frappe.get_doc({ - 'doctype': 'Domain', - 'domain': domain - }).insert(ignore_permissions=True) - - frappe.get_doc({ - 'doctype': 'Role', - 'role_name': 'Non Profit Portal User', - 'desk_access': 0, - 'restrict_to_domain': domain - }).insert(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v10_0/allow_operators_in_supplier_scorecard.py b/erpnext/patches/v10_0/allow_operators_in_supplier_scorecard.py deleted file mode 100644 index 827f9bc94f..0000000000 --- a/erpnext/patches/v10_0/allow_operators_in_supplier_scorecard.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2019, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('buying', 'doctype', 'supplier_scorecard_criteria') - frappe.reload_doc('buying', 'doctype', 'supplier_scorecard_scoring_criteria') - frappe.reload_doc('buying', 'doctype', 'supplier_scorecard') - - for criteria in frappe.get_all('Supplier Scorecard Criteria', fields=['name', 'formula'], limit_page_length=None): - frappe.db.set_value('Supplier Scorecard Criteria', criteria.name, - 'formula', criteria.formula.replace('<','<').replace('>','>')) - - for criteria in frappe.get_all('Supplier Scorecard Scoring Criteria', fields=['name', 'formula'], limit_page_length=None): - if criteria.formula: # not mandatory - frappe.db.set_value('Supplier Scorecard Scoring Criteria', criteria.name, - 'formula', criteria.formula.replace('<','<').replace('>','>')) - - for sc in frappe.get_all('Supplier Scorecard', fields=['name', 'weighting_function'], limit_page_length=None): - frappe.db.set_value('Supplier Scorecard', sc.name, 'weighting_function', - sc.weighting_function.replace('<','<').replace('>','>')) \ No newline at end of file diff --git a/erpnext/patches/v10_0/copy_projects_renamed_fields.py b/erpnext/patches/v10_0/copy_projects_renamed_fields.py deleted file mode 100644 index 80db3bdd1e..0000000000 --- a/erpnext/patches/v10_0/copy_projects_renamed_fields.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - """ copy data from old fields to new """ - frappe.reload_doc("projects", "doctype", "project") - - if frappe.db.has_column('Project', 'total_sales_cost'): - rename_field('Project', "total_sales_cost", "total_sales_amount") - - if frappe.db.has_column('Project', 'total_billing_amount'): - rename_field('Project', "total_billing_amount", "total_billable_amount") \ No newline at end of file diff --git a/erpnext/patches/v10_0/enabled_regional_print_format_based_on_country.py b/erpnext/patches/v10_0/enabled_regional_print_format_based_on_country.py deleted file mode 100644 index 38b04cebc2..0000000000 --- a/erpnext/patches/v10_0/enabled_regional_print_format_based_on_country.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - print_format_mapper = { - 'India': ['GST POS Invoice', 'GST Tax Invoice'], - 'Saudi Arabia': ['Simplified Tax Invoice', 'Detailed Tax Invoice', 'Tax Invoice'], - 'United Arab Emirates': ['Simplified Tax Invoice', 'Detailed Tax Invoice', 'Tax Invoice'] - } - - frappe.db.sql(""" update `tabPrint Format` set disabled = 1 where name - in ('GST POS Invoice', 'GST Tax Invoice', 'Simplified Tax Invoice', 'Detailed Tax Invoice')""") - - for d in frappe.get_all('Company', fields = ["country"], - filters={'country': ('in', ['India', 'Saudi Arabia', 'United Arab Emirates'])}): - if print_format_mapper.get(d.country): - print_formats = print_format_mapper.get(d.country) - frappe.db.sql(""" update `tabPrint Format` set disabled = 0 - where name in (%s)""" % ", ".join(["%s"]*len(print_formats)), tuple(print_formats)) \ No newline at end of file diff --git a/erpnext/patches/v10_0/fix_reserved_qty_for_sub_contract.py b/erpnext/patches/v10_0/fix_reserved_qty_for_sub_contract.py deleted file mode 100644 index c0a9e5eb5b..0000000000 --- a/erpnext/patches/v10_0/fix_reserved_qty_for_sub_contract.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.utils import get_bin - -def execute(): - frappe.reload_doc("stock", "doctype", "bin") - frappe.reload_doc("buying", "doctype", "purchase_order_item_supplied") - for d in frappe.db.sql(""" - select distinct rm_item_code, reserve_warehouse - from `tabPurchase Order Item Supplied` - where docstatus=1 and reserve_warehouse is not null and reserve_warehouse != ''"""): - - try: - bin_doc = get_bin(d[0], d[1]) - bin_doc.update_reserved_qty_for_sub_contracting() - except: - pass - - for d in frappe.db.sql("""select distinct item_code, source_warehouse - from `tabWork Order Item` - where docstatus=1 and transferred_qty > required_qty - and source_warehouse is not null and source_warehouse != ''""", as_list=1): - - try: - bin_doc = get_bin(d[0], d[1]) - bin_doc.update_reserved_qty_for_production() - except: - pass diff --git a/erpnext/patches/v10_0/recalculate_gross_margin_for_project.py b/erpnext/patches/v10_0/recalculate_gross_margin_for_project.py deleted file mode 100644 index 6d461f3bc9..0000000000 --- a/erpnext/patches/v10_0/recalculate_gross_margin_for_project.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('projects', 'doctype', 'project') - for d in frappe.db.sql(""" select name from `tabProject` where - ifnull(total_consumed_material_cost, 0 ) > 0 and ifnull(total_billed_amount, 0) > 0""", as_dict=1): - doc = frappe.get_doc("Project", d.name) - doc.calculate_gross_margin() - doc.db_set('gross_margin', doc.gross_margin) - doc.db_set('per_gross_margin', doc.per_gross_margin) \ No newline at end of file diff --git a/erpnext/patches/v10_0/rename_schools_to_education.py b/erpnext/patches/v10_0/rename_schools_to_education.py deleted file mode 100644 index 85c25a8943..0000000000 --- a/erpnext/patches/v10_0/rename_schools_to_education.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # rename the School module as Education - - # rename the school module - if frappe.db.exists('Module Def', 'Schools') and not frappe.db.exists('Module Def', 'Education'): - frappe.rename_doc("Module Def", "Schools", "Education") - - # delete the school module - if frappe.db.exists('Module Def', 'Schools') and frappe.db.exists('Module Def', 'Education'): - frappe.db.sql("""delete from `tabModule Def` where module_name = 'Schools'""") - - - # rename "School Settings" to the "Education Settings - if frappe.db.exists('DocType', 'School Settings'): - frappe.rename_doc("DocType", "School Settings", "Education Settings", force=True) - frappe.reload_doc("education", "doctype", "education_settings") - - # delete the discussion web form if exists - if frappe.db.exists('Web Form', 'Discussion'): - frappe.db.sql("""delete from `tabWeb Form` where name = 'discussion'""") - - # rename the select option field from "School Bus" to "Institute's Bus" - frappe.reload_doc("education", "doctype", "Program Enrollment") - if "mode_of_transportation" in frappe.db.get_table_columns("Program Enrollment"): - frappe.db.sql("""update `tabProgram Enrollment` set mode_of_transportation = "Institute's Bus" - where mode_of_transportation = "School Bus" """) diff --git a/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py b/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py deleted file mode 100644 index e6546e386b..0000000000 --- a/erpnext/patches/v10_0/repost_gle_for_purchase_receipts_with_rejected_items.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe, erpnext - -def execute(): - for company in frappe.get_all("Company"): - if not erpnext.is_perpetual_inventory_enabled(company.name): - continue - - acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto") or "1900-01-01" - pr_with_rejected_warehouse = frappe.db.sql(""" - select pr.name - from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item - where pr.name = pr_item.parent - and pr.posting_date > %s - and pr.docstatus=1 - and pr.company = %s - and pr_item.rejected_qty > 0 - """, (acc_frozen_upto, company.name), as_dict=1) - - for d in pr_with_rejected_warehouse: - doc = frappe.get_doc("Purchase Receipt", d.name) - - doc.docstatus = 2 - doc.make_gl_entries_on_cancel() - - - # update gl entries for submit state of PR - doc.docstatus = 1 - doc.make_gl_entries() diff --git a/erpnext/patches/v10_0/repost_requested_qty_for_non_stock_uom_items.py b/erpnext/patches/v10_0/repost_requested_qty_for_non_stock_uom_items.py deleted file mode 100644 index 4fe4e97cf5..0000000000 --- a/erpnext/patches/v10_0/repost_requested_qty_for_non_stock_uom_items.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2019, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty - - count=0 - for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse - from `tabMaterial Request Item` where docstatus = 1 and stock_uom<>uom"""): - try: - count += 1 - update_bin_qty(item_code, warehouse, { - "indented_qty": get_indented_qty(item_code, warehouse), - }) - if count % 200 == 0: - frappe.db.commit() - except: - frappe.db.rollback() diff --git a/erpnext/patches/v10_0/set_auto_created_serial_no_in_stock_entry.py b/erpnext/patches/v10_0/set_auto_created_serial_no_in_stock_entry.py deleted file mode 100644 index c6470f21d7..0000000000 --- a/erpnext/patches/v10_0/set_auto_created_serial_no_in_stock_entry.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - serialised_items = [d.name for d in frappe.get_all("Item", filters={"has_serial_no": 1})] - - if not serialised_items: - return - - for dt in ["Stock Entry Detail", "Purchase Receipt Item", "Purchase Invoice Item"]: - cond = "" - if dt=="Purchase Invoice Item": - cond = """ and parent in (select name from `tabPurchase Invoice` - where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.parent and update_stock=1)""" - - item_rows = frappe.db.sql(""" - select name - from `tab{0}` - where conversion_factor != 1 - and docstatus = 1 - and ifnull(serial_no, '') = '' - and item_code in ({1}) - {2} - """.format(dt, ', '.join(['%s']*len(serialised_items)), cond), tuple(serialised_items)) - - if item_rows: - sle_serial_nos = dict(frappe.db.sql(""" - select voucher_detail_no, serial_no - from `tabStock Ledger Entry` - where ifnull(serial_no, '') != '' - and voucher_detail_no in (%s) - """.format(', '.join(['%s']*len(item_rows))), - tuple([d[0] for d in item_rows]))) - - batch_size = 100 - for i in range(0, len(item_rows), batch_size): - batch_item_rows = item_rows[i:i + batch_size] - when_then = [] - for item_row in batch_item_rows: - - when_then.append('WHEN `name` = "{row_name}" THEN "{value}"'.format( - row_name=item_row[0], - value=sle_serial_nos.get(item_row[0]))) - - frappe.db.sql(""" - update - `tab{doctype}` - set - serial_no = CASE {when_then_cond} ELSE `serial_no` END - """.format( - doctype = dt, - when_then_cond=" ".join(when_then) - )) \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_b2c_limit.py b/erpnext/patches/v10_0/set_b2c_limit.py deleted file mode 100644 index 5d964e681a..0000000000 --- a/erpnext/patches/v10_0/set_b2c_limit.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("regional", "doctype", "gst_settings") - frappe.reload_doc("accounts", "doctype", "gst_account") - gst_settings = frappe.get_doc("GST Settings") - gst_settings.b2c_limit = 250000 - gst_settings.save() diff --git a/erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py b/erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py deleted file mode 100644 index a90e096390..0000000000 --- a/erpnext/patches/v10_0/set_default_payment_terms_based_on_company.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.patches.v8_10.change_default_customer_credit_days import make_payment_term, make_template - -def execute(): - for dt in ("Company", "Customer Group"): - frappe.reload_doc("setup", "doctype", frappe.scrub(dt)) - - credit_records = frappe.db.sql(""" - SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name` - from `tab{0}` - where - ((credit_days_based_on='Fixed Days' or credit_days_based_on is null) and credit_days is not null) - or credit_days_based_on='Last Day of the Next Month' - """.format(dt), as_dict=1) - - for d in credit_records: - template = create_payment_terms_template(d) - - frappe.db.sql(""" - update `tab{0}` - set `payment_terms` = %s - where name = %s - """.format(dt), (template.name, d.name)) - -def create_payment_terms_template(data): - if data.credit_days_based_on == "Fixed Days": - pyt_template_name = 'Default Payment Term - N{0}'.format(data.credit_days) - else: - pyt_template_name = 'Default Payment Term - EO2M' - - if not frappe.db.exists("Payment Terms Template", pyt_template_name): - payment_term = make_payment_term(data.credit_days, data.credit_days_based_on) - template = make_template(payment_term) - else: - template = frappe.get_doc("Payment Terms Template", pyt_template_name) - return template \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_discount_amount.py b/erpnext/patches/v10_0/set_discount_amount.py deleted file mode 100644 index d5e2c5a84b..0000000000 --- a/erpnext/patches/v10_0/set_discount_amount.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "sales_invoice_item") - frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_item') - frappe.reload_doc('buying', 'doctype', 'purchase_order_item') - frappe.reload_doc('buying', 'doctype', 'supplier_quotation_item') - frappe.reload_doc('selling', 'doctype', 'sales_order_item') - frappe.reload_doc('selling', 'doctype', 'quotation_item') - frappe.reload_doc('stock', 'doctype', 'delivery_note_item') - frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item') - - selling_doctypes = ["Sales Order Item", "Sales Invoice Item", "Delivery Note Item", "Quotation Item"] - buying_doctypes = ["Purchase Order Item", "Purchase Invoice Item", "Purchase Receipt Item", "Supplier Quotation Item"] - - for doctype in selling_doctypes: - frappe.db.sql(''' - UPDATE - `tab%s` - SET - discount_amount = if(rate_with_margin > 0, rate_with_margin, price_list_rate) * discount_percentage / 100 - WHERE - discount_percentage > 0 - ''' % (doctype)) - for doctype in buying_doctypes: - frappe.db.sql(''' - UPDATE - `tab%s` - SET - discount_amount = price_list_rate * discount_percentage / 100 - WHERE - discount_percentage > 0 - ''' % (doctype)) \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_numeric_ranges_in_template_if_blank.py b/erpnext/patches/v10_0/set_numeric_ranges_in_template_if_blank.py deleted file mode 100644 index 6825f19d74..0000000000 --- a/erpnext/patches/v10_0/set_numeric_ranges_in_template_if_blank.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - item_numeric_attributes = frappe.db.sql(""" - select name, numeric_values, from_range, to_range, increment - from `tabItem Attribute` - where numeric_values = 1 - """, as_dict=1) - - for d in item_numeric_attributes: - frappe.db.sql(""" - update `tabItem Variant Attribute` - set - from_range = CASE - WHEN from_range = 0 THEN %(from_range)s - ELSE from_range - END, - to_range = CASE - WHEN to_range = 0 THEN %(to_range)s - ELSE to_range - END, - increment = CASE - WHEN increment = 0 THEN %(increment)s - ELSE increment - END, - numeric_values = %(numeric_values)s - where - attribute = %(name)s - and exists(select name from tabItem - where name=`tabItem Variant Attribute`.parent and has_variants=1) - """, d) \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_primary_contact_for_customer.py b/erpnext/patches/v10_0/set_primary_contact_for_customer.py deleted file mode 100644 index ae0b31c21f..0000000000 --- a/erpnext/patches/v10_0/set_primary_contact_for_customer.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Customer') - - frappe.db.sql(""" - update - `tabCustomer`, ( - select `tabContact`.name, `tabContact`.mobile_no, `tabContact`.email_id, - `tabDynamic Link`.link_name from `tabContact`, `tabDynamic Link` - where `tabContact`.name = `tabDynamic Link`.parent and - `tabDynamic Link`.link_doctype = 'Customer' and `tabContact`.is_primary_contact = 1 - ) as contact - set - `tabCustomer`.customer_primary_contact = contact.name, - `tabCustomer`.mobile_no = contact.mobile_no, `tabCustomer`.email_id = contact.email_id - where `tabCustomer`.name = contact.link_name""") \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_qty_in_transactions_based_on_serial_no_input.py b/erpnext/patches/v10_0/set_qty_in_transactions_based_on_serial_no_input.py deleted file mode 100644 index 083b7f4b20..0000000000 --- a/erpnext/patches/v10_0/set_qty_in_transactions_based_on_serial_no_input.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("stock", "doctype", "stock_settings") - - ss = frappe.get_doc("Stock Settings") - ss.set_qty_in_transactions_based_on_serial_no_input = 1 - - if ss.default_warehouse \ - and not frappe.db.exists("Warehouse", ss.default_warehouse): - ss.default_warehouse = None - - if ss.stock_uom and not frappe.db.exists("UOM", ss.stock_uom): - ss.stock_uom = None - - ss.flags.ignore_mandatory = True - ss.save() \ No newline at end of file diff --git a/erpnext/patches/v10_0/set_student_party_type.py b/erpnext/patches/v10_0/set_student_party_type.py deleted file mode 100644 index 08376ae894..0000000000 --- a/erpnext/patches/v10_0/set_student_party_type.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if not frappe.db.exists("Party Type", "Student"): - party = frappe.new_doc("Party Type") - party.party_type = "Student" - party.save() diff --git a/erpnext/patches/v10_0/setup_vat_for_uae_and_saudi_arabia.py b/erpnext/patches/v10_0/setup_vat_for_uae_and_saudi_arabia.py deleted file mode 100644 index a8d90499d8..0000000000 --- a/erpnext/patches/v10_0/setup_vat_for_uae_and_saudi_arabia.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.setup.doctype.company.company import install_country_fixtures - -def execute(): - frappe.reload_doc("accounts", "doctype", "account") - frappe.reload_doc("accounts", "doctype", "payment_schedule") - for d in frappe.get_all('Company', - filters={'country': ('in', ['Saudi Arabia', 'United Arab Emirates'])}): - install_country_fixtures(d.name) \ No newline at end of file diff --git a/erpnext/patches/v10_0/show_leaves_of_all_department_members_in_calendar.py b/erpnext/patches/v10_0/show_leaves_of_all_department_members_in_calendar.py deleted file mode 100644 index 7e2ff7a8a7..0000000000 --- a/erpnext/patches/v10_0/show_leaves_of_all_department_members_in_calendar.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("hr", "doctype", "hr_settings") - frappe.db.set_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar", 1) \ No newline at end of file diff --git a/erpnext/patches/v10_0/taxes_issue_with_pos.py b/erpnext/patches/v10_0/taxes_issue_with_pos.py deleted file mode 100644 index 2a3275ac2c..0000000000 --- a/erpnext/patches/v10_0/taxes_issue_with_pos.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for d in frappe.get_all('Sales Invoice', fields=["name"], - filters = {'is_pos':1, 'docstatus': 1, 'creation': ('>', '2018-04-23')}): - doc = frappe.get_doc('Sales Invoice', d.name) - if (not doc.taxes and doc.taxes_and_charges and doc.pos_profile and doc.outstanding_amount != 0 and - frappe.db.get_value('POS Profile', doc.pos_profile, 'taxes_and_charges', cache=True) == doc.taxes_and_charges): - - doc.append_taxes_from_master() - doc.calculate_taxes_and_totals() - for d in doc.taxes: - d.db_update() - - doc.db_update() - - delete_gle_for_voucher(doc.name) - doc.make_gl_entries() - -def delete_gle_for_voucher(voucher_no): - frappe.db.sql("""delete from `tabGL Entry` where voucher_no = %(voucher_no)s""", - {'voucher_no': voucher_no}) \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_address_template_for_india.py b/erpnext/patches/v10_0/update_address_template_for_india.py deleted file mode 100644 index 1ddca93760..0000000000 --- a/erpnext/patches/v10_0/update_address_template_for_india.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.regional.address_template.setup import set_up_address_templates - -def execute(): - if frappe.db.get_value('Company', {'country': 'India'}, 'name'): - address_template = frappe.db.get_value('Address Template', 'India', 'template') - if not address_template or "gstin" not in address_template: - set_up_address_templates(default_country='India') diff --git a/erpnext/patches/v10_0/update_assessment_plan.py b/erpnext/patches/v10_0/update_assessment_plan.py deleted file mode 100644 index 174623c1a4..0000000000 --- a/erpnext/patches/v10_0/update_assessment_plan.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('education', 'doctype', 'assessment_plan') - - frappe.db.sql(""" - UPDATE `tabAssessment Plan` as ap - INNER JOIN `tabStudent Group` as sg ON sg.name = ap.student_group - SET ap.academic_term = sg.academic_term, - ap.academic_year = sg.academic_year, - ap.program = sg.program - WHERE ap.docstatus = 1 - """) \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_assessment_result.py b/erpnext/patches/v10_0/update_assessment_result.py deleted file mode 100644 index 96218db972..0000000000 --- a/erpnext/patches/v10_0/update_assessment_result.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('education', 'doctype', 'assessment_result') - - frappe.db.sql(""" - UPDATE `tabAssessment Result` AS ar - INNER JOIN `tabAssessment Plan` AS ap ON ap.name = ar.assessment_plan - SET ar.academic_term = ap.academic_term, - ar.academic_year = ap.academic_year, - ar.program = ap.program, - ar.course = ap.course, - ar.assessment_group = ap.assessment_group, - ar.student_group = ap.student_group - WHERE ap.docstatus = 1 - """) \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_asset_calculate_depreciation.py b/erpnext/patches/v10_0/update_asset_calculate_depreciation.py deleted file mode 100644 index b947a40b4a..0000000000 --- a/erpnext/patches/v10_0/update_asset_calculate_depreciation.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('assets', 'doctype', 'asset') - frappe.reload_doc('assets', 'doctype', 'depreciation_schedule') - - frappe.db.sql(""" - update tabAsset a - set calculate_depreciation = 1 - where exists(select ds.name from `tabDepreciation Schedule` ds where ds.parent=a.name) - """) \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_hub_connector_domain.py b/erpnext/patches/v10_0/update_hub_connector_domain.py deleted file mode 100644 index baf580a369..0000000000 --- a/erpnext/patches/v10_0/update_hub_connector_domain.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("Data Migration Connector"): - frappe.db.sql(""" - UPDATE `tabData Migration Connector` - SET hostname = 'https://hubmarket.org' - WHERE connector_name = 'Hub Connector' - """) \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_lft_rgt_for_employee.py b/erpnext/patches/v10_0/update_lft_rgt_for_employee.py deleted file mode 100644 index 46ca786e0d..0000000000 --- a/erpnext/patches/v10_0/update_lft_rgt_for_employee.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils.nestedset import rebuild_tree - -def execute(): - """ assign lft and rgt appropriately """ - frappe.reload_doc("hr", "doctype", "employee") - - rebuild_tree("Employee", "reports_to") \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_project_in_sle.py b/erpnext/patches/v10_0/update_project_in_sle.py deleted file mode 100644 index 08c64f18d8..0000000000 --- a/erpnext/patches/v10_0/update_project_in_sle.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ['Sales Invoice', 'Delivery Note', 'Stock Entry']: - frappe.db.sql(""" update - `tabStock Ledger Entry` sle, `tab{0}` parent_doc - set - sle.project = parent_doc.project - where - sle.voucher_no = parent_doc.name and sle.voucher_type = %s and sle.project is null - and parent_doc.project is not null and parent_doc.project != ''""".format(doctype), doctype) diff --git a/erpnext/patches/v10_0/update_reserved_qty_for_purchase_order.py b/erpnext/patches/v10_0/update_reserved_qty_for_purchase_order.py deleted file mode 100644 index 7b2c36698a..0000000000 --- a/erpnext/patches/v10_0/update_reserved_qty_for_purchase_order.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.stock.utils import get_bin - -def execute(): - po_item = list(frappe.db.sql((""" - select distinct po.name as poname, poitem.rm_item_code as rm_item_code, po.company - from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitem - where po.name = poitem.parent - and po.is_subcontracted = "Yes" - and po.docstatus = 1"""), as_dict=1)) - if not po_item: - return - - frappe.reload_doc("stock", "doctype", "bin") - frappe.reload_doc("buying", "doctype", "purchase_order_item_supplied") - company_warehouse = frappe._dict(frappe.db.sql("""select company, min(name) from `tabWarehouse` - where is_group = 0 group by company""")) - - items = list(set([d.rm_item_code for d in po_item])) - item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse - from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) - - # Update reserved warehouse - for item in po_item: - reserve_warehouse = get_warehouse(item.rm_item_code, item.company, company_warehouse, item_wh) - frappe.db.sql("""update `tabPurchase Order Item Supplied` - set reserve_warehouse = %s - where parent = %s and rm_item_code = %s - """, (reserve_warehouse, item["poname"], item["rm_item_code"])) - - # Update bin - item_wh_bin = frappe.db.sql((""" - select distinct poitemsup.rm_item_code as rm_item_code, - poitemsup.reserve_warehouse as reserve_warehouse - from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup - where po.name = poitemsup.parent - and po.is_subcontracted = "Yes" - and po.docstatus = 1"""), as_dict=1) - for d in item_wh_bin: - try: - stock_bin = get_bin(d["rm_item_code"], d["reserve_warehouse"]) - stock_bin.update_reserved_qty_for_sub_contracting() - except: - pass - -def get_warehouse(item_code, company, company_warehouse, item_wh): - reserve_warehouse = item_wh.get(item_code) - if frappe.db.get_value("Warehouse", reserve_warehouse, "company") != company: - reserve_warehouse = None - if not reserve_warehouse: - reserve_warehouse = company_warehouse.get(company) - return reserve_warehouse diff --git a/erpnext/patches/v10_0/update_sales_order_link_to_purchase_order.py b/erpnext/patches/v10_0/update_sales_order_link_to_purchase_order.py deleted file mode 100644 index b4f58384bf..0000000000 --- a/erpnext/patches/v10_0/update_sales_order_link_to_purchase_order.py +++ /dev/null @@ -1,18 +0,0 @@ -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("buying", "doctype", "supplier_quotation_item") - - for doctype in ['Purchase Order','Supplier Quotation']: - frappe.db.sql(""" - Update - `tab{doctype} Item`, `tabMaterial Request Item` - set - `tab{doctype} Item`.sales_order = `tabMaterial Request Item`.sales_order - where - `tab{doctype} Item`.material_request= `tabMaterial Request Item`.parent - and `tab{doctype} Item`.material_request_item = `tabMaterial Request Item`.name - and `tabMaterial Request Item`.sales_order is not null""".format(doctype=doctype)) \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_status_for_multiple_source_in_po.py b/erpnext/patches/v10_0/update_status_for_multiple_source_in_po.py deleted file mode 100644 index fd3be08b89..0000000000 --- a/erpnext/patches/v10_0/update_status_for_multiple_source_in_po.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - - - # update the sales order item in the material request - frappe.reload_doc('stock', 'doctype', 'material_request_item') - frappe.db.sql('''update `tabMaterial Request Item` mri, `tabSales Order Item` soi - set mri.sales_order_item = soi.name - where ifnull(mri.sales_order, "")!="" and soi.parent=mri.sales_order - and soi.item_code=mri.item_code and mri.docstatus=1 - ''') - - # update the sales order item in the purchase order - frappe.db.sql('''update `tabPurchase Order Item` poi, `tabSales Order Item` soi - set poi.sales_order_item = soi.name - where ifnull(poi.sales_order, "")!="" and soi.parent=poi.sales_order - and soi.item_code=poi.item_code and poi.docstatus = 1 - ''') - - # Update the status in material request and sales order - po_list = frappe.db.sql(''' - select parent from `tabPurchase Order Item` where ifnull(material_request, "")!="" and - ifnull(sales_order, "")!="" and docstatus=1 - ''',as_dict=1) - - for po in list(set([d.get("parent") for d in po_list if d.get("parent")])): - try: - po_doc = frappe.get_doc("Purchase Order", po) - - # update the so in the status updater - po_doc.update_status_updater() - po_doc.update_qty(update_modified=False) - - except Exception: - pass diff --git a/erpnext/patches/v10_0/update_status_in_purchase_receipt.py b/erpnext/patches/v10_0/update_status_in_purchase_receipt.py deleted file mode 100644 index a0bdd9e2cc..0000000000 --- a/erpnext/patches/v10_0/update_status_in_purchase_receipt.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("stock", "doctype", "purchase_receipt") - frappe.db.sql(''' - UPDATE `tabPurchase Receipt` SET status = "Completed" WHERE per_billed = 100 AND docstatus = 1 - ''') \ No newline at end of file diff --git a/erpnext/patches/v10_0/update_territory_and_customer_group.py b/erpnext/patches/v10_0/update_territory_and_customer_group.py deleted file mode 100644 index 7f3dae991d..0000000000 --- a/erpnext/patches/v10_0/update_territory_and_customer_group.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.rename_doc import get_fetch_fields - -def execute(): - ignore_doctypes = ["Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule"] - customers = frappe.get_all('Customer', fields=["name", "customer_group"]) - customer_group_fetch = get_fetch_fields('Customer', 'Customer Group', ignore_doctypes) - - batch_size = 1000 - for i in range(0, len(customers), batch_size): - batch_customers = customers[i:i + batch_size] - for d in customer_group_fetch: - when_then = [] - for customer in batch_customers: - value = frappe.db.escape(frappe.as_unicode(customer.get("customer_group"))) - - when_then.append(''' - WHEN `%s` = %s and %s != %s - THEN %s - '''%(d["master_fieldname"], frappe.db.escape(frappe.as_unicode(customer.name)), - d["linked_to_fieldname"], value, value)) - - frappe.db.sql(""" - update - `tab%s` - set - %s = CASE %s ELSE `%s` END - """%(d['doctype'], d.linked_to_fieldname, " ".join(when_then), d.linked_to_fieldname)) diff --git a/erpnext/patches/v10_0/update_user_image_in_employee.py b/erpnext/patches/v10_0/update_user_image_in_employee.py deleted file mode 100644 index 72d5d2a857..0000000000 --- a/erpnext/patches/v10_0/update_user_image_in_employee.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('hr', 'doctype', 'employee') - - frappe.db.sql(""" - UPDATE - `tabEmployee`, `tabUser` - SET - `tabEmployee`.image = `tabUser`.user_image - WHERE - `tabEmployee`.user_id = `tabUser`.name and - `tabEmployee`.user_id is not null and - `tabEmployee`.user_id != '' and `tabEmployee`.image is null - """) diff --git a/erpnext/patches/v10_0/update_warehouse_address_details.py b/erpnext/patches/v10_0/update_warehouse_address_details.py deleted file mode 100644 index b982b9a662..0000000000 --- a/erpnext/patches/v10_0/update_warehouse_address_details.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - warehouse = frappe.db.sql("""select name, email_id, phone_no, mobile_no, address_line_1, - address_line_2, city, state, pin from `tabWarehouse` where ifnull(address_line_1, '') != '' - or ifnull(mobile_no, '') != '' - or ifnull(email_id, '') != '' """, as_dict=1) - - for d in warehouse: - try: - address = frappe.new_doc('Address') - address.name = d.name - address.address_title = d.name - address.address_line1 = d.address_line_1 - address.city = d.city - address.state = d.state - address.pincode = d.pin - address.db_insert() - address.append('links',{'link_doctype':'Warehouse','link_name':d.name}) - address.links[0].db_insert() - if d.name and (d.email_id or d.mobile_no or d.phone_no): - contact = frappe.new_doc('Contact') - contact.name = d.name - contact.first_name = d.name - contact.mobile_no = d.mobile_no - contact.email_id = d.email_id - contact.phone = d.phone_no - contact.db_insert() - contact.append('links',{'link_doctype':'Warehouse','link_name':d.name}) - contact.links[0].db_insert() - except frappe.DuplicateEntryError: - pass - \ No newline at end of file diff --git a/erpnext/patches/v10_1/__init__.py b/erpnext/patches/v10_1/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v11_0/__init__.py b/erpnext/patches/v11_0/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v11_0/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v11_0/remove_subscriber_doctype.py b/erpnext/patches/v11_0/remove_subscriber_doctype.py deleted file mode 100644 index 4839a20f91..0000000000 --- a/erpnext/patches/v11_0/remove_subscriber_doctype.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - """ copy subscribe field to customer """ - frappe.reload_doc("accounts","doctype","subscription") - - if frappe.db.exists("DocType", "Subscriber"): - if frappe.db.has_column('Subscription','subscriber'): - frappe.db.sql(""" - update `tabSubscription` s1 - set customer=(select customer from tabSubscriber where name=s1.subscriber) - """) - - frappe.delete_doc("DocType", "Subscriber") \ No newline at end of file diff --git a/erpnext/patches/v11_1/__init__.py b/erpnext/patches/v11_1/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v12_0/__init__.py b/erpnext/patches/v12_0/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v13_0/__init__.py b/erpnext/patches/v13_0/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v13_0/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v4_0/__init__.py b/erpnext/patches/v4_0/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v4_0/apply_user_permissions.py b/erpnext/patches/v4_0/apply_user_permissions.py deleted file mode 100644 index 3c5d612c18..0000000000 --- a/erpnext/patches/v4_0/apply_user_permissions.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.hr.doctype.employee.employee import EmployeeUserDisabledError - -def execute(): - update_hr_permissions() - update_permissions() - remove_duplicate_user_permissions() - frappe.clear_cache() - -def update_hr_permissions(): - # add set user permissions rights to HR Manager - frappe.db.sql("""update `tabDocPerm` set `set_user_permissions`=1 where parent in ('Employee', 'Leave Application') - and role='HR Manager' and permlevel=0 and `read`=1""") - docperm_meta = frappe.get_meta('DocPerm') - if docperm_meta.get_field('apply_user_permissions'): - # apply user permissions on Employee and Leave Application - frappe.db.sql("""update `tabDocPerm` set `apply_user_permissions`=1 where parent in ('Employee', 'Leave Application') - and role in ('Employee', 'Leave Approver') and permlevel=0 and `read`=1""") - - frappe.clear_cache() - - # save employees to run on_update events - for employee in frappe.db.sql_list("""select name from `tabEmployee` where docstatus < 2"""): - try: - emp = frappe.get_doc("Employee", employee) - emp.flags.ignore_mandatory = True - emp.save() - except EmployeeUserDisabledError: - pass - -def update_permissions(): - # clear match conditions other than owner - frappe.db.sql("""update tabDocPerm set `match`='' - where ifnull(`match`,'') not in ('', 'owner')""") - -def remove_duplicate_user_permissions(): - # remove duplicate user_permissions (if they exist) - for d in frappe.db.sql("""select parent, defkey, defvalue, - count(*) as cnt from tabDefaultValue - where parent not in ('__global', '__default') - group by parent, defkey, defvalue""", as_dict=1): - if d.cnt > 1: - # order by parenttype so that user permission does not get removed! - frappe.db.sql("""delete from tabDefaultValue where `parent`=%s and `defkey`=%s and - `defvalue`=%s order by parenttype limit %s""", (d.parent, d.defkey, d.defvalue, d.cnt-1)) - diff --git a/erpnext/patches/v4_0/countrywise_coa.py b/erpnext/patches/v4_0/countrywise_coa.py deleted file mode 100644 index f45e6028c8..0000000000 --- a/erpnext/patches/v4_0/countrywise_coa.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("setup", 'doctype', "company") - frappe.reload_doc("accounts", 'doctype', "account") - - frappe.db.sql("""update tabAccount set account_type='Cash' - where account_type='Bank or Cash' and account_name in ('Cash', 'Cash In Hand')""") - - frappe.db.sql("""update tabAccount set account_type='Stock' - where account_name = 'Stock Assets'""") - - ac_types = {"Fixed Asset Account": "Fixed Asset", "Bank or Cash": "Bank"} - for old, new in ac_types.items(): - frappe.db.sql("""update tabAccount set account_type=%s - where account_type=%s""", (new, old)) - - try: - frappe.db.sql("""update `tabAccount` set report_type = - if(is_pl_account='Yes', 'Profit and Loss', 'Balance Sheet')""") - - frappe.db.sql("""update `tabAccount` set balance_must_be=debit_or_credit - where ifnull(allow_negative_balance, 0) = 0""") - except: - pass diff --git a/erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py b/erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py deleted file mode 100644 index fe50e444b5..0000000000 --- a/erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.custom.doctype.custom_field.custom_field import create_custom_field_if_values_exist - -def execute(): - frappe.reload_doc("stock", "doctype", "purchase_receipt") - frappe.reload_doc("hr", "doctype", "employee") - frappe.reload_doc("Payroll", "doctype", "salary_slip") - - india_specific_fields = { - "Purchase Receipt": [{ - "label": "Supplier Shipment No", - "fieldname": "challan_no", - "fieldtype": "Data", - "insert_after": "is_subcontracted" - }, { - "label": "Supplier Shipment Date", - "fieldname": "challan_date", - "fieldtype": "Date", - "insert_after": "is_subcontracted" - }], - "Employee": [{ - "label": "PAN Number", - "fieldname": "pan_number", - "fieldtype": "Data", - "insert_after": "company_email" - }, { - "label": "Gratuity LIC Id", - "fieldname": "gratuity_lic_id", - "fieldtype": "Data", - "insert_after": "company_email" - }, { - "label": "Esic Card No", - "fieldname": "esic_card_no", - "fieldtype": "Data", - "insert_after": "bank_ac_no" - }, { - "label": "PF Number", - "fieldname": "pf_number", - "fieldtype": "Data", - "insert_after": "bank_ac_no" - }], - "Salary Slip": [{ - "label": "Esic No", - "fieldname": "esic_no", - "fieldtype": "Data", - "insert_after": "letter_head", - "permlevel": 1 - }, { - "label": "PF Number", - "fieldname": "pf_no", - "fieldtype": "Data", - "insert_after": "letter_head", - "permlevel": 1 - }] - } - - for dt, docfields in india_specific_fields.items(): - for df in docfields: - create_custom_field_if_values_exist(dt, df) diff --git a/erpnext/patches/v4_0/create_price_list_if_missing.py b/erpnext/patches/v4_0/create_price_list_if_missing.py deleted file mode 100644 index 039e52111c..0000000000 --- a/erpnext/patches/v4_0/create_price_list_if_missing.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe import _ -from frappe.utils.nestedset import get_root_of - -def execute(): - # setup not complete - if not frappe.db.sql("""select name from tabCompany limit 1"""): - return - - if "shopping_cart" in frappe.get_installed_apps(): - frappe.reload_doc("shopping_cart", "doctype", "shopping_cart_settings") - - if not frappe.db.sql("select name from `tabPrice List` where buying=1"): - create_price_list(_("Standard Buying"), buying=1) - - if not frappe.db.sql("select name from `tabPrice List` where selling=1"): - create_price_list(_("Standard Selling"), selling=1) - -def create_price_list(pl_name, buying=0, selling=0): - price_list = frappe.get_doc({ - "doctype": "Price List", - "price_list_name": pl_name, - "enabled": 1, - "buying": buying, - "selling": selling, - "currency": frappe.db.get_default("currency"), - "territories": [{ - "territory": get_root_of("Territory") - }] - }) - price_list.insert() diff --git a/erpnext/patches/v4_0/customer_discount_to_pricing_rule.py b/erpnext/patches/v4_0/customer_discount_to_pricing_rule.py deleted file mode 100644 index 1b260c48cc..0000000000 --- a/erpnext/patches/v4_0/customer_discount_to_pricing_rule.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils.nestedset import get_root_of - -def execute(): - frappe.reload_doc("accounts", "doctype", "pricing_rule") - - frappe.db.auto_commit_on_many_writes = True - - default_item_group = get_root_of("Item Group") - - for d in frappe.db.sql("""select * from `tabCustomer Discount` - where ifnull(parent, '') != ''""", as_dict=1): - if not d.discount: - continue - - frappe.get_doc({ - "doctype": "Pricing Rule", - "apply_on": "Item Group", - "item_group": d.item_group or default_item_group, - "applicable_for": "Customer", - "customer": d.parent, - "price_or_discount": "Discount Percentage", - "discount_percentage": d.discount, - "selling": 1 - }).insert() - - frappe.db.auto_commit_on_many_writes = False - - frappe.delete_doc("DocType", "Customer Discount") diff --git a/erpnext/patches/v4_0/fields_to_be_renamed.py b/erpnext/patches/v4_0/fields_to_be_renamed.py deleted file mode 100644 index cc17697132..0000000000 --- a/erpnext/patches/v4_0/fields_to_be_renamed.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field -from frappe.modules import scrub, get_doctype_module - -rename_map = { - "Quotation Item": [ - ["ref_rate", "price_list_rate"], - ["base_ref_rate", "base_price_list_rate"], - ["adj_rate", "discount_percentage"], - ["export_rate", "rate"], - ["basic_rate", "base_rate"], - ["amount", "base_amount"], - ["export_amount", "amount"] - ], - - "Sales Order Item": [ - ["ref_rate", "price_list_rate"], - ["base_ref_rate", "base_price_list_rate"], - ["adj_rate", "discount_percentage"], - ["export_rate", "rate"], - ["basic_rate", "base_rate"], - ["amount", "base_amount"], - ["export_amount", "amount"], - ["reserved_warehouse", "warehouse"] - ], - - "Delivery Note Item": [ - ["ref_rate", "price_list_rate"], - ["base_ref_rate", "base_price_list_rate"], - ["adj_rate", "discount_percentage"], - ["export_rate", "rate"], - ["basic_rate", "base_rate"], - ["amount", "base_amount"], - ["export_amount", "amount"] - ], - - "Sales Invoice Item": [ - ["ref_rate", "price_list_rate"], - ["base_ref_rate", "base_price_list_rate"], - ["adj_rate", "discount_percentage"], - ["export_rate", "rate"], - ["basic_rate", "base_rate"], - ["amount", "base_amount"], - ["export_amount", "amount"] - ], - - "Supplier Quotation Item": [ - ["import_ref_rate", "price_list_rate"], - ["purchase_ref_rate", "base_price_list_rate"], - ["discount_rate", "discount_percentage"], - ["import_rate", "rate"], - ["purchase_rate", "base_rate"], - ["amount", "base_amount"], - ["import_amount", "amount"] - ], - - "Purchase Order Item": [ - ["import_ref_rate", "price_list_rate"], - ["purchase_ref_rate", "base_price_list_rate"], - ["discount_rate", "discount_percentage"], - ["import_rate", "rate"], - ["purchase_rate", "base_rate"], - ["amount", "base_amount"], - ["import_amount", "amount"] - ], - - "Purchase Receipt Item": [ - ["import_ref_rate", "price_list_rate"], - ["purchase_ref_rate", "base_price_list_rate"], - ["discount_rate", "discount_percentage"], - ["import_rate", "rate"], - ["purchase_rate", "base_rate"], - ["amount", "base_amount"], - ["import_amount", "amount"] - ], - - "Purchase Invoice Item": [ - ["import_ref_rate", "price_list_rate"], - ["purchase_ref_rate", "base_price_list_rate"], - ["discount_rate", "discount_percentage"], - ["import_rate", "rate"], - ["rate", "base_rate"], - ["amount", "base_amount"], - ["import_amount", "amount"], - ["expense_head", "expense_account"] - ], - - "Item": [ - ["purchase_account", "expense_account"], - ["default_sales_cost_center", "selling_cost_center"], - ["cost_center", "buying_cost_center"], - ["default_income_account", "income_account"], - ], - "Item Price": [ - ["ref_rate", "price_list_rate"] - ] -} - -def execute(): - for dn in rename_map: - frappe.reload_doc(get_doctype_module(dn), "doctype", scrub(dn)) - - for dt, field_list in rename_map.items(): - for field in field_list: - rename_field(dt, field[0], field[1]) diff --git a/erpnext/patches/v4_0/fix_address_template.py b/erpnext/patches/v4_0/fix_address_template.py deleted file mode 100644 index 905e3db3e8..0000000000 --- a/erpnext/patches/v4_0/fix_address_template.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors - -from __future__ import unicode_literals -import frappe - -def execute(): - missing_line = """{{ address_line1 }}
""" - for name, template in frappe.db.sql("select name, template from `tabAddress Template`"): - if missing_line not in template: - d = frappe.get_doc("Address Template", name) - d.template = missing_line + d.template - d.save() diff --git a/erpnext/patches/v4_0/fix_case_of_hr_module_def.py b/erpnext/patches/v4_0/fix_case_of_hr_module_def.py deleted file mode 100644 index e77b427b77..0000000000 --- a/erpnext/patches/v4_0/fix_case_of_hr_module_def.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors - -from __future__ import unicode_literals -import frappe - -def execute(): - hr = frappe.db.get_value("Module Def", "HR") - if hr == "Hr": - frappe.rename_doc("Module Def", "Hr", "HR") - frappe.db.set_value("Module Def", "HR", "module_name", "HR") - - frappe.clear_cache() - frappe.setup_module_map() diff --git a/erpnext/patches/v4_0/fix_contact_address.py b/erpnext/patches/v4_0/fix_contact_address.py deleted file mode 100644 index 6a3e106b8c..0000000000 --- a/erpnext/patches/v4_0/fix_contact_address.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("website", "doctype", "contact_us_settings") - address = frappe.db.get_value("Contact Us Settings", None, "address") - if address: - address = frappe.get_doc("Address", address) - contact = frappe.get_doc("Contact Us Settings", "Contact Us Settings") - for f in ("address_title", "address_line1", "address_line2", "city", "state", "country", "pincode"): - contact.set(f, address.get(f)) - - contact.save() \ No newline at end of file diff --git a/erpnext/patches/v4_0/fix_employee_user_id.py b/erpnext/patches/v4_0/fix_employee_user_id.py deleted file mode 100644 index 6f449f97bb..0000000000 --- a/erpnext/patches/v4_0/fix_employee_user_id.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.utils import get_fullname - -def execute(): - for user_id in frappe.db.sql_list("""select distinct user_id from `tabEmployee` - where ifnull(user_id, '')!='' - group by user_id having count(name) > 1"""): - - fullname = get_fullname(user_id) - employee = frappe.db.get_value("Employee", {"employee_name": fullname, "user_id": user_id}) - - if employee: - frappe.db.sql("""update `tabEmployee` set user_id=null - where user_id=%s and name!=%s""", (user_id, employee)) - else: - count = frappe.db.sql("""select count(*) from `tabEmployee` where user_id=%s""", user_id)[0][0] - frappe.db.sql("""update `tabEmployee` set user_id=null - where user_id=%s limit %s""", (user_id, count - 1)) diff --git a/erpnext/patches/v4_0/global_defaults_to_system_settings.py b/erpnext/patches/v4_0/global_defaults_to_system_settings.py deleted file mode 100644 index 2905fe1e6a..0000000000 --- a/erpnext/patches/v4_0/global_defaults_to_system_settings.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -from __future__ import unicode_literals - -import frappe -from collections import Counter -from frappe.core.doctype.user.user import STANDARD_USERS - -def execute(): - frappe.reload_doc("core", "doctype", "system_settings") - system_settings = frappe.get_doc("System Settings") - - # set values from global_defauls - global_defaults = frappe.db.get_value("Global Defaults", None, - ["time_zone", "date_format", "number_format", "float_precision", "session_expiry"], as_dict=True) - - if global_defaults: - for key, val in global_defaults.items(): - if not system_settings.get(key): - system_settings.set(key, val) - - # language - if not system_settings.get("language"): - # find most common language - lang = frappe.db.sql_list("""select language from `tabUser` - where ifnull(language, '')!='' and language not like "Loading%%" and name not in ({standard_users})""".format( - standard_users=", ".join(["%s"]*len(STANDARD_USERS))), tuple(STANDARD_USERS)) - lang = Counter(lang).most_common(1) - lang = (len(lang) > 0) and lang[0][0] or "english" - - system_settings.language = lang - - system_settings.flags.ignore_mandatory = True - system_settings.save() - - global_defaults = frappe.get_doc("Global Defaults") - global_defaults.flags.ignore_mandatory = True - global_defaults.save() diff --git a/erpnext/patches/v4_0/import_country_codes.py b/erpnext/patches/v4_0/import_country_codes.py deleted file mode 100644 index 43e23d5b63..0000000000 --- a/erpnext/patches/v4_0/import_country_codes.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.geo.country_info import get_all -from frappe.utils.install import import_country_and_currency - -from six import iteritems - -def execute(): - frappe.reload_doc("setup", "doctype", "country") - import_country_and_currency() - for name, country in iteritems(get_all()): - frappe.set_value("Country", name, "code", country.get("code")) \ No newline at end of file diff --git a/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py b/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py deleted file mode 100644 index 97e217aa05..0000000000 --- a/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # update sales cycle - for d in ['Sales Invoice', 'Sales Order', 'Quotation', 'Delivery Note']: - frappe.db.sql("""update `tab%s` set taxes_and_charges=charge""" % d) - - # update purchase cycle - for d in ['Purchase Invoice', 'Purchase Order', 'Supplier Quotation', 'Purchase Receipt']: - frappe.db.sql("""update `tab%s` set taxes_and_charges=purchase_other_charges""" % d) - - frappe.db.sql("""update `tabPurchase Taxes and Charges` set parentfield='other_charges'""") diff --git a/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py b/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py deleted file mode 100644 index 8b81936d8d..0000000000 --- a/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import frappe.permissions - -def execute(): - for warehouse, user in frappe.db.sql("""select parent, user from `tabWarehouse User`"""): - frappe.permissions.add_user_permission("Warehouse", warehouse, user) - - frappe.delete_doc_if_exists("DocType", "Warehouse User") - frappe.reload_doc("stock", "doctype", "warehouse") diff --git a/erpnext/patches/v4_0/new_address_template.py b/erpnext/patches/v4_0/new_address_template.py deleted file mode 100644 index fa6602706e..0000000000 --- a/erpnext/patches/v4_0/new_address_template.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - frappe.reload_doc("utilities", "doctype", "address_template") - if not frappe.db.sql("select name from `tabAddress Template`"): - try: - d = frappe.new_doc("Address Template") - d.update({"country":frappe.db.get_default("country") or - frappe.db.get_value("Global Defaults", "Global Defaults", "country")}) - d.insert() - except: - print(frappe.get_traceback()) - diff --git a/erpnext/patches/v4_0/reload_sales_print_format.py b/erpnext/patches/v4_0/reload_sales_print_format.py deleted file mode 100644 index b8f090f9f3..0000000000 --- a/erpnext/patches/v4_0/reload_sales_print_format.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'Print Format', 'POS Invoice') diff --git a/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py b/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py deleted file mode 100644 index 8766ace54f..0000000000 --- a/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import frappe.permissions - -def execute(): - for user in frappe.db.sql_list("select distinct parent from `tabHas Role` where role='Employee'"): - # if employee record does not exists, remove employee role! - if not frappe.db.get_value("Employee", {"user_id": user}): - try: - user = frappe.get_doc("User", user) - for role in user.get("roles", {"role": "Employee"}): - user.get("roles").remove(role) - user.save() - except frappe.DoesNotExistError: - pass diff --git a/erpnext/patches/v4_0/remove_module_home_pages.py b/erpnext/patches/v4_0/remove_module_home_pages.py deleted file mode 100644 index a2720e0ebf..0000000000 --- a/erpnext/patches/v4_0/remove_module_home_pages.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for page in ("accounts-home", "website-home", "support-home", "stock-home", "selling-home", "projects-home", - "manufacturing-home", "hr-home", "buying-home"): - frappe.delete_doc("Page", page) \ No newline at end of file diff --git a/erpnext/patches/v4_0/rename_sitemap_to_route.py b/erpnext/patches/v4_0/rename_sitemap_to_route.py deleted file mode 100644 index ffb1fda144..0000000000 --- a/erpnext/patches/v4_0/rename_sitemap_to_route.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -import frappe -import frappe.model - -def execute(): - frappe.reload_doc("setup", "doctype", "item_group") - frappe.reload_doc("stock", "doctype", "item") - frappe.reload_doc("setup", "doctype", "sales_partner") - - try: - frappe.model.rename_field("Item Group", "parent_website_sitemap", "parent_website_route") - frappe.model.rename_field("Item", "parent_website_sitemap", "parent_website_route") - frappe.model.rename_field("Sales Partner", "parent_website_sitemap", - "parent_website_route") - except Exception as e: - if e.args[0]!=1054: - raise diff --git a/erpnext/patches/v4_0/reset_permissions_for_masters.py b/erpnext/patches/v4_0/reset_permissions_for_masters.py deleted file mode 100644 index bc1b438e2b..0000000000 --- a/erpnext/patches/v4_0/reset_permissions_for_masters.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -from frappe.permissions import reset_perms - -def execute(): - for doctype in ("About Us Settings", "Accounts Settings", "Activity Type", - "Blog Category", "Blog Settings", "Blogger", "Branch", "Brand", "Buying Settings", - "Communication", "Company", "Contact Us Settings", - "Country", "Currency", "Currency Exchange", "Deduction Type", "Department", - "Designation", "Earning Type", "Event", "Feed", "File", "Fiscal Year", - "HR Settings", "Industry Type", "Leave Type", "Letter Head", - "Mode of Payment", "Module Def", "Naming Series", "POS Setting", "Print Heading", - "Report", "Role", "Selling Settings", "Stock Settings", "Supplier Type", "UOM"): - try: - reset_perms(doctype) - except: - print("Error resetting perms for", doctype) - raise diff --git a/erpnext/patches/v4_0/save_default_letterhead.py b/erpnext/patches/v4_0/save_default_letterhead.py deleted file mode 100644 index 5d75f096b3..0000000000 --- a/erpnext/patches/v4_0/save_default_letterhead.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - """save default letterhead to set default_letter_head_content""" - try: - letter_head = frappe.get_doc("Letter Head", {"is_default": 1}) - letter_head.save() - except frappe.DoesNotExistError: - pass diff --git a/erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py b/erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py deleted file mode 100644 index 7e472e2195..0000000000 --- a/erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "pricing_rule") - frappe.db.sql("""update `tabPricing Rule` set selling=1 where ifnull(applicable_for, '') in - ('', 'Customer', 'Customer Group', 'Territory', 'Sales Partner', 'Campaign')""") - - frappe.db.sql("""update `tabPricing Rule` set buying=1 where ifnull(applicable_for, '') in - ('', 'Supplier', 'Supplier Type')""") diff --git a/erpnext/patches/v4_0/split_email_settings.py b/erpnext/patches/v4_0/split_email_settings.py deleted file mode 100644 index 5d1dea60ee..0000000000 --- a/erpnext/patches/v4_0/split_email_settings.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - print("WARNING!!!! Email Settings not migrated. Please setup your email again.") - - # this will happen if you are migrating very old accounts - # comment out this line below and remember to create new Email Accounts - # for incoming and outgoing mails - raise Exception - - return - - - frappe.reload_doc("core", "doctype", "outgoing_email_settings") - frappe.reload_doc("support", "doctype", "support_email_settings") - - email_settings = get_email_settings() - map_outgoing_email_settings(email_settings) - map_support_email_settings(email_settings) - - -def map_outgoing_email_settings(email_settings): - outgoing_email_settings = frappe.get_doc("Outgoing Email Settings") - for fieldname in (("outgoing_mail_server", "mail_server"), - "use_ssl", "mail_port", "mail_login", "mail_password", - "always_use_login_id_as_sender", "auto_email_id"): - - if isinstance(fieldname, tuple): - from_fieldname, to_fieldname = fieldname - else: - from_fieldname = to_fieldname = fieldname - - outgoing_email_settings.set(to_fieldname, email_settings.get(from_fieldname)) - - outgoing_email_settings._fix_numeric_types() - outgoing_email_settings.save() - -def map_support_email_settings(email_settings): - support_email_settings = frappe.get_doc("Support Email Settings") - - for fieldname in ("sync_support_mails", "support_email", - ("support_host", "mail_server"), - ("support_use_ssl", "use_ssl"), - ("support_username", "mail_login"), - ("support_password", "mail_password"), - "support_signature", "send_autoreply", "support_autoreply"): - - if isinstance(fieldname, tuple): - from_fieldname, to_fieldname = fieldname - else: - from_fieldname = to_fieldname = fieldname - - support_email_settings.set(to_fieldname, email_settings.get(from_fieldname)) - - support_email_settings._fix_numeric_types() - support_email_settings.save() - -def get_email_settings(): - ret = {} - for field, value in frappe.db.sql("select field, value from tabSingles where doctype='Email Settings'"): - ret[field] = value - return ret - diff --git a/erpnext/patches/v4_0/update_account_root_type.py b/erpnext/patches/v4_0/update_account_root_type.py deleted file mode 100644 index 15ddf032a4..0000000000 --- a/erpnext/patches/v4_0/update_account_root_type.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "account") - - account_table_columns = frappe.db.get_table_columns("Account") - if "debit_or_credit" in account_table_columns and "is_pl_account" in account_table_columns: - frappe.db.sql("""UPDATE tabAccount - SET root_type = CASE - WHEN (debit_or_credit='Debit' and is_pl_account = 'No') THEN 'Asset' - WHEN (debit_or_credit='Credit' and is_pl_account = 'No') THEN 'Liability' - WHEN (debit_or_credit='Debit' and is_pl_account = 'Yes') THEN 'Expense' - WHEN (debit_or_credit='Credit' and is_pl_account = 'Yes') THEN 'Income' - END - WHERE ifnull(parent_account, '') = '' - """) - - else: - for key, root_type in (("asset", "Asset"), ("liabilities", "Liability"), ("expense", "Expense"), - ("income", "Income")): - frappe.db.sql("""update tabAccount set root_type=%s where name like %s - and ifnull(parent_account, '')=''""", (root_type, "%" + key + "%")) - - for root in frappe.db.sql("""SELECT name, lft, rgt, root_type FROM `tabAccount` - WHERE ifnull(parent_account, '')=''""", as_dict=True): - if root.root_type: - frappe.db.sql("""UPDATE tabAccount SET root_type=%s WHERE lft>%s and rgt<%s""", - (root.root_type, root.lft, root.rgt)) - else: - print(b"Root type not found for {0}".format(root.name.encode("utf-8"))) diff --git a/erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py b/erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py deleted file mode 100644 index d784a1b182..0000000000 --- a/erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import re - -def execute(): - # NOTE: sequence is important - fields_list = ( - ("amount", "base_amount"), - ("ref_rate", "price_list_rate"), - ("base_ref_rate", "base_price_list_rate"), - ("adj_rate", "discount_percentage"), - ("export_rate", "rate"), - ("basic_rate", "base_rate"), - ("export_amount", "amount"), - ("reserved_warehouse", "warehouse"), - ("import_ref_rate", "price_list_rate"), - ("purchase_ref_rate", "base_price_list_rate"), - ("discount_rate", "discount_percentage"), - ("import_rate", "rate"), - ("purchase_rate", "base_rate"), - ("import_amount", "amount") - ) - - condition = " or ".join("""html like "%%{}%%" """.format(d[0].replace("_", "\\_")) for d in fields_list - if d[0] != "amount") - - for name, html in frappe.db.sql("""select name, html from `tabPrint Format` - where standard = 'No' and ({}) and html not like '%%frappe.%%'""".format(condition)): - html = html.replace("wn.", "frappe.") - for from_field, to_field in fields_list: - html = re.sub(r"\b{}\b".format(from_field), to_field, html) - - frappe.db.set_value("Print Format", name, "html", html) diff --git a/erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py b/erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py deleted file mode 100644 index fe66a5e3ef..0000000000 --- a/erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("support", "doctype", "schedules") - frappe.reload_doc("support", "doctype", "maintenance_schedule_item") - - frappe.db.sql("""update `tabMaintenance Schedule Detail` set sales_person=incharge_name""") - frappe.db.sql("""update `tabMaintenance Schedule Item` set sales_person=incharge_name""") \ No newline at end of file diff --git a/erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py b/erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py deleted file mode 100644 index 2e2e77a9fc..0000000000 --- a/erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import re - -def execute(): - for name, html in frappe.db.sql("""select name, html from `tabPrint Format` - where standard = 'No' and html like '%%purchase\\_tax\\_details%%'"""): - html = re.sub(r"\bpurchase_tax_details\b", "taxes", html) - frappe.db.set_value("Print Format", name, "html", html) diff --git a/erpnext/patches/v4_0/update_tax_amount_after_discount.py b/erpnext/patches/v4_0/update_tax_amount_after_discount.py deleted file mode 100644 index d10329ef37..0000000000 --- a/erpnext/patches/v4_0/update_tax_amount_after_discount.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "sales_taxes_and_charges") - docs_with_discount_amount = frappe._dict() - for dt in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]: - records = frappe.db.sql_list("""select name from `tab%s` - where ifnull(discount_amount, 0) > 0 and docstatus=1""" % dt) - docs_with_discount_amount[dt] = records - - for dt, discounted_records in docs_with_discount_amount.items(): - frappe.db.sql("""update `tabSales Taxes and Charges` - set tax_amount_after_discount_amount = tax_amount - where parenttype = %s and parent not in (%s)""" % - ('%s', ', '.join(['%s']*(len(discounted_records)+1))), - tuple([dt, ''] + discounted_records)) diff --git a/erpnext/patches/v4_0/update_user_properties.py b/erpnext/patches/v4_0/update_user_properties.py deleted file mode 100644 index f2085ce4df..0000000000 --- a/erpnext/patches/v4_0/update_user_properties.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import frappe.permissions -import frappe.defaults - -def execute(): - frappe.reload_doc("core", "doctype", "docfield") - frappe.reload_doc("hr", "doctype", "employee") - - set_print_email_permissions() - migrate_user_properties_to_user_permissions() - - frappe.clear_cache() - -def migrate_user_properties_to_user_permissions(): - for d in frappe.db.sql("""select parent, defkey, defvalue from tabDefaultValue - where parent not in ('__global', '__default')""", as_dict=True): - df = frappe.db.sql("""select options from tabDocField - where fieldname=%s and fieldtype='Link'""", d.defkey, as_dict=True) - - if df: - frappe.db.sql("""update tabDefaultValue - set defkey=%s, parenttype='User Permission' - where defkey=%s and - parent not in ('__global', '__default')""", (df[0].options, d.defkey)) - -def set_print_email_permissions(): - # reset Page perms - from frappe.core.page.permission_manager.permission_manager import reset - reset("Page") - reset("Report") - - if "allow_print" not in frappe.db.get_table_columns("DocType"): - return - - # patch to move print, email into DocPerm - # NOTE: allow_print and allow_email are misnamed. They were used to hide print / hide email - for doctype, hide_print, hide_email in frappe.db.sql("""select name, ifnull(allow_print, 0), ifnull(allow_email, 0) - from `tabDocType` where ifnull(issingle, 0)=0 and ifnull(istable, 0)=0 and - (ifnull(allow_print, 0)=0 or ifnull(allow_email, 0)=0)"""): - - if not hide_print: - frappe.db.sql("""update `tabDocPerm` set `print`=1 - where permlevel=0 and `read`=1 and parent=%s""", doctype) - - if not hide_email: - frappe.db.sql("""update `tabDocPerm` set `email`=1 - where permlevel=0 and `read`=1 and parent=%s""", doctype) diff --git a/erpnext/patches/v4_0/update_users_report_view_settings.py b/erpnext/patches/v4_0/update_users_report_view_settings.py deleted file mode 100644 index 6f216f5b38..0000000000 --- a/erpnext/patches/v4_0/update_users_report_view_settings.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -from frappe.model.utils.rename_field import update_users_report_view_settings -from erpnext.patches.v4_0.fields_to_be_renamed import rename_map - -def execute(): - for dt, field_list in rename_map.items(): - for field in field_list: - update_users_report_view_settings(dt, field[0], field[1]) diff --git a/erpnext/patches/v4_0/validate_v3_patch.py b/erpnext/patches/v4_0/validate_v3_patch.py deleted file mode 100644 index 3df39edea6..0000000000 --- a/erpnext/patches/v4_0/validate_v3_patch.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - from frappe.modules.patch_handler import executed - last_v3_patch = 'patches.1401.fix_pos_outstanding' - if not executed(last_v3_patch): - raise Exception("site not ready to migrate to version 4") diff --git a/erpnext/patches/v4_1/__init__.py b/erpnext/patches/v4_1/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v4_1/fix_delivery_and_billing_status.py b/erpnext/patches/v4_1/fix_delivery_and_billing_status.py deleted file mode 100644 index 8cc6a4b0be..0000000000 --- a/erpnext/patches/v4_1/fix_delivery_and_billing_status.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""update `tabSales Order` set delivery_status = 'Not Delivered' - where delivery_status = 'Delivered' and ifnull(per_delivered, 0) = 0 and ifnull(docstatus, 0) in (0, 1)""") - - frappe.db.sql("""update `tabSales Order` set billing_status = 'Not Billed' - where billing_status = 'Billed' and ifnull(per_billed, 0) = 0 and ifnull(docstatus, 0) in (0, 1)""") diff --git a/erpnext/patches/v4_1/fix_jv_remarks.py b/erpnext/patches/v4_1/fix_jv_remarks.py deleted file mode 100644 index e07bf05f1a..0000000000 --- a/erpnext/patches/v4_1/fix_jv_remarks.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - reference_date = guess_reference_date() - for name in frappe.db.sql_list("""select name from `tabJournal Entry` - where date(creation)>=%s""", reference_date): - jv = frappe.get_doc("Journal Entry", name) - try: - jv.create_remarks() - except frappe.MandatoryError: - pass - else: - frappe.db.set_value("Journal Entry", jv.name, "remark", jv.remark) - -def guess_reference_date(): - return (frappe.db.get_value("Patch Log", {"patch": "erpnext.patches.v4_0.validate_v3_patch"}, "creation") - or "2014-05-06") diff --git a/erpnext/patches/v4_1/fix_sales_order_delivered_status.py b/erpnext/patches/v4_1/fix_sales_order_delivered_status.py deleted file mode 100644 index 66037b8958..0000000000 --- a/erpnext/patches/v4_1/fix_sales_order_delivered_status.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for si in frappe.db.sql_list("""select name - from `tabSales Invoice` - where ifnull(update_stock,0) = 1 and docstatus = 1 and exists( - select name from `tabSales Invoice Item` where parent=`tabSales Invoice`.name and - ifnull(so_detail, "") != "")"""): - - invoice = frappe.get_doc("Sales Invoice", si) - invoice.update_qty() diff --git a/erpnext/patches/v4_1/set_outgoing_email_footer.py b/erpnext/patches/v4_1/set_outgoing_email_footer.py deleted file mode 100644 index 54d016bf5f..0000000000 --- a/erpnext/patches/v4_1/set_outgoing_email_footer.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.setup.install import default_mail_footer - -def execute(): - return - mail_footer = frappe.db.get_default('mail_footer') or '' - mail_footer += default_mail_footer - frappe.db.set_value("Outgoing Email Settings", "Outgoing Email Settings", "footer", mail_footer) diff --git a/erpnext/patches/v4_2/__init__.py b/erpnext/patches/v4_2/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v4_2/add_currency_turkish_lira.py b/erpnext/patches/v4_2/add_currency_turkish_lira.py deleted file mode 100644 index 1a46089f94..0000000000 --- a/erpnext/patches/v4_2/add_currency_turkish_lira.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - return - # country = get_country_info(country="Turkey") - # add_country_and_currency("Turkey", country) diff --git a/erpnext/patches/v4_2/default_website_style.py b/erpnext/patches/v4_2/default_website_style.py deleted file mode 100644 index e8f9502ea6..0000000000 --- a/erpnext/patches/v4_2/default_website_style.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - return - # frappe.reload_doc('website', 'doctype', 'style_settings') - # style_settings = frappe.get_doc("Style Settings", "Style Settings") - # if not style_settings.apply_style: - # style_settings.update(default_properties) - # style_settings.apply_style = 1 - # style_settings.save() diff --git a/erpnext/patches/v4_2/delete_gl_entries_for_cancelled_invoices.py b/erpnext/patches/v4_2/delete_gl_entries_for_cancelled_invoices.py deleted file mode 100644 index 169b1e2927..0000000000 --- a/erpnext/patches/v4_2/delete_gl_entries_for_cancelled_invoices.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - cancelled_invoices = frappe.db.sql_list("""select name from `tabSales Invoice` - where docstatus = 2 and ifnull(update_stock, 0) = 1""") - - if cancelled_invoices: - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type = 'Sales Invoice' and voucher_no in (%s)""" - % (', '.join(['%s']*len(cancelled_invoices))), tuple(cancelled_invoices)) \ No newline at end of file diff --git a/erpnext/patches/v4_2/delete_old_print_formats.py b/erpnext/patches/v4_2/delete_old_print_formats.py deleted file mode 100644 index cacdb85ce0..0000000000 --- a/erpnext/patches/v4_2/delete_old_print_formats.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - old_formats = ("Sales Invoice", "Sales Invoice Spartan", "Sales Invoice Modern", - "Sales Invoice Classic", - "Sales Order Spartan", "Sales Order Modern", "Sales Order Classic", - "Purchase Order Spartan", "Purchase Order Modern", "Purchase Order Classic", - "Quotation Spartan", "Quotation Modern", "Quotation Classic", - "Delivery Note Spartan", "Delivery Note Modern", "Delivery Note Classic") - - for fmt in old_formats: - # update property setter - for ps in frappe.db.sql_list("""select name from `tabProperty Setter` - where property='default_print_format' and value=%s""", fmt): - ps = frappe.get_doc("Property Setter", ps) - ps.value = "Standard" - ps.save(ignore_permissions = True) - - frappe.delete_doc_if_exists("Print Format", fmt) diff --git a/erpnext/patches/v4_2/discount_amount.py b/erpnext/patches/v4_2/discount_amount.py deleted file mode 100644 index 7ab61bdbea..0000000000 --- a/erpnext/patches/v4_2/discount_amount.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.modules import scrub, get_doctype_module - -def execute(): - for dt in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]: - frappe.reload_doc(get_doctype_module(dt), "doctype", scrub(dt)) - frappe.db.sql("""update `tab{0}` set base_discount_amount=discount_amount, - discount_amount=discount_amount/conversion_rate""".format(dt)) diff --git a/erpnext/patches/v4_2/fix_account_master_type.py b/erpnext/patches/v4_2/fix_account_master_type.py deleted file mode 100644 index 99444ce83b..0000000000 --- a/erpnext/patches/v4_2/fix_account_master_type.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for d in frappe.db.sql("""select name from `tabAccount` - where ifnull(master_type, '') not in ('Customer', 'Supplier', 'Employee', '') and docstatus=0"""): - ac = frappe.get_doc("Account", d[0]) - ac.master_type = None - ac.save() diff --git a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py deleted file mode 100644 index c6c94d4179..0000000000 --- a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe -from frappe.utils import flt - -def execute(): - from erpnext.stock.stock_balance import repost - repost(allow_zero_rate=True, only_actual=True) - - frappe.reload_doctype("Account") - - warehouse_account = frappe.db.sql("""select name, master_name from tabAccount - where ifnull(account_type, '') = 'Warehouse'""") - if warehouse_account: - warehouses = [d[1] for d in warehouse_account] - accounts = [d[0] for d in warehouse_account] - - stock_vouchers = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no - from `tabStock Ledger Entry` sle - where sle.warehouse in (%s) - order by sle.posting_date""" % - ', '.join(['%s']*len(warehouses)), tuple(warehouses)) - - rejected = [] - for voucher_type, voucher_no in stock_vouchers: - stock_bal = frappe.db.sql("""select sum(stock_value_difference) from `tabStock Ledger Entry` - where voucher_type=%s and voucher_no =%s and warehouse in (%s)""" % - ('%s', '%s', ', '.join(['%s']*len(warehouses))), tuple([voucher_type, voucher_no] + warehouses)) - - account_bal = frappe.db.sql("""select ifnull(sum(ifnull(debit, 0) - ifnull(credit, 0)), 0) - from `tabGL Entry` - where voucher_type=%s and voucher_no =%s and account in (%s) - group by voucher_type, voucher_no""" % - ('%s', '%s', ', '.join(['%s']*len(accounts))), tuple([voucher_type, voucher_no] + accounts)) - - if stock_bal and account_bal and abs(flt(stock_bal[0][0]) - flt(account_bal[0][0])) > 0.1: - try: - print(voucher_type, voucher_no, stock_bal[0][0], account_bal[0][0]) - - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no)) - - voucher = frappe.get_doc(voucher_type, voucher_no) - voucher.make_gl_entries() - frappe.db.commit() - except Exception as e: - print(frappe.get_traceback()) - rejected.append([voucher_type, voucher_no]) - frappe.db.rollback() - - print("Failed to repost: ") - print(rejected) diff --git a/erpnext/patches/v4_2/fix_recurring_orders.py b/erpnext/patches/v4_2/fix_recurring_orders.py deleted file mode 100644 index ea1724a040..0000000000 --- a/erpnext/patches/v4_2/fix_recurring_orders.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - sales_orders = frappe.db.sql("""select name from `tabSales Order` - where docstatus = 1 and ifnull(is_recurring, 0) = 1 - and (per_delivered > 0 or per_billed > 0)""", as_dict=1) - - for so in sales_orders: - if not frappe.db.exists("Delivery Note Item", {"against_sales_order": so.name, "docstatus": 1}): - frappe.db.sql("""update `tabSales Order` set per_delivered = 0, - delivery_status = 'Not Delivered' where name = %s""", so.name) - frappe.db.sql("""update `tabSales Order Item` set delivered_qty = 0 - where parent = %s""", so.name) - - if not frappe.db.exists("Sales Invoice Item", {"sales_order": so.name, "docstatus": 1}): - frappe.db.sql("""update `tabSales Order` set per_billed = 0, - billing_status = 'Not Billed' where name = %s""", so.name) - frappe.db.sql("""update `tabSales Order Item` set billed_amt = 0 - where parent = %s""", so.name) - - purchase_orders = frappe.db.sql("""select name from `tabPurchase Order` - where docstatus = 1 and ifnull(is_recurring, 0) = 1 - and (per_received > 0 or per_billed > 0)""", as_dict=1) - - for po in purchase_orders: - if not frappe.db.exists("Purchase Receipt Item", {"prevdoc_doctype": "Purchase Order", - "prevdoc_docname": po.name, "docstatus": 1}): - frappe.db.sql("""update `tabPurchase Order` set per_received = 0 - where name = %s""", po.name) - frappe.db.sql("""update `tabPurchase Order Item` set received_qty = 0 - where parent = %s""", po.name) - - if not frappe.db.exists("Purchase Invoice Item", {"purchase_order": po.name, "docstatus": 1}): - frappe.db.sql("""update `tabPurchase Order` set per_billed = 0 - where name = %s""", po.name) - frappe.db.sql("""update `tabPurchase Order Item` set billed_amt = 0 - where parent = %s""", po.name) \ No newline at end of file diff --git a/erpnext/patches/v4_2/party_model.py b/erpnext/patches/v4_2/party_model.py deleted file mode 100644 index 46d7fffee1..0000000000 --- a/erpnext/patches/v4_2/party_model.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "account") - frappe.reload_doc("setup", "doctype", "company") - frappe.reload_doc("accounts", "doctype", "gl_entry") - frappe.reload_doc("accounts", "doctype", "journal_entry_account") - receivable_payable_accounts = create_receivable_payable_account() - if receivable_payable_accounts: - set_party_in_jv_and_gl_entry(receivable_payable_accounts) - delete_individual_party_account() - remove_customer_supplier_account_report() - -def create_receivable_payable_account(): - receivable_payable_accounts = frappe._dict() - - def _create_account(args): - if args["parent_account"] and frappe.db.exists("Account", args["parent_account"]): - account_id = frappe.db.get_value("Account", - {"account_name": args["account_name"], "company": args["company"]}) - if not account_id: - account = frappe.new_doc("Account") - account.is_group = 0 - account.update(args) - account.insert() - - account_id = account.name - - frappe.db.set_value("Company", args["company"], ("default_receivable_account" - if args["account_type"]=="Receivable" else "default_payable_account"), account_id) - - receivable_payable_accounts.setdefault(args["company"], {}).setdefault(args["account_type"], account_id) - - for company in frappe.db.sql_list("select name from tabCompany"): - _create_account({ - "account_name": "Debtors", - "account_type": "Receivable", - "company": company, - "parent_account": get_parent_account(company, "Customer") - }) - - _create_account({ - "account_name": "Creditors", - "account_type": "Payable", - "company": company, - "parent_account": get_parent_account(company, "Supplier") - }) - - return receivable_payable_accounts - -def get_parent_account(company, master_type): - parent_account = None - - if "receivables_group" in frappe.db.get_table_columns("Company"): - parent_account = frappe.get_cached_value('Company', company, - "receivables_group" if master_type=="Customer" else "payables_group") - if not parent_account: - parent_account = frappe.db.get_value("Account", {"company": company, - "account_name": "Accounts Receivable" if master_type=="Customer" else "Accounts Payable"}) - - if not parent_account: - parent_account = frappe.db.sql_list("""select parent_account from tabAccount - where company=%s and ifnull(master_type, '')=%s and ifnull(master_name, '')!='' limit 1""", - (company, master_type)) - parent_account = parent_account[0][0] if parent_account else None - - return parent_account - -def set_party_in_jv_and_gl_entry(receivable_payable_accounts): - accounts = frappe.db.sql("""select name, master_type, master_name, company from `tabAccount` - where ifnull(master_type, '') in ('Customer', 'Supplier') and ifnull(master_name, '') != ''""", as_dict=1) - - account_map = frappe._dict() - for d in accounts: - account_map.setdefault(d.name, d) - - if not account_map: - return - - for dt in ["Journal Entry Account", "GL Entry"]: - records = frappe.db.sql("""select name, account from `tab%s` - where account in (%s) and ifnull(party, '') = '' and docstatus < 2""" % - (dt, ", ".join(['%s']*len(account_map))), tuple(account_map.keys()), as_dict=1) - for i, d in enumerate(records): - account_details = account_map.get(d.account, {}) - account_type = "Receivable" if account_details.get("master_type")=="Customer" else "Payable" - new_account = receivable_payable_accounts[account_details.get("company")][account_type] - - frappe.db.sql("update `tab{0}` set account=%s, party_type=%s, party=%s where name=%s".format(dt), - (new_account, account_details.get("master_type"), account_details.get("master_name"), d.name)) - - if i%500 == 0: - frappe.db.commit() - -def delete_individual_party_account(): - frappe.db.sql("""delete from `tabAccount` - where ifnull(master_type, '') in ('Customer', 'Supplier') - and ifnull(master_name, '') != '' - and not exists(select gle.name from `tabGL Entry` gle - where gle.account = tabAccount.name)""") - - accounts_not_deleted = frappe.db.sql_list("""select tabAccount.name from `tabAccount` - where ifnull(master_type, '') in ('Customer', 'Supplier') - and ifnull(master_name, '') != '' - and exists(select gle.name from `tabGL Entry` gle where gle.account = tabAccount.name)""") - - if accounts_not_deleted: - print("Accounts not deleted: " + "\n".join(accounts_not_deleted)) - - -def remove_customer_supplier_account_report(): - for d in ["Customer Account Head", "Supplier Account Head"]: - frappe.delete_doc("Report", d) diff --git a/erpnext/patches/v4_2/recalculate_bom_cost.py b/erpnext/patches/v4_2/recalculate_bom_cost.py deleted file mode 100644 index eee89fce96..0000000000 --- a/erpnext/patches/v4_2/recalculate_bom_cost.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for d in frappe.db.sql("select name from `tabBOM` where docstatus < 2"): - try: - document = frappe.get_doc('BOM', d[0]) - if document.docstatus == 1: - document.flags.ignore_validate_update_after_submit = True - document.calculate_cost() - document.save() - except: - pass diff --git a/erpnext/patches/v4_2/repost_sle_for_si_with_no_warehouse.py b/erpnext/patches/v4_2/repost_sle_for_si_with_no_warehouse.py deleted file mode 100644 index 1356129dc0..0000000000 --- a/erpnext/patches/v4_2/repost_sle_for_si_with_no_warehouse.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe -from erpnext.stock.stock_ledger import NegativeStockError - -def execute(): - si_list = frappe.db.sql("""select distinct si.name - from `tabSales Invoice Item` si_item, `tabSales Invoice` si - where si.name = si_item.parent and si.modified > '2015-02-16' and si.docstatus=1 - and ifnull(si_item.warehouse, '') = '' and ifnull(si.update_stock, 0) = 1 - order by posting_date, posting_time""", as_dict=1) - - failed_list = [] - for si in si_list: - try: - si_doc = frappe.get_doc("Sales Invoice", si.name) - si_doc.docstatus = 2 - si_doc.on_cancel() - - si_doc.docstatus = 1 - si_doc.set_missing_item_details() - si_doc.on_submit() - frappe.db.commit() - except: - failed_list.append(si.name) - frappe.local.stockledger_exceptions = None - frappe.db.rollback() - - print("Failed to repost: ", failed_list) - - - \ No newline at end of file diff --git a/erpnext/patches/v4_2/repost_stock_reconciliation.py b/erpnext/patches/v4_2/repost_stock_reconciliation.py deleted file mode 100644 index ad20ebbae4..0000000000 --- a/erpnext/patches/v4_2/repost_stock_reconciliation.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import json - -def execute(): - existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") - frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) - - head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] - stock_reco_to_be_reposted = [] - for d in frappe.db.sql("""select name, reconciliation_json from `tabStock Reconciliation` - where docstatus=1 and creation > '2014-03-01'""", as_dict=1): - data = json.loads(d.reconciliation_json) - for row in data[data.index(head_row)+1:]: - if row[3] in ["", None]: - stock_reco_to_be_reposted.append(d.name) - break - - for dn in stock_reco_to_be_reposted: - reco = frappe.get_doc("Stock Reconciliation", dn) - reco.docstatus = 2 - reco.on_cancel() - - reco.docstatus = 1 - reco.validate() - reco.on_submit() - - frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) diff --git a/erpnext/patches/v4_2/reset_bom_costs.py b/erpnext/patches/v4_2/reset_bom_costs.py deleted file mode 100644 index 42ca759467..0000000000 --- a/erpnext/patches/v4_2/reset_bom_costs.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('manufacturing', 'doctype', 'bom_operation') - for d in frappe.db.sql("""select name from `tabBOM` where docstatus < 2""", as_dict=1): - try: - bom = frappe.get_doc('BOM', d.name) - bom.flags.ignore_validate_update_after_submit = True - bom.calculate_cost() - bom.save() - frappe.db.commit() - except: - frappe.db.rollback() diff --git a/erpnext/patches/v4_2/seprate_manufacture_and_repack.py b/erpnext/patches/v4_2/seprate_manufacture_and_repack.py deleted file mode 100644 index 2c935436a2..0000000000 --- a/erpnext/patches/v4_2/seprate_manufacture_and_repack.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""update `tabStock Entry` set purpose='Manufacture' where purpose='Manufacture/Repack' and ifnull(work_order,"")!="" """) - frappe.db.sql("""update `tabStock Entry` set purpose='Repack' where purpose='Manufacture/Repack' and ifnull(work_order,"")="" """) \ No newline at end of file diff --git a/erpnext/patches/v4_2/set_company_country.py b/erpnext/patches/v4_2/set_company_country.py deleted file mode 100644 index 89f07f2873..0000000000 --- a/erpnext/patches/v4_2/set_company_country.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - country = frappe.db.get_single_value("Global Defaults", "country") - if not country: - print("Country not specified in Global Defaults") - return - - for company in frappe.db.sql_list("""select name from `tabCompany` - where ifnull(country, '')=''"""): - frappe.db.set_value("Company", company, "country", country) diff --git a/erpnext/patches/v4_2/set_item_has_batch.py b/erpnext/patches/v4_2/set_item_has_batch.py deleted file mode 100644 index 7e52d2def0..0000000000 --- a/erpnext/patches/v4_2/set_item_has_batch.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("update tabItem set has_batch_no = 0 where ifnull(has_batch_no, '') = ''") - frappe.db.sql("update tabItem set has_serial_no = 0 where ifnull(has_serial_no, '') = ''") - - item_list = frappe.db.sql("""select name, has_batch_no, has_serial_no from tabItem - where is_stock_item = 1""", as_dict=1) - - sle_count = get_sle_count() - sle_with_batch = get_sle_with_batch() - sle_with_serial = get_sle_with_serial() - - batch_items = get_items_with_batch() - serialized_items = get_items_with_serial() - - for d in item_list: - if d.has_batch_no == 1: - if d.name not in batch_items and sle_count.get(d.name) and sle_count.get(d.name) != sle_with_batch.get(d.name): - frappe.db.set_value("Item", d.name, "has_batch_no", 0) - else: - if d.name in batch_items or (sle_count.get(d.name) and sle_count.get(d.name) == sle_with_batch.get(d.name)): - frappe.db.set_value("Item", d.name, "has_batch_no", 1) - - if d.has_serial_no == 1: - if d.name not in serialized_items and sle_count.get(d.name) and sle_count.get(d.name) != sle_with_serial.get(d.name): - frappe.db.set_value("Item", d.name, "has_serial_no", 0) - else: - if d.name in serialized_items or (sle_count.get(d.name) and sle_count.get(d.name) == sle_with_serial.get(d.name)): - frappe.db.set_value("Item", d.name, "has_serial_no", 1) - - -def get_sle_count(): - sle_count = {} - for d in frappe.db.sql("""select item_code, count(name) as cnt from `tabStock Ledger Entry` group by item_code""", as_dict=1): - sle_count.setdefault(d.item_code, d.cnt) - - return sle_count - -def get_sle_with_batch(): - sle_with_batch = {} - for d in frappe.db.sql("""select item_code, count(name) as cnt from `tabStock Ledger Entry` - where ifnull(batch_no, '') != '' group by item_code""", as_dict=1): - sle_with_batch.setdefault(d.item_code, d.cnt) - - return sle_with_batch - - -def get_sle_with_serial(): - sle_with_serial = {} - for d in frappe.db.sql("""select item_code, count(name) as cnt from `tabStock Ledger Entry` - where ifnull(serial_no, '') != '' group by item_code""", as_dict=1): - sle_with_serial.setdefault(d.item_code, d.cnt) - - return sle_with_serial - -def get_items_with_batch(): - return frappe.db.sql_list("select item from tabBatch") - -def get_items_with_serial(): - return frappe.db.sql_list("select item_code from `tabSerial No`") diff --git a/erpnext/patches/v4_2/toggle_rounded_total.py b/erpnext/patches/v4_2/toggle_rounded_total.py deleted file mode 100644 index e571208eb6..0000000000 --- a/erpnext/patches/v4_2/toggle_rounded_total.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - global_defaults = frappe.get_doc("Global Defaults", "Global Defaults") - global_defaults.toggle_rounded_total() diff --git a/erpnext/patches/v4_2/update_landed_cost_voucher.py b/erpnext/patches/v4_2/update_landed_cost_voucher.py deleted file mode 100644 index ec0029671e..0000000000 --- a/erpnext/patches/v4_2/update_landed_cost_voucher.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("stock", "doctype", "landed_cost_voucher") - frappe.db.sql("""update `tabLanded Cost Voucher` set distribute_charges_based_on = 'Amount' - where docstatus=1""") diff --git a/erpnext/patches/v4_2/update_project_milestones.py b/erpnext/patches/v4_2/update_project_milestones.py deleted file mode 100644 index e704116d05..0000000000 --- a/erpnext/patches/v4_2/update_project_milestones.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for project in frappe.db.sql_list("select name from tabProject"): - frappe.reload_doc("projects", "doctype", "project") - p = frappe.get_doc("Project", project) - p.update_milestones_completed() - p.db_set("percent_milestones_completed", p.percent_milestones_completed) diff --git a/erpnext/patches/v4_2/update_sales_order_invoice_field_name.py b/erpnext/patches/v4_2/update_sales_order_invoice_field_name.py deleted file mode 100644 index 28dd5c0d4e..0000000000 --- a/erpnext/patches/v4_2/update_sales_order_invoice_field_name.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'sales_invoice') - frappe.db.sql("""update `tabSales Invoice` set from_date = invoice_period_from_date, - to_date = invoice_period_to_date, is_recurring = convert_into_recurring_invoice""") diff --git a/erpnext/patches/v4_2/update_stock_uom_for_dn_in_sle.py b/erpnext/patches/v4_2/update_stock_uom_for_dn_in_sle.py deleted file mode 100644 index 89bf795534..0000000000 --- a/erpnext/patches/v4_2/update_stock_uom_for_dn_in_sle.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""update `tabStock Ledger Entry` sle, tabItem item - set sle.stock_uom = item.stock_uom - where sle.voucher_type="Delivery Note" and item.name = sle.item_code - and sle.stock_uom != item.stock_uom""") diff --git a/erpnext/patches/v4_4/__init__.py b/erpnext/patches/v4_4/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v4_4/make_email_accounts.py b/erpnext/patches/v4_4/make_email_accounts.py deleted file mode 100644 index 57df1ae491..0000000000 --- a/erpnext/patches/v4_4/make_email_accounts.py +++ /dev/null @@ -1,96 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model import default_fields - -from six import iteritems - -def execute(): - frappe.reload_doc("email", "doctype", "email_account") - - # outgoing - outgoing = dict(frappe.db.sql("select field, value from tabSingles where doctype='Outgoing Email Settings'")) - if outgoing and outgoing['mail_server'] and outgoing['mail_login']: - account = frappe.new_doc("Email Account") - mapping = { - "login_id_is_different": 1, - "email_id": "auto_email_id", - "login_id": "mail_login", - "password": "mail_password", - "footer": "footer", - "smtp_server": "mail_server", - "smtp_port": "mail_port", - "use_tls": "use_ssl" - } - - for target_fieldname, source_fieldname in iteritems(mapping): - account.set(target_fieldname, outgoing.get(source_fieldname)) - - account.enable_outgoing = 1 - account.enable_incoming = 0 - - account.insert() - - # support - support = dict(frappe.db.sql("select field, value from tabSingles where doctype='Support Email Settings'")) - if support and support['mail_server'] and support['mail_login']: - account = frappe.new_doc("Email Account") - mapping = { - "enable_incoming": "sync_support_mails", - "email_id": "mail_login", - "password": "mail_password", - "email_server": "mail_server", - "use_ssl": "use_ssl", - "signature": "support_signature", - "enable_auto_reply": "send_autoreply", - "auto_reply_message": "support_autoreply" - } - - for target_fieldname, source_fieldname in iteritems(mapping): - account.set(target_fieldname, support.get(source_fieldname)) - - account.enable_outgoing = 0 - account.append_to = "Issue" - - insert_or_update(account) - - # sales, jobs - for doctype in ("Sales Email Settings", "Jobs Email Settings"): - source = dict(frappe.db.sql("select field, value from tabSingles where doctype=%s", doctype)) - if source and source.get('host') and source.get('username'): - account = frappe.new_doc("Email Account") - mapping = { - "enable_incoming": "extract_emails", - "email_id": "username", - "password": "password", - "email_server": "host", - "use_ssl": "use_ssl", - } - - for target_fieldname, source_fieldname in iteritems(mapping): - account.set(target_fieldname, source.get(source_fieldname)) - - account.enable_outgoing = 0 - account.append_to = "Lead" if doctype=="Sales Email Settings" else "Job Applicant" - - insert_or_update(account) - - for doctype in ("Outgoing Email Settings", "Support Email Settings", - "Sales Email Settings", "Jobs Email Settings"): - frappe.delete_doc("DocType", doctype) - -def insert_or_update(account): - try: - account.insert() - except frappe.NameError as e: - if e.args[0]=="Email Account": - existing_account = frappe.get_doc("Email Account", e.args[1]) - for key, value in account.as_dict().items(): - if not existing_account.get(key) and value \ - and key not in default_fields \ - and key != "__islocal": - existing_account.set(key, value) - - existing_account.save() - else: - raise - diff --git a/erpnext/patches/v5_0/__init__.py b/erpnext/patches/v5_0/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v5_0/convert_stock_reconciliation.py b/erpnext/patches/v5_0/convert_stock_reconciliation.py deleted file mode 100644 index 75d1da752f..0000000000 --- a/erpnext/patches/v5_0/convert_stock_reconciliation.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import unicode_literals -import frappe, json - -def execute(): - # stock reco now amendable - frappe.db.sql("""update tabDocPerm set `amend` = 1 where parent='Stock Reconciliation' and submit = 1""") - - frappe.reload_doc("stock", "doctype", "stock_reconciliation_item") - frappe.reload_doctype("Stock Reconciliation") - - if frappe.db.has_column("Stock Reconciliation", "reconciliation_json"): - for sr in frappe.db.get_all("Stock Reconciliation", ["name"], - {"reconciliation_json": ["!=", ""]}): - start = False - sr = frappe.get_doc("Stock Reconciliation", sr.name) - for row in json.loads(sr.reconciliation_json): - if start: - sr.append("items", { - "item_code": row[0], - "warehouse": row[1], - "qty": row[2] if len(row) > 2 else None, - "valuation_rate": row[3] if len(row) > 3 else None - }) - - elif row[0]=="Item Code": - start = True - - - for item in sr.items: - item.db_update() - diff --git a/erpnext/patches/v5_0/execute_on_doctype_update.py b/erpnext/patches/v5_0/execute_on_doctype_update.py deleted file mode 100644 index 70b1d8ded6..0000000000 --- a/erpnext/patches/v5_0/execute_on_doctype_update.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt in ("Stock Ledger Entry", "Communication", "DefaultValue", "DocShare", "File", "ToDo"): - frappe.get_doc("DocType", dt).run_module_method("on_doctype_update") diff --git a/erpnext/patches/v5_0/fix_taxes_and_totals_in_party_currency.py b/erpnext/patches/v5_0/fix_taxes_and_totals_in_party_currency.py deleted file mode 100644 index 30dc0f8db4..0000000000 --- a/erpnext/patches/v5_0/fix_taxes_and_totals_in_party_currency.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.meta import get_field_precision - -def execute(): - if not frappe.db.sql("""select name from `tabPatch Log` - where patch = 'erpnext.patches.v5_0.taxes_and_totals_in_party_currency'"""): - return - selling_doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"] - buying_doctypes = ["Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"] - - for dt in selling_doctypes: - update_values(dt, "Sales Taxes and Charges") - - for dt in buying_doctypes: - update_values(dt, "Purchase Taxes and Charges") - -def update_values(dt, tax_table): - rate_field_precision = get_field_precision(frappe.get_meta(dt + " Item").get_field("rate")) - tax_amount_precision = get_field_precision(frappe.get_meta(tax_table).get_field("tax_amount")) - - # update net_total, discount_on - frappe.db.sql(""" - UPDATE - `tab{0}` - SET - total_taxes_and_charges = round(base_total_taxes_and_charges / conversion_rate, {1}) - WHERE - docstatus < 2 - and ifnull(base_total_taxes_and_charges, 0) != 0 - and ifnull(total_taxes_and_charges, 0) = 0 - """.format(dt, tax_amount_precision)) - - # update net_amount - frappe.db.sql(""" - UPDATE - `tab{0}` par, `tab{1}` item - SET - item.net_amount = round(item.base_net_amount / par.conversion_rate, {2}), - item.net_rate = round(item.base_net_rate / par.conversion_rate, {2}) - WHERE - par.name = item.parent - and par.docstatus < 2 - and ((ifnull(item.base_net_amount, 0) != 0 and ifnull(item.net_amount, 0) = 0) - or (ifnull(item.base_net_rate, 0) != 0 and ifnull(item.net_rate, 0) = 0)) - """.format(dt, dt + " Item", rate_field_precision)) - - # update tax in party currency - frappe.db.sql(""" - UPDATE - `tab{0}` par, `tab{1}` tax - SET - tax.tax_amount = round(tax.base_tax_amount / par.conversion_rate, {2}), - tax.total = round(tax.base_total / conversion_rate, {2}), - tax.tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount / conversion_rate, {2}) - WHERE - par.name = tax.parent - and par.docstatus < 2 - and ((ifnull(tax.base_tax_amount, 0) != 0 and ifnull(tax.tax_amount, 0) = 0) - or (ifnull(tax.base_total, 0) != 0 and ifnull(tax.total, 0) = 0) - or (ifnull(tax.base_tax_amount_after_discount_amount, 0) != 0 and - ifnull(tax.tax_amount_after_discount_amount, 0) = 0)) - """.format(dt, tax_table, tax_amount_precision)) \ No newline at end of file diff --git a/erpnext/patches/v5_0/index_on_account_and_gl_entry.py b/erpnext/patches/v5_0/index_on_account_and_gl_entry.py deleted file mode 100644 index 2920e9293d..0000000000 --- a/erpnext/patches/v5_0/index_on_account_and_gl_entry.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -def execute(): - index_map = { - "Account": ["parent_account", "lft", "rgt"], - "GL Entry": ["posting_date", "account", 'party', "voucher_no"], - "Sales Invoice": ["posting_date", "debit_to", "customer"], - "Purchase Invoice": ["posting_date", "credit_to", "supplier"] - } - - for dt, indexes in index_map.items(): - existing_indexes = [(d.Key_name, d.Column_name) for d in frappe.db.sql("""show index from `tab{0}` - where Column_name != 'name'""".format(dt), as_dict=1)] - - for old, column in existing_indexes: - if column in ("parent", "group_or_ledger", "is_group", "is_pl_account", "debit_or_credit", - "account_name", "company", "project", "voucher_date", "due_date", "bill_no", - "bill_date", "is_opening", "fiscal_year", "outstanding_amount"): - frappe.db.sql("alter table `tab{0}` drop index {1}".format(dt, old)) - - existing_indexes = [(d.Key_name, d.Column_name) for d in frappe.db.sql("""show index from `tab{0}` - where Column_name != 'name'""".format(dt), as_dict=1)] - - existing_indexed_columns = list(set([x[1] for x in existing_indexes])) - - for new in indexes: - if new not in existing_indexed_columns: - frappe.db.sql("alter table `tab{0}` add index ({1})".format(dt, new)) \ No newline at end of file diff --git a/erpnext/patches/v5_0/is_group.py b/erpnext/patches/v5_0/is_group.py deleted file mode 100644 index 4e3f760bed..0000000000 --- a/erpnext/patches/v5_0/is_group.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -def execute(): - frappe.reload_doctype("Account") - frappe.reload_doctype("Cost Center") - frappe.db.sql("update tabAccount set is_group = if(group_or_ledger='Group', 1, 0)") - frappe.db.sql("update `tabCost Center` set is_group = if(group_or_ledger='Group', 1, 0)") diff --git a/erpnext/patches/v5_0/item_patches.py b/erpnext/patches/v5_0/item_patches.py deleted file mode 100644 index e223e09f5b..0000000000 --- a/erpnext/patches/v5_0/item_patches.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("update `tabItem` set end_of_life='2099-12-31' where ifnull(end_of_life, '0000-00-00')='0000-00-00'") - frappe.db.sql("update `tabItem` set website_image = image where ifnull(website_image, '') = 'attach_files:'") diff --git a/erpnext/patches/v5_0/link_warehouse_with_account.py b/erpnext/patches/v5_0/link_warehouse_with_account.py deleted file mode 100644 index 338fd7ad7f..0000000000 --- a/erpnext/patches/v5_0/link_warehouse_with_account.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if "master_name" in frappe.db.get_table_columns("Account"): - frappe.db.sql("""update tabAccount set warehouse=master_name - where ifnull(account_type, '') = 'Warehouse' and ifnull(master_name, '') != ''""") \ No newline at end of file diff --git a/erpnext/patches/v5_0/new_crm_module.py b/erpnext/patches/v5_0/new_crm_module.py deleted file mode 100644 index f5dda1f273..0000000000 --- a/erpnext/patches/v5_0/new_crm_module.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import json -import frappe - -def execute(): - frappe.reload_doc('crm', 'doctype', 'lead') - frappe.reload_doc('crm', 'doctype', 'opportunity') - - add_crm_to_user_desktop_items() - -def add_crm_to_user_desktop_items(): - key = "_user_desktop_items" - for user in frappe.get_all("User", filters={"enabled": 1, "user_type": "System User"}): - user = user.name - user_desktop_items = frappe.db.get_defaults(key, parent=user) - if user_desktop_items: - user_desktop_items = json.loads(user_desktop_items) - if "CRM" not in user_desktop_items: - user_desktop_items.append("CRM") - frappe.db.set_default(key, json.dumps(user_desktop_items), parent=user) - diff --git a/erpnext/patches/v5_0/newsletter.py b/erpnext/patches/v5_0/newsletter.py deleted file mode 100644 index 63e3312413..0000000000 --- a/erpnext/patches/v5_0/newsletter.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import frappe.permissions - -def execute(): - frappe.reload_doc("core", "doctype", "block_module") - frappe.reload_doctype("User") - frappe.reload_doctype("Lead") - frappe.reload_doctype("Contact") - - frappe.reload_doc('email', 'doctype', 'email_group') - frappe.reload_doc('email', 'doctype', 'email_group_member') - frappe.reload_doc('email', 'doctype', 'newsletter') - - frappe.permissions.reset_perms("Newsletter") - - if not frappe.db.exists("Role", "Newsletter Manager"): - frappe.get_doc({"doctype": "Role", "role": "Newsletter Manager"}).insert() - - for userrole in frappe.get_all("Has Role", "parent", {"role": "Sales Manager", "parenttype": "User"}): - if frappe.db.exists("User", userrole.parent): - user = frappe.get_doc("User", userrole.parent) - user.append("roles", { - "doctype": "Has Role", - "role": "Newsletter Manager" - }) - user.flags.ignore_mandatory = True - user.save() - - # create default lists - general = frappe.new_doc("Email Group") - general.title = "General" - general.insert() - general.import_from("Lead") - general.import_from("Contact") diff --git a/erpnext/patches/v5_0/opportunity_not_submittable.py b/erpnext/patches/v5_0/opportunity_not_submittable.py deleted file mode 100644 index e29d66f284..0000000000 --- a/erpnext/patches/v5_0/opportunity_not_submittable.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Opportunity") - frappe.db.sql("update tabDocPerm set submit=0, cancel=0, amend=0 where parent='Opportunity'") - frappe.db.sql("update tabOpportunity set docstatus=0 where docstatus=1") diff --git a/erpnext/patches/v5_0/party_model_patch_fix.py b/erpnext/patches/v5_0/party_model_patch_fix.py deleted file mode 100644 index d9b6709792..0000000000 --- a/erpnext/patches/v5_0/party_model_patch_fix.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for company in frappe.get_all("Company", - ["name", "default_receivable_account", "default_payable_account"]): - - if company.default_receivable_account: - frappe.db.sql("""update `tabSales Invoice` invoice set `debit_to`=%(account)s - where company=%(company)s - and not exists (select name from `tabAccount` account where account.name=invoice.debit_to)""", - {"company": company.name, "account": company.default_receivable_account}) - - if company.default_payable_account: - frappe.db.sql("""update `tabPurchase Invoice` invoice set `credit_to`=%(account)s - where company=%(company)s - and not exists (select name from `tabAccount` account where account.name=invoice.credit_to)""", - {"company": company.name, "account": company.default_payable_account}) diff --git a/erpnext/patches/v5_0/portal_fixes.py b/erpnext/patches/v5_0/portal_fixes.py deleted file mode 100644 index 1fefd99167..0000000000 --- a/erpnext/patches/v5_0/portal_fixes.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe -import erpnext.setup.install - -def execute(): - frappe.reload_doc("website", "doctype", "web_form_field", force=True, reset_permissions=True) - #erpnext.setup.install.add_web_forms() diff --git a/erpnext/patches/v5_0/project_costing.py b/erpnext/patches/v5_0/project_costing.py deleted file mode 100644 index e2d65d0594..0000000000 --- a/erpnext/patches/v5_0/project_costing.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Project") - frappe.db.sql("update `tabProject` set expected_start_date = project_start_date, \ - expected_end_date = completion_date, actual_end_date = act_completion_date, \ - estimated_costing = project_value, gross_margin = gross_margin_value") \ No newline at end of file diff --git a/erpnext/patches/v5_0/recalculate_total_amount_in_jv.py b/erpnext/patches/v5_0/recalculate_total_amount_in_jv.py deleted file mode 100644 index d5af43c541..0000000000 --- a/erpnext/patches/v5_0/recalculate_total_amount_in_jv.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import money_in_words - -def execute(): - company_currency = dict(frappe.db.sql("select name, default_currency from `tabCompany`")) - bank_or_cash_accounts = frappe.db.sql_list("""select name from `tabAccount` - where account_type in ('Bank', 'Cash') and docstatus < 2""") - - for je in frappe.db.sql_list("""select name from `tabJournal Entry` where docstatus < 2"""): - total_amount = 0 - total_amount_in_words = "" - - je_doc = frappe.get_doc('Journal Entry', je) - for d in je_doc.get("accounts"): - if (d.party_type and d.party) or d.account in bank_or_cash_accounts: - total_amount = d.debit or d.credit - if total_amount: - total_amount_in_words = money_in_words(total_amount, company_currency.get(je_doc.company)) - - if total_amount: - frappe.db.sql("""update `tabJournal Entry` set total_amount=%s, total_amount_in_words=%s - where name = %s""", (total_amount, total_amount_in_words, je)) diff --git a/erpnext/patches/v5_0/reclculate_planned_operating_cost_in_production_order.py b/erpnext/patches/v5_0/reclculate_planned_operating_cost_in_production_order.py deleted file mode 100644 index 6d392831b4..0000000000 --- a/erpnext/patches/v5_0/reclculate_planned_operating_cost_in_production_order.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for wo in frappe.db.sql("""select name from `tabWork Order` where docstatus < 2""", as_dict=1): - work_order = frappe.get_doc("Work Order", wo.name) - if work_order.operations: - work_order.flags.ignore_validate_update_after_submit = True - work_order.calculate_time() - work_order.save() \ No newline at end of file diff --git a/erpnext/patches/v5_0/remove_birthday_events.py b/erpnext/patches/v5_0/remove_birthday_events.py deleted file mode 100644 index 3ead8669b8..0000000000 --- a/erpnext/patches/v5_0/remove_birthday_events.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for e in frappe.db.sql_list("""select name from tabEvent where - repeat_on='Every Year' and ref_type='Employee'"""): - frappe.delete_doc("Event", e, force=True) diff --git a/erpnext/patches/v5_0/rename_customer_issue.py b/erpnext/patches/v5_0/rename_customer_issue.py deleted file mode 100644 index 1bd69ceec1..0000000000 --- a/erpnext/patches/v5_0/rename_customer_issue.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("Customer Issue"): - frappe.rename_doc("DocType", "Customer Issue", "Warranty Claim") diff --git a/erpnext/patches/v5_0/rename_pos_setting.py b/erpnext/patches/v5_0/rename_pos_setting.py deleted file mode 100644 index bf10333564..0000000000 --- a/erpnext/patches/v5_0/rename_pos_setting.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("POS Setting"): - frappe.rename_doc("DocType", "POS Setting", "POS Profile") diff --git a/erpnext/patches/v5_0/rename_table_fieldnames.py b/erpnext/patches/v5_0/rename_table_fieldnames.py deleted file mode 100644 index aefb0a2037..0000000000 --- a/erpnext/patches/v5_0/rename_table_fieldnames.py +++ /dev/null @@ -1,243 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field -from frappe.modules import scrub, get_doctype_module - -rename_map = { - "Opportunity": [ - ["enquiry_details", "items"] - ], - "Quotation": [ - ["quotation_details", "items"], - ["other_charges", "taxes"] - ], - "Sales Order": [ - ["sales_order_details", "items"], - ["other_charges", "taxes"], - ["packing_details", "packed_items"] - ], - "Delivery Note": [ - ["delivery_note_details", "items"], - ["other_charges", "taxes"], - ["packing_details", "packed_items"] - ], - "Sales Invoice": [ - ["entries", "items"], - ["other_charges", "taxes"], - ["packing_details", "packed_items"], - ["advance_adjustment_details", "advances"] - ], - "Material Request": [ - ["indent_details", "items"] - ], - "Supplier Quotation": [ - ["quotation_items", "items"], - ["other_charges", "taxes"] - ], - "Purchase Order": [ - ["po_details", "items"], - ["other_charges", "taxes"], - ["po_raw_material_details", "supplied_items"] - ], - "Purchase Receipt": [ - ["purchase_receipt_details", "items"], - ["other_charges", "taxes"], - ["pr_raw_material_details", "supplied_items"] - ], - "Purchase Invoice": [ - ["entries", "items"], - ["other_charges", "taxes"], - ["advance_allocation_details", "advances"] - ], - "Work Order": [ - ["production_order_operations", "operations"] - ], - "BOM": [ - ["bom_operations", "operations"], - ["bom_materials", "items"], - ["flat_bom_details", "exploded_items"] - ], - "Payment Reconciliation": [ - ["payment_reconciliation_payments", "payments"], - ["payment_reconciliation_invoices", "invoices"] - ], - "Sales Taxes and Charges Template": [ - ["other_charges", "taxes"], - ["valid_for_territories", "territories"] - ], - "Purchase Taxes and Charges Template": [ - ["other_charges", "taxes"] - ], - "Shipping Rule": [ - ["shipping_rule_conditions", "conditions"], - ["valid_for_territories", "territories"] - ], - "Price List": [ - ["valid_for_territories", "territories"] - ], - "Appraisal": [ - ["appraisal_details", "goals"] - ], - "Appraisal Template": [ - ["kra_sheet", "goals"] - ], - "Bank Reconciliation": [ - ["entries", "journal_entries"] - ], - "C-Form": [ - ["invoice_details", "invoices"] - ], - "Employee": [ - ["employee_leave_approvers", "leave_approvers"], - ["educational_qualification_details", "education"], - ["previous_experience_details", "external_work_history"], - ["experience_in_company_details", "internal_work_history"] - ], - "Expense Claim": [ - ["expense_voucher_details", "expenses"] - ], - "Fiscal Year": [ - ["fiscal_year_companies", "companies"] - ], - "Holiday List": [ - ["holiday_list_details", "holidays"] - ], - "Installation Note": [ - ["installed_item_details", "items"] - ], - "Item": [ - ["item_reorder", "reorder_levels"], - ["uom_conversion_details", "uoms"], - ["item_supplier_details", "supplier_items"], - ["item_customer_details", "customer_items"], - ["item_tax", "taxes"], - ["item_specification_details", "quality_parameters"], - ["item_website_specifications", "website_specifications"] - ], - "Item Group": [ - ["item_website_specifications", "website_specifications"] - ], - "Landed Cost Voucher": [ - ["landed_cost_purchase_receipts", "purchase_receipts"], - ["landed_cost_items", "items"], - ["landed_cost_taxes_and_charges", "taxes"] - ], - "Maintenance Schedule": [ - ["item_maintenance_detail", "items"], - ["maintenance_schedule_detail", "schedules"] - ], - "Maintenance Visit": [ - ["maintenance_visit_details", "purposes"] - ], - "Packing Slip": [ - ["item_details", "items"] - ], - "Customer": [ - ["party_accounts", "accounts"] - ], - "Customer Group": [ - ["party_accounts", "accounts"] - ], - "Supplier": [ - ["party_accounts", "accounts"] - ], - "Supplier Type": [ - ["party_accounts", "accounts"] - ], - "Payment Tool": [ - ["payment_tool_details", "vouchers"] - ], - "Production Planning Tool": [ - ["pp_so_details", "sales_orders"], - ["pp_details", "items"] - ], - "Quality Inspection": [ - ["qa_specification_details", "readings"] - ], - "Salary Slip": [ - ["earning_details", "earnings"], - ["deduction_details", "deductions"] - ], - "Salary Structure": [ - ["earning_details", "earnings"], - ["deduction_details", "deductions"] - ], - "Product Bundle": [ - ["sales_bom_items", "items"] - ], - "SMS Settings": [ - ["static_parameter_details", "parameters"] - ], - "Stock Entry": [ - ["mtn_details", "items"] - ], - "Sales Partner": [ - ["partner_target_details", "targets"] - ], - "Sales Person": [ - ["target_details", "targets"] - ], - "Territory": [ - ["target_details", "targets"] - ], - "Time Sheet": [ - ["time_sheet_details", "time_logs"] - ], - "Workstation": [ - ["workstation_operation_hours", "working_hours"] - ], - "Payment Reconciliation Payment": [ - ["journal_voucher", "journal_entry"], - ], - "Purchase Invoice Advance": [ - ["journal_voucher", "journal_entry"], - ], - "Sales Invoice Advance": [ - ["journal_voucher", "journal_entry"], - ], - "Journal Entry": [ - ["entries", "accounts"] - ], - "Monthly Distribution": [ - ["budget_distribution_details", "percentages"] - ] -} - -def execute(): - # rename doctypes - tables = frappe.db.sql_list("show tables") - for old_dt, new_dt in [["Journal Voucher Detail", "Journal Entry Account"], - ["Journal Voucher", "Journal Entry"], - ["Budget Distribution Detail", "Monthly Distribution Percentage"], - ["Budget Distribution", "Monthly Distribution"]]: - if "tab"+new_dt not in tables: - frappe.rename_doc("DocType", old_dt, new_dt, force=True) - - # reload new child doctypes - frappe.reload_doc("manufacturing", "doctype", "work_order_operation") - frappe.reload_doc("manufacturing", "doctype", "workstation_working_hour") - frappe.reload_doc("stock", "doctype", "item_variant") - frappe.reload_doc("Payroll", "doctype", "salary_detail") - frappe.reload_doc("accounts", "doctype", "party_account") - frappe.reload_doc("accounts", "doctype", "fiscal_year_company") - - #rename table fieldnames - for dn in rename_map: - if not frappe.db.exists("DocType", dn): - continue - frappe.reload_doc(get_doctype_module(dn), "doctype", scrub(dn)) - - for dt, field_list in rename_map.items(): - if not frappe.db.exists("DocType", dt): - continue - for field in field_list: - rename_field(dt, field[0], field[1]) - - # update voucher type - for old, new in [["Bank Voucher", "Bank Entry"], ["Cash Voucher", "Cash Entry"], - ["Credit Card Voucher", "Credit Card Entry"], ["Contra Voucher", "Contra Entry"], - ["Write Off Voucher", "Write Off Entry"], ["Excise Voucher", "Excise Entry"]]: - frappe.db.sql("update `tabJournal Entry` set voucher_type=%s where voucher_type=%s", (new, old)) diff --git a/erpnext/patches/v5_0/rename_taxes_and_charges_master.py b/erpnext/patches/v5_0/rename_taxes_and_charges_master.py deleted file mode 100644 index e26f48cda1..0000000000 --- a/erpnext/patches/v5_0/rename_taxes_and_charges_master.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - - -def execute(): - if frappe.db.table_exists("Sales Taxes and Charges Master"): - frappe.rename_doc("DocType", "Sales Taxes and Charges Master", - "Sales Taxes and Charges Template") - frappe.delete_doc("DocType", "Sales Taxes and Charges Master") - - if frappe.db.table_exists("Purchase Taxes and Charges Master"): - frappe.rename_doc("DocType", "Purchase Taxes and Charges Master", - "Purchase Taxes and Charges Template") - frappe.delete_doc("DocType", "Purchase Taxes and Charges Master") diff --git a/erpnext/patches/v5_0/rename_total_fields.py b/erpnext/patches/v5_0/rename_total_fields.py deleted file mode 100644 index 6657dd843e..0000000000 --- a/erpnext/patches/v5_0/rename_total_fields.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field -from frappe.modules import scrub, get_doctype_module - -selling_doctypes = ("Quotation", "Sales Order", "Delivery Note", "Sales Invoice") - -buying_doctypes = ("Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice") - -selling_renamed_fields = ( - ("net_total", "base_net_total"), - ("net_total_export", "net_total"), - ("other_charges_total", "base_total_taxes_and_charges"), - ("other_charges_total_export", "total_taxes_and_charges"), - ("grand_total", "base_grand_total"), - ("grand_total_export", "grand_total"), - ("rounded_total", "base_rounded_total"), - ("rounded_total_export", "rounded_total"), - ("in_words", "base_in_words"), - ("in_words_export", "in_words") -) - -buying_renamed_fields = ( - ("net_total", "base_net_total"), - ("net_total_import", "net_total"), - ("grand_total", "base_grand_total"), - ("grand_total_import", "grand_total"), - ("rounded_total", "base_rounded_total"), - ("in_words", "base_in_words"), - ("in_words_import", "in_words"), - ("other_charges_added", "base_taxes_and_charges_added"), - ("other_charges_added_import", "taxes_and_charges_added"), - ("other_charges_deducted", "base_taxes_and_charges_deducted"), - ("other_charges_deducted_import", "taxes_and_charges_deducted"), - ("total_tax", "base_total_taxes_and_charges") -) - -def execute(): - for doctypes, fields in [[selling_doctypes, selling_renamed_fields], [buying_doctypes, buying_renamed_fields]]: - for dt in doctypes: - frappe.reload_doc(get_doctype_module(dt), "doctype", scrub(dt)) - table_columns = frappe.db.get_table_columns(dt) - base_net_total = frappe.db.sql("select sum(ifnull({0}, 0)) from `tab{1}`".format(fields[0][1], dt))[0][0] - if not base_net_total: - for f in fields: - if f[0] in table_columns: - rename_field(dt, f[0], f[1]) - - # Added new field "total_taxes_and_charges" in buying cycle, updating value - if dt in ("Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"): - frappe.db.sql("""update `tab{0}` set total_taxes_and_charges = - round(base_total_taxes_and_charges/conversion_rate, 2)""".format(dt)) diff --git a/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py b/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py deleted file mode 100644 index c564f8b02a..0000000000 --- a/erpnext/patches/v5_0/replace_renamed_fields_in_custom_scripts_and_print_formats.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import re - -def execute(): - # NOTE: sequence is important - renamed_fields = get_all_renamed_fields() - - for dt, script_field, ref_dt_field in (("Client Script", "script", "dt"), ("Print Format", "html", "doc_type")): - - cond1 = " or ".join("""{0} like "%%{1}%%" """.format(script_field, d[0].replace("_", "\\_")) for d in renamed_fields) - cond2 = " and standard = 'No'" if dt == "Print Format" else "" - - for name, script, ref_dt in frappe.db.sql("select name, {0} as script, {1} as ref_dt from `tab{2}` where ({3}) {4}".format(script_field, ref_dt_field, dt, cond1, cond2)): - update_script(dt, name, ref_dt, script_field, script, renamed_fields) - -def get_all_renamed_fields(): - from erpnext.patches.v5_0.rename_table_fieldnames import rename_map - - renamed_fields = ( - ("base_amount", "base_net_amount"), - ("net_total", "base_net_total"), - ("net_total_export", "total"), - ("net_total_import", "total"), - ("other_charges_total", "base_total_taxes_and_charges"), - ("other_charges_total_export", "total_taxes_and_charges"), - ("other_charges_added", "base_taxes_and_charges_added"), - ("other_charges_added_import", "taxes_and_charges_added"), - ("other_charges_deducted", "base_taxes_and_charges_deducted"), - ("other_charges_deducted_import", "taxes_and_charges_deducted"), - ("total_tax", "base_total_taxes_and_charges"), - ("grand_total", "base_grand_total"), - ("grand_total_export", "grand_total"), - ("grand_total_import", "grand_total"), - ("rounded_total", "base_rounded_total"), - ("rounded_total_export", "rounded_total"), - ("rounded_total_import", "rounded_total"), - ("in_words", "base_in_words"), - ("in_words_export", "in_words"), - ("in_words_import", "in_words"), - ("tax_amount", "base_tax_amount"), - ("tax_amount_after_discount_amount", "base_tax_amount_after_discount_amount"), - ) - - for fields in rename_map.values(): - renamed_fields += tuple(fields) - - return renamed_fields - -def update_script(dt, name, ref_dt, script_field, script, renamed_fields): - for from_field, to_field in renamed_fields: - if from_field != "entries": - script = re.sub(r"\b{}\b".format(from_field), to_field, script) - - if ref_dt == "Journal Entry": - script = re.sub(r"\bentries\b", "accounts", script) - elif ref_dt == "Bank Reconciliation": - script = re.sub(r"\bentries\b", "journal_entries", script) - elif ref_dt in ("Sales Invoice", "Purchase Invoice"): - script = re.sub(r"\bentries\b", "items", script) - - frappe.db.set_value(dt, name, script_field, script) \ No newline at end of file diff --git a/erpnext/patches/v5_0/repost_gle_for_jv_with_multiple_party.py b/erpnext/patches/v5_0/repost_gle_for_jv_with_multiple_party.py deleted file mode 100644 index 76efdcc7c6..0000000000 --- a/erpnext/patches/v5_0/repost_gle_for_jv_with_multiple_party.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - je_list = frappe.db.sql_list(""" - select par.name from `tabJournal Entry` par - where par.docstatus=1 and par.creation > '2015-03-01' - and (select count(distinct child.party) from `tabJournal Entry Account` child - where par.name=child.parent and ifnull(child.party, '') != '') > 1 - """) - - for d in je_list: - # delete existing gle - frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d) - - # repost gl entries - je = frappe.get_doc("Journal Entry", d) - je.make_gl_entries() - - if je_list: - print(je_list) - - \ No newline at end of file diff --git a/erpnext/patches/v5_0/repost_requested_qty.py b/erpnext/patches/v5_0/repost_requested_qty.py deleted file mode 100644 index 6af71f3fc4..0000000000 --- a/erpnext/patches/v5_0/repost_requested_qty.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty - - count=0 - for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse - from `tabMaterial Request Item` where docstatus = 1"""): - try: - count += 1 - update_bin_qty(item_code, warehouse, { - "indented_qty": get_indented_qty(item_code, warehouse), - }) - if count % 200 == 0: - frappe.db.commit() - except: - frappe.db.rollback() diff --git a/erpnext/patches/v5_0/reset_values_in_tools.py b/erpnext/patches/v5_0/reset_values_in_tools.py deleted file mode 100644 index fd970ba1b0..0000000000 --- a/erpnext/patches/v5_0/reset_values_in_tools.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt in ["Payment Tool", "Bank Reconciliation", "Payment Reconciliation", "Leave Control Panel", - "Salary Manager", "Upload Attenadance", "Production Planning Tool", "BOM Update Tool", "Customize Form", - "Employee Attendance Tool", "Rename Tool", "BOM Update Tool", "Process Payroll", "Naming Series"]: - frappe.db.sql("delete from `tabSingles` where doctype=%s", dt) - \ No newline at end of file diff --git a/erpnext/patches/v5_0/set_appraisal_remarks.py b/erpnext/patches/v5_0/set_appraisal_remarks.py deleted file mode 100644 index 8652c32cf0..0000000000 --- a/erpnext/patches/v5_0/set_appraisal_remarks.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Appraisal") - frappe.db.sql("update `tabAppraisal` set remarks = comments") \ No newline at end of file diff --git a/erpnext/patches/v5_0/set_default_company_in_bom.py b/erpnext/patches/v5_0/set_default_company_in_bom.py deleted file mode 100644 index a5cd761119..0000000000 --- a/erpnext/patches/v5_0/set_default_company_in_bom.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("manufacturing", "doctype", "bom") - company = frappe.db.get_value("Global Defaults", None, "default_company") - frappe.db.sql("""update `tabBOM` set company = %s""",company) diff --git a/erpnext/patches/v5_0/set_footer_address.py b/erpnext/patches/v5_0/set_footer_address.py deleted file mode 100644 index 8120d834e1..0000000000 --- a/erpnext/patches/v5_0/set_footer_address.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("System Settings") - ss = frappe.get_doc("System Settings", "System Settings") - ss.email_footer_address = frappe.db.get_default("company") - ss.flags.ignore_mandatory = True - ss.save() diff --git a/erpnext/patches/v5_0/stock_entry_update_value.py b/erpnext/patches/v5_0/stock_entry_update_value.py deleted file mode 100644 index ba1af310f5..0000000000 --- a/erpnext/patches/v5_0/stock_entry_update_value.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for d in frappe.db.get_all("Stock Entry"): - se = frappe.get_doc("Stock Entry", d.name) - se.set_total_incoming_outgoing_value() - se.db_update() diff --git a/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py b/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py deleted file mode 100644 index 76d10820b5..0000000000 --- a/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.meta import get_field_precision -from frappe.custom.doctype.property_setter.property_setter import make_property_setter - -def execute(): - selling_doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"] - buying_doctypes = ["Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"] - - for dt in selling_doctypes: - update_values(dt, "Sales Taxes and Charges") - - for dt in buying_doctypes: - update_values(dt, "Purchase Taxes and Charges") - -def update_values(dt, tax_table): - frappe.reload_doctype(dt) - frappe.reload_doctype(dt + " Item") - frappe.reload_doctype(tax_table) - - net_total_precision = get_field_precision(frappe.get_meta(dt).get_field("net_total")) - for field in ("total", "base_total", "base_net_total"): - make_property_setter(dt, field, "precision", net_total_precision, "Select") - - rate_field_precision = get_field_precision(frappe.get_meta(dt + " Item").get_field("rate")) - for field in ("net_rate", "base_net_rate", "net_amount", "base_net_amount", "base_rate", "base_amount"): - make_property_setter(dt + " Item", field, "precision", rate_field_precision, "Select") - - tax_amount_precision = get_field_precision(frappe.get_meta(tax_table).get_field("tax_amount")) - for field in ("base_tax_amount", "total", "base_total", "tax_amount_after_discount_amount", - "base_tax_amount_after_discount_amount"): - make_property_setter(tax_table, field, "precision", tax_amount_precision, "Select") - - # update net_total, discount_on - frappe.db.sql(""" - UPDATE - `tab{0}` - SET - total = round(net_total, {1}), - base_total = round(net_total*conversion_rate, {1}), - net_total = round(base_net_total / conversion_rate, {1}), - apply_discount_on = "Grand Total" - WHERE - docstatus < 2 - """.format(dt, net_total_precision)) - - # update net_amount - frappe.db.sql(""" - UPDATE - `tab{0}` par, `tab{1}` item - SET - item.base_net_amount = round(item.base_amount, {2}), - item.base_net_rate = round(item.base_rate, {2}), - item.net_amount = round(item.base_amount / par.conversion_rate, {2}), - item.net_rate = round(item.base_rate / par.conversion_rate, {2}), - item.base_amount = round(item.amount * par.conversion_rate, {2}), - item.base_rate = round(item.rate * par.conversion_rate, {2}) - WHERE - par.name = item.parent - and par.docstatus < 2 - """.format(dt, dt + " Item", rate_field_precision)) - - # update tax in party currency - frappe.db.sql(""" - UPDATE - `tab{0}` par, `tab{1}` tax - SET - tax.base_tax_amount = round(tax.tax_amount, {2}), - tax.tax_amount = round(tax.tax_amount / par.conversion_rate, {2}), - tax.base_total = round(tax.total, {2}), - tax.total = round(tax.total / conversion_rate, {2}), - tax.base_tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount, {2}), - tax.tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount / conversion_rate, {2}) - WHERE - par.name = tax.parent - and par.docstatus < 2 - """.format(dt, tax_table, tax_amount_precision)) diff --git a/erpnext/patches/v5_0/update_account_types.py b/erpnext/patches/v5_0/update_account_types.py deleted file mode 100644 index 424743efaa..0000000000 --- a/erpnext/patches/v5_0/update_account_types.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for company in frappe.db.get_all("Company"): - company = frappe.get_doc("Company", company.name) - - match_types = ("Stock Received But Not Billed", "Stock Adjustment", "Expenses Included In Valuation", - "Cost of Goods Sold") - - for account_type in match_types: - account_name = "{0} - {1}".format(account_type, company.abbr) - current_account_type = frappe.db.get_value("Account", account_name, "account_type") - if current_account_type != account_type: - frappe.db.set_value("Account", account_name, "account_type", account_type) - - company.set_default_accounts() diff --git a/erpnext/patches/v5_0/update_advance_paid.py b/erpnext/patches/v5_0/update_advance_paid.py deleted file mode 100644 index 74e71e84c8..0000000000 --- a/erpnext/patches/v5_0/update_advance_paid.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt in ("Sales Order", "Purchase Order"): - orders_with_advance = frappe.db.sql("""select name from `tab{0}` - where docstatus < 2 and ifnull(advance_paid, 0) != 0""".format(dt), as_dict=1) - - for order in orders_with_advance: - frappe.get_doc(dt, order.name).set_total_advance_paid() \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_companywise_payment_account.py b/erpnext/patches/v5_0/update_companywise_payment_account.py deleted file mode 100644 index fb4b919c85..0000000000 --- a/erpnext/patches/v5_0/update_companywise_payment_account.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'mode_of_payment') - frappe.reload_doc('accounts', 'doctype', 'mode_of_payment_account') - - mode_of_payment_list = frappe.db.sql("""select name, default_account - from `tabMode of Payment`""", as_dict=1) - - for d in mode_of_payment_list: - if d.get("default_account"): - parent_doc = frappe.get_doc("Mode of Payment", d.get("name")) - - parent_doc.set("accounts", - [{"company": frappe.db.get_value("Account", d.get("default_account"), "company"), - "default_account": d.get("default_account")}]) - parent_doc.save() diff --git a/erpnext/patches/v5_0/update_dn_against_doc_fields.py b/erpnext/patches/v5_0/update_dn_against_doc_fields.py deleted file mode 100644 index 56f4f484b1..0000000000 --- a/erpnext/patches/v5_0/update_dn_against_doc_fields.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('stock', 'doctype', 'delivery_note_item') - - frappe.db.sql("""update `tabDelivery Note Item` set so_detail = prevdoc_detail_docname - where ifnull(against_sales_order, '') != ''""") - - frappe.db.sql("""update `tabDelivery Note Item` set si_detail = prevdoc_detail_docname - where ifnull(against_sales_invoice, '') != ''""") diff --git a/erpnext/patches/v5_0/update_from_bom.py b/erpnext/patches/v5_0/update_from_bom.py deleted file mode 100644 index 4b3e62d7a5..0000000000 --- a/erpnext/patches/v5_0/update_from_bom.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Stock Entry") - frappe.db.sql("update `tabStock Entry` set from_bom = if(ifnull(bom_no, '')='', 0, 1)") diff --git a/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py b/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py deleted file mode 100644 index b52785ae60..0000000000 --- a/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - account_settings = frappe.get_doc("Accounts Settings") - - if not account_settings.frozen_accounts_modifier and account_settings.bde_auth_role: - frappe.db.set_value("Accounts Settings", None, - "frozen_accounts_modifier", account_settings.bde_auth_role) - diff --git a/erpnext/patches/v5_0/update_item_and_description_again.py b/erpnext/patches/v5_0/update_item_and_description_again.py deleted file mode 100644 index 35dedcc072..0000000000 --- a/erpnext/patches/v5_0/update_item_and_description_again.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cstr -import re - -def execute(): - item_details = frappe._dict() - for d in frappe.db.sql("select name, description from `tabItem`", as_dict=1): - description = cstr(d.description).strip() - new_desc = extract_description(description) - - item_details.setdefault(d.name, frappe._dict({ - "old_description": description, - "new_description": new_desc - })) - - - dt_list= ["Purchase Order Item","Supplier Quotation Item", "BOM", "BOM Explosion Item" , \ - "BOM Item", "Opportunity Item" , "Quotation Item" , "Sales Order Item" , "Delivery Note Item" , \ - "Material Request Item" , "Purchase Receipt Item" , "Stock Entry Detail"] - for dt in dt_list: - frappe.reload_doctype(dt) - records = frappe.db.sql("""select name, `{0}` as item_code, description from `tab{1}` - where description is not null and description like '%%]*\>".format(tag), "", desc) - - return desc diff --git a/erpnext/patches/v5_0/update_item_desc_in_invoice.py b/erpnext/patches/v5_0/update_item_desc_in_invoice.py deleted file mode 100644 index dba35d5693..0000000000 --- a/erpnext/patches/v5_0/update_item_desc_in_invoice.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.website.utils import find_first_image -from frappe.utils import cstr -import re - -def execute(): - item_details = frappe._dict() - for d in frappe.db.sql("select name, description, image from `tabItem`", as_dict=1): - description = cstr(d.description).strip() - item_details.setdefault(d.name, frappe._dict({ - "description": description, - "image": d.image - })) - - - dt_list= ["Sales Invoice Item","Purchase Invoice Item"] - for dt in dt_list: - frappe.reload_doctype(dt) - records = frappe.db.sql("""select name, item_code, description from `tab{0}` - where ifnull(item_code, '') != '' and description is not null """.format(dt), as_dict=1) - - count = 1 - for d in records: - if item_details.get(d.item_code) and cstr(d.description) == item_details.get(d.item_code).description: - desc = item_details.get(d.item_code).description - image = item_details.get(d.item_code).image - else: - desc, image = extract_image_and_description(cstr(d.description)) - - if not image: - item_detail = item_details.get(d.item_code) - if item_detail: - image = item_detail.image - - frappe.db.sql("""update `tab{0}` set description = %s, image = %s - where name = %s """.format(dt), (desc, image, d.name)) - - count += 1 - if count % 500 == 0: - frappe.db.commit() - - -def extract_image_and_description(data): - image_url = find_first_image(data) - desc = data - for tag in ("img", "table", "tr", "td"): - desc = re.sub("\]*\>".format(tag), "", desc) - return desc, image_url \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_item_description_and_image.py b/erpnext/patches/v5_0/update_item_description_and_image.py deleted file mode 100644 index 75df39ee39..0000000000 --- a/erpnext/patches/v5_0/update_item_description_and_image.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.website.utils import find_first_image -from frappe.utils import cstr -import re - -def execute(): - item_details = frappe._dict() - for d in frappe.db.sql("select name, description_html, description from `tabItem`", as_dict=1): - description = cstr(d.description_html).strip() or cstr(d.description).strip() - image_url, new_desc = extract_image_and_description(description) - - item_details.setdefault(d.name, frappe._dict({ - "old_description": description, - "new_description": new_desc, - "image_url": image_url - })) - - - dt_list= ["Purchase Order Item","Supplier Quotation Item", "BOM", "BOM Explosion Item" , \ - "BOM Item", "Opportunity Item" , "Quotation Item" , "Sales Order Item" , "Delivery Note Item" , \ - "Material Request Item" , "Purchase Receipt Item" , "Stock Entry Detail"] - for dt in dt_list: - frappe.reload_doctype(dt) - records = frappe.db.sql("""select name, `{0}` as item_code, description from `tab{1}` - where description is not null and image is null and description like '%%]+\>", "", data) - - return image_url, desc diff --git a/erpnext/patches/v5_0/update_item_name_in_bom.py b/erpnext/patches/v5_0/update_item_name_in_bom.py deleted file mode 100644 index 5781542a2a..0000000000 --- a/erpnext/patches/v5_0/update_item_name_in_bom.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("manufacturing", "doctype", "bom") - frappe.reload_doc("manufacturing", "doctype", "bom_item") - frappe.reload_doc("manufacturing", "doctype", "bom_explosion_item") - frappe.reload_doc("manufacturing", "doctype", "bom_operation") - - frappe.db.sql("""update `tabBOM` as bom set bom.item_name = \ - ( select item.item_name from `tabItem` as item where item.name = bom.item)""") - frappe.db.sql("""update `tabBOM Item` as bomItem set bomItem.item_name = ( select item.item_name \ - from `tabItem` as item where item.name = bomItem.item_code)""") - frappe.db.sql("""update `tabBOM Explosion Item` as explosionItem set explosionItem.item_name = \ - ( select item.item_name from `tabItem` as item where item.name = explosionItem.item_code)""") diff --git a/erpnext/patches/v5_0/update_journal_entry_title.py b/erpnext/patches/v5_0/update_journal_entry_title.py deleted file mode 100644 index eaa2be054f..0000000000 --- a/erpnext/patches/v5_0/update_journal_entry_title.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Journal Entry") - frappe.db.sql("""update `tabJournal Entry` set title = - if(ifnull(pay_to_recd_from, "")!="", pay_to_recd_from, - (select account from `tabJournal Entry Account` - where parent=`tabJournal Entry`.name and idx=1 limit 1))""") diff --git a/erpnext/patches/v5_0/update_material_transfer_for_manufacture.py b/erpnext/patches/v5_0/update_material_transfer_for_manufacture.py deleted file mode 100644 index f31c9fed4d..0000000000 --- a/erpnext/patches/v5_0/update_material_transfer_for_manufacture.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""update `tabStock Entry` set purpose='Material Transfer for Manufacture' - where ifnull(work_order, '')!='' and purpose='Material Transfer'""") diff --git a/erpnext/patches/v5_0/update_material_transferred_for_manufacturing.py b/erpnext/patches/v5_0/update_material_transferred_for_manufacturing.py deleted file mode 100644 index 2a09aa29af..0000000000 --- a/erpnext/patches/v5_0/update_material_transferred_for_manufacturing.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Work Order") - frappe.db.sql("""update `tabWork Order` set material_transferred_for_manufacturing= - (select sum(fg_completed_qty) from `tabStock Entry` - where docstatus=1 - and work_order=`tabWork Order`.name - and purpose = "Material Transfer for Manufacture")""") diff --git a/erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py b/erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py deleted file mode 100644 index 5847c83d38..0000000000 --- a/erpnext/patches/v5_0/update_material_transferred_for_manufacturing_again.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - wo_order_qty_transferred = frappe._dict() - for se in frappe.db.sql("""select work_order, sum(fg_completed_qty) as transferred_qty - from `tabStock Entry` - where docstatus=1 and ifnull(work_order, '') != '' - and purpose = 'Material Transfer for Manufacture' - group by work_order""", as_dict=1): - wo_order_qty_transferred.setdefault(se.work_order, se.transferred_qty) - - for d in frappe.get_all("Work Order", filters={"docstatus": 1}, fields=["name", "qty"]): - if d.name in wo_order_qty_transferred: - material_transferred_for_manufacturing = wo_order_qty_transferred.get(d.name) \ - if wo_order_qty_transferred.get(d.name) <= d.qty else d.qty - - frappe.db.sql("""update `tabWork Order` set material_transferred_for_manufacturing=%s - where name=%s""", (material_transferred_for_manufacturing, d.name)) \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_operation_description.py b/erpnext/patches/v5_0/update_operation_description.py deleted file mode 100644 index 4ce32f35f1..0000000000 --- a/erpnext/patches/v5_0/update_operation_description.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import frappe.permissions - -def execute(): - if "opn_description" in frappe.db.get_table_columns("BOM Operation"): - frappe.db.sql("""update `tabBOM Operation` set description = opn_description - where ifnull(description, '') = ''""") \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_opportunity.py b/erpnext/patches/v5_0/update_opportunity.py deleted file mode 100644 index 8eb45c48e7..0000000000 --- a/erpnext/patches/v5_0/update_opportunity.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('crm', 'doctype', 'opportunity') - frappe.reload_doc('crm', 'doctype', 'opportunity_item') - - # all existing opportunities were with items - frappe.db.sql("update `tabDocType` set module = 'CRM' where name='Opportunity Item'") - frappe.db.sql("update tabOpportunity set with_items=1, title=customer_name") - frappe.db.sql("update `tabEmail Account` set append_to='Opportunity' where append_to='Lead'") diff --git a/erpnext/patches/v5_0/update_projects.py b/erpnext/patches/v5_0/update_projects.py deleted file mode 100644 index 68e03c9bdb..0000000000 --- a/erpnext/patches/v5_0/update_projects.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals -import frappe - -def execute(): - # convert milestones to tasks - frappe.reload_doctype("Project") - frappe.reload_doc("projects", "doctype", "project_task") - frappe.reload_doctype("Task") - frappe.reload_doc("projects", "doctype", "task_depends_on") - frappe.reload_doc("projects", "doctype", "time_log") - - for m in frappe.get_all("Project Milestone", "*"): - if (m.milestone and m.milestone_date - and frappe.db.exists("Project", m.parent)): - subject = (m.milestone[:139] + "…") if (len(m.milestone) > 140) else m.milestone - description = m.milestone - task = frappe.get_doc({ - "doctype": "Task", - "subject": subject, - "description": description if description!=subject else None, - "expected_start_date": m.milestone_date, - "status": "Open" if m.status=="Pending" else "Closed", - "project": m.parent, - }) - task.flags.ignore_mandatory = True - task.insert(ignore_permissions=True) - - # remove project milestone - frappe.delete_doc("DocType", "Project Milestone") - - # remove calendar events for milestone - for e in frappe.get_all("Event", ["name"], {"ref_type": "Project"}): - frappe.delete_doc("Event", e.name) diff --git a/erpnext/patches/v5_0/update_sms_sender.py b/erpnext/patches/v5_0/update_sms_sender.py deleted file mode 100644 index 7ffc703c43..0000000000 --- a/erpnext/patches/v5_0/update_sms_sender.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.set_value("SMS Settings", "SMS Settings", "sms_sender_name", - frappe.db.get_single_value("Global Defaults", "sms_sender_name")) diff --git a/erpnext/patches/v5_0/update_tax_amount_after_discount_in_purchase_cycle.py b/erpnext/patches/v5_0/update_tax_amount_after_discount_in_purchase_cycle.py deleted file mode 100644 index 53df9422b3..0000000000 --- a/erpnext/patches/v5_0/update_tax_amount_after_discount_in_purchase_cycle.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql(""" - update - `tabPurchase Taxes and Charges` - set - tax_amount_after_discount_amount = tax_amount, - base_tax_amount_after_discount_amount = base_tax_amount - where - ifnull(tax_amount_after_discount_amount, 0) = 0 - and ifnull(base_tax_amount_after_discount_amount, 0) = 0 - """) \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_temporary_account.py b/erpnext/patches/v5_0/update_temporary_account.py deleted file mode 100644 index 078c8714ff..0000000000 --- a/erpnext/patches/v5_0/update_temporary_account.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""Update `tabAccount` set account_type = 'Temporary' - where account_name in ('Temporary Assets', 'Temporary Liabilities', 'Temporary Opening')""") \ No newline at end of file diff --git a/erpnext/patches/v5_0/update_time_log_title.py b/erpnext/patches/v5_0/update_time_log_title.py deleted file mode 100644 index 8263be0007..0000000000 --- a/erpnext/patches/v5_0/update_time_log_title.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Time Log") - for d in frappe.get_all("Time Log"): - time_log = frappe.get_doc("Time Log", d.name) - time_log.set_title() - frappe.db.set_value("Time Log", time_log.name, "title", time_log.title) diff --git a/erpnext/patches/v5_1/__init__.py b/erpnext/patches/v5_1/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v5_1/default_bom.py b/erpnext/patches/v5_1/default_bom.py deleted file mode 100644 index 6484edd603..0000000000 --- a/erpnext/patches/v5_1/default_bom.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -def execute(): - frappe.db.sql("""Update `tabItem` as item set default_bom = NULL where - not exists(select name from `tabBOM` as bom where item.default_bom = bom.name and bom.docstatus =1 )""") \ No newline at end of file diff --git a/erpnext/patches/v5_1/fix_against_account.py b/erpnext/patches/v5_1/fix_against_account.py deleted file mode 100644 index a62c15b7d1..0000000000 --- a/erpnext/patches/v5_1/fix_against_account.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -from erpnext.accounts.doctype.gl_entry.gl_entry import update_against_account - -def execute(): - from_date = "2015-05-01" - - for doc in frappe.get_all("Journal Entry", - filters={"creation": (">", from_date), "docstatus": "1"}): - - # update in gl_entry - update_against_account("Journal Entry", doc.name) - - # update in jv - doc = frappe.get_doc("Journal Entry", doc.name) - doc.set_against_account() - doc.db_update() - - for doc in frappe.get_all("Sales Invoice", - filters={"creation": (">", from_date), "docstatus": "1"}, - fields=["name", "customer"]): - - frappe.db.sql("""update `tabGL Entry` set against=%s - where voucher_type='Sales Invoice' and voucher_no=%s - and credit > 0 and ifnull(party, '')=''""", - (doc.customer, doc.name)) - - for doc in frappe.get_all("Purchase Invoice", - filters={"creation": (">", from_date), "docstatus": "1"}, - fields=["name", "supplier"]): - - frappe.db.sql("""update `tabGL Entry` set against=%s - where voucher_type='Purchase Invoice' and voucher_no=%s - and debit > 0 and ifnull(party, '')=''""", - (doc.supplier, doc.name)) diff --git a/erpnext/patches/v5_1/rename_roles.py b/erpnext/patches/v5_1/rename_roles.py deleted file mode 100644 index e19c22a614..0000000000 --- a/erpnext/patches/v5_1/rename_roles.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if not frappe.db.exists("Role", "Stock User"): - frappe.rename_doc("Role", "Material User", "Stock User") - if not frappe.db.exists("Role", "Stock Manager"): - frappe.rename_doc("Role", "Material Manager", "Stock Manager") - if not frappe.db.exists("Role", "Item Manager"): - frappe.rename_doc("Role", "Material Master Manager", "Item Manager") diff --git a/erpnext/patches/v5_1/sales_bom_rename.py b/erpnext/patches/v5_1/sales_bom_rename.py deleted file mode 100644 index e06012f3e4..0000000000 --- a/erpnext/patches/v5_1/sales_bom_rename.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - tables = frappe.db.sql_list("show tables") - for old_dt, new_dt in [["Sales BOM Item", "Product Bundle Item"], - ["Sales BOM", "Product Bundle"]]: - if "tab"+new_dt not in tables: - frappe.rename_doc("DocType", old_dt, new_dt, force=True) diff --git a/erpnext/patches/v5_2/__init__.py b/erpnext/patches/v5_2/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v5_2/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v5_2/change_item_selects_to_checks.py b/erpnext/patches/v5_2/change_item_selects_to_checks.py deleted file mode 100644 index 1ee8f6caa5..0000000000 --- a/erpnext/patches/v5_2/change_item_selects_to_checks.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -def execute(): - fields = ("is_stock_item", "is_asset_item", "has_batch_no", "has_serial_no", - "is_sales_item", "is_purchase_item", "inspection_required", "is_sub_contracted_item") - - # convert to 1 or 0 - update_str = ", ".join(["`{0}`=if(`{0}`='Yes',1,0)".format(f) for f in fields]) - frappe.db.sql("update tabItem set {0}".format(update_str)) - - frappe.db.commit() - - # alter fields to int - for f in fields: - frappe.db.sql("alter table tabItem change {0} {0} int(1) default '0'".format(f, f)) - - frappe.reload_doctype("Item") diff --git a/erpnext/patches/v5_4/__init__.py b/erpnext/patches/v5_4/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v5_4/cleanup_journal_entry.py b/erpnext/patches/v5_4/cleanup_journal_entry.py deleted file mode 100644 index 6860e6ad09..0000000000 --- a/erpnext/patches/v5_4/cleanup_journal_entry.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -import frappe -from pymysql import InternalError - -def execute(): - frappe.reload_doctype("Journal Entry Account") - for doctype, fieldname in ( - ("Sales Order", "against_sales_order"), - ("Purchase Order", "against_purchase_order"), - ("Sales Invoice", "against_invoice"), - ("Purchase Invoice", "against_voucher"), - ("Journal Entry", "against_jv"), - ("Expense Claim", "against_expense_claim"), - ): - try: - frappe.db.sql("""update `tabJournal Entry Account` - set reference_type=%s, reference_name={0} where ifnull({0}, '') != '' - """.format(fieldname), doctype) - except InternalError: - # column not found - pass diff --git a/erpnext/patches/v5_4/fix_invoice_outstanding.py b/erpnext/patches/v5_4/fix_invoice_outstanding.py deleted file mode 100644 index 54a1da69ef..0000000000 --- a/erpnext/patches/v5_4/fix_invoice_outstanding.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt - -def execute(): - frappe.reload_doctype("Sales Invoice") - return_entries = frappe.get_list("Sales Invoice", filters={"is_return": 1, "docstatus": 1}, - fields=["debit_to", "customer", "return_against"]) - for d in return_entries: - update_outstanding_amt(d.debit_to, "Customer", d.customer, "Sales Invoice", d.return_against) diff --git a/erpnext/patches/v5_4/fix_missing_item_images.py b/erpnext/patches/v5_4/fix_missing_item_images.py deleted file mode 100644 index c6fe57896f..0000000000 --- a/erpnext/patches/v5_4/fix_missing_item_images.py +++ /dev/null @@ -1,126 +0,0 @@ -from __future__ import print_function, unicode_literals -import frappe -import os -from frappe.utils import get_files_path -from frappe.core.doctype.file.file import get_content_hash - -def execute(): - files_path = get_files_path() - - # get files that don't have attached_to_name but exist - unlinked_files = get_unlinked_files(files_path) - if not unlinked_files: - return - - fixed_files = fix_files_for_item(files_path, unlinked_files) - - # fix remaining files - for key, file_data in unlinked_files.items(): - if key not in fixed_files: - rename_and_set_content_hash(files_path, unlinked_files, key) - frappe.db.commit() - -def fix_files_for_item(files_path, unlinked_files): - fixed_files = [] - - # make a list of files/something and /files/something to check in child table's image column - file_urls = [key for key in unlinked_files.keys()] + ["/" + key for key in unlinked_files.keys()] - file_item_code = get_file_item_code(file_urls) - - for (file_url, item_code), children in file_item_code.items(): - new_file_url = "/files/{0}".format(unlinked_files[file_url]["file_name"]) - - for row in children: - # print file_url, new_file_url, item_code, row.doctype, row.name - - # replace image in these rows with the new file url - frappe.db.set_value(row.doctype, row.name, "image", new_file_url, update_modified=False) - - # set it as attachment of this item code - file_data = frappe.get_doc("File", unlinked_files[file_url]["file"]) - file_data.attached_to_doctype = "Item" - file_data.attached_to_name = item_code - file_data.flags.ignore_folder_validate = True - - try: - file_data.save() - except IOError: - print("File {0} does not exist".format(new_file_url)) - - # marking fix to prevent further errors - fixed_files.append(file_url) - - continue - - # set it as image in Item - if not frappe.db.get_value("Item", item_code, "image"): - frappe.db.set_value("Item", item_code, "image", new_file_url, update_modified=False) - - rename_and_set_content_hash(files_path, unlinked_files, file_url) - - fixed_files.append(file_url) - - # commit - frappe.db.commit() - - return fixed_files - -def rename_and_set_content_hash(files_path, unlinked_files, file_url): - # rename this file - old_filename = os.path.join(files_path, unlinked_files[file_url]["file"]) - new_filename = os.path.join(files_path, unlinked_files[file_url]["file_name"]) - - if not os.path.exists(new_filename): - os.rename(old_filename, new_filename) - - # set content hash if missing - file_data_name = unlinked_files[file_url]["file"] - if not frappe.db.get_value("File", file_data_name, "content_hash"): - with open(new_filename, "r") as f: - content_hash = get_content_hash(f.read()) - frappe.db.set_value("File", file_data_name, "content_hash", content_hash) - -def get_unlinked_files(files_path): - # find files that have the same name as a File doc - # and the file_name mentioned in that File doc doesn't exist - # and it isn't already attached to a doc - unlinked_files = {} - files = os.listdir(files_path) - for file in files: - if not frappe.db.exists("File", {"file_name": file}): - file_data = frappe.db.get_value("File", {"name": file}, - ["file_name", "attached_to_doctype", "attached_to_name"], as_dict=True) - - if (file_data - and file_data.file_name - and file_data.file_name not in files - and not file_data.attached_to_doctype - and not file_data.attached_to_name): - - file_data["file"] = file - unlinked_files["files/{0}".format(file)] = file_data - - return unlinked_files - -def get_file_item_code(file_urls): - # get a map of file_url, item_code and list of documents where file_url will need to be changed in image field - file_item_code = {} - - doctypes = frappe.db.sql_list("""select name from `tabDocType` dt - where istable=1 - and exists (select name from `tabDocField` df where df.parent=dt.name and df.fieldname='item_code') - and exists (select name from `tabDocField` df where df.parent=dt.name and df.fieldname='image')""") - - for doctype in doctypes: - result = frappe.db.sql("""select name, image, item_code, '{0}' as doctype from `tab{0}` - where image in ({1})""".format(doctype, ", ".join(["%s"]*len(file_urls))), - file_urls, as_dict=True) - - for r in result: - key = (r.image, r.item_code) - if key not in file_item_code: - file_item_code[key] = [] - - file_item_code[key].append(r) - - return file_item_code diff --git a/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py b/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py deleted file mode 100644 index 6eb3994c7c..0000000000 --- a/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import repost_actual_qty - -def execute(): - cancelled_invoices = frappe.db.sql_list("""select name from `tabSales Invoice` - where docstatus = 2 and ifnull(update_stock, 0) = 1""") - - if cancelled_invoices: - repost_for = frappe.db.sql("""select distinct item_code, warehouse from `tabStock Ledger Entry` - where voucher_type = 'Sales Invoice' and voucher_no in (%s)""" - % (', '.join(['%s']*len(cancelled_invoices))), tuple(cancelled_invoices)) - - frappe.db.sql("""delete from `tabStock Ledger Entry` - where voucher_type = 'Sales Invoice' and voucher_no in (%s)""" - % (', '.join(['%s']*len(cancelled_invoices))), tuple(cancelled_invoices)) - - for item_code, warehouse in repost_for: - repost_actual_qty(item_code, warehouse) \ No newline at end of file diff --git a/erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py b/erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py deleted file mode 100644 index ba311225bb..0000000000 --- a/erpnext/patches/v5_4/notify_system_managers_regarding_wrong_tax_calculation.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe -from frappe.email import sendmail_to_system_managers -from frappe.utils import get_link_to_form - -def execute(): - wrong_records = [] - for dt in ("Quotation", "Sales Order", "Delivery Note", "Sales Invoice", - "Purchase Order", "Purchase Receipt", "Purchase Invoice"): - records = frappe.db.sql_list("""select name from `tab{0}` - where apply_discount_on = 'Net Total' and ifnull(discount_amount, 0) != 0 - and modified >= '2015-02-17' and docstatus=1""".format(dt)) - - if records: - records = [get_link_to_form(dt, d) for d in records] - wrong_records.append([dt, records]) - - if wrong_records: - content = """Dear System Manager, - -Due to an error related to Discount Amount on Net Total, tax calculation might be wrong in the following records. We did not fix the tax amount automatically because it can corrupt the entries, so we request you to check these records and amend if you found the calculation wrong. - -Please check following Entries: - -%s - - -Regards, - -Administrator""" % "\n".join([(d[0] + ": " + ", ".join(d[1])) for d in wrong_records]) - try: - sendmail_to_system_managers("[Important] [ERPNext] Tax calculation might be wrong, please check.", content) - except: - pass - - print("="*50) - print(content) - print("="*50) \ No newline at end of file diff --git a/erpnext/patches/v5_4/set_root_and_report_type.py b/erpnext/patches/v5_4/set_root_and_report_type.py deleted file mode 100644 index 9147644da2..0000000000 --- a/erpnext/patches/v5_4/set_root_and_report_type.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - roots = frappe.db.sql("""select lft, rgt, report_type, root_type - from `tabAccount` where ifnull(parent_account, '')=''""", as_dict=1) - for d in roots: - frappe.db.sql("update `tabAccount` set report_type=%s, root_type=%s where lft > %s and rgt < %s", - (d.report_type, d.root_type, d.lft, d.rgt)) \ No newline at end of file diff --git a/erpnext/patches/v5_4/stock_entry_additional_costs.py b/erpnext/patches/v5_4/stock_entry_additional_costs.py deleted file mode 100644 index 3a98deb918..0000000000 --- a/erpnext/patches/v5_4/stock_entry_additional_costs.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2015, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import flt - -def execute(): - frappe.reload_doctype("Stock Entry") - frappe.reload_doctype("Stock Entry Detail") - frappe.reload_doctype("Landed Cost Taxes and Charges") - - stock_entry_db_columns = frappe.db.get_table_columns("Stock Entry") - if "additional_operating_cost" in stock_entry_db_columns: - operating_cost_fieldname = "additional_operating_cost" - elif "total_fixed_cost" in stock_entry_db_columns: - operating_cost_fieldname = "total_fixed_cost" - else: - return - - - frappe.db.sql("""update `tabStock Entry Detail` sed, `tabStock Entry` se - set sed.valuation_rate=sed.incoming_rate, sed.basic_rate=sed.incoming_rate, sed.basic_amount=sed.amount - where sed.parent = se.name - and (se.purpose not in ('Manufacture', 'Repack') or ifnull({0}, 0)=0) - """.format(operating_cost_fieldname)) - - - stock_entries = frappe.db.sql_list("""select name from `tabStock Entry` - where purpose in ('Manufacture', 'Repack') and ifnull({0}, 0)!=0 - and docstatus < 2""".format(operating_cost_fieldname)) - - for d in stock_entries: - stock_entry = frappe.get_doc("Stock Entry", d) - stock_entry.append("additional_costs", { - "description": "Additional Operating Cost", - "amount": stock_entry.get(operating_cost_fieldname) - }) - - number_of_fg_items = len([t.t_warehouse for t in stock_entry.get("items") if t.t_warehouse]) - - for d in stock_entry.get("items"): - d.valuation_rate = d.incoming_rate - - if d.bom_no or (d.t_warehouse and number_of_fg_items == 1): - d.additional_cost = stock_entry.get(operating_cost_fieldname) - - d.basic_rate = flt(d.valuation_rate) - flt(d.additional_cost) - d.basic_amount = flt(flt(d.basic_rate) *flt(d.transfer_qty), d.precision("basic_amount")) - - stock_entry.flags.ignore_validate = True - stock_entry.flags.ignore_validate_update_after_submit = True - stock_entry.save() diff --git a/erpnext/patches/v5_4/update_purchase_cost_against_project.py b/erpnext/patches/v5_4/update_purchase_cost_against_project.py deleted file mode 100644 index 1b917c83c4..0000000000 --- a/erpnext/patches/v5_4/update_purchase_cost_against_project.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2015, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for p in frappe.get_all("Project"): - purchase_cost = frappe.db.sql("""select sum(ifnull(base_net_amount, 0)) - from `tabPurchase Invoice Item` where project = %s and docstatus=1""", p.name) - purchase_cost = purchase_cost and purchase_cost[0][0] or 0 - - frappe.db.set_value("Project", p.name, "total_purchase_cost", purchase_cost) \ No newline at end of file diff --git a/erpnext/patches/v5_7/__init__.py b/erpnext/patches/v5_7/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v5_7/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v5_7/item_template_attributes.py b/erpnext/patches/v5_7/item_template_attributes.py deleted file mode 100644 index 6aa81f79b2..0000000000 --- a/erpnext/patches/v5_7/item_template_attributes.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe -from frappe.exceptions import SQLError - -def execute(): - """ - Structure History: - 1. Item and Item Variant - 2. Item, Variant Attribute, Manage Variants and Manage Variant Items - 3. Item, Item Variant Attribute, Item Attribute and Item Attribute Type (latest) - """ - rename_and_reload_doctypes() - - variant_templates = frappe.get_all("Item", filters={"has_variants": 1}, limit_page_length=1) - if not variant_templates: - # database does not have items that have variants - # so no point in running the patch - return - - variant_attributes = frappe.get_all("Item Variant Attribute", fields=["*"], limit_page_length=1) - - if variant_attributes: - # manage variant patch is already applied - migrate_manage_variants() - - else: - # old structure based on "Item Variant" table - try: - migrate_item_variants() - - except SQLError: - print("`tabItem Variant` not found") - -def rename_and_reload_doctypes(): - if "tabVariant Attribute" in frappe.db.get_tables(): - frappe.rename_doc("DocType", "Variant Attribute", "Item Variant Attribute") - - frappe.reload_doctype("Item") - frappe.reload_doc("Stock", "DocType", "Item Variant Attribute") - frappe.reload_doc("Stock", "DocType", "Item Attribute Value") - frappe.reload_doc("Stock", "DocType", "Item Attribute") - -def migrate_manage_variants(): - item_attribute = {} - for d in frappe.db.sql("""select DISTINCT va.attribute, i.variant_of - from `tabItem Variant Attribute` va, `tabItem` i - where va.parent = i.name and ifnull(i.variant_of, '')!=''""", as_dict=1): - item_attribute.setdefault(d.variant_of, []).append({"attribute": d.attribute}) - - for item, attributes in item_attribute.items(): - template = frappe.get_doc("Item", item) - template.set('attributes', attributes) - template.save() - -# patch old style -def migrate_item_variants(): - for item in frappe.get_all("Item", filters={"has_variants": 1}): - all_variants = frappe.get_all("Item", filters={"variant_of": item.name}, fields=["name", "description"]) - item_attributes = frappe.db.sql("""select distinct item_attribute, item_attribute_value - from `tabItem Variant` where parent=%s""", item.name) - - if not item_attributes and not all_variants: - item = frappe.get_doc("Item", item.name) - item.has_variants = 0 - item.save() - continue - - attribute_value_options = {} - for attribute, value in item_attributes: - attribute_value_options.setdefault(attribute, []).append(value) - - possible_combinations = get_possible_combinations(attribute_value_options) - - for variant in all_variants: - for combination in possible_combinations: - match = True - for attribute, value in combination.items(): - if "{0}: {1}".format(attribute, value) not in variant.description: - match = False - break - - if match: - # found the right variant - save_attributes_in_variant(variant, combination) - break - - save_attributes_in_template(item, attribute_value_options) - - frappe.delete_doc("DocType", "Item Variant") - -def save_attributes_in_template(item, attribute_value_options): - # store attribute in Item Variant Attribute table for template - template = frappe.get_doc("Item", item) - template.set("attributes", [{"attribute": attribute} for attribute in attribute_value_options.keys()]) - template.save() - -def get_possible_combinations(attribute_value_options): - possible_combinations = [] - - for attribute, values in attribute_value_options.items(): - if not possible_combinations: - for v in values: - possible_combinations.append({attribute: v}) - - else: - for v in values: - for combination in possible_combinations: - combination[attribute] = v - - return possible_combinations - -def save_attributes_in_variant(variant, combination): - # add data into attributes table - variant_item = frappe.get_doc("Item", variant.name) - variant_item.set("attributes", []) - for attribute, value in combination.items(): - variant_item.append("attributes", { - "attribute": attribute, - "attribute_value": value - }) - variant_item.save() diff --git a/erpnext/patches/v5_8/__init__.py b/erpnext/patches/v5_8/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v5_8/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v5_8/add_credit_note_print_heading.py b/erpnext/patches/v5_8/add_credit_note_print_heading.py deleted file mode 100644 index 476cbc8956..0000000000 --- a/erpnext/patches/v5_8/add_credit_note_print_heading.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe import _ - -def execute(): - for print_heading in (_("Credit Note"), _("Debit Note")): - if not frappe.db.exists("Print Heading", print_heading): - frappe.get_doc({ - "doctype": "Print Heading", - "print_heading": print_heading - }).insert() diff --git a/erpnext/patches/v5_8/tax_rule.py b/erpnext/patches/v5_8/tax_rule.py deleted file mode 100644 index 8da28ba4c9..0000000000 --- a/erpnext/patches/v5_8/tax_rule.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "tax_rule") - - customers = frappe.db.sql("""select name, default_taxes_and_charges from tabCustomer where - ifnull(default_taxes_and_charges, '') != '' """, as_dict=1) - - for d in customers: - if not frappe.db.sql("select name from `tabTax Rule` where customer=%s", d.name): - tr = frappe.new_doc("Tax Rule") - tr.tax_type = "Sales" - tr.customer = d.name - tr.sales_tax_template = d.default_taxes_and_charges - tr.save() - - - suppliers = frappe.db.sql("""select name, default_taxes_and_charges from tabSupplier where - ifnull(default_taxes_and_charges, '') != '' """, as_dict=1) - - for d in suppliers: - if not frappe.db.sql("select name from `tabTax Rule` where supplier=%s", d.name): - tr = frappe.new_doc("Tax Rule") - tr.tax_type = "Purchase" - tr.supplier = d.name - tr.purchase_tax_template = d.default_taxes_and_charges - tr.save() \ No newline at end of file diff --git a/erpnext/patches/v5_8/update_order_reference_in_return_entries.py b/erpnext/patches/v5_8/update_order_reference_in_return_entries.py deleted file mode 100644 index 503263834c..0000000000 --- a/erpnext/patches/v5_8/update_order_reference_in_return_entries.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Delivery Note") - frappe.reload_doctype("Sales Invoice") - frappe.reload_doctype("Purchase Receipt") - frappe.reload_doctype("Sales Order Item") - frappe.reload_doctype("Purchase Order Item") - frappe.reload_doctype("Purchase Order Item Supplied") - - # sales return - return_entries = list(frappe.db.sql(""" - select dn.name as name, dn_item.name as row_id, dn.return_against, - dn_item.item_code, "Delivery Note" as doctype - from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn - where dn_item.parent=dn.name and dn.is_return=1 and dn.docstatus < 2 - """, as_dict=1)) - - return_entries += list(frappe.db.sql(""" - select si.name as name, si_item.name as row_id, si.return_against, - si_item.item_code, "Sales Invoice" as doctype, update_stock - from `tabSales Invoice Item` si_item, `tabSales Invoice` si - where si_item.parent=si.name and si.is_return=1 and si.docstatus < 2 - """, as_dict=1)) - - for d in return_entries: - ref_field = "against_sales_order" if d.doctype == "Delivery Note" else "sales_order" - order_details = frappe.db.sql(""" - select {ref_field} as sales_order, so_detail, - (select transaction_date from `tabSales Order` where name=item.{ref_field}) as sales_order_date - from `tab{doctype} Item` item - where - parent=%s - and item_code=%s - and ifnull(so_detail, '') !='' - order by sales_order_date DESC limit 1 - """.format(ref_field=ref_field, doctype=d.doctype), (d.return_against, d.item_code), as_dict=1) - - if order_details: - frappe.db.sql(""" - update `tab{doctype} Item` - set {ref_field}=%s, so_detail=%s - where name=%s - """.format(doctype=d.doctype, ref_field=ref_field), - (order_details[0].sales_order, order_details[0].so_detail, d.row_id)) - - if (d.doctype=="Sales Invoice" and d.update_stock) or d.doctype=="Delivery Note": - doc = frappe.get_doc(d.doctype, d.name) - doc.update_reserved_qty() - - if d.doctype=="Sales Invoice": - doc.status_updater = [] - doc.update_status_updater_args() - - doc.update_prevdoc_status() - - #-------------------------- - # purchase return - return_entries = frappe.db.sql(""" - select pr.name as name, pr_item.name as row_id, pr.return_against, pr_item.item_code - from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr - where pr_item.parent=pr.name and pr.is_return=1 and pr.docstatus < 2 - """, as_dict=1) - - for d in return_entries: - order_details = frappe.db.sql(""" - select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail, - (select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) as purchase_order_date - from `tabPurchase Receipt Item` item - where - parent=%s - and item_code=%s - and ifnull(prevdoc_detail_docname, '') !='' - and ifnull(prevdoc_doctype, '') = 'Purchase Order' and ifnull(prevdoc_detail_docname, '') != '' - order by purchase_order_date DESC limit 1 - """, (d.return_against, d.item_code), as_dict=1) - - if order_details: - frappe.db.sql(""" - update `tabPurchase Receipt Item` - set prevdoc_doctype='Purchase Order', prevdoc_docname=%s, prevdoc_detail_docname=%s - where name=%s - """, (order_details[0].purchase_order, order_details[0].po_detail, d.row_id)) - - pr = frappe.get_doc("Purchase Receipt", d.name) - pr.update_ordered_and_reserved_qty() - pr.update_prevdoc_status() - diff --git a/erpnext/patches/v6_0/__init__.py b/erpnext/patches/v6_0/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_0/default_activity_rate.py b/erpnext/patches/v6_0/default_activity_rate.py deleted file mode 100644 index cfbfb723bc..0000000000 --- a/erpnext/patches/v6_0/default_activity_rate.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("projects", "doctype", "activity_cost") - - for cost in frappe.db.get_list("Activity Cost", filters = {"employee": ""}, - fields = ("name", "activity_type", "costing_rate", "billing_rate")): - activity_type = frappe.get_doc("Activity Type", cost.activity_type) - activity_type.costing_rate = cost.costing_rate - activity_type.billing_rate = cost.billing_rate - activity_type.save() - - frappe.delete_doc("Activity Cost", cost.name) diff --git a/erpnext/patches/v6_0/fix_outstanding_amount.py b/erpnext/patches/v6_0/fix_outstanding_amount.py deleted file mode 100644 index 0de689074f..0000000000 --- a/erpnext/patches/v6_0/fix_outstanding_amount.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt - -def execute(): - for dt, party_field, account_field in (("Sales Invoice", "customer", "debit_to"), - ("Purchase Invoice", "supplier", "credit_to")): - - wrong_invoices = frappe.db.sql("""select name, {0} as account from `tab{1}` - where docstatus=1 and ifnull({2}, '')=''""".format(account_field, dt, party_field)) - - for invoice, account in wrong_invoices: - update_outstanding_amt(account, party_field.title(), None, dt, invoice) \ No newline at end of file diff --git a/erpnext/patches/v6_0/fix_planned_qty.py b/erpnext/patches/v6_0/fix_planned_qty.py deleted file mode 100644 index cf7b429249..0000000000 --- a/erpnext/patches/v6_0/fix_planned_qty.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty - -def execute(): - for item_code, warehouse in frappe.db.sql("""select distinct production_item, fg_warehouse - from `tabWork Order`"""): - if frappe.db.exists("Item", item_code) and frappe.db.exists("Warehouse", warehouse): - update_bin_qty(item_code, warehouse, { - "planned_qty": get_planned_qty(item_code, warehouse) - }) diff --git a/erpnext/patches/v6_0/multi_currency.py b/erpnext/patches/v6_0/multi_currency.py deleted file mode 100644 index b4c37fc253..0000000000 --- a/erpnext/patches/v6_0/multi_currency.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # Reload doctype - for dt in ("Account", "GL Entry", "Journal Entry", - "Journal Entry Account", "Sales Invoice", "Purchase Invoice", "Customer", "Supplier"): - frappe.reload_doctype(dt) - - company_list = frappe.get_all("Company", fields=["name", "default_currency", "default_receivable_account"]) - for company in company_list: - - # update currency in account and gl entry as per company currency - frappe.db.sql("""update `tabAccount` set account_currency = %s - where ifnull(account_currency, '') = '' and company=%s""", (company.default_currency, company.name)) - - # update newly introduced field's value in sales / purchase invoice - frappe.db.sql(""" - update - `tabSales Invoice` - set - base_paid_amount=paid_amount, - base_write_off_amount=write_off_amount, - party_account_currency=%s - where company=%s - """, (company.default_currency, company.name)) - - frappe.db.sql(""" - update - `tabPurchase Invoice` - set - base_write_off_amount=write_off_amount, - party_account_currency=%s - where company=%s - """, (company.default_currency, company.name)) - - # update exchange rate, debit/credit in account currency in Journal Entry - frappe.db.sql(""" - update `tabJournal Entry Account` jea - set exchange_rate=1, - debit_in_account_currency=debit, - credit_in_account_currency=credit, - account_type=(select account_type from `tabAccount` where name=jea.account) - """) - - frappe.db.sql(""" - update `tabJournal Entry Account` jea, `tabJournal Entry` je - set account_currency=%s - where jea.parent = je.name and je.company=%s - """, (company.default_currency, company.name)) - - # update debit/credit in account currency in GL Entry - frappe.db.sql(""" - update - `tabGL Entry` - set - debit_in_account_currency=debit, - credit_in_account_currency=credit, - account_currency=%s - where - company=%s - """, (company.default_currency, company.name)) diff --git a/erpnext/patches/v6_0/set_default_title.py b/erpnext/patches/v6_0/set_default_title.py deleted file mode 100644 index cceff3f480..0000000000 --- a/erpnext/patches/v6_0/set_default_title.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Quotation") - frappe.db.sql("""update tabQuotation set title = customer_name""") - - frappe.reload_doctype("Sales Order") - frappe.db.sql("""update `tabSales Order` set title = customer_name""") - - frappe.reload_doctype("Delivery Note") - frappe.db.sql("""update `tabDelivery Note` set title = customer_name""") - - frappe.reload_doctype("Material Request") - frappe.db.sql("""update `tabMaterial Request` set title = material_request_type""") - - frappe.reload_doctype("Supplier Quotation") - frappe.db.sql("""update `tabSupplier Quotation` set title = supplier_name""") - - frappe.reload_doctype("Purchase Order") - frappe.db.sql("""update `tabPurchase Order` set title = supplier_name""") - - frappe.reload_doctype("Purchase Receipt") - frappe.db.sql("""update `tabPurchase Receipt` set title = supplier_name""") - - frappe.reload_doctype("Purchase Invoice") - frappe.db.sql("""update `tabPurchase Invoice` set title = supplier_name""") - - frappe.reload_doctype("Stock Entry") - frappe.db.sql("""update `tabStock Entry` set title = purpose""") - - frappe.reload_doctype("Sales Invoice") - frappe.db.sql("""update `tabSales Invoice` set title = customer_name""") - - frappe.reload_doctype("Expense Claim") - frappe.db.sql("""update `tabExpense Claim` set title = employee_name""") diff --git a/erpnext/patches/v6_10/__init__.py b/erpnext/patches/v6_10/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_10/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_10/email_digest_default_quote.py b/erpnext/patches/v6_10/email_digest_default_quote.py deleted file mode 100644 index 6139f1a88a..0000000000 --- a/erpnext/patches/v6_10/email_digest_default_quote.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Email Digest") - frappe.db.sql("update `tabEmail Digest` set add_quote = 1") diff --git a/erpnext/patches/v6_10/fix_billed_amount_in_drop_ship_po.py b/erpnext/patches/v6_10/fix_billed_amount_in_drop_ship_po.py deleted file mode 100644 index d7f72b5880..0000000000 --- a/erpnext/patches/v6_10/fix_billed_amount_in_drop_ship_po.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""update `tabPurchase Order Item` set billed_amt = 0 - where delivered_by_supplier=1 and docstatus=1""") - - drop_ship_pos = frappe.db.sql("""select distinct parent from `tabPurchase Order Item` - where delivered_by_supplier=1 and docstatus=1""") - - for po in drop_ship_pos: - invoices = frappe.db.sql("""select distinct parent from `tabPurchase Invoice Item` - where purchase_order=%s and docstatus=1""", po[0]) - if invoices: - for inv in invoices: - frappe.get_doc("Purchase Invoice", inv[0]).update_qty(update_modified=False) - else: - frappe.db.sql("""update `tabPurchase Order` set per_billed=0 where name=%s""", po[0]) \ No newline at end of file diff --git a/erpnext/patches/v6_10/fix_delivery_status_of_drop_ship_item.py b/erpnext/patches/v6_10/fix_delivery_status_of_drop_ship_item.py deleted file mode 100644 index 9a53b7f5d3..0000000000 --- a/erpnext/patches/v6_10/fix_delivery_status_of_drop_ship_item.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Sales Order Item") - for so_name in frappe.db.sql("""select distinct parent from `tabSales Order Item` - where delivered_by_supplier=1 and docstatus=1"""): - so = frappe.get_doc("Sales Order", so_name[0]) - so.update_delivery_status() - so.set_status(update=True, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v6_10/fix_jv_total_amount.py b/erpnext/patches/v6_10/fix_jv_total_amount.py deleted file mode 100644 index 42cb9e9e15..0000000000 --- a/erpnext/patches/v6_10/fix_jv_total_amount.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -# patch all for-print field (total amount) in Journal Entry in 2015 -def execute(): - for je in frappe.get_all("Journal Entry", filters={"creation": (">", "2015-01-01")}): - je = frappe.get_doc("Journal Entry", je.name) - original = je.total_amount - - je.set_print_format_fields() - - if je.total_amount != original: - je.db_set("total_amount", je.total_amount, update_modified=False) - je.db_set("total_amount_in_words", je.total_amount_in_words, update_modified=False) diff --git a/erpnext/patches/v6_10/fix_ordered_received_billed.py b/erpnext/patches/v6_10/fix_ordered_received_billed.py deleted file mode 100644 index c81a20ec54..0000000000 --- a/erpnext/patches/v6_10/fix_ordered_received_billed.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - not_null_patch_date = frappe.db.sql("""select date(creation) from `tabPatch Log` where patch='frappe.patches.v6_9.int_float_not_null'""") - if not not_null_patch_date: - return - - not_null_patch_date = not_null_patch_date[0][0] - - for doctype in ("Purchase Invoice", "Sales Invoice", "Purchase Order", "Delivery Note", "Installation Note", "Delivery Note", "Purchase Receipt"): - for name in frappe.db.sql_list("""select name from `tab{doctype}` - where docstatus > 0 and (date(creation) >= %(patch_date)s or date(modified) >= %(patch_date)s)""".format(doctype=doctype), - {"patch_date": not_null_patch_date}): - - doc = frappe.get_doc(doctype, name) - doc.update_qty(update_modified=False) diff --git a/erpnext/patches/v6_12/__init__.py b/erpnext/patches/v6_12/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_12/repost_entries_with_target_warehouse.py b/erpnext/patches/v6_12/repost_entries_with_target_warehouse.py deleted file mode 100644 index fb5eab4e05..0000000000 --- a/erpnext/patches/v6_12/repost_entries_with_target_warehouse.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -""" -This patch is written to fix Stock Ledger Entries and GL Entries -against Delivery Notes and Sales Invoice where Target Warehouse has been set wrongly -due to User Permissions on Warehouse. - -This cannot be run automatically because we can't take a call that -Target Warehouse has been set purposefully or by mistake. -Thats why we left it to the users to take the call, and manually run the patch. - -This patch has 2 main functions, `check()` and `repost()`. -- Run `check` function, to list out all the Sales Orders, Delivery Notes - and Sales Invoice with Target Warehouse. -- Run `repost` function to remove the Target Warehouse value and repost SLE and GLE again. - -To execute this patch run following commands from frappe-bench directory: -``` - bench --site [your-site-name] execute erpnext.patches.v6_12.repost_entries_with_target_warehouse.check - bench --site [your-site-name] backup - bench --site [your-site-name] execute erpnext.patches.v6_12.repost_entries_with_target_warehouse.repost -``` - -Exception Handling: -While reposting, if you get any exception, it will printed on screen. -Mostly it can be due to negative stock issue. If that is the case, follow these steps - - Ensure that stock is available for those items in the mentioned warehouse on the date mentioned in the error - - Execute `repost` funciton again -""" - -def check(): - so_list = get_affected_sales_order() - dn_list = get_affected_delivery_notes() - si_list = get_affected_sales_invoice() - - if so_list or dn_list or si_list: - print("Entries with Target Warehouse:") - - if so_list: - print("Sales Order") - print(so_list) - - if dn_list: - print("Delivery Notes") - print([d.name for d in dn_list]) - - if si_list: - print("Sales Invoice") - print([d.name for d in si_list]) - - -def repost(): - dn_failed_list, si_failed_list = [], [] - repost_dn(dn_failed_list) - repost_si(si_failed_list) - repost_so() - frappe.db.commit() - - if dn_failed_list: - print("-"*40) - print("Delivery Note Failed to Repost") - print(dn_failed_list) - - if si_failed_list: - print("-"*40) - print("Sales Invoice Failed to Repost") - print(si_failed_list) - print() - - print(""" -If above Delivery Notes / Sales Invoice failed due to negative stock, follow these steps: - - Ensure that stock is available for those items in the mentioned warehouse on the date mentioned in the error - - Run this patch again -""") - -def repost_dn(dn_failed_list): - dn_list = get_affected_delivery_notes() - - if dn_list: - print("-"*40) - print("Reposting Delivery Notes") - - for dn in dn_list: - if dn.docstatus == 0: - continue - - print(dn.name) - - try: - dn_doc = frappe.get_doc("Delivery Note", dn.name) - dn_doc.docstatus = 2 - dn_doc.update_prevdoc_status() - dn_doc.update_stock_ledger() - dn_doc.cancel_packing_slips() - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type='Delivery Note' and voucher_no=%s""", dn.name) - - frappe.db.sql("update `tabDelivery Note Item` set target_warehouse='' where parent=%s", dn.name) - dn_doc = frappe.get_doc("Delivery Note", dn.name) - dn_doc.docstatus = 1 - dn_doc.on_submit() - frappe.db.commit() - except Exception: - dn_failed_list.append(dn.name) - frappe.local.stockledger_exceptions = None - print(frappe.get_traceback()) - frappe.db.rollback() - - frappe.db.sql("update `tabDelivery Note Item` set target_warehouse='' where docstatus=0") - -def repost_si(si_failed_list): - si_list = get_affected_sales_invoice() - - if si_list: - print("-"*40) - print("Reposting Sales Invoice") - - for si in si_list: - if si.docstatus == 0: - continue - - print(si.name) - - try: - si_doc = frappe.get_doc("Sales Invoice", si.name) - si_doc.docstatus = 2 - si_doc.update_stock_ledger() - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type='Sales Invoice' and voucher_no=%s""", si.name) - - frappe.db.sql("update `tabSales Invoice Item` set target_warehouse='' where parent=%s", si.name) - si_doc = frappe.get_doc("Sales Invoice", si.name) - si_doc.docstatus = 1 - si_doc.update_stock_ledger() - si_doc.make_gl_entries() - frappe.db.commit() - except Exception: - si_failed_list.append(si.name) - frappe.local.stockledger_exceptions = None - print(frappe.get_traceback()) - frappe.db.rollback() - - frappe.db.sql("update `tabSales Invoice Item` set target_warehouse='' where docstatus=0") - -def repost_so(): - so_list = get_affected_sales_order() - - frappe.db.sql("update `tabSales Order Item` set target_warehouse=''") - - if so_list: - print("-"*40) - print("Sales Order reposted") - - -def get_affected_delivery_notes(): - return frappe.db.sql("""select distinct dn.name, dn.docstatus - from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item - where dn.name=dn_item.parent and dn.docstatus < 2 - and dn_item.target_warehouse is not null and dn_item.target_warehouse != '' - order by dn.posting_date asc""", as_dict=1) - -def get_affected_sales_invoice(): - return frappe.db.sql("""select distinct si.name, si.docstatus - from `tabSales Invoice` si, `tabSales Invoice Item` si_item - where si.name=si_item.parent and si.docstatus < 2 and si.update_stock=1 - and si_item.target_warehouse is not null and si_item.target_warehouse != '' - order by si.posting_date asc""", as_dict=1) - -def get_affected_sales_order(): - return frappe.db.sql_list("""select distinct parent from `tabSales Order Item` - where target_warehouse is not null and target_warehouse != '' and docstatus <2""") \ No newline at end of file diff --git a/erpnext/patches/v6_12/set_overdue_tasks.py b/erpnext/patches/v6_12/set_overdue_tasks.py deleted file mode 100644 index 7dbb8ba8b6..0000000000 --- a/erpnext/patches/v6_12/set_overdue_tasks.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Task") - - from erpnext.projects.doctype.task.task import set_tasks_as_overdue - set_tasks_as_overdue() diff --git a/erpnext/patches/v6_16/__init__.py b/erpnext/patches/v6_16/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_16/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_16/create_manufacturer_records.py b/erpnext/patches/v6_16/create_manufacturer_records.py deleted file mode 100644 index 5ae65f0660..0000000000 --- a/erpnext/patches/v6_16/create_manufacturer_records.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cstr - -def execute(): - frappe.reload_doc("stock", "doctype", "manufacturer") - frappe.reload_doctype("Item") - - for d in frappe.db.sql("""select distinct manufacturer from tabItem - where ifnull(manufacturer, '') != '' and disabled=0"""): - manufacturer_name = cstr(d[0]).strip() - if manufacturer_name and not frappe.db.exists("Manufacturer", manufacturer_name): - man = frappe.new_doc("Manufacturer") - man.short_name = manufacturer_name - man.full_name = manufacturer_name - man.save() diff --git a/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py b/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py deleted file mode 100644 index 481f13005b..0000000000 --- a/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt in ("Delivery Note", "Purchase Receipt"): - frappe.reload_doctype(dt) - frappe.reload_doctype(dt + " Item") - - # Update billed_amt in DN and PR which are not against any order - for d in frappe.db.sql("""select name from `tabDelivery Note Item` item - where (so_detail is null or so_detail = '') and docstatus=1""", as_dict=1): - - billed_amt = frappe.db.sql("""select sum(amount) from `tabSales Invoice Item` - where dn_detail=%s and docstatus=1""", d.name) - billed_amt = billed_amt and billed_amt[0][0] or 0 - frappe.db.set_value("Delivery Note Item", d.name, "billed_amt", billed_amt, update_modified=False) - - frappe.db.commit() - - # Update billed_amt in DN and PR which are not against any order - for d in frappe.db.sql("""select name from `tabPurchase Receipt Item` item - where (purchase_order_item is null or purchase_order_item = '') and docstatus=1""", as_dict=1): - - billed_amt = frappe.db.sql("""select sum(amount) from `tabPurchase Invoice Item` - where pr_detail=%s and docstatus=1""", d.name) - billed_amt = billed_amt and billed_amt[0][0] or 0 - frappe.db.set_value("Purchase Receipt Item", d.name, "billed_amt", billed_amt, update_modified=False) - - frappe.db.commit() - - for dt in ("Delivery Note", "Purchase Receipt"): - # Update billed amt which are against order or invoice - # Update billing status for all - for d in frappe.db.sql("select name from `tab{0}` where docstatus=1".format(dt), as_dict=1): - doc = frappe.get_doc(dt, d.name) - doc.update_billing_status(update_modified=False) - doc.set_status(update=True, update_modified=False) - - frappe.db.commit() diff --git a/erpnext/patches/v6_19/__init__.py b/erpnext/patches/v6_19/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_19/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_19/comment_feed_communication.py b/erpnext/patches/v6_19/comment_feed_communication.py deleted file mode 100644 index bc41c2d8ff..0000000000 --- a/erpnext/patches/v6_19/comment_feed_communication.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.patches.v6_19.comment_feed_communication import update_timeline_doc_for - -def execute(): - for doctype in ("Customer", "Supplier", "Employee", "Project"): - update_timeline_doc_for(doctype) diff --git a/erpnext/patches/v6_2/__init__.py b/erpnext/patches/v6_2/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_2/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_2/fix_missing_default_taxes_and_lead.py b/erpnext/patches/v6_2/fix_missing_default_taxes_and_lead.py deleted file mode 100644 index b0cfc3d3bf..0000000000 --- a/erpnext/patches/v6_2/fix_missing_default_taxes_and_lead.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - # remove missing lead - for customer in frappe.db.sql_list("""select name from `tabCustomer` - where ifnull(lead_name, '')!='' and not exists (select name from `tabLead` where name=`tabCustomer`.lead_name)"""): - frappe.db.set_value("Customer", customer, "lead_name", None) - - # remove missing default taxes - for customer in frappe.db.sql_list("""select name from `tabCustomer` - where ifnull(default_taxes_and_charges, '')!='' and not exists ( - select name from `tabSales Taxes and Charges Template` where name=`tabCustomer`.default_taxes_and_charges - )"""): - c = frappe.get_doc("Customer", customer) - c.default_taxes_and_charges = None - c.save() - - for supplier in frappe.db.sql_list("""select name from `tabSupplier` - where ifnull(default_taxes_and_charges, '')!='' and not exists ( - select name from `tabPurchase Taxes and Charges Template` where name=`tabSupplier`.default_taxes_and_charges - )"""): - c = frappe.get_doc("Supplier", supplier) - c.default_taxes_and_charges = None - c.save() diff --git a/erpnext/patches/v6_2/remove_newsletter_duplicates.py b/erpnext/patches/v6_2/remove_newsletter_duplicates.py deleted file mode 100644 index f9d15475d1..0000000000 --- a/erpnext/patches/v6_2/remove_newsletter_duplicates.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - duplicates = frappe.db.sql("""select email_group, email, count(name) - from `tabEmail Group Member` - group by email_group, email - having count(name) > 1""") - - # delete all duplicates except 1 - for email_group, email, count in duplicates: - frappe.db.sql("""delete from `tabEmail Group Member` - where email_group=%s and email=%s limit %s""", (email_group, email, count-1)) diff --git a/erpnext/patches/v6_20/__init__.py b/erpnext/patches/v6_20/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_20/set_party_account_currency_in_orders.py b/erpnext/patches/v6_20/set_party_account_currency_in_orders.py deleted file mode 100644 index ae7ad9592d..0000000000 --- a/erpnext/patches/v6_20/set_party_account_currency_in_orders.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ("Sales Order", "Purchase Order"): - frappe.reload_doctype(doctype) - - for order in frappe.db.sql("""select name, {0} as party from `tab{1}` - where advance_paid > 0 and docstatus=1""" - .format(("customer" if doctype=="Sales Order" else "supplier"), doctype), as_dict=1): - - party_account_currency = frappe.db.get_value("Journal Entry Account", { - "reference_type": doctype, - "reference_name": order.name, - "party": order.party, - "docstatus": 1, - "is_advance": "Yes" - }, "account_currency") - - frappe.db.set_value(doctype, order.name, "party_account_currency", party_account_currency) - \ No newline at end of file diff --git a/erpnext/patches/v6_20x/__init__.py b/erpnext/patches/v6_20x/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_20x/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_20x/remove_customer_supplier_roles.py b/erpnext/patches/v6_20x/remove_customer_supplier_roles.py deleted file mode 100644 index a651576887..0000000000 --- a/erpnext/patches/v6_20x/remove_customer_supplier_roles.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("buying", "doctype", "request_for_quotation_supplier") - frappe.reload_doc("buying", "doctype", "request_for_quotation_item") - frappe.reload_doc("buying", "doctype", "request_for_quotation") - frappe.reload_doc("projects", "doctype", "timesheet") - - for role in ('Customer', 'Supplier'): - frappe.db.sql('''delete from `tabHas Role` - where role=%s and parent in ("Administrator", "Guest")''', role) - - if not frappe.db.sql('select name from `tabHas Role` where role=%s', role): - - # delete DocPerm - for doctype in frappe.db.sql('select parent from tabDocPerm where role=%s', role): - d = frappe.get_doc("DocType", doctype[0]) - d.permissions = [p for p in d.permissions if p.role != role] - d.save() - - # delete Role - frappe.delete_doc_if_exists('Role', role) diff --git a/erpnext/patches/v6_20x/remove_fiscal_year_from_holiday_list.py b/erpnext/patches/v6_20x/remove_fiscal_year_from_holiday_list.py deleted file mode 100644 index d440c6859e..0000000000 --- a/erpnext/patches/v6_20x/remove_fiscal_year_from_holiday_list.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Holiday List") - - default_holiday_list = frappe.db.get_value("Holiday List", {"is_default": 1}) - if default_holiday_list: - for company in frappe.get_all("Company", fields=["name", "default_holiday_list"]): - if not company.default_holiday_list: - frappe.db.set_value("Company", company.name, "default_holiday_list", default_holiday_list) - - - fiscal_years = frappe._dict((fy.name, fy) for fy in frappe.get_all("Fiscal Year", fields=["name", "year_start_date", "year_end_date"])) - - for holiday_list in frappe.get_all("Holiday List", fields=["name", "fiscal_year"]): - fy = fiscal_years[holiday_list.fiscal_year] - frappe.db.set_value("Holiday List", holiday_list.name, "from_date", fy.year_start_date) - frappe.db.set_value("Holiday List", holiday_list.name, "to_date", fy.year_end_date) diff --git a/erpnext/patches/v6_20x/rename_project_name_to_project.py b/erpnext/patches/v6_20x/rename_project_name_to_project.py deleted file mode 100644 index 49ec9d22bc..0000000000 --- a/erpnext/patches/v6_20x/rename_project_name_to_project.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - - doc_list = ["Work Order", "BOM", "Purchase Invoice Item", "Sales Invoice", - "Purchase Order Item", "Stock Entry", "Delivery Note", "Sales Order", - "Purchase Receipt Item", "Supplier Quotation Item"] - - for doctype in doc_list: - frappe.reload_doctype(doctype) - rename_field(doctype, "project_name", "project") - \ No newline at end of file diff --git a/erpnext/patches/v6_20x/repost_valuation_rate_for_negative_inventory.py b/erpnext/patches/v6_20x/repost_valuation_rate_for_negative_inventory.py deleted file mode 100644 index 8369fea317..0000000000 --- a/erpnext/patches/v6_20x/repost_valuation_rate_for_negative_inventory.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cint -from erpnext.stock.stock_balance import repost - -def execute(): - if cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")): - repost(only_actual=True) \ No newline at end of file diff --git a/erpnext/patches/v6_20x/set_compact_print.py b/erpnext/patches/v6_20x/set_compact_print.py deleted file mode 100644 index 495407f0e0..0000000000 --- a/erpnext/patches/v6_20x/set_compact_print.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from erpnext.setup.install import create_compact_item_print_custom_field - -def execute(): - create_compact_item_print_custom_field() - frappe.db.set_value("Print Settings", None, "compact_item_print", 1) diff --git a/erpnext/patches/v6_20x/update_product_bundle_description.py b/erpnext/patches/v6_20x/update_product_bundle_description.py deleted file mode 100644 index 1fac44b001..0000000000 --- a/erpnext/patches/v6_20x/update_product_bundle_description.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import sanitize_html - -def execute(): - for product_bundle in frappe.get_all('Product Bundle'): - doc = frappe.get_doc('Product Bundle', product_bundle.name) - for item in doc.items: - if item.description: - description = sanitize_html(item.description) - item.db_set('description', description, update_modified=False) diff --git a/erpnext/patches/v6_21/__init__.py b/erpnext/patches/v6_21/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_21/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_21/fix_reorder_level.py b/erpnext/patches/v6_21/fix_reorder_level.py deleted file mode 100644 index 82a35ebab1..0000000000 --- a/erpnext/patches/v6_21/fix_reorder_level.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from erpnext.stock.doctype.item.item import DuplicateReorderRows - -def execute(): - if frappe.db.has_column("Item", "re_order_level"): - for item in frappe.db.sql("""select name, default_warehouse, re_order_level, re_order_qty - from tabItem - where ifnull(re_order_level, 0) != 0 - and ifnull(re_order_qty, 0) != 0""", as_dict=1): - - item_doc = frappe.get_doc("Item", item.name) - item_doc.append("reorder_levels", { - "warehouse": item.default_warehouse, - "warehouse_reorder_level": item.re_order_level, - "warehouse_reorder_qty": item.re_order_qty, - "material_request_type": "Purchase" - }) - - try: - item_doc.save() - except DuplicateReorderRows: - pass diff --git a/erpnext/patches/v6_21/rename_material_request_fields.py b/erpnext/patches/v6_21/rename_material_request_fields.py deleted file mode 100644 index 07be27a5d6..0000000000 --- a/erpnext/patches/v6_21/rename_material_request_fields.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - frappe.reload_doc('stock', 'doctype', 'material_request_item') - rename_field("Material Request Item", "sales_order_no", "sales_order") - - frappe.reload_doc('support', 'doctype', 'maintenance_schedule_item') - rename_field("Maintenance Schedule Item", "prevdoc_docname", "sales_order") - \ No newline at end of file diff --git a/erpnext/patches/v6_23/__init__.py b/erpnext/patches/v6_23/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_23/update_stopped_status_to_closed.py b/erpnext/patches/v6_23/update_stopped_status_to_closed.py deleted file mode 100644 index 79d1e0ac30..0000000000 --- a/erpnext/patches/v6_23/update_stopped_status_to_closed.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt in ("Sales Order", "Purchase Order"): - frappe.db.sql("update `tab{0}` set status='Closed' where status='Stopped'".format(dt)) \ No newline at end of file diff --git a/erpnext/patches/v6_24/__init__.py b/erpnext/patches/v6_24/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_24/map_customer_address_to_shipping_address_on_po.py b/erpnext/patches/v6_24/map_customer_address_to_shipping_address_on_po.py deleted file mode 100644 index 1dd8083c7c..0000000000 --- a/erpnext/patches/v6_24/map_customer_address_to_shipping_address_on_po.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Purchase Order") - - if not frappe.db.has_column("Purchase Order", "shipping_address"): - return - - if not frappe.db.has_column("Purchase Order", "customer_address"): - return - - frappe.db.sql("""update `tabPurchase Order` set shipping_address=customer_address, - shipping_address_display=customer_address_display""") - - frappe.db.commit() \ No newline at end of file diff --git a/erpnext/patches/v6_24/set_recurring_id.py b/erpnext/patches/v6_24/set_recurring_id.py deleted file mode 100644 index 527a2fd3d9..0000000000 --- a/erpnext/patches/v6_24/set_recurring_id.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ('Sales Order', 'Purchase Order', 'Sales Invoice', - 'Purchase Invoice'): - frappe.reload_doctype(doctype) - frappe.db.sql('''update `tab{0}` set submit_on_creation=1, notify_by_email=1 - where is_recurring=1'''.format(doctype)) - frappe.db.sql('''update `tab{0}` set notify_by_email=1 - where is_recurring=1'''.format(doctype)) - frappe.db.sql('''update `tab{0}` set recurring_id = name - where is_recurring=1 and ifnull(recurring_id, '') = "" '''.format(doctype)) diff --git a/erpnext/patches/v6_27/__init__.py b/erpnext/patches/v6_27/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_27/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_27/fix_recurring_order_status.py b/erpnext/patches/v6_27/fix_recurring_order_status.py deleted file mode 100644 index 5843c9fbe5..0000000000 --- a/erpnext/patches/v6_27/fix_recurring_order_status.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for doc in ( - { - "doctype": "Sales Order", - "stock_doctype": "Delivery Note", - "invoice_doctype": "Sales Invoice", - "stock_doctype_ref_field": "against_sales_order", - "invoice_ref_field": "sales_order", - "qty_field": "delivered_qty" - }, - { - "doctype": "Purchase Order", - "stock_doctype": "Purchase Receipt", - "invoice_doctype": "Purchase Invoice", - "stock_doctype_ref_field": "prevdoc_docname", - "invoice_ref_field": "purchase_order", - "qty_field": "received_qty" - }): - - order_list = frappe.db.sql("""select name from `tab{0}` - where docstatus=1 and is_recurring=1 - and ifnull(recurring_id, '') != name and creation >= '2016-01-25'""" - .format(doc["doctype"]), as_dict=1) - - for order in order_list: - frappe.db.sql("""update `tab{0} Item` - set {1}=0, billed_amt=0 where parent=%s""".format(doc["doctype"], - doc["qty_field"]), order.name) - - # Check against Delivery Note and Purchase Receipt - stock_doc_list = frappe.db.sql("""select distinct parent from `tab{0} Item` - where docstatus=1 and ifnull({1}, '')=%s""" - .format(doc["stock_doctype"], doc["stock_doctype_ref_field"]), order.name) - - if stock_doc_list: - for dn in stock_doc_list: - frappe.get_doc(doc["stock_doctype"], dn[0]).update_qty(update_modified=False) - - # Check against Invoice - invoice_list = frappe.db.sql("""select distinct parent from `tab{0} Item` - where docstatus=1 and ifnull({1}, '')=%s""" - .format(doc["invoice_doctype"], doc["invoice_ref_field"]), order.name) - - if invoice_list: - for dn in invoice_list: - frappe.get_doc(doc["invoice_doctype"], dn[0]).update_qty(update_modified=False) - - frappe.get_doc(doc["doctype"], order.name).set_status(update=True, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v6_3/__init__.py b/erpnext/patches/v6_3/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_3/convert_applicable_territory.py b/erpnext/patches/v6_3/convert_applicable_territory.py deleted file mode 100644 index 231a483ea2..0000000000 --- a/erpnext/patches/v6_3/convert_applicable_territory.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("stock", "doctype", "price_list_country") - frappe.reload_doc("accounts", "doctype", "shipping_rule_country") - frappe.reload_doctype("Price List") - frappe.reload_doctype("Shipping Rule") - frappe.reload_doctype("shopping_cart", "doctype", "shopping_cart_settings") - - # for price list - countries = frappe.db.sql_list("select name from tabCountry") - - for doctype in ("Price List", "Shipping Rule"): - for at in frappe.db.sql("""select name, parent, territory from `tabApplicable Territory` where - parenttype = %s """, doctype, as_dict=True): - if at.territory in countries: - parent = frappe.get_doc(doctype, at.parent) - if not parent.countries: - parent.append("countries", {"country": at.territory}) - parent.save() - - - frappe.delete_doc("DocType", "Applicable Territory") diff --git a/erpnext/patches/v6_4/__init__.py b/erpnext/patches/v6_4/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_4/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_4/email_digest_update.py b/erpnext/patches/v6_4/email_digest_update.py deleted file mode 100644 index 8342b7fce6..0000000000 --- a/erpnext/patches/v6_4/email_digest_update.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Email Digest") - frappe.db.sql("""update `tabEmail Digest` set expense_year_to_date = - income_year_to_date""") - - if frappe.db.exists("Email Digest", "Scheduler Errors"): - frappe.delete_doc("Email Digest", "Scheduler Errors") diff --git a/erpnext/patches/v6_4/fix_duplicate_bins.py b/erpnext/patches/v6_4/fix_duplicate_bins.py deleted file mode 100644 index 77d05273e8..0000000000 --- a/erpnext/patches/v6_4/fix_duplicate_bins.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import repost_stock - -def execute(): - bins = frappe.db.sql("""select item_code, warehouse, count(*) from `tabBin` - group by item_code, warehouse having count(*) > 1""", as_dict=True) - - for d in bins: - try: - frappe.db.sql("delete from tabBin where item_code=%s and warehouse=%s", (d.item_code, d.warehouse)) - - repost_stock(d.item_code, d.warehouse, allow_zero_rate=True, only_actual=False, only_bin=True) - - frappe.db.commit() - except: - frappe.db.rollback() \ No newline at end of file diff --git a/erpnext/patches/v6_4/fix_expense_included_in_valuation.py b/erpnext/patches/v6_4/fix_expense_included_in_valuation.py deleted file mode 100644 index 7ed15ab010..0000000000 --- a/erpnext/patches/v6_4/fix_expense_included_in_valuation.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe -from frappe.utils import cstr - -def execute(): - for company in frappe.db.sql("select name, expenses_included_in_valuation from tabCompany", as_dict=1): - frozen_date = get_frozen_date(company.name, company.expenses_included_in_valuation) - - # Purchase Invoices after frozen date - # which are not against Receipt, but valuation related tax is there - pi_list = frappe.db.sql(""" - select distinct pi.name - from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item - where - pi.name = pi_item.parent - and pi.company = %s - and pi.posting_date > %s - and pi.docstatus = 1 - and pi.is_opening = 'No' - and (pi_item.item_tax_amount is not null and pi_item.item_tax_amount > 0) - and (pi_item.purchase_receipt is null or pi_item.purchase_receipt = '') - and (pi_item.item_code is not null and pi_item.item_code != '') - and exists(select name from `tabItem` where name=pi_item.item_code and is_stock_item=1) - """, (company.name, frozen_date), as_dict=1) - - for pi in pi_list: - # Check whether gle exists for Expenses Included in Valuation account against the PI - gle_for_expenses_included_in_valuation = frappe.db.sql("""select name from `tabGL Entry` - where voucher_type='Purchase Invoice' and voucher_no=%s and account=%s""", - (pi.name, company.expenses_included_in_valuation)) - - if gle_for_expenses_included_in_valuation: - print(pi.name) - - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type='Purchase Invoice' and voucher_no=%s""", pi.name) - - purchase_invoice = frappe.get_doc("Purchase Invoice", pi.name) - - # some old entries have missing expense accounts - if purchase_invoice.against_expense_account: - expense_account = purchase_invoice.against_expense_account.split(",") - if len(expense_account) == 1: - expense_account = expense_account[0] - for item in purchase_invoice.items: - if not item.expense_account: - item.db_set("expense_account", expense_account, update_modified=False) - - purchase_invoice.make_gl_entries() - -def get_frozen_date(company, account): - # Accounting frozen upto - accounts_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto") - - # Last adjustment entry to correct Expenses Included in Valuation account balance - last_adjustment_entry = frappe.db.sql("""select posting_date from `tabGL Entry` - where account=%s and company=%s and voucher_type = 'Journal Entry' - order by posting_date desc limit 1""", (account, company)) - - last_adjustment_date = cstr(last_adjustment_entry[0][0]) if last_adjustment_entry else None - - # Last period closing voucher - last_closing_entry = frappe.db.sql("""select posting_date from `tabGL Entry` - where company=%s and voucher_type = 'Period Closing Voucher' - order by posting_date desc limit 1""", company) - - last_closing_date = cstr(last_closing_entry[0][0]) if last_closing_entry else None - - frozen_date = max([accounts_frozen_upto, last_adjustment_date, last_closing_date]) - - return frozen_date or '1900-01-01' diff --git a/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py b/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py deleted file mode 100644 index b53412d7eb..0000000000 --- a/erpnext/patches/v6_4/fix_journal_entries_due_to_reconciliation.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Sales Invoice Advance") - frappe.reload_doctype("Purchase Invoice Advance") - - je_rows = frappe.db.sql(""" - select name, parent, reference_type, reference_name, debit, credit - from `tabJournal Entry Account` - where docstatus=1 and date(modified) >= '2015-09-17' - and ((ifnull(debit_in_account_currency, 0)*exchange_rate != ifnull(debit, 0)) - or (ifnull(credit_in_account_currency, 0)*exchange_rate != ifnull(credit, 0))) - order by parent - """, as_dict=True) - - journal_entries = [] - - for d in je_rows: - if d.parent not in journal_entries: - journal_entries.append(d.parent) - - is_advance_entry=None - if d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name: - is_advance_entry = frappe.db.sql("""select name from `tab{0}` - where reference_name=%s and reference_row=%s - and ifnull(allocated_amount, 0) > 0 and docstatus=1""" - .format(d.reference_type + " Advance"), (d.parent, d.name)) - - if is_advance_entry or not (d.debit or d.credit): - frappe.db.sql(""" - update `tabJournal Entry Account` - set debit=debit_in_account_currency*exchange_rate, - credit=credit_in_account_currency*exchange_rate - where name=%s""", d.name) - else: - frappe.db.sql(""" - update `tabJournal Entry Account` - set debit_in_account_currency=debit/exchange_rate, - credit_in_account_currency=credit/exchange_rate - where name=%s""", d.name) - - for d in journal_entries: - print(d) - # delete existing gle - frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d) - - # repost gl entries - je = frappe.get_doc("Journal Entry", d) - je.make_gl_entries() \ No newline at end of file diff --git a/erpnext/patches/v6_4/fix_modified_in_sales_order_and_purchase_order.py b/erpnext/patches/v6_4/fix_modified_in_sales_order_and_purchase_order.py deleted file mode 100644 index f27489e7b0..0000000000 --- a/erpnext/patches/v6_4/fix_modified_in_sales_order_and_purchase_order.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ("Sales Order", "Purchase Order"): - data = frappe.db.sql("""select parent, modified_by, modified - from `tab{doctype} Item` where docstatus=1 group by parent""".format(doctype=doctype), as_dict=True) - for item in data: - frappe.db.sql("""update `tab{doctype}` set modified_by=%(modified_by)s, modified=%(modified)s - where name=%(parent)s""".format(doctype=doctype), item) diff --git a/erpnext/patches/v6_4/fix_sales_order_maintenance_status.py b/erpnext/patches/v6_4/fix_sales_order_maintenance_status.py deleted file mode 100644 index 50aa9e542e..0000000000 --- a/erpnext/patches/v6_4/fix_sales_order_maintenance_status.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for doc in frappe.get_all("Sales Order", filters={"docstatus": 1, - "order_type": "Maintenance"}): - doc = frappe.get_doc("Sales Order", doc.name) - doc.set_status(update=True) diff --git a/erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py b/erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py deleted file mode 100644 index 746a99004a..0000000000 --- a/erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ("Sales Order", "Purchase Order"): - for doc in frappe.get_all(doctype, filters={"docstatus": 1}): - doc = frappe.get_doc(doctype, doc.name) - doc.set_status(update=True) diff --git a/erpnext/patches/v6_4/make_image_thumbnail.py b/erpnext/patches/v6_4/make_image_thumbnail.py deleted file mode 100644 index 2c86e8af86..0000000000 --- a/erpnext/patches/v6_4/make_image_thumbnail.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("File") - frappe.reload_doctype("Item") - for item in frappe.get_all("Item", fields=("name", "website_image", "thumbnail")): - if item.website_image and not item.thumbnail: - item_doc = frappe.get_doc("Item", item.name) - try: - item_doc.make_thumbnail() - if item_doc.thumbnail: - item_doc.db_set("thumbnail", item_doc.thumbnail, update_modified=False) - except Exception: - print("Unable to make thumbnail for {0}".format(item.website_image.encode("utf-8"))) diff --git a/erpnext/patches/v6_4/repost_gle_for_journal_entries_where_reference_name_missing.py b/erpnext/patches/v6_4/repost_gle_for_journal_entries_where_reference_name_missing.py deleted file mode 100644 index 1319b53558..0000000000 --- a/erpnext/patches/v6_4/repost_gle_for_journal_entries_where_reference_name_missing.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe - -def execute(): - je_list = frappe.db.sql_list("""select distinct parent from `tabJournal Entry Account` je - where docstatus=1 and ifnull(reference_name, '') !='' and creation > '2015-03-01' - and not exists(select name from `tabGL Entry` - where voucher_type='Journal Entry' and voucher_no=je.parent - and against_voucher_type=je.reference_type - and against_voucher=je.reference_name)""") - - for d in je_list: - print(d) - - # delete existing gle - frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d) - - # repost gl entries - je = frappe.get_doc("Journal Entry", d) - je.make_gl_entries() \ No newline at end of file diff --git a/erpnext/patches/v6_4/round_status_updater_percentages.py b/erpnext/patches/v6_4/round_status_updater_percentages.py deleted file mode 100644 index 900e906b7b..0000000000 --- a/erpnext/patches/v6_4/round_status_updater_percentages.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype, fieldname in ( - ("Sales Order", "per_billed"), - ("Sales Order", "per_delivered"), - ("Delivery Note", "per_installed"), - ("Purchase Order", "per_billed"), - ("Purchase Order", "per_received"), - ("Material Request", "per_ordered"), - ): - frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=round(`{fieldname}`, 2)""".format( - doctype=doctype, fieldname=fieldname)) diff --git a/erpnext/patches/v6_4/set_user_in_contact.py b/erpnext/patches/v6_4/set_user_in_contact.py deleted file mode 100644 index 7e8a6eecd5..0000000000 --- a/erpnext/patches/v6_4/set_user_in_contact.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Contact") - frappe.db.sql("""update tabContact, tabUser set tabContact.user = tabUser.name - where tabContact.email_id = tabUser.email""") diff --git a/erpnext/patches/v6_5/__init__.py b/erpnext/patches/v6_5/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_5/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_5/show_in_website_for_template_item.py b/erpnext/patches/v6_5/show_in_website_for_template_item.py deleted file mode 100644 index af6e8304d6..0000000000 --- a/erpnext/patches/v6_5/show_in_website_for_template_item.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe -import frappe.website.render - -def execute(): - for item_code in frappe.db.sql_list("""select distinct variant_of from `tabItem` - where variant_of is not null and variant_of !='' and show_in_website=1"""): - - item = frappe.get_doc("Item", item_code) - item.db_set("show_in_website", 1, update_modified=False) - - item.make_route() - item.db_set("route", item.route, update_modified=False) - - frappe.website.render.clear_cache() diff --git a/erpnext/patches/v6_6/__init__.py b/erpnext/patches/v6_6/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v6_6/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v6_6/fix_website_image.py b/erpnext/patches/v6_6/fix_website_image.py deleted file mode 100644 index cc3e2d852c..0000000000 --- a/erpnext/patches/v6_6/fix_website_image.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import print_function, unicode_literals -import frappe -from frappe.utils import encode - -def execute(): - """Fix the File records created via item.py even if the website_image file didn't exist""" - for item in frappe.db.sql_list("""select name from `tabItem` - where website_image is not null and website_image != '' - and website_image like '/files/%' - and exists ( - select name from `tabFile` - where attached_to_doctype='Item' - and attached_to_name=`tabItem`.name - and file_url=`tabItem`.website_image - and (file_name is null or file_name = '') - )"""): - - item = frappe.get_doc("Item", item) - file = frappe.get_doc("File", { - "attached_to_doctype": "Item", - "attached_to_name": item.name, - "file_url": item.website_image - }) - - try: - file.validate_file() - except IOError: - print(encode(item.website_image), "does not exist") - file.delete() - item.db_set("website_image", None, update_modified=False) - - diff --git a/erpnext/patches/v6_6/remove_fiscal_year_from_leave_allocation.py b/erpnext/patches/v6_6/remove_fiscal_year_from_leave_allocation.py deleted file mode 100644 index 11c582fc49..0000000000 --- a/erpnext/patches/v6_6/remove_fiscal_year_from_leave_allocation.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Leave Allocation") - if frappe.db.has_column("Leave Allocation", "fiscal_year"): - for leave_allocation in frappe.db.sql("select name, fiscal_year from `tabLeave Allocation`", as_dict=True): - dates = frappe.db.get_value("Fiscal Year", leave_allocation["fiscal_year"], - ["year_start_date", "year_end_date"]) - - if dates: - year_start_date, year_end_date = dates - - frappe.db.sql("""update `tabLeave Allocation` - set from_date=%s, to_date=%s where name=%s""", - (year_start_date, year_end_date, leave_allocation["name"])) - diff --git a/erpnext/patches/v6_8/__init__.py b/erpnext/patches/v6_8/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v6_8/make_webform_standard.py b/erpnext/patches/v6_8/make_webform_standard.py deleted file mode 100644 index 2cc16a286f..0000000000 --- a/erpnext/patches/v6_8/make_webform_standard.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - pass - - # done via fixtures - - # frappe.reload_doctype("Web Form") - # frappe.delete_doc("Web Form", "Issues") - # frappe.delete_doc("Web Form", "Addresses") - - # from erpnext.setup.install import add_web_forms - # add_web_forms() diff --git a/erpnext/patches/v6_8/move_drop_ship_to_po_items.py b/erpnext/patches/v6_8/move_drop_ship_to_po_items.py deleted file mode 100644 index 7184deeccc..0000000000 --- a/erpnext/patches/v6_8/move_drop_ship_to_po_items.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Purchase Order") - frappe.reload_doctype("Purchase Order Item") - - if not frappe.db.has_column("Purchase Order", "delivered_by_supplier"): - return - - for po in frappe.get_all("Purchase Order", filters={"delivered_by_supplier": 1}, fields=["name"]): - purchase_order = frappe.get_doc("Purchase Order", po) - - for item in purchase_order.items: - if item.prevdoc_doctype == "Sales Order": - delivered_by_supplier = frappe.get_value("Sales Order Item", item.prevdoc_detail_docname, - "delivered_by_supplier") - - if delivered_by_supplier: - frappe.db.sql("""update `tabPurchase Order Item` - set delivered_by_supplier=1, billed_amt=amount, received_qty=qty - where name=%s """, item.name) - - update_per_received(purchase_order) - update_per_billed(purchase_order) - -def update_per_received(po): - frappe.db.sql(""" update `tabPurchase Order` - set per_received = round((select sum(if(qty > ifnull(received_qty, 0), - ifnull(received_qty, 0), qty)) / sum(qty) *100 - from `tabPurchase Order Item` - where parent = %(name)s), 2) - where name = %(name)s """, {"name": po.name}) - -def update_per_billed(po): - frappe.db.sql(""" update `tabPurchase Order` - set per_billed = round((select sum( if(amount > ifnull(billed_amt, 0), - ifnull(billed_amt, 0), amount)) / sum(amount) *100 - from `tabPurchase Order Item` - where parent = %(name)s), 2) - where name = %(name)s """, {"name": po.name}) - - diff --git a/erpnext/patches/v7_0/__init__.py b/erpnext/patches/v7_0/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v7_0/calculate_total_costing_amount.py b/erpnext/patches/v7_0/calculate_total_costing_amount.py deleted file mode 100644 index 8ed60a2955..0000000000 --- a/erpnext/patches/v7_0/calculate_total_costing_amount.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import flt - -def execute(): - frappe.reload_doc('projects', 'doctype', 'timesheet') - - for data in frappe.get_all('Timesheet', fields=["name, total_costing_amount"], - filters = [["docstatus", "<", "2"]]): - if flt(data.total_costing_amount) == 0.0: - ts = frappe.get_doc('Timesheet', data.name) - ts.update_cost() - ts.calculate_total_amounts() - ts.flags.ignore_validate = True - ts.flags.ignore_mandatory = True - ts.flags.ignore_validate_update_after_submit = True - ts.flags.ignore_links = True - ts.save() diff --git a/erpnext/patches/v7_0/convert_timelog_to_timesheet.py b/erpnext/patches/v7_0/convert_timelog_to_timesheet.py deleted file mode 100644 index 8c60b5b71e..0000000000 --- a/erpnext/patches/v7_0/convert_timelog_to_timesheet.py +++ /dev/null @@ -1,69 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('projects', 'doctype', 'task') - frappe.reload_doc('projects', 'doctype', 'timesheet') - if not frappe.db.table_exists("Time Log"): - return - - from erpnext.manufacturing.doctype.work_order.work_order \ - import make_timesheet, add_timesheet_detail - - for data in frappe.db.sql("select * from `tabTime Log`", as_dict=1): - if data.task: - company = frappe.db.get_value("Task", data.task, "company") - elif data.work_order: - company = frappe.db.get_value("Work Order", data.work_order, "company") - else: - company = frappe.db.get_single_value('Global Defaults', 'default_company') - - time_sheet = make_timesheet(data.work_order, company) - args = get_timelog_data(data) - add_timesheet_detail(time_sheet, args) - if data.docstatus == 2: - time_sheet.docstatus = 0 - else: - time_sheet.docstatus = data.docstatus - time_sheet.employee = data.employee - time_sheet.note = data.note - time_sheet.company = company - - time_sheet.set_status() - time_sheet.set_dates() - time_sheet.update_cost() - time_sheet.calculate_total_amounts() - time_sheet.flags.ignore_validate = True - time_sheet.flags.ignore_links = True - time_sheet.save(ignore_permissions=True) - - # To ignore validate_mandatory_fields function - if data.docstatus == 1: - time_sheet.db_set("docstatus", 1) - for d in time_sheet.get("time_logs"): - d.db_set("docstatus", 1) - time_sheet.update_work_order(time_sheet.name) - time_sheet.update_task_and_project() - if data.docstatus == 2: - time_sheet.db_set("docstatus", 2) - for d in time_sheet.get("time_logs"): - d.db_set("docstatus", 2) - -def get_timelog_data(data): - return { - 'is_billable': data.billable, - 'from_time': data.from_time, - 'hours': data.hours, - 'to_time': data.to_time, - 'project': data.project, - 'task': data.task, - 'activity_type': data.activity_type, - 'operation': data.operation, - 'operation_id': data.operation_id, - 'workstation': data.workstation, - 'completed_qty': data.completed_qty, - 'billing_rate': data.billing_rate, - 'billing_amount': data.billing_amount, - 'costing_rate': data.costing_rate, - 'costing_amount': data.costing_amount - } diff --git a/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py b/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py deleted file mode 100644 index e78f163e07..0000000000 --- a/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import cint - -def execute(): - if not frappe.db.exists("DocType", "Time Log Batch"): - return - - from erpnext.manufacturing.doctype.work_order.work_order import add_timesheet_detail - - for tlb in frappe.get_all('Time Log Batch', fields=["*"], - filters = [["docstatus", "<", "2"]]): - time_sheet = frappe.new_doc('Timesheet') - time_sheet.employee= "" - time_sheet.company = frappe.db.get_single_value('Global Defaults', 'default_company') - time_sheet.sales_invoice = tlb.sales_invoice - - for data in frappe.get_all('Time Log Batch Detail', fields=["*"], - filters = {'parent': tlb.name}): - args = get_timesheet_data(data) - add_timesheet_detail(time_sheet, args) - - time_sheet.docstatus = tlb.docstatus - time_sheet.flags.ignore_links = True - time_sheet.save(ignore_permissions=True) - -def get_timesheet_data(data): - from erpnext.patches.v7_0.convert_timelog_to_timesheet import get_timelog_data - - time_log = frappe.get_all('Time Log', fields=["*"], filters = {'name': data.time_log}) - if time_log: - return get_timelog_data(time_log[0]) \ No newline at end of file diff --git a/erpnext/patches/v7_0/create_budget_record.py b/erpnext/patches/v7_0/create_budget_record.py deleted file mode 100644 index fd8bec9f32..0000000000 --- a/erpnext/patches/v7_0/create_budget_record.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from erpnext.accounts.doctype.budget.budget import DuplicateBudgetError - -def execute(): - frappe.reload_doc("accounts", "doctype", "budget") - frappe.reload_doc("accounts", "doctype", "budget_account") - - existing_budgets = frappe.db.sql(""" - select - cc.name, cc.company, cc.distribution_id, - budget.account, budget.budget_allocated, budget.fiscal_year - from - `tabCost Center` cc, `tabBudget Detail` budget - where - cc.name=budget.parent - """, as_dict=1) - - actions = {} - for d in frappe.db.sql("select name, yearly_bgt_flag, monthly_bgt_flag from tabCompany", as_dict=1): - actions.setdefault(d.name, d) - - budget_records = [] - for d in existing_budgets: - budget = frappe.db.get_value("Budget", - {"cost_center": d.name, "fiscal_year": d.fiscal_year, "company": d.company}) - - if not budget: - budget = frappe.new_doc("Budget") - budget.cost_center = d.name - budget.fiscal_year = d.fiscal_year - budget.monthly_distribution = d.distribution_id - budget.company = d.company - if actions[d.company]["yearly_bgt_flag"]: - budget.action_if_annual_budget_exceeded = actions[d.company]["yearly_bgt_flag"] - if actions[d.company]["monthly_bgt_flag"]: - budget.action_if_accumulated_monthly_budget_exceeded = actions[d.company]["monthly_bgt_flag"] - else: - budget = frappe.get_doc("Budget", budget) - - budget.append("accounts", { - "account": d.account, - "budget_amount": d.budget_allocated - }) - - try: - budget.insert() - budget_records.append(budget) - except DuplicateBudgetError: - pass - - for budget in budget_records: - budget.submit() - - if frappe.db.get_value("DocType", "Budget Detail"): - frappe.delete_doc("DocType", "Budget Detail") \ No newline at end of file diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py deleted file mode 100644 index 1c9fc32142..0000000000 --- a/erpnext/patches/v7_0/create_warehouse_nestedset.py +++ /dev/null @@ -1,128 +0,0 @@ - -from __future__ import unicode_literals -import frappe, erpnext -from frappe import _ -from frappe.utils import cint -from frappe.utils.nestedset import rebuild_tree - -def execute(): - """ - Patch Reference: - 1. check whether warehouse is associated to company or not - 2. if warehouse is associated with company - a. create warehouse group for company - b. set warehouse group as parent to other warehouses and set is_group as 0 - 3. if warehouses is not associated with company - a. get distinct companies from stock ledger entries - b. if sle have only company, - i. set default company to all warehouse - ii. repeat 2.a and 2.b - c. if have multiple companies, - i. create group warehouse without company - ii. repeat 2.b - """ - - frappe.reload_doc("stock", "doctype", "warehouse") - - if check_is_warehouse_associated_with_company(): - for company in frappe.get_all("Company", fields=["name", "abbr"]): - make_warehouse_nestedset(company) - else: - sle_against_companies = frappe.db.sql_list("""select distinct company from `tabStock Ledger Entry`""") - - if len(sle_against_companies) == 1: - company = frappe.get_cached_value('Company', sle_against_companies[0], - fieldname=["name", "abbr"], as_dict=1) - set_company_to_warehouse(company.name) - make_warehouse_nestedset(company) - - elif len(sle_against_companies) > 1: - make_warehouse_nestedset() - -def check_is_warehouse_associated_with_company(): - warehouse_associcated_with_company = False - - for warehouse in frappe.get_all("Warehouse", fields=["name", "company"]): - if warehouse.company: - warehouse_associcated_with_company = True - - return warehouse_associcated_with_company - -def make_warehouse_nestedset(company=None): - validate_parent_account_for_warehouse(company) - stock_account_group = get_stock_account_group(company.name) - enable_perpetual_inventory = cint(erpnext.is_perpetual_inventory_enabled(company.name)) or 0 - if not stock_account_group and enable_perpetual_inventory: - return - - if company: - warehouse_group = "{0} - {1}".format(_("All Warehouses"), company.abbr) - ignore_mandatory = False - else: - warehouse_group = _("All Warehouses") - ignore_mandatory = True - - if not frappe.db.get_value("Warehouse", warehouse_group): - create_default_warehouse_group(company, stock_account_group, ignore_mandatory) - - set_parent_to_warehouse(warehouse_group, company) - if enable_perpetual_inventory: - set_parent_to_warehouse_account(company) - -def validate_parent_account_for_warehouse(company=None): - if not company: - return - - if cint(erpnext.is_perpetual_inventory_enabled(company.name)): - parent_account = frappe.db.sql("""select name from tabAccount - where account_type='Stock' and company=%s and is_group=1 - and (warehouse is null or warehouse = '')""", company.name) - - if not parent_account: - current_parent_accounts_for_warehouse = frappe.db.sql("""select parent_account from tabAccount - where account_type='Warehouse' and (warehouse is not null or warehouse != '') """) - - if current_parent_accounts_for_warehouse: - frappe.db.set_value("Account", current_parent_accounts_for_warehouse[0][0], "account_type", "Stock") - -def create_default_warehouse_group(company=None, stock_account_group=None, ignore_mandatory=False): - wh = frappe.get_doc({ - "doctype": "Warehouse", - "warehouse_name": _("All Warehouses"), - "is_group": 1, - "company": company.name if company else "", - "parent_warehouse": "" - }) - - if ignore_mandatory: - wh.flags.ignore_mandatory = ignore_mandatory - - wh.insert(ignore_permissions=True) - -def set_parent_to_warehouse(warehouse_group, company=None): - frappe.db.sql(""" update tabWarehouse set parent_warehouse = %s, is_group = 0 - where (is_group = 0 or is_group is null or is_group = '') and ifnull(company, '') = %s - """,(warehouse_group, company.name if company else "")) - - rebuild_tree("Warehouse", "parent_warehouse") - -def set_parent_to_warehouse_account(company): - frappe.db.sql(""" update tabAccount set parent_account = %s - where is_group = 0 and account_type = "Warehouse" - and (warehouse is not null or warehouse != '') and company = %s - """,("{0} - {1}".format(_("All Warehouses"), company.abbr), company.name)) - - rebuild_tree("Account", "parent_account") - -def set_company_to_warehouse(company): - frappe.db.sql("update tabWahouse set company=%s", company) - -def get_stock_account_group(company): - stock_account_group = frappe.db.get_all('Account', filters = {'company': company, 'is_group': 1, - 'account_type': 'Stock', 'root_type': 'Asset'}, limit=1) - - if not stock_account_group: - stock_account_group = frappe.db.get_all('Account', filters = {'company': company, 'is_group': 1, - 'parent_account': '', 'root_type': 'Asset'}, limit=1) - - return stock_account_group[0].name if stock_account_group else None \ No newline at end of file diff --git a/erpnext/patches/v7_0/fix_duplicate_icons.py b/erpnext/patches/v7_0/fix_duplicate_icons.py deleted file mode 100644 index 9f442029b5..0000000000 --- a/erpnext/patches/v7_0/fix_duplicate_icons.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from frappe.desk.doctype.desktop_icon.desktop_icon import (sync_desktop_icons, - get_desktop_icons, set_hidden) -from erpnext.patches.v7_0.migrate_schools_to_erpnext import reload_doctypes_for_schools_icons - -def execute(): - '''hide new style icons if old ones are set''' - frappe.reload_doc('desk', 'doctype', 'desktop_icon') - - reload_doctypes_for_schools_icons() - - sync_desktop_icons() - - for user in frappe.get_all('User', filters={'user_type': 'System User'}): - desktop_icons = get_desktop_icons(user.name) - icons_dict = {} - for d in desktop_icons: - if not d.hidden: - icons_dict[d.module_name] = d - - for key in (('Selling', 'Customer'), ('Stock', 'Item'), ('Buying', 'Supplier'), - ('HR', 'Employee'), ('CRM', 'Lead'), ('Support', 'Issue'), ('Projects', 'Project')): - if key[0] in icons_dict and key[1] in icons_dict: - set_hidden(key[1], user.name, 1) - diff --git a/erpnext/patches/v7_0/fix_nonwarehouse_ledger_gl_entries_for_transactions.py b/erpnext/patches/v7_0/fix_nonwarehouse_ledger_gl_entries_for_transactions.py deleted file mode 100644 index 2bc09714d8..0000000000 --- a/erpnext/patches/v7_0/fix_nonwarehouse_ledger_gl_entries_for_transactions.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import print_function, unicode_literals -import frappe, erpnext - -def execute(): - frappe.reload_doctype("Account") - - warehouses = frappe.db.sql("""select name, company from tabAccount - where account_type = 'Stock' and is_group = 0 - and (warehouse is null or warehouse = '')""", as_dict=1) - warehouses = [d.name for d in warehouses if erpnext.is_perpetual_inventory_enabled(d.company)] - - if len(warehouses) > 0: - warehouses = set_warehouse_for_stock_account(warehouses) - if not warehouses: - return - - stock_vouchers = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no - from `tabStock Ledger Entry` sle - where sle.warehouse in (%s) and creation > '2016-05-01' - and not exists(select name from `tabGL Entry` - where account=sle.warehouse and voucher_type=sle.voucher_type and voucher_no=sle.voucher_no) - order by sle.posting_date""" % - ', '.join(['%s']*len(warehouses)), tuple(warehouses)) - - rejected = [] - for voucher_type, voucher_no in stock_vouchers: - try: - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no)) - - voucher = frappe.get_doc(voucher_type, voucher_no) - voucher.make_gl_entries() - frappe.db.commit() - except Exception as e: - print(frappe.get_traceback()) - rejected.append([voucher_type, voucher_no]) - frappe.db.rollback() - - print(rejected) - -def set_warehouse_for_stock_account(warehouse_account): - for account in warehouse_account: - if frappe.db.exists('Warehouse', account): - frappe.db.set_value("Account", account, "warehouse", account) - else: - warehouse_account.remove(account) - - return warehouse_account diff --git a/erpnext/patches/v7_0/make_guardian.py b/erpnext/patches/v7_0/make_guardian.py deleted file mode 100644 index 519969b38d..0000000000 --- a/erpnext/patches/v7_0/make_guardian.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists("DocType", "Student"): - student_table_cols = frappe.db.get_table_columns("Student") - if "father_name" in student_table_cols: - - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", "student") - # frappe.reload_doc("schools", "doctype", "guardian") - # frappe.reload_doc("schools", "doctype", "guardian_interest") - - frappe.reload_doc("education", "doctype", "student") - frappe.reload_doc("education", "doctype", "guardian") - frappe.reload_doc("education", "doctype", "guardian_interest") - frappe.reload_doc("hr", "doctype", "interest") - - fields = ["name", "father_name", "mother_name"] - - if "father_email_id" in student_table_cols: - fields += ["father_email_id", "mother_email_id"] - - students = frappe.get_all("Student", fields) - for stud in students: - if stud.father_name: - make_guardian(stud.father_name, stud.name, stud.father_email_id) - if stud.mother_name: - make_guardian(stud.mother_name, stud.name, stud.mother_email_id) - -def make_guardian(name, student, email=None): - frappe.get_doc({ - 'doctype': 'Guardian', - 'guardian_name': name, - 'email': email, - 'student': student - }).insert() diff --git a/erpnext/patches/v7_0/make_is_group_fieldtype_as_check.py b/erpnext/patches/v7_0/make_is_group_fieldtype_as_check.py deleted file mode 100644 index ba82e869fa..0000000000 --- a/erpnext/patches/v7_0/make_is_group_fieldtype_as_check.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ["Sales Person", "Customer Group", "Item Group", "Territory"]: - - # convert to 1 or 0 - frappe.db.sql("update `tab{doctype}` set is_group = if(is_group='Yes',1,0) " - .format(doctype=doctype)) - - frappe.db.commit() - - # alter fields to int - - frappe.db.sql("alter table `tab{doctype}` change is_group is_group int(1) default '0'" - .format(doctype=doctype)) - - frappe.reload_doctype(doctype) diff --git a/erpnext/patches/v7_0/merge_account_type_stock_and_warehouse_to_stock.py b/erpnext/patches/v7_0/merge_account_type_stock_and_warehouse_to_stock.py deleted file mode 100644 index 02808a742f..0000000000 --- a/erpnext/patches/v7_0/merge_account_type_stock_and_warehouse_to_stock.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "account") - - frappe.db.sql(""" update tabAccount set account_type = "Stock" - where account_type = "Warehouse" """) - - frappe.db.commit() \ No newline at end of file diff --git a/erpnext/patches/v7_0/migrate_mode_of_payments_v6_to_v7.py b/erpnext/patches/v7_0/migrate_mode_of_payments_v6_to_v7.py deleted file mode 100644 index e0e3f7075a..0000000000 --- a/erpnext/patches/v7_0/migrate_mode_of_payments_v6_to_v7.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_payment') - frappe.reload_doc('accounts', 'doctype', 'mode_of_payment') - - count = 0 - for data in frappe.db.sql("""select name, mode_of_payment, cash_bank_account, paid_amount, company - from `tabSales Invoice` si - where si.is_pos = 1 and si.docstatus < 2 - and si.cash_bank_account is not null and si.cash_bank_account != '' - and not exists(select name from `tabSales Invoice Payment` where parent=si.name)""", as_dict=1): - - if not data.mode_of_payment and not frappe.db.exists("Mode of Payment", "Cash"): - mop = frappe.new_doc("Mode of Payment") - mop.mode_of_payment = "Cash" - mop.type = "Cash" - mop.save() - - si_doc = frappe.get_doc('Sales Invoice', data.name) - row = si_doc.append('payments', { - 'mode_of_payment': data.mode_of_payment or 'Cash', - 'account': data.cash_bank_account, - 'type': frappe.db.get_value('Mode of Payment', data.mode_of_payment, 'type') or 'Cash', - 'amount': data.paid_amount - }) - row.db_update() - - si_doc.set_paid_amount() - si_doc.db_set("paid_amount", si_doc.paid_amount, update_modified = False) - si_doc.db_set("base_paid_amount", si_doc.base_paid_amount, update_modified = False) - - count +=1 - - if count % 200 == 0: - frappe.db.commit() \ No newline at end of file diff --git a/erpnext/patches/v7_0/migrate_schools_to_erpnext.py b/erpnext/patches/v7_0/migrate_schools_to_erpnext.py deleted file mode 100644 index b72bc137b6..0000000000 --- a/erpnext/patches/v7_0/migrate_schools_to_erpnext.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import unicode_literals -import frappe, os -from frappe.installer import remove_from_installed_apps - -def execute(): - reload_doctypes_for_schools_icons() - - frappe.reload_doc('website', 'doctype', 'portal_settings') - frappe.reload_doc('website', 'doctype', 'portal_menu_item') - frappe.reload_doc('buying', 'doctype', 'request_for_quotation') - - if 'schools' in frappe.get_installed_apps(): - if not frappe.db.exists('Module Def', 'Schools') and frappe.db.exists('Module Def', 'Academics'): - - # 'Schools' module changed to the 'Education' - # frappe.rename_doc("Module Def", "Academics", "Schools") - - frappe.rename_doc("Module Def", "Academics", "Education") - - remove_from_installed_apps("schools") - -def reload_doctypes_for_schools_icons(): - # 'Schools' module changed to the 'Education' - # base_path = frappe.get_app_path('erpnext', 'schools', 'doctype') - - base_path = frappe.get_app_path('erpnext', 'education', 'doctype') - for doctype in os.listdir(base_path): - if os.path.exists(os.path.join(base_path, doctype, doctype + '.json')) \ - and doctype not in ("fee_component", "assessment", "assessment_result"): - frappe.reload_doc('education', 'doctype', doctype) \ No newline at end of file diff --git a/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py b/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py deleted file mode 100644 index 998c4b674b..0000000000 --- a/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'sales_invoice') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_payment') - for time_sheet in frappe.db.sql(""" select sales_invoice, name, total_billable_amount from `tabTimesheet` - where sales_invoice is not null and docstatus < 2""", as_dict=True): - if not frappe.db.exists('Sales Invoice', time_sheet.sales_invoice): - continue - si_doc = frappe.get_doc('Sales Invoice', time_sheet.sales_invoice) - ts = si_doc.append('timesheets',{}) - ts.time_sheet = time_sheet.name - ts.billing_amount = time_sheet.total_billable_amount - ts.db_update() - si_doc.calculate_billing_amount_from_timesheet() - si_doc.db_set("total_billing_amount", si_doc.total_billing_amount, update_modified = False) \ No newline at end of file diff --git a/erpnext/patches/v7_0/po_status_issue_for_pr_return.py b/erpnext/patches/v7_0/po_status_issue_for_pr_return.py deleted file mode 100644 index 910814fd22..0000000000 --- a/erpnext/patches/v7_0/po_status_issue_for_pr_return.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - parent_list = [] - count = 0 - - frappe.reload_doc('stock', 'doctype', 'purchase_receipt') - frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item') - - for data in frappe.db.sql(""" - select - `tabPurchase Receipt Item`.purchase_order, `tabPurchase Receipt Item`.name, - `tabPurchase Receipt Item`.item_code, `tabPurchase Receipt Item`.idx, - `tabPurchase Receipt Item`.parent - from - `tabPurchase Receipt Item`, `tabPurchase Receipt` - where - `tabPurchase Receipt Item`.parent = `tabPurchase Receipt`.name and - `tabPurchase Receipt Item`.purchase_order_item is null and - `tabPurchase Receipt Item`.purchase_order is not null and - `tabPurchase Receipt`.is_return = 1""", as_dict=1): - name = frappe.db.get_value('Purchase Order Item', - {'item_code': data.item_code, 'parent': data.purchase_order, 'idx': data.idx}, 'name') - - if name: - frappe.db.set_value('Purchase Receipt Item', data.name, 'purchase_order_item', name, update_modified=False) - parent_list.append(data.parent) - - count +=1 - if count % 200 == 0: - frappe.db.commit() - - if len(parent_list) > 0: - for parent in set(parent_list): - doc = frappe.get_doc('Purchase Receipt', parent) - doc.update_qty(update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v7_0/re_route.py b/erpnext/patches/v7_0/re_route.py deleted file mode 100644 index 3cec6f39b2..0000000000 --- a/erpnext/patches/v7_0/re_route.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import unicode_literals -from frappe.patches.v7_0.re_route import update_routes - -def execute(): - update_routes(['Item', 'Item Group', 'Sales Partner', 'Job Opening']) \ No newline at end of file diff --git a/erpnext/patches/v7_0/remove_administrator_role_in_doctypes.py b/erpnext/patches/v7_0/remove_administrator_role_in_doctypes.py deleted file mode 100644 index 8c87c4e3d3..0000000000 --- a/erpnext/patches/v7_0/remove_administrator_role_in_doctypes.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""delete from tabDocPerm where role="Administrator" and parent in - ("Payment Gateway", "Payment Gateway Account", "Payment Request", "Academic Term", "Academic Year", "Course", - "Course Schedule", "Examination", "Fee Category", "Fee Structure", "Fees", "Instructor", "Program", "Program Enrollment Tool", - "Room", "Scheduling Tool", "Student", "Student Applicant", "Student Attendance", "Student Group", "Student Group Creation Tool") - """) \ No newline at end of file diff --git a/erpnext/patches/v7_0/remove_doctypes_and_reports.py b/erpnext/patches/v7_0/remove_doctypes_and_reports.py deleted file mode 100644 index 2356e2f6ee..0000000000 --- a/erpnext/patches/v7_0/remove_doctypes_and_reports.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("Time Log"): - frappe.db.sql("""delete from `tabDocType` - where name in('Time Log Batch', 'Time Log Batch Detail', 'Time Log')""") - - frappe.db.sql("""delete from `tabDocField` where parent in ('Time Log', 'Time Log Batch')""") - frappe.db.sql("""update `tabClient Script` set dt = 'Timesheet' where dt = 'Time Log'""") - - for data in frappe.db.sql(""" select label, fieldname from `tabCustom Field` where dt = 'Time Log'""", as_dict=1): - custom_field = frappe.get_doc({ - 'doctype': 'Custom Field', - 'label': data.label, - 'dt': 'Timesheet Detail', - 'fieldname': data.fieldname, - 'fieldtype': data.fieldtype or "Data" - }).insert(ignore_permissions=True) - - frappe.db.sql("""delete from `tabCustom Field` where dt = 'Time Log'""") - frappe.reload_doc('projects', 'doctype', 'timesheet') - frappe.reload_doc('projects', 'doctype', 'timesheet_detail') - - report = "Daily Time Log Summary" - if frappe.db.exists("Report", report): - frappe.delete_doc('Report', report) diff --git a/erpnext/patches/v7_0/remove_features_setup.py b/erpnext/patches/v7_0/remove_features_setup.py deleted file mode 100644 index 49393cc248..0000000000 --- a/erpnext/patches/v7_0/remove_features_setup.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from erpnext.setup.install import create_compact_item_print_custom_field -from frappe.utils import cint - -def execute(): - frappe.reload_doctype('Stock Settings') - stock_settings = frappe.get_doc('Stock Settings', 'Stock Settings') - stock_settings.show_barcode_field = cint(frappe.db.get_value("Features Setup", None, "fs_item_barcode")) - if not frappe.db.exists("UOM", stock_settings.stock_uom): - stock_settings.stock_uom = None - stock_settings.save() - - create_compact_item_print_custom_field() - - compact_item_print = frappe.db.get_value("Features Setup", None, "compact_item_print") - frappe.db.set_value("Print Settings", None, "compact_item_print", compact_item_print) - - # remove defaults - frappe.db.sql("""delete from tabDefaultValue where defkey in ('fs_item_serial_nos', - 'fs_item_batch_nos', 'fs_brands', 'fs_item_barcode', - 'fs_item_advanced', 'fs_packing_details', 'fs_item_group_in_details', - 'fs_exports', 'fs_imports', 'fs_discounts', 'fs_purchase_discounts', - 'fs_after_sales_installations', 'fs_projects', 'fs_sales_extras', - 'fs_recurring_invoice', 'fs_pos', 'fs_manufacturing', 'fs_quality', - 'fs_page_break', 'fs_more_info', 'fs_pos_view', 'compact_item_print')""") - - frappe.delete_doc('DocType', 'Features Setup') diff --git a/erpnext/patches/v7_0/remove_old_earning_deduction_doctypes.py b/erpnext/patches/v7_0/remove_old_earning_deduction_doctypes.py deleted file mode 100644 index 05a2c49461..0000000000 --- a/erpnext/patches/v7_0/remove_old_earning_deduction_doctypes.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists("DocType", "Salary Component"): - for dt in ("Salary Structure Earning", "Salary Structure Deduction", "Salary Slip Earning", - "Salary Slip Deduction", "Earning Type", "Deduction Type"): - frappe.delete_doc("DocType", dt) - - - for d in frappe.db.sql("""select name from `tabCustom Field` - where dt in ('Salary Detail', 'Salary Component')"""): - frappe.get_doc("Custom Field", d[0]).save() \ No newline at end of file diff --git a/erpnext/patches/v7_0/rename_advance_table_fields.py b/erpnext/patches/v7_0/rename_advance_table_fields.py deleted file mode 100644 index 34d81343e2..0000000000 --- a/erpnext/patches/v7_0/rename_advance_table_fields.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - for dt in ("Sales Invoice Advance", "Purchase Invoice Advance"): - frappe.reload_doctype(dt) - - frappe.db.sql("update `tab{0}` set reference_type = 'Journal Entry'".format(dt)) - - if frappe.get_meta(dt).has_field('journal_entry'): - rename_field(dt, "journal_entry", "reference_name") - - if frappe.get_meta(dt).has_field('jv_detail_no'): - rename_field(dt, "jv_detail_no", "reference_row") \ No newline at end of file diff --git a/erpnext/patches/v7_0/rename_examination_to_assessment.py b/erpnext/patches/v7_0/rename_examination_to_assessment.py deleted file mode 100644 index dc248de4fa..0000000000 --- a/erpnext/patches/v7_0/rename_examination_to_assessment.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -from frappe.model.utils.rename_field import rename_field - -def execute(): - if frappe.db.exists("DocType", "Examination"): - frappe.rename_doc("DocType", "Examination", "Assessment") - frappe.rename_doc("DocType", "Examination Result", "Assessment Result") - - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", "assessment") - # frappe.reload_doc("schools", "doctype", "assessment_result") - - frappe.reload_doc("education", "doctype", "assessment") - frappe.reload_doc("education", "doctype", "assessment_result") - - rename_field("Assessment", "exam_name", "assessment_name") - rename_field("Assessment", "exam_code", "assessment_code") - - frappe.db.sql("delete from `tabPortal Menu Item` where route = '/examination'") \ No newline at end of file diff --git a/erpnext/patches/v7_0/rename_fee_amount_to_fee_component.py b/erpnext/patches/v7_0/rename_fee_amount_to_fee_component.py deleted file mode 100644 index 5cb6a3b7c4..0000000000 --- a/erpnext/patches/v7_0/rename_fee_amount_to_fee_component.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -from frappe.model.utils.rename_field import rename_field - -def execute(): - if frappe.db.exists("DocType", "Fee Amount"): - frappe.rename_doc("DocType", "Fee Amount", "Fee Component") - for dt in ("Fees", "Fee Structure"): - frappe.reload_doctype(dt) - rename_field(dt, "amount", "components") - - \ No newline at end of file diff --git a/erpnext/patches/v7_0/rename_prevdoc_fields.py b/erpnext/patches/v7_0/rename_prevdoc_fields.py deleted file mode 100644 index ded4ad4aae..0000000000 --- a/erpnext/patches/v7_0/rename_prevdoc_fields.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import unicode_literals -import frappe -import json -from frappe.model.utils.rename_field import update_reports, rename_field, update_property_setters -from frappe.custom.doctype.property_setter.property_setter import make_property_setter - -def execute(): - frappe.reload_doctype('Purchase Order Item') - frappe.reload_doctype('Purchase Receipt Item') - update_po_fields() - update_prop_setters_reports_print_format_for_po() - set_sales_order_field() - rename_pr_fields() - -def update_po_fields(): - for data in frappe.db.sql(""" select prevdoc_docname, prevdoc_detail_docname, name, prevdoc_doctype - from `tabPurchase Order Item` where prevdoc_doctype is not null""", as_dict=True): - if data.prevdoc_doctype == 'Material Request': - frappe.db.set_value("Purchase Order Item", data.name, "material_request", data.prevdoc_docname, update_modified=False) - frappe.db.set_value("Purchase Order Item", data.name, "material_request_item", data.prevdoc_detail_docname, update_modified=False) - elif data.prevdoc_doctype == 'Sales Order': - frappe.db.set_value("Purchase Order Item", data.name, "sales_order", data.prevdoc_docname, update_modified=False) - frappe.db.set_value("Purchase Order Item", data.name, "sales_order_item", data.prevdoc_detail_docname, update_modified=False) - -def get_columns(): - return { - 'prevdoc_docname': 'material_request', - 'prevdoc_detail_docname': 'material_request_item' - } - -def update_prop_setters_reports_print_format_for_po(): - for key, val in get_columns().items(): - update_property_setters('Purchase Order Item', key, val) - update_reports('Purchase Order Item', key, val) - update_print_format_for_po(key, val, 'Purchase Order') - -def update_print_format_for_po(old_fieldname, new_fieldname, doc_type): - column_mapper = get_columns() - - for data in frappe.db.sql(""" select name, format_data from `tabPrint Format` where - format_data like %(old_fieldname)s and doc_type = %(doc_type)s""", - {'old_fieldname': '%%%s%%'%(old_fieldname), 'doc_type': doc_type}, as_dict=True): - - update_print_format_fields(old_fieldname, new_fieldname, data) - -def update_print_format_fields(old_fieldname, new_fieldname, args): - report_dict = json.loads(args.format_data) - update = False - - for col in report_dict: - if col.get('fieldname') and col.get('fieldname') == old_fieldname: - col['fieldname'] = new_fieldname - update = True - - if col.get('visible_columns'): - for key in col.get('visible_columns'): - if key.get('fieldname') == old_fieldname: - key['fieldname'] = new_fieldname - update = True - - if update: - val = json.dumps(report_dict) - frappe.db.sql("""update `tabPrint Format` set `format_data`=%s where name=%s""", (val, args.name)) - -def set_sales_order_field(): - for data in frappe.db.sql("""select doc_type, field_name, property, value, property_type - from `tabProperty Setter` where doc_type = 'Purchase Order Item' - and field_name in('material_request', 'material_request_item')""", as_dict=True): - if data.field_name == 'material_request': - make_property_setter(data.doc_type, 'sales_order', data.property, data.value, data.property_type) - else: - make_property_setter(data.doc_type, 'sales_order_item', data.property, data.value, data.property_type) - -def rename_pr_fields(): - rename_field("Purchase Receipt Item", "prevdoc_docname", "purchase_order") - rename_field("Purchase Receipt Item", "prevdoc_detail_docname", "purchase_order_item") diff --git a/erpnext/patches/v7_0/rename_salary_components.py b/erpnext/patches/v7_0/rename_salary_components.py deleted file mode 100644 index 1693f3bdf1..0000000000 --- a/erpnext/patches/v7_0/rename_salary_components.py +++ /dev/null @@ -1,149 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import update_property_setters - -def execute(): - if not frappe.db.exists("DocType", "Salary Structure Earning"): - return - - frappe.reload_doc("Payroll", "doctype", "salary_detail") - frappe.reload_doc("Payroll", "doctype", "salary_component") - - standard_cols = ["name", "creation", "modified", "owner", "modified_by", "parent", "parenttype", "parentfield", "idx"] - - dt_cols = { - "Salary Structure Deduction": ["d_type", "d_modified_amt", "depend_on_lwp"], - "Salary Structure Earning": ["e_type", "modified_value", "depend_on_lwp"], - "Salary Slip Earning": ["e_type", "e_modified_amount", "e_depends_on_lwp", "e_amount"], - "Salary Slip Deduction": ["d_type", "d_modified_amount", "d_depends_on_lwp", "d_amount"], - } - - earning_type_exists = True if "earning_type" in frappe.db.get_table_columns("Salary Slip Earning") else False - e_type_exists = True if "e_type" in frappe.db.get_table_columns("Salary Slip Earning") else False - - - if e_type_exists and earning_type_exists: - frappe.db.sql("""update `tabSalary Slip Earning` - set e_type = earning_type, e_modified_amount = earning_amount - where e_type is null and earning_type is not null""") - - frappe.db.sql("""update `tabSalary Structure Earning` set e_type = earning_type - where e_type is null and earning_type is not null""") - - frappe.db.sql("""update `tabSalary Slip Deduction` set - d_type = deduction_type, d_modified_amount = deduction_amount - where d_type is null and deduction_type is not null""") - - frappe.db.sql("""update `tabSalary Structure Deduction` set d_type = deduction_type - where d_type is null and deduction_type is not null""") - - if earning_type_exists and not e_type_exists: - for val in dt_cols.values(): - if val[0] == "e_type": - val[0] = "earning_type" - - if val[0] == "d_type": - val[0] = "deduction_type" - - if val[1] == "e_modified_amount": - val[1] ="earning_amount" - - if val[1] == "d_modified_amount": - val[1] ="deduction_amount" - - - - target_cols = standard_cols + ["salary_component", "amount", "depends_on_payment_days", "default_amount"] - target_cols = "`" + "`, `".join(target_cols) + "`" - - for doctype, cols in dt_cols.items(): - source_cols = "`" + "`, `".join(standard_cols + cols) + "`" - if len(cols) == 3: - source_cols += ", 0" - - - frappe.db.sql("""INSERT INTO `tabSalary Detail` ({0}) SELECT {1} FROM `tab{2}`""" - .format(target_cols, source_cols, doctype)) - - - dt_cols_de = { - "Deduction Type": ["deduction_name", "description"], - "Earning Type": ["earning_name", "description"], - } - - standard_cols_de = standard_cols - - - target_cols = standard_cols_de + ["salary_component", "description"] - target_cols = "`" + "`, `".join(target_cols) + "`" - - for doctype, cols in dt_cols_de.items(): - source_cols = "`" + "`, `".join(standard_cols_de + cols) + "`" - try: - frappe.db.sql("""INSERT INTO `tabSalary Component` ({0}) SELECT {1} FROM `tab{2}`""" - .format(target_cols, source_cols, doctype)) - except Exception as e: - if e.args[0]==1062: - pass - - update_customizations() - - for doctype in ["Salary Structure Deduction", "Salary Structure Earning", "Salary Slip Earning", - "Salary Slip Deduction", "Deduction Type", "Earning Type"] : - frappe.delete_doc("DocType", doctype) - - -def update_customizations(): - dt_cols = { - "Salary Structure Deduction": { - "d_type": "salary_component", - "deduction_type": "salary_component", - "d_modified_amt": "amount", - "depend_on_lwp": "depends_on_payment_days" - }, - "Salary Structure Earning": { - "e_type": "salary_component", - "earning_type": "salary_component", - "modified_value": "amount", - "depend_on_lwp": "depends_on_payment_days" - }, - "Salary Slip Earning": { - "e_type": "salary_component", - "earning_type": "salary_component", - "e_modified_amount": "amount", - "e_amount" : "default_amount", - "e_depends_on_lwp": "depends_on_payment_days" - }, - "Salary Slip Deduction": { - "d_type": "salary_component", - "deduction_type": "salary_component", - "d_modified_amount": "amount", - "d_amount" : "default_amount", - "d_depends_on_lwp": "depends_on_payment_days" - } - } - - update_property_setters_and_custom_fields("Salary Detail", dt_cols) - - dt_cols = { - "Earning Type": { - "earning_name": "salary_component" - }, - "Deduction Type": { - "deduction_name": "salary_component" - } - } - - update_property_setters_and_custom_fields("Salary Component", dt_cols) - - - - -def update_property_setters_and_custom_fields(new_dt, dt_cols): - for doctype, cols in dt_cols.items(): - frappe.db.sql("update `tabProperty Setter` set doc_type = %s where doc_type=%s", (new_dt, doctype)) - frappe.db.sql("update `tabCustom Field` set dt = %s where dt=%s", (new_dt, doctype)) - - - for old_fieldname, new_fieldname in cols.items(): - update_property_setters(new_dt, old_fieldname, new_fieldname) diff --git a/erpnext/patches/v7_0/rename_time_sheet_doctype.py b/erpnext/patches/v7_0/rename_time_sheet_doctype.py deleted file mode 100644 index f80a8301d7..0000000000 --- a/erpnext/patches/v7_0/rename_time_sheet_doctype.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("Time Sheet") and not frappe.db.table_exists("Timesheet"): - frappe.rename_doc("DocType", "Time Sheet", "Timesheet") - frappe.rename_doc("DocType", "Time Sheet Detail", "Timesheet Detail") - - for doctype in ['Time Sheet', 'Time Sheet Detail']: - frappe.delete_doc('DocType', doctype) - - report = "Daily Time Sheet Summary" - if frappe.db.exists("Report", report): - frappe.delete_doc('Report', report) diff --git a/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py b/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py deleted file mode 100644 index a5cf22cf01..0000000000 --- a/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - repost_bin_qty() - -def repost_bin_qty(): - for bin in frappe.db.sql(""" select name from `tabBin` - where (actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty - reserved_qty_for_production - reserved_qty_for_sub_contract) != projected_qty """, as_dict=1): - bin_doc = frappe.get_doc('Bin', bin.name) - bin_doc.set_projected_qty() - bin_doc.db_set("projected_qty", bin_doc.projected_qty, update_modified = False) diff --git a/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py b/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py deleted file mode 100644 index b864e597b8..0000000000 --- a/erpnext/patches/v7_0/repost_gle_for_pi_with_update_stock.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cint - -def execute(): - frappe.reload_doctype("Purchase Invoice") - - for pi in frappe.db.sql("""select name from `tabPurchase Invoice` - where company in(select name from tabCompany where enable_perpetual_inventory = 1) and - update_stock=1 and docstatus=1 order by posting_date asc""", as_dict=1): - - frappe.db.sql("""delete from `tabGL Entry` - where voucher_type = 'Purchase Invoice' and voucher_no = %s""", pi.name) - - pi_doc = frappe.get_doc("Purchase Invoice", pi.name) - pi_doc.make_gl_entries() - frappe.db.commit() \ No newline at end of file diff --git a/erpnext/patches/v7_0/repost_gle_for_pos_sales_return.py b/erpnext/patches/v7_0/repost_gle_for_pos_sales_return.py deleted file mode 100644 index 77ecafd6f1..0000000000 --- a/erpnext/patches/v7_0/repost_gle_for_pos_sales_return.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cint, flt - -def execute(): - frappe.reload_doctype("Sales Invoice") - frappe.reload_doctype("Sales Invoice Item") - - for si in frappe.get_all("Sales Invoice", fields = ["name"], - filters={"docstatus": 1, "is_pos": 1, "is_return": 1}): - si_doc = frappe.get_doc("Sales Invoice", si.name) - if len(si_doc.payments) > 0: - si_doc.set_paid_amount() - si_doc.flags.ignore_validate_update_after_submit = True - si_doc.save() - if si_doc.grand_total <= si_doc.paid_amount and si_doc.paid_amount < 0: - delete_gle_for_voucher(si_doc.name) - si_doc.run_method("make_gl_entries") - -def delete_gle_for_voucher(voucher_no): - frappe.db.sql("""delete from `tabGL Entry` where voucher_no = %(voucher_no)s""", - {'voucher_no': voucher_no}) diff --git a/erpnext/patches/v7_0/set_base_amount_in_invoice_payment_table.py b/erpnext/patches/v7_0/set_base_amount_in_invoice_payment_table.py deleted file mode 100644 index 5dd61a06cc..0000000000 --- a/erpnext/patches/v7_0/set_base_amount_in_invoice_payment_table.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import flt - -def execute(): - si_list = frappe.db.sql(""" - select distinct parent - from `tabSales Invoice Payment` - where docstatus!=2 and parenttype = 'Sales Invoice' - and amount != 0 and base_amount = 0 - """) - - count = 0 - for d in si_list: - si = frappe.get_doc("Sales Invoice", d[0]) - for p in si.get("payments"): - if p.amount and not p.base_amount: - base_amount = flt(p.amount*si.conversion_rate, si.precision("base_paid_amount")) - frappe.db.set_value("Sales Invoice Payment", p.name, "base_amount", base_amount, update_modified=False) - - count +=1 - - if count % 200 == 0: - frappe.db.commit() diff --git a/erpnext/patches/v7_0/set_is_group_for_warehouse.py b/erpnext/patches/v7_0/set_is_group_for_warehouse.py deleted file mode 100644 index 3e69616b80..0000000000 --- a/erpnext/patches/v7_0/set_is_group_for_warehouse.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("stock", "doctype", "warehouse") - frappe.db.sql("""update tabWarehouse - set is_group = if ((ifnull(is_group, "No") = "Yes" or ifnull(is_group, 0) = 1), 1, 0)""") \ No newline at end of file diff --git a/erpnext/patches/v7_0/set_material_request_type_in_item.py b/erpnext/patches/v7_0/set_material_request_type_in_item.py deleted file mode 100644 index 5fb14adbc8..0000000000 --- a/erpnext/patches/v7_0/set_material_request_type_in_item.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Item") - if "default_bom" in frappe.db.get_table_columns("Item"): - frappe.db.sql("""update `tabItem` - set default_material_request_type = ( - case - when (default_bom is not null and default_bom != '') - then 'Manufacture' - else 'Purchase' - end )""") - - else: - frappe.db.sql("update tabItem set default_material_request_type='Purchase'") \ No newline at end of file diff --git a/erpnext/patches/v7_0/set_naming_series_for_timesheet.py b/erpnext/patches/v7_0/set_naming_series_for_timesheet.py deleted file mode 100644 index d4d1a69d21..0000000000 --- a/erpnext/patches/v7_0/set_naming_series_for_timesheet.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.custom.doctype.property_setter.property_setter import make_property_setter - -def execute(): - frappe.reload_doc('projects', 'doctype', 'timesheet') - frappe.reload_doc('projects', 'doctype', 'timesheet_detail') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') - - make_property_setter('Timesheet', "naming_series", "options", 'TS-', "Text") - make_property_setter('Timesheet', "naming_series", "default", 'TS-', "Text") \ No newline at end of file diff --git a/erpnext/patches/v7_0/set_party_name_in_payment_entry.py b/erpnext/patches/v7_0/set_party_name_in_payment_entry.py deleted file mode 100644 index bbdcf5cf3c..0000000000 --- a/erpnext/patches/v7_0/set_party_name_in_payment_entry.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe - -def execute(): - customers = frappe._dict(frappe.db.sql("select name, customer_name from tabCustomer")) - suppliers = frappe._dict(frappe.db.sql("select name, supplier_name from tabSupplier")) - - frappe.reload_doc('accounts', 'doctype', 'payment_entry') - - pe_list = frappe.db.sql("""select name, party_type, party from `tabPayment Entry` - where party is not null and party != ''""", as_dict=1) - for pe in pe_list: - party_name = customers.get(pe.party) if pe.party_type=="Customer" else suppliers.get(pe.party) - - frappe.db.set_value("Payment Entry", pe.name, "party_name", party_name, update_modified=False) - diff --git a/erpnext/patches/v7_0/set_portal_settings.py b/erpnext/patches/v7_0/set_portal_settings.py deleted file mode 100644 index 5259d4fbd4..0000000000 --- a/erpnext/patches/v7_0/set_portal_settings.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe - -def execute(): - frappe.reload_doctype('Role') - for dt in ("assessment", "course", "fees"): - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", dt) - frappe.reload_doc("education", "doctype", dt) - - for dt in ("domain", "has_domain", "domain_settings"): - frappe.reload_doc("core", "doctype", dt) - - frappe.reload_doc('website', 'doctype', 'portal_menu_item') - - frappe.get_doc('Portal Settings').sync_menu() - - if 'schools' in frappe.get_installed_apps(): - domain = frappe.get_doc('Domain', 'Education') - domain.setup_domain() - else: - domain = frappe.get_doc('Domain', 'Manufacturing') - domain.setup_data() - domain.setup_sidebar_items() diff --git a/erpnext/patches/v7_0/setup_account_table_for_expense_claim_type_if_exists.py b/erpnext/patches/v7_0/setup_account_table_for_expense_claim_type_if_exists.py deleted file mode 100644 index c5657079b3..0000000000 --- a/erpnext/patches/v7_0/setup_account_table_for_expense_claim_type_if_exists.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("hr", "doctype", "expense_claim_type") - frappe.reload_doc("hr", "doctype", "expense_claim_account") - - if not frappe.db.has_column('Expense Claim Type', 'default_account'): - return - - for expense_claim_type in frappe.get_all("Expense Claim Type", fields=["name", "default_account"]): - if expense_claim_type.default_account \ - and frappe.db.exists("Account", expense_claim_type.default_account): - doc = frappe.get_doc("Expense Claim Type", expense_claim_type.name) - doc.append("accounts", { - "company": frappe.db.get_value("Account", expense_claim_type.default_account, "company"), - "default_account": expense_claim_type.default_account, - }) - doc.flags.ignore_mandatory = True - doc.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v7_0/system_settings_setup_complete.py b/erpnext/patches/v7_0/system_settings_setup_complete.py deleted file mode 100644 index 0feeee981e..0000000000 --- a/erpnext/patches/v7_0/system_settings_setup_complete.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('System Settings') - companies = frappe.db.sql("""select name, country - from tabCompany order by creation asc""", as_dict=True) - if companies: - frappe.db.set_value('System Settings', 'System Settings', 'setup_complete', 1) - - for company in companies: - if company.country: - frappe.db.set_value('System Settings', 'System Settings', 'country', company.country) - break - - diff --git a/erpnext/patches/v7_0/update_autoname_field.py b/erpnext/patches/v7_0/update_autoname_field.py deleted file mode 100644 index bfa9b281df..0000000000 --- a/erpnext/patches/v7_0/update_autoname_field.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - doctypes = frappe.db.sql(""" select name, autoname from `tabDocType` - where autoname like 'field:%' and allow_rename = 1""", as_dict=1) - - for doctype in doctypes: - fieldname = doctype.autoname.split(":")[1] - if fieldname: - frappe.db.sql(""" update `tab%s` set %s = name """%(doctype.name, fieldname)) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_change_amount_account.py b/erpnext/patches/v7_0/update_change_amount_account.py deleted file mode 100644 index 1741095ea9..0000000000 --- a/erpnext/patches/v7_0/update_change_amount_account.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'sales_invoice') - - for company in frappe.db.sql("""select company from `tabSales Invoice` - where change_amount <> 0 and account_for_change_amount is null group by company""", as_list = 1): - cash_account = get_default_bank_cash_account(company[0], 'Cash').get('account') - if not cash_account: - bank_account = get_default_bank_cash_account(company[0], 'Bank').get('account') - cash_account = bank_account - - if cash_account: - frappe.db.sql("""update `tabSales Invoice` - set account_for_change_amount = %(cash_account)s where change_amount <> 0 - and company = %(company)s and account_for_change_amount is null""", - {'cash_account': cash_account, 'company': company[0]}) diff --git a/erpnext/patches/v7_0/update_conversion_factor_in_supplier_quotation_item.py b/erpnext/patches/v7_0/update_conversion_factor_in_supplier_quotation_item.py deleted file mode 100644 index 24da4b1aeb..0000000000 --- a/erpnext/patches/v7_0/update_conversion_factor_in_supplier_quotation_item.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('buying', 'doctype', 'supplier_quotation_item') - - frappe.db.sql("""update - `tabSupplier Quotation Item` as sqi_t, - (select sqi.item_code as item_code, sqi.uom as uom, ucd.conversion_factor as conversion_factor - from `tabSupplier Quotation Item` sqi left join `tabUOM Conversion Detail` ucd - on ucd.uom = sqi.uom and sqi.item_code = ucd.parent) as conversion_data, - `tabItem` as item - set - sqi_t.conversion_factor= ifnull(conversion_data.conversion_factor, 1), - sqi_t.stock_qty = (ifnull(conversion_data.conversion_factor, 1) * sqi_t.qty), - sqi_t.stock_uom = item.stock_uom - where - sqi_t.item_code = conversion_data.item_code and - sqi_t.uom = conversion_data.uom and sqi_t.item_code = item.name""") \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_home_page.py b/erpnext/patches/v7_0/update_home_page.py deleted file mode 100644 index 909825c572..0000000000 --- a/erpnext/patches/v7_0/update_home_page.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import unicode_literals -import frappe -import erpnext - -def execute(): - frappe.reload_doc('portal', 'doctype', 'homepage_featured_product') - frappe.reload_doc('portal', 'doctype', 'homepage') - frappe.reload_doc('portal', 'doctype', 'products_settings') - frappe.reload_doctype('Item') - frappe.reload_doctype('Item Group') - - website_settings = frappe.get_doc('Website Settings', 'Website Settings') - if frappe.db.exists('Web Page', website_settings.home_page): - header = frappe.db.get_value('Web Page', website_settings.home_page, 'header') - if header and header.startswith("
"): - homepage = frappe.get_doc('Homepage', 'Homepage') - homepage.company = erpnext.get_default_company() or frappe.get_all("Company")[0].name - if '

' in header: - homepage.tag_line = header.split('

')[1].split('

')[0] or 'Default Website' - else: - homepage.tag_line = 'Default Website' - homepage.setup_items() - homepage.save() - - website_settings.home_page = 'home' - website_settings.save() - diff --git a/erpnext/patches/v7_0/update_maintenance_module_in_doctype.py b/erpnext/patches/v7_0/update_maintenance_module_in_doctype.py deleted file mode 100644 index 4c0c6a9313..0000000000 --- a/erpnext/patches/v7_0/update_maintenance_module_in_doctype.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.set_value("DocType", "Maintenance Schedule", "module", "Maintenance") - frappe.db.set_value("DocType", "Maintenance Schedule Detail", "module", "Maintenance") - frappe.db.set_value("DocType", "Maintenance Schedule Item", "module", "Maintenance") - frappe.db.set_value("DocType", "Maintenance Visit", "module", "Maintenance") - frappe.db.set_value("DocType", "Maintenance Visit Purpose", "module", "Maintenance") \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_mins_to_first_response.py b/erpnext/patches/v7_0/update_mins_to_first_response.py deleted file mode 100644 index 16681357e6..0000000000 --- a/erpnext/patches/v7_0/update_mins_to_first_response.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from frappe.core.doctype.communication.communication import update_mins_to_first_communication - -def execute(): - frappe.reload_doctype('Issue') - frappe.reload_doctype('Opportunity') - - for doctype in ('Issue', 'Opportunity'): - frappe.db.sql('update tab{0} set mins_to_first_response=0'.format(doctype)) - for parent in frappe.get_all(doctype, order_by='creation desc', limit=500): - parent_doc = frappe.get_doc(doctype, parent.name) - for communication in frappe.get_all('Communication', - filters={'reference_doctype': doctype, 'reference_name': parent.name, - 'communication_medium': 'Email'}, - order_by = 'creation asc', limit=2): - - communication_doc = frappe.get_doc('Communication', communication.name) - - update_mins_to_first_communication(parent_doc, communication_doc) - - if parent_doc.mins_to_first_response: - continue \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_missing_employee_in_timesheet.py b/erpnext/patches/v7_0/update_missing_employee_in_timesheet.py deleted file mode 100644 index 54d492b265..0000000000 --- a/erpnext/patches/v7_0/update_missing_employee_in_timesheet.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("Time Log") and "employee" in frappe.db.get_table_columns("Time Log"): - timesheet = frappe.db.sql("""select tl.employee as employee, ts.name as name, - tl.modified as modified, tl.modified_by as modified_by, tl.creation as creation, tl.owner as owner - from - `tabTimesheet` ts, `tabTimesheet Detail` tsd, `tabTime Log` tl - where - tsd.parent = ts.name and tl.from_time = tsd.from_time and tl.to_time = tsd.to_time - and tl.hours = tsd.hours and tl.billing_rate = tsd.billing_rate and tsd.idx=1 - and tl.docstatus < 2 and (ts.employee = '' or ts.employee is null)""", as_dict=1) - - for data in timesheet: - ts_doc = frappe.get_doc('Timesheet', data.name) - if len(ts_doc.time_logs) == 1: - frappe.db.sql(""" update `tabTimesheet` set creation = %(creation)s, - owner = %(owner)s, modified = %(modified)s, modified_by = %(modified_by)s, - employee = %(employee)s where name = %(name)s""", data) diff --git a/erpnext/patches/v7_0/update_mode_of_payment_type.py b/erpnext/patches/v7_0/update_mode_of_payment_type.py deleted file mode 100644 index 9292a1be1b..0000000000 --- a/erpnext/patches/v7_0/update_mode_of_payment_type.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import flt - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'mode_of_payment') - - frappe.db.sql(""" update `tabMode of Payment` set type = 'Cash' where (type is null or type = '') and name = 'Cash'""") - - for data in frappe.db.sql("""select name from `tabSales Invoice` where is_pos=1 and docstatus<2 and - (ifnull(paid_amount, 0) - ifnull(change_amount, 0)) > ifnull(grand_total, 0) and modified > '2016-05-01'""", as_dict=1): - if data.name: - si_doc = frappe.get_doc("Sales Invoice", data.name) - remove_payment = [] - mode_of_payment = [d.mode_of_payment for d in si_doc.payments if flt(d.amount) > 0] - if mode_of_payment != set(mode_of_payment): - for payment_data in si_doc.payments: - if payment_data.idx != 1 and payment_data.amount == si_doc.grand_total: - remove_payment.append(payment_data) - frappe.db.sql(""" delete from `tabSales Invoice Payment` - where name = %(name)s""", {'name': payment_data.name}) - - if len(remove_payment) > 0: - for d in remove_payment: - si_doc.remove(d) - - si_doc.set_paid_amount() - si_doc.db_set("paid_amount", si_doc.paid_amount, update_modified = False) - si_doc.db_set("base_paid_amount", si_doc.base_paid_amount, update_modified = False) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_party_status.py b/erpnext/patches/v7_0/update_party_status.py deleted file mode 100644 index 0c6b4ea598..0000000000 --- a/erpnext/patches/v7_0/update_party_status.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - return - # for party_type in ('Customer', 'Supplier'): - # frappe.reload_doctype(party_type) - # - # # set all as default status - # frappe.db.sql('update `tab{0}` set status=%s'.format(party_type), default_status[party_type]) - # - # for doctype in status_depends_on[party_type]: - # filters = get_filters_for(doctype) - # parties = frappe.get_all(doctype, fields="{0} as party".format(party_type.lower()), - # filters=filters, limit_page_length=1) - # - # parties = filter(None, [p.party for p in parties]) - # - # if parties: - # frappe.db.sql('update `tab{0}` set status="Open" where name in ({1})'.format(party_type, - # ', '.join(len(parties) * ['%s'])), parties) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_prevdoc_values_for_supplier_quotation_item.py b/erpnext/patches/v7_0/update_prevdoc_values_for_supplier_quotation_item.py deleted file mode 100644 index e90de50c1e..0000000000 --- a/erpnext/patches/v7_0/update_prevdoc_values_for_supplier_quotation_item.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Supplier Quotation Item') - for data in frappe.db.sql(""" select prevdoc_docname, prevdoc_detail_docname, name - from `tabSupplier Quotation Item` where prevdoc_docname is not null""", as_dict=True): - frappe.db.set_value("Supplier Quotation Item", data.name, "material_request", data.prevdoc_docname) - frappe.db.set_value("Supplier Quotation Item", data.name, "material_request_item", data.prevdoc_detail_docname) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_project_in_gl_entry.py b/erpnext/patches/v7_0/update_project_in_gl_entry.py deleted file mode 100644 index d99e9a41e3..0000000000 --- a/erpnext/patches/v7_0/update_project_in_gl_entry.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("GL Entry") - - for doctype in ("Delivery Note", "Sales Invoice", "Stock Entry"): - frappe.db.sql(""" - update `tabGL Entry` gle, `tab{0}` dt - set gle.project = dt.project - where gle.voucher_type=%s and gle.voucher_no = dt.name - and ifnull(gle.cost_center, '') != '' and ifnull(dt.project, '') != '' - """.format(doctype), doctype) - - for doctype in ("Purchase Receipt", "Purchase Invoice"): - frappe.db.sql(""" - update `tabGL Entry` gle, `tab{0} Item` dt - set gle.project = dt.project - where gle.voucher_type=%s and gle.voucher_no = dt.parent and gle.cost_center=dt.cost_center - and ifnull(gle.cost_center, '') != '' and ifnull(dt.project, '') != '' - """.format(doctype), doctype) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_refdoc_in_landed_cost_voucher.py b/erpnext/patches/v7_0/update_refdoc_in_landed_cost_voucher.py deleted file mode 100644 index 2d562bb40e..0000000000 --- a/erpnext/patches/v7_0/update_refdoc_in_landed_cost_voucher.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if "purchase_receipt" not in frappe.db.get_table_columns("Landed Cost Purchase Receipt"): - return - - frappe.reload_doctype("Landed Cost Purchase Receipt") - - frappe.db.sql(""" - update `tabLanded Cost Purchase Receipt` - set receipt_document_type = 'Purchase Receipt', receipt_document = purchase_receipt - where (receipt_document is null or receipt_document = '') - and (purchase_receipt is not null and purchase_receipt != '') - """) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_status_for_timesheet.py b/erpnext/patches/v7_0/update_status_for_timesheet.py deleted file mode 100644 index 117c40c59f..0000000000 --- a/erpnext/patches/v7_0/update_status_for_timesheet.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""update - `tabTimesheet` as ts, - ( - select min(from_time)as from_time, max(to_time) as to_time, parent from `tabTimesheet Detail` group by parent - ) as tsd - set ts.status = 'Submitted', ts.start_date = tsd.from_time, ts.end_date = tsd.to_time - where tsd.parent = ts.name and ts.status = 'Draft' and ts.docstatus =1""") \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_status_of_po_so.py b/erpnext/patches/v7_0/update_status_of_po_so.py deleted file mode 100644 index d630e8f0f2..0000000000 --- a/erpnext/patches/v7_0/update_status_of_po_so.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cint, flt - -def execute(): - update_po_per_received_per_billed() - update_so_per_delivered_per_billed() - update_status() - -def update_po_per_received_per_billed(): - frappe.db.sql(""" - update - `tabPurchase Order` - set - `tabPurchase Order`.per_received = round((select sum(if(qty > ifnull(received_qty, 0), - ifnull(received_qty, 0), qty)) / sum(qty) *100 from `tabPurchase Order Item` - where parent = `tabPurchase Order`.name), 2), - `tabPurchase Order`.per_billed = ifnull(round((select sum( if(amount > ifnull(billed_amt, 0), - ifnull(billed_amt, 0), amount)) / sum(amount) *100 from `tabPurchase Order Item` - where parent = `tabPurchase Order`.name), 2), 0) - where - net_total > 0 - """) - -def update_so_per_delivered_per_billed(): - frappe.db.sql(""" - update - `tabSales Order` - set - `tabSales Order`.per_delivered = round((select sum( if(qty > ifnull(delivered_qty, 0), - ifnull(delivered_qty, 0), qty)) / sum(qty) *100 from `tabSales Order Item` - where parent = `tabSales Order`.name), 2), - `tabSales Order`.per_billed = ifnull(round((select sum( if(amount > ifnull(billed_amt, 0), - ifnull(billed_amt, 0), amount)) / sum(amount) *100 from `tabSales Order Item` - where parent = `tabSales Order`.name), 2), 0) - where - net_total > 0 - """) - -def update_status(): - frappe.db.sql(""" - update - `tabSales Order` - set status = (Case when status = 'Closed' then 'Closed' - When per_delivered < 100 and per_billed < 100 and docstatus = 1 then 'To Deliver and Bill' - when per_delivered = 100 and per_billed < 100 and docstatus = 1 then 'To Bill' - when per_delivered < 100 and per_billed = 100 and docstatus = 1 then 'To Deliver' - when per_delivered = 100 and per_billed = 100 and docstatus = 1 then 'Completed' - when order_type = 'Maintenance' and per_billed = 100 and docstatus = 1 then 'Completed' - when docstatus = 2 then 'Cancelled' - else 'Draft' - End)""") - - frappe.db.sql(""" - update - `tabPurchase Order` - set status = (Case when status = 'Closed' then 'Closed' - when status = 'Delivered' then 'Delivered' - When per_received < 100 and per_billed < 100 and docstatus = 1 then 'To Receive and Bill' - when per_received = 100 and per_billed < 100 and docstatus = 1 then 'To Bill' - when per_received < 100 and per_billed = 100 and docstatus = 1 then 'To Receive' - when per_received = 100 and per_billed = 100 and docstatus = 1 then 'Completed' - when docstatus = 2 then 'Cancelled' - else 'Draft' - End)""") \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_status_of_zero_amount_sales_order.py b/erpnext/patches/v7_0/update_status_of_zero_amount_sales_order.py deleted file mode 100644 index 9b2b24785a..0000000000 --- a/erpnext/patches/v7_0/update_status_of_zero_amount_sales_order.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for data in frappe.get_all('Sales Order', fields = ["name"], filters = [["docstatus", "=", "1"], ["grand_total", "=", "0"]]): - sales_order = frappe.get_doc('Sales Order', data.name) - sales_order.set_status(update=True, update_modified = False) \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_timesheet_communications.py b/erpnext/patches/v7_0/update_timesheet_communications.py deleted file mode 100644 index 203471ea8f..0000000000 --- a/erpnext/patches/v7_0/update_timesheet_communications.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("Time Log"): - timesheet = frappe.db.sql("""SELECT ts.name AS name, tl.name AS timelogname, - tl.modified AS modified, tl.modified_by AS modified_by, tl.creation AS creation, tl.owner AS owner - FROM - `tabTimesheet` ts, `tabTimesheet Detail` tsd, `tabTime Log` tl - WHERE - tsd.parent = ts.name AND tl.from_time = tsd.from_time AND tl.to_time = tsd.to_time - AND tl.hours = tsd.hours AND tl.billing_rate = tsd.billing_rate AND tsd.idx=1 - AND tl.docstatus < 2""", as_dict=1) - - for data in timesheet: - frappe.db.sql(""" update `tabTimesheet` set creation = %(creation)s, - owner = %(owner)s, modified = %(modified)s, modified_by = %(modified_by)s - where name = %(name)s""", data) - - frappe.db.sql(""" - update - tabCommunication - set - reference_doctype = "Timesheet", reference_name = %(timesheet)s - where - reference_doctype = "Time Log" and reference_name = %(timelog)s - """, {'timesheet': data.name, 'timelog': data.timelogname}, auto_commit=1) diff --git a/erpnext/patches/v7_1/__init__.py b/erpnext/patches/v7_1/__init__.py deleted file mode 100644 index 519ff49eac..0000000000 --- a/erpnext/patches/v7_1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals \ No newline at end of file diff --git a/erpnext/patches/v7_1/add_account_user_role_for_timesheet.py b/erpnext/patches/v7_1/add_account_user_role_for_timesheet.py deleted file mode 100644 index 7372b0cc5f..0000000000 --- a/erpnext/patches/v7_1/add_account_user_role_for_timesheet.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if not frappe.db.get_value('DocPerm', {'parent': 'Timesheet', 'role': 'Accounts User', 'permlevel': 1}): - doc = frappe.get_doc('DocType', 'Timesheet') - doc.append('permissions', { - 'role': "Accounts User", - 'permlevel': 0, - 'read': 1, - 'write': 1, - 'create': 1, - 'delete': 1, - 'submit': 1, - 'cancel': 1, - 'amend': 1, - 'report': 1, - 'email': 1 - }) - - doc.append('permissions', { - 'role': "Accounts User", - 'permlevel': 1, - 'read': 1, - 'write': 1 - }) - - doc.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v7_1/add_field_for_task_dependent.py b/erpnext/patches/v7_1/add_field_for_task_dependent.py deleted file mode 100644 index 65b1c74e87..0000000000 --- a/erpnext/patches/v7_1/add_field_for_task_dependent.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Task') - for t in frappe.get_all('Task', fields=['name']): - task = frappe.get_doc('Task', t.name) - task.update_depends_on() - if task.depends_on_tasks: - task.db_set('depends_on_tasks', task.depends_on_tasks, update_modified=False) diff --git a/erpnext/patches/v7_1/fix_link_for_customer_from_lead.py b/erpnext/patches/v7_1/fix_link_for_customer_from_lead.py deleted file mode 100644 index 33f809fe37..0000000000 --- a/erpnext/patches/v7_1/fix_link_for_customer_from_lead.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - for c in frappe.db.sql('select name from tabCustomer where ifnull(lead_name,"")!=""'): - customer = frappe.get_doc('Customer', c[0]) - customer.update_lead_status() \ No newline at end of file diff --git a/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py b/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py deleted file mode 100644 index d1ec7c697e..0000000000 --- a/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('projects', 'doctype', 'timesheet_detail') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') - - frappe.db.sql(""" update - `tabTimesheet` as ts, - (select - sum(billing_amount) as billing_amount, sum(billing_hours) as billing_hours, time_sheet - from `tabSales Invoice Timesheet` where docstatus = 1 group by time_sheet - ) as sit - set - ts.total_billed_amount = sit.billing_amount, ts.total_billed_hours = sit.billing_hours, - ts.per_billed = ((sit.billing_amount * 100)/ts.total_billable_amount) - where ts.name = sit.time_sheet and ts.docstatus = 1""") - - frappe.db.sql(""" update `tabTimesheet Detail` tsd, `tabTimesheet` ts set tsd.sales_invoice = ts.sales_invoice - where tsd.parent = ts.name and ts.sales_invoice is not null""") \ No newline at end of file diff --git a/erpnext/patches/v7_1/rename_field_timesheet.py b/erpnext/patches/v7_1/rename_field_timesheet.py deleted file mode 100644 index 3690a2e79d..0000000000 --- a/erpnext/patches/v7_1/rename_field_timesheet.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - doctype = 'Timesheet' - fields_dict = {'total_billing_amount': 'total_billable_amount', 'total_billing_hours': 'total_billable_hours'} - - for old_fieldname, new_fieldname in fields_dict.items(): - if old_fieldname in frappe.db.get_table_columns(doctype): - rename_field(doctype, old_fieldname, new_fieldname) diff --git a/erpnext/patches/v7_1/rename_quality_inspection_field.py b/erpnext/patches/v7_1/rename_quality_inspection_field.py deleted file mode 100644 index 3b5a7d95eb..0000000000 --- a/erpnext/patches/v7_1/rename_quality_inspection_field.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import * - -def execute(): - for doctype in ("Purchase Receipt Item", "Delivery Note Item"): - frappe.reload_doctype(doctype) - - table_columns = frappe.db.get_table_columns(doctype) - if "qa_no" in table_columns: - rename_field(doctype, "qa_no", "quality_inspection") - - frappe.reload_doctype("Item") - rename_field("Item", "inspection_required", "inspection_required_before_purchase") - - frappe.reload_doc('stock', 'doctype', 'quality_inspection') - frappe.db.sql(""" - update - `tabQuality Inspection` - set - reference_type = 'Purchase Receipt', reference_name = purchase_receipt_no - where - ifnull(purchase_receipt_no, '') != '' and inspection_type = 'Incoming' - """) - - frappe.db.sql(""" - update - `tabQuality Inspection` - set - reference_type = 'Delivery Note', reference_name = delivery_note_no - where - ifnull(delivery_note_no, '') != '' and inspection_type = 'Outgoing' - """) - - for old_fieldname in ["purchase_receipt_no", "delivery_note_no"]: - update_reports("Quality Inspection", old_fieldname, "reference_name") - update_users_report_view_settings("Quality Inspection", old_fieldname, "reference_name") - update_property_setters("Quality Inspection", old_fieldname, "reference_name") diff --git a/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py b/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py deleted file mode 100644 index aca21085cc..0000000000 --- a/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import repost_stock - -def execute(): - frappe.reload_doc('manufacturing', 'doctype', 'work_order_item') - frappe.reload_doc('manufacturing', 'doctype', 'work_order') - - modified_items = frappe.db.sql_list(""" - select name from `tabItem` - where is_stock_item=1 and modified >= '2016-10-31' - """) - - if not modified_items: - return - - item_warehouses_with_transactions = [] - transactions = ("Sales Order Item", "Material Request Item", "Purchase Order Item", - "Stock Ledger Entry", "Packed Item") - - for doctype in transactions: - item_warehouses_with_transactions += list(frappe.db.sql(""" - select distinct item_code, warehouse - from `tab{0}` where docstatus=1 and item_code in ({1})""" - .format(doctype, ', '.join(['%s']*len(modified_items))), tuple(modified_items))) - - item_warehouses_with_transactions += list(frappe.db.sql(""" - select distinct production_item, fg_warehouse - from `tabWork Order` where docstatus=1 and production_item in ({0})""" - .format(', '.join(['%s']*len(modified_items))), tuple(modified_items))) - - item_warehouses_with_transactions += list(frappe.db.sql(""" - select distinct pr_item.item_code, pr_item.source_warehouse - from `tabWork Order` pr, `tabWork Order Item` pr_item - where pr_item.parent and pr.name and pr.docstatus=1 and pr_item.item_code in ({0})""" - .format(', '.join(['%s']*len(modified_items))), tuple(modified_items))) - - item_warehouses_with_bin = list(frappe.db.sql("select distinct item_code, warehouse from `tabBin`")) - - item_warehouses_with_missing_bin = list( - set(item_warehouses_with_transactions) - set(item_warehouses_with_bin)) - - for item_code, warehouse in item_warehouses_with_missing_bin: - repost_stock(item_code, warehouse) diff --git a/erpnext/patches/v7_1/save_stock_settings.py b/erpnext/patches/v7_1/save_stock_settings.py deleted file mode 100644 index d3f0263c10..0000000000 --- a/erpnext/patches/v7_1/save_stock_settings.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - stock_settings = frappe.get_doc('Stock Settings') - - if stock_settings.default_warehouse \ - and not frappe.db.exists("Warehouse", stock_settings.default_warehouse): - stock_settings.default_warehouse = None - - if stock_settings.stock_uom and not frappe.db.exists("UOM", stock_settings.stock_uom): - stock_settings.stock_uom = None - - stock_settings.flags.ignore_mandatory = True - stock_settings.save() diff --git a/erpnext/patches/v7_1/set_budget_against_as_cost_center.py b/erpnext/patches/v7_1/set_budget_against_as_cost_center.py deleted file mode 100644 index dd9a432cf0..0000000000 --- a/erpnext/patches/v7_1/set_budget_against_as_cost_center.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("accounts", "doctype", "budget") - frappe.db.sql(""" - update - `tabBudget` - set - budget_against = 'Cost Center' - """) diff --git a/erpnext/patches/v7_1/set_currency_exchange_date.py b/erpnext/patches/v7_1/set_currency_exchange_date.py deleted file mode 100644 index 2a2d420f21..0000000000 --- a/erpnext/patches/v7_1/set_currency_exchange_date.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Currency Exchange") - frappe.db.sql(""" - update `tabCurrency Exchange` - set `date` = '2010-01-01' - where date is null or date = '0000-00-00' - """) \ No newline at end of file diff --git a/erpnext/patches/v7_1/set_prefered_contact_email.py b/erpnext/patches/v7_1/set_prefered_contact_email.py deleted file mode 100644 index 3b68e22269..0000000000 --- a/erpnext/patches/v7_1/set_prefered_contact_email.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('User') - for d in frappe.get_all("Employee"): - employee = frappe.get_doc("Employee", d.name) - if employee.company_email: - employee.prefered_contact_email = "Company Email" - employee.prefered_email = employee.company_email - elif employee.personal_email: - employee.prefered_contact_email = "Personal Email" - employee.prefered_email = employee.personal_email - elif employee.user_id: - employee.prefered_contact_email = "User ID" - employee.prefered_email = employee.user_id - employee.db_update() diff --git a/erpnext/patches/v7_1/set_sales_person_status.py b/erpnext/patches/v7_1/set_sales_person_status.py deleted file mode 100644 index 929beac27f..0000000000 --- a/erpnext/patches/v7_1/set_sales_person_status.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('setup','doctype','sales_person') - frappe.db.sql("""update `tabSales Person` set enabled=1 - where (employee is null or employee = '' - or employee IN (select employee from tabEmployee where status != "Left"))""") diff --git a/erpnext/patches/v7_1/set_student_guardian.py b/erpnext/patches/v7_1/set_student_guardian.py deleted file mode 100644 index 093c0bf6d9..0000000000 --- a/erpnext/patches/v7_1/set_student_guardian.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists("DocType", "Guardian"): - - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", "student") - # frappe.reload_doc("schools", "doctype", "student_guardian") - # frappe.reload_doc("schools", "doctype", "student_sibling") - - frappe.reload_doc("education", "doctype", "student") - frappe.reload_doc("education", "doctype", "student_guardian") - frappe.reload_doc("education", "doctype", "student_sibling") - if "student" not in frappe.db.get_table_columns("Guardian"): - return - guardian = frappe.get_all("Guardian", fields=["name", "student"]) - for d in guardian: - if d.student: - student = frappe.get_doc("Student", d.student) - if student: - student.append("guardians", {"guardian": d.name}) - student.save() diff --git a/erpnext/patches/v7_1/set_total_amount_currency_in_je.py b/erpnext/patches/v7_1/set_total_amount_currency_in_je.py deleted file mode 100644 index 8426ddcd7d..0000000000 --- a/erpnext/patches/v7_1/set_total_amount_currency_in_je.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext import get_default_currency - -def execute(): - frappe.reload_doc("accounts", "doctype", "journal_entry") - - frappe.db.sql(""" update `tabJournal Entry` set total_amount_currency = %s - where ifnull(multi_currency, 0) = 0 - and (pay_to_recd_from is not null or pay_to_recd_from != "") """, get_default_currency()) - - for je in frappe.db.sql(""" select name from `tabJournal Entry` where multi_currency = 1 - and (pay_to_recd_from is not null or pay_to_recd_from != "")""", as_dict=1): - - doc = frappe.get_doc("Journal Entry", je.name) - for d in doc.get('accounts'): - if d.party_type and d.party: - total_amount_currency = d.account_currency - - elif frappe.db.get_value("Account", d.account, "account_type") in ["Bank", "Cash"]: - total_amount_currency = d.account_currency - - frappe.db.set_value("Journal Entry", je.name, "total_amount_currency", - total_amount_currency, update_modified=False) diff --git a/erpnext/patches/v7_1/update_bom_base_currency.py b/erpnext/patches/v7_1/update_bom_base_currency.py deleted file mode 100644 index 9a59209ea5..0000000000 --- a/erpnext/patches/v7_1/update_bom_base_currency.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext import get_default_currency - -def execute(): - frappe.reload_doc("manufacturing", "doctype", "bom") - frappe.reload_doc("manufacturing", "doctype", "bom_item") - frappe.reload_doc("manufacturing", "doctype", "bom_explosion_item") - frappe.reload_doc("manufacturing", "doctype", "bom_operation") - frappe.reload_doc("manufacturing", "doctype", "bom_scrap_item") - - frappe.db.sql(""" update `tabBOM Operation` set base_hour_rate = hour_rate, - base_operating_cost = operating_cost """) - - frappe.db.sql(""" update `tabBOM Item` set base_rate = rate, base_amount = amount """) - frappe.db.sql(""" update `tabBOM Scrap Item` set base_rate = rate, base_amount = amount """) - - frappe.db.sql(""" update `tabBOM` set `tabBOM`.base_operating_cost = `tabBOM`.operating_cost, - `tabBOM`.base_raw_material_cost = `tabBOM`.raw_material_cost, - `tabBOM`.currency = (select default_currency from `tabCompany` where name = `tabBOM`.company)""") diff --git a/erpnext/patches/v7_1/update_component_type.py b/erpnext/patches/v7_1/update_component_type.py deleted file mode 100644 index 24ca0570e0..0000000000 --- a/erpnext/patches/v7_1/update_component_type.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import flt - -def execute(): - frappe.reload_doc('Payroll', 'doctype', 'salary_component') - sal_components = frappe.db.sql(""" - select DISTINCT salary_component, parentfield from `tabSalary Detail`""", as_dict=True) - - if sal_components: - for sal_component in sal_components: - if sal_component.parentfield == "earnings": - frappe.db.sql("""update `tabSalary Component` set type='Earning' where salary_component=%(sal_comp)s""",{"sal_comp": sal_component.salary_component}) - else: - frappe.db.sql("""update `tabSalary Component` set type='Deduction' where salary_component=%(sal_comp)s""",{"sal_comp": sal_component.salary_component}) \ No newline at end of file diff --git a/erpnext/patches/v7_1/update_invoice_status.py b/erpnext/patches/v7_1/update_invoice_status.py deleted file mode 100644 index 851af80f7a..0000000000 --- a/erpnext/patches/v7_1/update_invoice_status.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'sales_invoice') - frappe.reload_doc('accounts', 'doctype', 'purchase_invoice') - - frappe.db.sql(""" - update - `tabPurchase Invoice` - set - status = (Case When outstanding_amount = 0 and docstatus = 1 and is_return = 0 then 'Paid' - when due_date < CURDATE() and outstanding_amount > 0 and docstatus =1 then 'Overdue' - when due_date >= CURDATE() and outstanding_amount > 0 and docstatus =1 then 'Unpaid' - when outstanding_amount < 0 and docstatus =1 then 'Debit Note Issued' - when is_return = 1 and docstatus =1 then 'Return' - when docstatus = 2 then 'Cancelled' - else 'Draft' - End)""") - - frappe.db.sql(""" - update - `tabSales Invoice` - set status = (Case When outstanding_amount = 0 and docstatus = 1 and is_return = 0 then 'Paid' - when due_date < CURDATE() and outstanding_amount > 0 and docstatus =1 then 'Overdue' - when due_date >= CURDATE() and outstanding_amount > 0 and docstatus =1 then 'Unpaid' - when outstanding_amount < 0 and docstatus =1 then 'Credit Note Issued' - when is_return = 1 and docstatus =1 then 'Return' - when docstatus = 2 then 'Cancelled' - else 'Draft' - End)""") \ No newline at end of file diff --git a/erpnext/patches/v7_1/update_lead_source.py b/erpnext/patches/v7_1/update_lead_source.py deleted file mode 100644 index a2a48a62e1..0000000000 --- a/erpnext/patches/v7_1/update_lead_source.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe import _ - -def execute(): - from erpnext.setup.setup_wizard.operations.install_fixtures import default_lead_sources - - frappe.reload_doc('crm', 'doctype', 'lead_source') - - frappe.local.lang = frappe.db.get_default("lang") or 'en' - - for s in default_lead_sources: - insert_lead_source(_(s)) - - # get lead sources in existing forms (customized) - # and create a document if not created - for d in ['Lead', 'Opportunity', 'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']: - sources = frappe.db.sql_list('select distinct source from `tab{0}`'.format(d)) - for s in sources: - if s and s not in default_lead_sources: - insert_lead_source(s) - - # remove customization for source - for p in frappe.get_all('Property Setter', {'doc_type':d, 'field_name':'source', 'property':'options'}): - frappe.delete_doc('Property Setter', p.name) - -def insert_lead_source(s): - if not frappe.db.exists('Lead Source', s): - frappe.get_doc(dict(doctype='Lead Source', source_name=s)).insert() diff --git a/erpnext/patches/v7_1/update_missing_salary_component_type.py b/erpnext/patches/v7_1/update_missing_salary_component_type.py deleted file mode 100644 index 824f2b881f..0000000000 --- a/erpnext/patches/v7_1/update_missing_salary_component_type.py +++ /dev/null @@ -1,50 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from frappe.utils import cstr - -''' -Some components do not have type set, try and guess whether they turn up in -earnings or deductions in existing salary slips -''' - -def execute(): - frappe.reload_doc("accounts", "doctype", "salary_component_account") - frappe.reload_doc("Payroll", "doctype", "salary_component") - frappe.reload_doc("Payroll", "doctype", "taxable_salary_slab") - - for s in frappe.db.sql('''select name, type, salary_component_abbr from `tabSalary Component` - where ifnull(type, "")="" or ifnull(salary_component_abbr, "") = ""''', as_dict=1): - - component = frappe.get_doc('Salary Component', s.name) - - # guess - if not s.type: - guess = frappe.db.sql('''select - parentfield from `tabSalary Detail` - where salary_component=%s limit 1''', s.name) - - if guess: - component.type = 'Earning' if guess[0][0]=='earnings' else 'Deduction' - - else: - component.type = 'Deduction' - - if not s.salary_component_abbr: - abbr = ''.join([c[0] for c in component.salary_component.split()]).upper() - - abbr_count = frappe.db.sql(""" - select - count(name) - from - `tabSalary Component` - where - salary_component_abbr = %s or salary_component_abbr like %s - """, (abbr, abbr + "-%%")) - - if abbr_count and abbr_count[0][0] > 0: - abbr = abbr + "-" + cstr(abbr_count[0][0]) - - component.salary_component_abbr = abbr - - component.save() diff --git a/erpnext/patches/v7_1/update_portal_roles.py b/erpnext/patches/v7_1/update_portal_roles.py deleted file mode 100644 index 482586b8ef..0000000000 --- a/erpnext/patches/v7_1/update_portal_roles.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Role') - frappe.reload_doctype('User') - for role_name in ('Customer', 'Supplier', 'Student'): - if frappe.db.exists('Role', role_name): - frappe.db.set_value('Role', role_name, 'desk_access', 0) - else: - frappe.get_doc(dict(doctype='Role', role_name=role_name, desk_access=0)).insert() - - - # set customer, supplier roles - for c in frappe.get_all('Contact', fields=['user'], filters={'ifnull(user, "")': ('!=', '')}): - user = frappe.get_doc('User', c.user) - user.flags.ignore_validate = True - user.flags.ignore_mandatory = True - user.save() - - diff --git a/erpnext/patches/v7_1/update_total_billing_hours.py b/erpnext/patches/v7_1/update_total_billing_hours.py deleted file mode 100644 index b9c96028f5..0000000000 --- a/erpnext/patches/v7_1/update_total_billing_hours.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('projects', 'doctype', 'timesheet_detail') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') - - frappe.db.sql("""update tabTimesheet set total_billable_hours=total_hours - where total_billable_amount>0 and docstatus = 1""") - - frappe.db.sql("""update `tabTimesheet Detail` set billing_hours=hours where docstatus < 2""") - - frappe.db.sql(""" update `tabSales Invoice Timesheet` set billing_hours = (select total_billable_hours from `tabTimesheet` - where name = time_sheet) where time_sheet is not null""") \ No newline at end of file diff --git a/erpnext/patches/v7_2/__init__.py b/erpnext/patches/v7_2/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v7_2/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py b/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py deleted file mode 100644 index d2583b9422..0000000000 --- a/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - # frappe.reload_doctype('Salary Slip', 'Salary Component') - frappe.reload_doc("Payroll", "doctype", "Salary Slip") - frappe.reload_doc("Payroll", "doctype", "Salary Component") - salary_components = [['Arrear', "ARR"], ['Leave Encashment', 'LENC']] - for salary_component, salary_abbr in salary_components: - if not frappe.db.exists('Salary Component', salary_component): - sal_comp = frappe.get_doc({ - "doctype": "Salary Component", - "salary_component": salary_component, - "type": "Earning", - "salary_component_abbr": salary_abbr - }).insert() - - salary_slips = frappe.db.sql("""select name, arrear_amount, leave_encashment_amount from `tabSalary Slip` - where docstatus !=2 and (arrear_amount > 0 or leave_encashment_amount > 0)""", as_dict=True) - - for salary_slip in salary_slips: - doc = frappe.get_doc('Salary Slip', salary_slip.name) - - if salary_slip.get("arrear_amount") > 0: - r = doc.append('earnings', { - 'salary_component': 'Arrear', - 'amount': salary_slip.arrear_amount - }) - r.db_update() - - if salary_slip.get("leave_encashment_amount") > 0: - r = doc.append('earnings', { - 'salary_component': 'Leave Encashment', - 'amount': salary_slip.leave_encashment_amount - }) - r.db_update() \ No newline at end of file diff --git a/erpnext/patches/v7_2/contact_address_links.py b/erpnext/patches/v7_2/contact_address_links.py deleted file mode 100644 index 200434c208..0000000000 --- a/erpnext/patches/v7_2/contact_address_links.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links -from frappe.utils import update_progress_bar - -def execute(): - frappe.reload_doc('core', 'doctype', 'dynamic_link') - frappe.reload_doc('contacts', 'doctype', 'contact') - frappe.reload_doc('contacts', 'doctype', 'address') - map_fields = ( - ('Customer', 'customer'), - ('Supplier', 'supplier'), - ('Lead', 'lead'), - ('Sales Partner', 'sales_partner') - ) - for doctype in ('Contact', 'Address'): - if frappe.db.has_column(doctype, 'customer'): - items = frappe.get_all(doctype) - for i, doc in enumerate(items): - doc = frappe.get_doc(doctype, doc.name) - dirty = False - for field in map_fields: - if doc.get(field[1]): - doc.append('links', dict(link_doctype=field[0], link_name=doc.get(field[1]))) - dirty = True - - if dirty: - deduplicate_dynamic_links(doc) - doc.update_children() - - update_progress_bar('Updating {0}'.format(doctype), i, len(items)) - print \ No newline at end of file diff --git a/erpnext/patches/v7_2/delete_fleet_management_module_def.py b/erpnext/patches/v7_2/delete_fleet_management_module_def.py deleted file mode 100644 index 542ac11e3f..0000000000 --- a/erpnext/patches/v7_2/delete_fleet_management_module_def.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists('Module Def', 'Fleet Management'): - frappe.db.sql("""delete from `tabModule Def` - where module_name = 'Fleet Management'""") \ No newline at end of file diff --git a/erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py b/erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py deleted file mode 100644 index ec6f8afc3a..0000000000 --- a/erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]: - child_table = 'Purchase Receipt Item Supplied' if doctype != 'Purchase Order' else 'Purchase Order Item Supplied' - for data in frappe.db.sql(""" select distinct `tab{doctype}`.name from `tab{doctype}` , `tab{child_table}` - where `tab{doctype}`.name = `tab{child_table}`.parent and `tab{doctype}`.docstatus != 2 - and `tab{doctype}`.is_subcontracted = 'No' """.format(doctype = doctype, child_table = child_table), as_dict=1): - frappe.db.sql(""" delete from `tab{child_table}` - where parent = %s and parenttype = %s""".format(child_table= child_table), (data.name, doctype)) \ No newline at end of file diff --git a/erpnext/patches/v7_2/make_all_assessment_group.py b/erpnext/patches/v7_2/make_all_assessment_group.py deleted file mode 100644 index f3ec628374..0000000000 --- a/erpnext/patches/v7_2/make_all_assessment_group.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if not frappe.db.exists({"doctype": "Assessment Group","assessment_group_name": "All Assessment Groups"}): - frappe.reload_doc("education", "doctype", "assessment_group") - doc = frappe.new_doc("Assessment Group") - doc.assessment_group_name = "All Assessment Groups" - doc.is_group = 1 - doc.flags.ignore_mandatory = True - doc.save() \ No newline at end of file diff --git a/erpnext/patches/v7_2/mark_students_active.py b/erpnext/patches/v7_2/mark_students_active.py deleted file mode 100644 index 7289e4a915..0000000000 --- a/erpnext/patches/v7_2/mark_students_active.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - # 'Schools' module changed to the 'Education' - # frappe.reload_doc('schools', 'doctype', 'student_group_student') - - frappe.reload_doc('education', 'doctype', 'student_group_student') - frappe.db.sql("update `tabStudent Group Student` set active=1") diff --git a/erpnext/patches/v7_2/rename_att_date_attendance.py b/erpnext/patches/v7_2/rename_att_date_attendance.py deleted file mode 100644 index 7f06d8f123..0000000000 --- a/erpnext/patches/v7_2/rename_att_date_attendance.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import update_reports, update_users_report_view_settings, update_property_setters - -def execute(): - if "att_date" not in frappe.db.get_table_columns("Attendance"): - return - frappe.reload_doc("hr", "doctype", "attendance") - frappe.db.sql("""update `tabAttendance` - set attendance_date = att_date - where attendance_date is null or attendance_date = '0000-00-00'""") - - update_reports("Attendance", "att_date", "attendance_date") - update_users_report_view_settings("Attendance", "att_date", "attendance_date") - update_property_setters("Attendance", "att_date", "attendance_date") diff --git a/erpnext/patches/v7_2/rename_evaluation_criteria.py b/erpnext/patches/v7_2/rename_evaluation_criteria.py deleted file mode 100644 index c6520b1b72..0000000000 --- a/erpnext/patches/v7_2/rename_evaluation_criteria.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - # 'Schools' module changed to the 'Education' - - - frappe.rename_doc("DocType", "Evaluation Criteria", "Assessment Criteria", force=True) - # frappe.reload_doc("schools", "doctype", "assessment_criteria") - frappe.reload_doc("education", "doctype", "assessment_criteria") - if 'evaluation_criteria' in frappe.db.get_table_columns('Assessment Criteria'): - rename_field("Assessment Criteria", "evaluation_criteria", "assessment_criteria") - - frappe.rename_doc("DocType", "Assessment Evaluation Criteria", "Assessment Plan Criteria", force=True) - # frappe.reload_doc("schools", "doctype", "assessment_plan_criteria") - frappe.reload_doc("education", "doctype", "assessment_plan_criteria") - if 'evaluation_criteria' in frappe.db.get_table_columns('Assessment Plan'): - rename_field("Assessment Plan Criteria", "evaluation_criteria", "assessment_criteria") - - # frappe.reload_doc("schools", "doctype", "assessment_plan") - frappe.reload_doc("education", "doctype", "assessment_plan") - rename_field("Assessment Plan", "evaluation_criterias", "assessment_criteria") - - # frappe.reload_doc("schools", "doctype", "assessment_result_detail") - frappe.reload_doc("education", "doctype", "assessment_result_detail") - if 'evaluation_criteria' in frappe.db.get_table_columns('Assessment Result Detail'): - rename_field("Assessment Result Detail", "evaluation_criteria", "assessment_criteria") - - frappe.rename_doc("DocType", "Course Evaluation Criteria", "Course Assessment Criteria", force=True) - # frappe.reload_doc("schools", "doctype", "course_assessment_criteria") - frappe.reload_doc("education", "doctype", "course_assessment_criteria") - if 'evaluation_criteria' in frappe.db.get_table_columns('Course Assessment Criteria'): - rename_field("Course Assessment Criteria", "evaluation_criteria", "assessment_criteria") - - # frappe.reload_doc("schools", "doctype", "course") - frappe.reload_doc("education", "doctype", "course") - if 'evaluation_criteria' in frappe.db.get_table_columns('Course'): - rename_field("Course", "evaluation_criterias", "assessment_criteria") diff --git a/erpnext/patches/v7_2/set_null_value_to_fields.py b/erpnext/patches/v7_2/set_null_value_to_fields.py deleted file mode 100644 index 6388be438d..0000000000 --- a/erpnext/patches/v7_2/set_null_value_to_fields.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - fields = {"Cost Center": "project", "Project": "cost_center"} - for budget_against, field in fields.items(): - frappe.db.sql(""" update `tabBudget` set {field} = null - where budget_against = %s """.format(field = field), budget_against) diff --git a/erpnext/patches/v7_2/setup_auto_close_settings.py b/erpnext/patches/v7_2/setup_auto_close_settings.py deleted file mode 100644 index 4eef2b9c8a..0000000000 --- a/erpnext/patches/v7_2/setup_auto_close_settings.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # update the selling settings and set the close_opportunity_after_days - frappe.reload_doc("selling", "doctype", "selling_settings") - frappe.db.set_value("Selling Settings", "Selling Settings", "close_opportunity_after_days", 15) - - # Auto close Replied opportunity - frappe.db.sql("""update `tabOpportunity` set status='Closed' where status='Replied' - and date_sub(curdate(), interval 15 Day)>modified""") - - # create Support Settings doctype and update close_issue_after_days - frappe.reload_doc("support", "doctype", "support_settings") - frappe.db.set_value("Support Settings", "Support Settings", "close_issue_after_days", 7) \ No newline at end of file diff --git a/erpnext/patches/v7_2/stock_uom_in_selling.py b/erpnext/patches/v7_2/stock_uom_in_selling.py deleted file mode 100644 index d029555747..0000000000 --- a/erpnext/patches/v7_2/stock_uom_in_selling.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Sales Order') - frappe.reload_doctype('Sales Invoice') - frappe.reload_doctype('Quotation') - frappe.reload_doctype('Delivery Note') - - doctype_list = ['Sales Order Item', 'Delivery Note Item', 'Quotation Item', 'Sales Invoice Item'] - - for doctype in doctype_list: - frappe.reload_doctype(doctype) - frappe.db.sql("""update `tab{doctype}` - set uom = stock_uom, conversion_factor = 1, stock_qty = qty""".format(doctype=doctype)) \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_abbr_in_salary_slips.py b/erpnext/patches/v7_2/update_abbr_in_salary_slips.py deleted file mode 100644 index 57432fe986..0000000000 --- a/erpnext/patches/v7_2/update_abbr_in_salary_slips.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('Payroll', 'doctype', 'Salary Slip') - if not frappe.db.has_column('Salary Detail', 'abbr'): - return - - salary_details = frappe.db.sql("""select abbr, salary_component, name from `tabSalary Detail` - where abbr is null or abbr = ''""", as_dict=True) - - for salary_detail in salary_details: - salary_component_abbr = frappe.get_value("Salary Component", salary_detail.salary_component, "salary_component_abbr") - frappe.db.sql("""update `tabSalary Detail` set abbr = %s where name = %s""",(salary_component_abbr, salary_detail.name)) \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_assessment_modules.py b/erpnext/patches/v7_2/update_assessment_modules.py deleted file mode 100644 index 2b5e774d46..0000000000 --- a/erpnext/patches/v7_2/update_assessment_modules.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - #Rename Grading Structure to Grading Scale - if not frappe.db.exists("DocType", "Grading Scale"): - frappe.rename_doc("DocType", "Grading Structure", "Grading Scale", force=True) - if not frappe.db.exists("DocType", "Grading Scale Interval"): - frappe.rename_doc("DocType", "Grade Interval", "Grading Scale Interval", force=True) - - # frappe.reload_doc("schools", "doctype", "grading_scale_interval") - frappe.reload_doc("education", "doctype", "grading_scale_interval") - if "to_score" in frappe.db.get_table_columns("Grading Scale Interval"): - rename_field("Grading Scale Interval", "to_score", "threshold") - - if not frappe.db.exists("DocType", "Assessment Plan"): - frappe.rename_doc("DocType", "Assessment", "Assessment Plan", force=True) - - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", "assessment_plan") - - #Rename Assessment Results - frappe.reload_doc("education", "doctype", "assessment_plan") - if "grading_structure" in frappe.db.get_table_columns("Assessment Plan"): - rename_field("Assessment Plan", "grading_structure", "grading_scale") - - # frappe.reload_doc("schools", "doctype", "assessment_result") - # frappe.reload_doc("schools", "doctype", "assessment_result_detail") - # frappe.reload_doc("schools", "doctype", "assessment_criteria") - frappe.reload_doc("education", "doctype", "assessment_result") - frappe.reload_doc("education", "doctype", "assessment_result_detail") - frappe.reload_doc("education", "doctype", "assessment_criteria") - - - for assessment in frappe.get_all("Assessment Plan", - fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]): - for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s", - assessment.name, as_dict=True): - if stud_result.result: - assessment_result = frappe.new_doc("Assessment Result") - assessment_result.student = stud_result.student - assessment_result.student_name = stud_result.student_name - assessment_result.assessment_plan = assessment.name - assessment_result.grading_scale = assessment.grading_scale - assessment_result.total_score = stud_result.result - assessment_result.flags.ignore_validate = True - assessment_result.flags.ignore_mandatory = True - assessment_result.save() - - frappe.db.sql("""delete from `tabAssessment Result` where parent != '' or parent is not null""") \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_attendance_docstatus.py b/erpnext/patches/v7_2/update_attendance_docstatus.py deleted file mode 100644 index a69052657d..0000000000 --- a/erpnext/patches/v7_2/update_attendance_docstatus.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("education", "doctype", "student_attendance") - frappe.db.sql(''' - update `tabStudent Attendance` set - docstatus=0 - where - docstatus=1''') \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_doctype_status.py b/erpnext/patches/v7_2/update_doctype_status.py deleted file mode 100644 index c66f3f2e73..0000000000 --- a/erpnext/patches/v7_2/update_doctype_status.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - doctypes = ["Opportunity", "Quotation", "Sales Order", "Sales Invoice", "Purchase Invoice", "Purchase Order", "Delivery Note", "Purchase Receipt"] - for doctype in doctypes: - frappe.db.sql(""" update `tab{doctype}` set status = 'Draft' - where status = 'Cancelled' and docstatus = 0 """.format(doctype = doctype)) \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_guardian_name_in_student_master.py b/erpnext/patches/v7_2/update_guardian_name_in_student_master.py deleted file mode 100644 index 9f589ef00e..0000000000 --- a/erpnext/patches/v7_2/update_guardian_name_in_student_master.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", "student_guardian") - frappe.reload_doc("education", "doctype", "student_guardian") - - student_guardians = frappe.get_all("Student Guardian", fields=["guardian"]) - for student_guardian in student_guardians: - guardian_name = frappe.db.get_value("Guardian", student_guardian.guardian, "guardian_name") - frappe.db.sql("update `tabStudent Guardian` set guardian_name = %s where guardian= %s", - (guardian_name, student_guardian.guardian)) \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_party_type.py b/erpnext/patches/v7_2/update_party_type.py deleted file mode 100644 index 147f5a3643..0000000000 --- a/erpnext/patches/v7_2/update_party_type.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('setup', 'doctype', 'party_type') - make_party_type() - -def make_party_type(): - for party_type in ["Customer", "Supplier", "Employee"]: - if not frappe.db.get_value("Party Type", party_type): - doc = frappe.new_doc("Party Type") - doc.party_type = party_type - doc.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_salary_slips.py b/erpnext/patches/v7_2/update_salary_slips.py deleted file mode 100644 index 9fcce62d8f..0000000000 --- a/erpnext/patches/v7_2/update_salary_slips.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details -from frappe.utils import cint - -def execute(): - frappe.reload_doc("Payroll", "doctype", "Salary Slip") - if not frappe.db.has_column('Salary Slip', 'fiscal_year'): - return - - salary_slips = frappe.db.sql("""select month, name, fiscal_year from `tabSalary Slip` - where (month is not null and month != '') and - start_date is null and end_date is null and docstatus != 2""", as_dict=True) - - for salary_slip in salary_slips: - if not cint(salary_slip.month): - continue - get_start_end_date = get_month_details(salary_slip.fiscal_year, cint(salary_slip.month)) - start_date = get_start_end_date['month_start_date'] - end_date = get_start_end_date['month_end_date'] - frappe.db.sql("""update `tabSalary Slip` set start_date = %s, end_date = %s where name = %s""", - (start_date, end_date, salary_slip.name)) \ No newline at end of file diff --git a/erpnext/patches/v7_2/update_website_for_variant.py b/erpnext/patches/v7_2/update_website_for_variant.py deleted file mode 100644 index e8eef6e7da..0000000000 --- a/erpnext/patches/v7_2/update_website_for_variant.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - # variant must have show_in_website = 0 - frappe.reload_doctype('Item') - frappe.db.sql(''' - update tabItem set - show_variant_in_website = 1, - show_in_website = 0 - where - show_in_website=1 - and ifnull(variant_of, "")!=""''') \ No newline at end of file diff --git a/erpnext/patches/v8_0/__init__.py b/erpnext/patches/v8_0/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v8_0/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v8_0/addresses_linked_to_lead.py b/erpnext/patches/v8_0/addresses_linked_to_lead.py deleted file mode 100644 index b5f2234228..0000000000 --- a/erpnext/patches/v8_0/addresses_linked_to_lead.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql("""UPDATE `tabDynamic Link` SET link_doctype = 'Lead' WHERE link_doctype = 'Load'""") diff --git a/erpnext/patches/v8_0/change_in_words_varchar_length.py b/erpnext/patches/v8_0/change_in_words_varchar_length.py deleted file mode 100644 index 68ff95b5ed..0000000000 --- a/erpnext/patches/v8_0/change_in_words_varchar_length.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - doctypes = frappe.db.sql_list("""select parent from tabDocField where fieldname = 'in_words'""") - - for dt in doctypes: - for fieldname in ("in_words", "base_in_words"): - frappe.db.sql("alter table `tab{0}` change column `{1}` `{2}` varchar(255)" - .format(dt, fieldname, fieldname)) - - frappe.db.sql("""alter table `tabJournal Entry` - change column `total_amount_in_words` `total_amount_in_words` varchar(255)""") diff --git a/erpnext/patches/v8_0/create_address_doc_from_address_field_in_company.py b/erpnext/patches/v8_0/create_address_doc_from_address_field_in_company.py deleted file mode 100644 index cf1bc5af05..0000000000 --- a/erpnext/patches/v8_0/create_address_doc_from_address_field_in_company.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # new field address_html is created in place of address field for the company's address in PR #8754 (without patch) - # so here is the patch for moving the address details in the address doc - company_list = [] - if 'address' in frappe.db.get_table_columns('Company'): - company_list = frappe.db.sql('''select name, address from `tabCompany` - where address is not null and address != ""''', as_dict=1) - - for company in company_list: - add_list = company.address.split(" ") - if ',' in company.address: - add_list = company.address.rpartition(',') - elif ' ' in company.address: - add_list = company.address.rpartition(' ') - else: - add_list = [company.address, None, company.address] - - doc = frappe.get_doc({ - "doctype":"Address", - "address_line1": add_list[0], - "city": add_list[2], - "links": [{ - "link_doctype": "Company", - "link_name": company.name - }] - }) - doc.save() diff --git a/erpnext/patches/v8_0/create_domain_docs.py b/erpnext/patches/v8_0/create_domain_docs.py deleted file mode 100644 index 3ef4f3c1bb..0000000000 --- a/erpnext/patches/v8_0/create_domain_docs.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -import erpnext - -def execute(): - """Create domain documents""" - frappe.reload_doc("core", "doctype", "domain") - frappe.reload_doc("core", "doctype", "domain_settings") - frappe.reload_doc("core", "doctype", "has_domain") - frappe.reload_doc("core", "doctype", "role") - - for domain in ("Distribution", "Manufacturing", "Retail", "Services", "Education"): - if not frappe.db.exists({"doctype": "Domain", "domain": domain}): - create_domain(domain) - - # set domain in domain settings based on company domain - - domains = [] - condition = "" - company = erpnext.get_default_company() - if company: - condition = " and name={0}".format(frappe.db.escape(company)) - - domains = frappe.db.sql_list("select distinct domain from `tabCompany` where domain != 'Other' {0}".format(condition)) - - if not domains: - return - - domain_settings = frappe.get_doc("Domain Settings", "Domain Settings") - checked_domains = [row.domain for row in domain_settings.active_domains] - - for domain in domains: - # check and ignore if the domains is already checked in domain settings - if domain in checked_domains: - continue - - if not frappe.db.get_value("Domain", domain): - # user added custom domain in companies domain field - create_domain(domain) - - row = domain_settings.append("active_domains", dict(domain=domain)) - - domain_settings.save(ignore_permissions=True) - -def create_domain(domain): - # create new domain - - doc = frappe.new_doc("Domain") - doc.domain = domain - doc.db_update() \ No newline at end of file diff --git a/erpnext/patches/v8_0/delete_bin_indexes.py b/erpnext/patches/v8_0/delete_bin_indexes.py deleted file mode 100644 index 12cacdb952..0000000000 --- a/erpnext/patches/v8_0/delete_bin_indexes.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals -import frappe - -def execute(): - # delete bin indexes - unwanted_indexes = ["item_code", "warehouse"] - - for k in unwanted_indexes: - try: - frappe.db.sql("drop index {0} on `tabBin`".format(k)) - except: - pass \ No newline at end of file diff --git a/erpnext/patches/v8_0/delete_schools_depricated_doctypes.py b/erpnext/patches/v8_0/delete_schools_depricated_doctypes.py deleted file mode 100644 index 09a78ed3ca..0000000000 --- a/erpnext/patches/v8_0/delete_schools_depricated_doctypes.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - """ delete doctypes """ - - if frappe.db.exists("DocType", "Grading Structure"): - frappe.delete_doc("DocType", "Grading Structure", force=1) - - if frappe.db.exists("DocType", "Grade Interval"): - frappe.delete_doc("DocType", "Grade Interval", force=1) \ No newline at end of file diff --git a/erpnext/patches/v8_0/disable_instructor_role.py b/erpnext/patches/v8_0/disable_instructor_role.py deleted file mode 100644 index 4ba78d172c..0000000000 --- a/erpnext/patches/v8_0/disable_instructor_role.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - """ - disable the instructor role for companies with domain other than - Education. - """ - - domains = frappe.db.sql_list("select domain from tabCompany") - if "Education" not in domains: - if frappe.db.exists("Role", "Instructor"): - role = frappe.get_doc("Role", "Instructor") - role.disabled = 1 - role.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v8_0/enable_booking_asset_depreciation_automatically.py b/erpnext/patches/v8_0/enable_booking_asset_depreciation_automatically.py deleted file mode 100644 index 1088d702dd..0000000000 --- a/erpnext/patches/v8_0/enable_booking_asset_depreciation_automatically.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.set_value("Accounts Settings", None, - "book_asset_depreciation_entry_automatically", 1) \ No newline at end of file diff --git a/erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py b/erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py deleted file mode 100644 index 2e7f360c97..0000000000 --- a/erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt, status in [["Sales Invoice", "Credit Note Issued"], ["Purchase Invoice", "Debit Note Issued"]]: - invoices = frappe.db.sql(""" - select name - from `tab{0}` - where - status = %s - and outstanding_amount < 0 - and docstatus=1 - and is_return=0 - """.format(dt), status) - - for inv in invoices: - return_inv = frappe.db.sql("""select name from `tab{0}` - where is_return=1 and return_against=%s and docstatus=1""".format(dt), inv[0]) - if not return_inv: - frappe.db.sql("update `tab{0}` set status='Paid' where name = %s".format(dt), inv[0]) \ No newline at end of file diff --git a/erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py b/erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py deleted file mode 100644 index 9750fb7222..0000000000 --- a/erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Sales Invoice') - - frappe.db.sql(""" - delete from - `tabSales Invoice Payment` - where - parent in (select name from `tabSales Invoice` where is_pos = 0) - """) \ No newline at end of file diff --git a/erpnext/patches/v8_0/merge_student_batch_and_student_group.py b/erpnext/patches/v8_0/merge_student_batch_and_student_group.py deleted file mode 100644 index fb9021fd68..0000000000 --- a/erpnext/patches/v8_0/merge_student_batch_and_student_group.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import * -from frappe.model.mapper import get_mapped_doc - - -def execute(): - # for converting student batch into student group - for doctype in ["Student Group", "Student Group Student", 'Program Enrollment', - "Student Group Instructor", "Student Attendance", "Student", "Student Batch Name"]: - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", frappe.scrub(doctype)) - - frappe.reload_doc("education", "doctype", frappe.scrub(doctype)) - - if frappe.db.table_exists("Student Batch"): - student_batches = frappe.db.sql('''select name as student_group_name, student_batch_name as batch, - program, academic_year, academic_term from `tabStudent Batch`''', as_dict=1) - - for student_batch in student_batches: - # create student batch name if does not exists !! - if student_batch.get("batch") and not frappe.db.exists("Student Batch Name", student_batch.get("batch")): - frappe.get_doc({ - "doctype": "Student Batch Name", - "batch_name": student_batch.get("batch") - }).insert(ignore_permissions=True) - - student_batch.update({"doctype":"Student Group", "group_based_on": "Batch"}) - doc = frappe.get_doc(student_batch) - - if frappe.db.sql("SHOW COLUMNS FROM `tabStudent Batch Student` LIKE 'active'"): - cond = ", active" - else: - cond = " " - student_list = frappe.db.sql('''select student, student_name {cond} from `tabStudent Batch Student` - where parent=%s'''.format(cond=cond), (doc.student_group_name), as_dict=1) - - if student_list: - for i, student in enumerate(student_list): - student.update({"group_roll_number": i+1}) - doc.extend("students", student_list) - - instructor_list = None - if frappe.db.table_exists("Student Batch Instructor"): - instructor_list = frappe.db.sql('''select instructor, instructor_name from `tabStudent Batch Instructor` - where parent=%s''', (doc.student_group_name), as_dict=1) - if instructor_list: - doc.extend("instructors", instructor_list) - doc.save() - - # delete the student batch and child-table - if frappe.db.table_exists("Student Batch"): - frappe.delete_doc("DocType", "Student Batch", force=1) - if frappe.db.table_exists("Student Batch Student"): - frappe.delete_doc("DocType", "Student Batch Student", force=1) - if frappe.db.table_exists("Student Batch Instructor"): - frappe.delete_doc("DocType", "Student Batch Instructor", force=1) - - # delete the student batch creation tool - if frappe.db.table_exists("Student Batch Creation Tool"): - frappe.delete_doc("DocType", "Student Batch Creation Tool", force=1) - - # delete the student batch creation tool - if frappe.db.table_exists("Attendance Tool Student"): - frappe.delete_doc("DocType", "Attendance Tool Student", force=1) - - # change the student batch to student group in the student attendance - table_columns = frappe.db.get_table_columns("Student Attendance") - if "student_batch" in table_columns: - rename_field("Student Attendance", "student_batch", "student_group") diff --git a/erpnext/patches/v8_0/move_account_head_from_account_to_warehouse_for_inventory.py b/erpnext/patches/v8_0/move_account_head_from_account_to_warehouse_for_inventory.py deleted file mode 100644 index b59d81831f..0000000000 --- a/erpnext/patches/v8_0/move_account_head_from_account_to_warehouse_for_inventory.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Warehouse") - frappe.db.sql(""" - update - `tabWarehouse` - set - account = (select name from `tabAccount` - where account_type = 'Stock' and - warehouse = `tabWarehouse`.name and is_group = 0 limit 1)""") \ No newline at end of file diff --git a/erpnext/patches/v8_0/move_perpetual_inventory_setting.py b/erpnext/patches/v8_0/move_perpetual_inventory_setting.py deleted file mode 100644 index 78322d4575..0000000000 --- a/erpnext/patches/v8_0/move_perpetual_inventory_setting.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Company') - enabled = frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock") or 0 - for data in frappe.get_all('Company', fields = ["name"]): - doc = frappe.get_doc('Company', data.name) - doc.enable_perpetual_inventory = enabled - doc.db_update() \ No newline at end of file diff --git a/erpnext/patches/v8_0/rename_is_sample_item_to_allow_zero_valuation_rate.py b/erpnext/patches/v8_0/rename_is_sample_item_to_allow_zero_valuation_rate.py deleted file mode 100644 index e517df5fdb..0000000000 --- a/erpnext/patches/v8_0/rename_is_sample_item_to_allow_zero_valuation_rate.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - - doc_list = ["Purchase Invoice Item", "Stock Entry Detail", "Delivery Note Item", - "Purchase Receipt Item", "Sales Invoice Item"] - - for doctype in doc_list: - frappe.reload_doctype(doctype) - if "is_sample_item" in frappe.db.get_table_columns(doctype): - rename_field(doctype, "is_sample_item", "allow_zero_valuation_rate") \ No newline at end of file diff --git a/erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py b/erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py deleted file mode 100644 index 5ad862a436..0000000000 --- a/erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql( - """ - UPDATE `tabMaterial Request` - SET status = CASE - WHEN docstatus = 2 THEN 'Cancelled' - WHEN docstatus = 0 THEN 'Draft' - ELSE CASE - WHEN status = 'Stopped' THEN 'Stopped' - WHEN status != 'Stopped' AND per_ordered = 0 THEN 'Pending' - WHEN per_ordered < 100 AND per_ordered > 0 AND status != 'Stopped' - THEN 'Partially Ordered' - WHEN per_ordered = 100 AND material_request_type = 'Purchase' - AND status != 'Stopped' THEN 'Ordered' - WHEN per_ordered = 100 AND material_request_type = 'Material Transfer' - AND status != 'Stopped' THEN 'Transferred' - WHEN per_ordered = 100 AND material_request_type = 'Material Issue' - AND status != 'Stopped' THEN 'Issued' - END - END - """ - ) \ No newline at end of file diff --git a/erpnext/patches/v8_0/rename_total_margin_to_rate_with_margin.py b/erpnext/patches/v8_0/rename_total_margin_to_rate_with_margin.py deleted file mode 100644 index 4065438796..0000000000 --- a/erpnext/patches/v8_0/rename_total_margin_to_rate_with_margin.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from frappe.model.utils.rename_field import rename_field - -def execute(): - """ - Rename Total Margin field to Rate With Margin in - "Sales Order Item", "Sales Invoice Item", "Delivery Note Item", - "Quotation Item" - """ - - for d in ("Sales Order Item", "Sales Invoice Item", - "Delivery Note Item", "Quotation Item"): - frappe.reload_doctype(d) - rename_field_if_exists(d, "total_margin", "rate_with_margin") - - -def rename_field_if_exists(doctype, old_fieldname, new_fieldname): - try: - rename_field(doctype, old_fieldname, new_fieldname) - except Exception as e: - if e.args[0] != 1054: - raise diff --git a/erpnext/patches/v8_0/repost_reserved_qty_for_multiple_sales_uom.py b/erpnext/patches/v8_0/repost_reserved_qty_for_multiple_sales_uom.py deleted file mode 100644 index 3030b8e2f3..0000000000 --- a/erpnext/patches/v8_0/repost_reserved_qty_for_multiple_sales_uom.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty - -def execute(): - for doctype in ("Sales Order Item", "Bin"): - frappe.reload_doctype(doctype) - - repost_for = frappe.db.sql("""select distinct item_code, warehouse - from `tabSales Order Item` where docstatus=1 and uom != stock_uom and - exists(select name from tabItem where name=`tabSales Order Item`.item_code and ifnull(is_stock_item, 0)=1)""") - - for item_code, warehouse in repost_for: - update_bin_qty(item_code, warehouse, { - "reserved_qty": get_reserved_qty(item_code, warehouse) - }) \ No newline at end of file diff --git a/erpnext/patches/v8_0/revert_manufacturers_table_from_item.py b/erpnext/patches/v8_0/revert_manufacturers_table_from_item.py deleted file mode 100644 index 60cbb33b80..0000000000 --- a/erpnext/patches/v8_0/revert_manufacturers_table_from_item.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists("DocType", "Item Manufacturer"): - frappe.reload_doctype("Item") - item_manufacturers = frappe.db.sql(""" - select parent, manufacturer, manufacturer_part_no - from `tabItem Manufacturer` - """, as_dict=1) - - for im in item_manufacturers: - frappe.db.sql(""" - update tabItem - set manufacturer=%s, manufacturer_part_no=%s - where name=%s - """, (im.manufacturer, im.manufacturer_part_no, im.parent)) - - frappe.delete_doc("DocType", "Item Manufacturer") \ No newline at end of file diff --git a/erpnext/patches/v8_0/save_system_settings.py b/erpnext/patches/v8_0/save_system_settings.py deleted file mode 100644 index d479ece8a6..0000000000 --- a/erpnext/patches/v8_0/save_system_settings.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import cint - -def execute(): - """ - save system settings document - """ - - frappe.reload_doc("core", "doctype", "system_settings") - doc = frappe.get_doc("System Settings") - doc.flags.ignore_mandatory = True - - if cint(doc.currency_precision) == 0: - doc.currency_precision = '' - - doc.save(ignore_permissions=True) diff --git a/erpnext/patches/v8_0/set_null_to_serial_nos_for_disabled_sales_invoices.py b/erpnext/patches/v8_0/set_null_to_serial_nos_for_disabled_sales_invoices.py deleted file mode 100644 index 197d6ded61..0000000000 --- a/erpnext/patches/v8_0/set_null_to_serial_nos_for_disabled_sales_invoices.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty - -def execute(): - frappe.db.sql(""" - update - `tabSales Invoice Item` - set serial_no = NULL - where - parent in (select name from `tabSales Invoice` where update_stock = 0 and docstatus = 1)""") \ No newline at end of file diff --git a/erpnext/patches/v8_0/set_project_copied_from.py b/erpnext/patches/v8_0/set_project_copied_from.py deleted file mode 100644 index d4287978cf..0000000000 --- a/erpnext/patches/v8_0/set_project_copied_from.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Project") - - frappe.db.sql(''' - UPDATE `tabProject` - SET copied_from=name - WHERE copied_from is NULL - ''') \ No newline at end of file diff --git a/erpnext/patches/v8_0/set_sales_invoice_serial_number_from_delivery_note.py b/erpnext/patches/v8_0/set_sales_invoice_serial_number_from_delivery_note.py deleted file mode 100644 index 8a4ef4086b..0000000000 --- a/erpnext/patches/v8_0/set_sales_invoice_serial_number_from_delivery_note.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty - -def execute(): - """ Set the Serial Numbers in Sales Invoice Item from Delivery Note Item """ - - frappe.reload_doc("stock", "doctype", "serial_no") - - frappe.db.sql(""" update `tabSales Invoice Item` sii inner join - `tabDelivery Note Item` dni on sii.dn_detail=dni.name and sii.qty=dni.qty - set sii.serial_no=dni.serial_no where sii.parent IN (select si.name - from `tabSales Invoice` si where si.update_stock=0 and si.docstatus=1)""") - - items = frappe.db.sql(""" select sii.parent, sii.serial_no from `tabSales Invoice Item` sii - left join `tabSales Invoice` si on sii.parent=si.name - where si.docstatus=1 and si.update_stock=0""", as_dict=True) - - for item in items: - sales_invoice = item.get("parent", None) - serial_nos = item.get("serial_no", "") - - if not sales_invoice or not serial_nos: - continue - - serial_nos = ["{}".format(frappe.db.escape(no)) for no in serial_nos.split("\n")] - - frappe.db.sql(""" - UPDATE - `tabSerial No` - SET - sales_invoice={sales_invoice} - WHERE - name in ({serial_nos}) - """.format( - sales_invoice=frappe.db.escape(sales_invoice), - serial_nos=",".join(serial_nos) - ) - ) \ No newline at end of file diff --git a/erpnext/patches/v8_0/update_customer_pos_id.py b/erpnext/patches/v8_0/update_customer_pos_id.py deleted file mode 100644 index a772ae90c5..0000000000 --- a/erpnext/patches/v8_0/update_customer_pos_id.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Customer") - frappe.db.sql(""" update `tabCustomer` set customer_pos_id = name """) \ No newline at end of file diff --git a/erpnext/patches/v8_0/update_production_orders.py b/erpnext/patches/v8_0/update_production_orders.py deleted file mode 100644 index 8e993cc102..0000000000 --- a/erpnext/patches/v8_0/update_production_orders.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # reload schema - for doctype in ("Work Order", "Work Order Item", "Work Order Operation", - "BOM Item", "BOM Explosion Item", "BOM"): - frappe.reload_doctype(doctype) - - frappe.reload_doc("stock", "doctype", "item") - frappe.reload_doc("stock", "doctype", "item_default") - - # fetch all draft and submitted work orders - fields = ["name"] - if "source_warehouse" in frappe.db.get_table_columns("Work Order"): - fields.append("source_warehouse") - - wo_orders = frappe.get_all("Work Order", filters={"docstatus": ["!=", 2]}, fields=fields) - - count = 0 - for p in wo_orders: - wo_order = frappe.get_doc("Work Order", p.name) - count += 1 - - # set required items table - wo_order.set_required_items() - - for item in wo_order.get("required_items"): - # set source warehouse based on parent - if not item.source_warehouse and "source_warehouse" in fields: - item.source_warehouse = wo_order.get("source_warehouse") - item.db_update() - - if wo_order.docstatus == 1: - # update transferred qty based on Stock Entry, it also updates db - wo_order.update_transaferred_qty_for_required_items() - - # Set status where it was 'Unstopped', as it is deprecated - if wo_order.status == "Unstopped": - status = wo_order.get_status() - wo_order.db_set("status", status) - elif wo_order.status == "Stopped": - wo_order.update_reserved_qty_for_production() - - if count % 200 == 0: - frappe.db.commit() \ No newline at end of file diff --git a/erpnext/patches/v8_0/update_sales_cost_in_project.py b/erpnext/patches/v8_0/update_sales_cost_in_project.py deleted file mode 100644 index 1a29fc4db4..0000000000 --- a/erpnext/patches/v8_0/update_sales_cost_in_project.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("projects", "doctype", "project") - - frappe.db.sql(""" - update `tabProject` p - set total_sales_amount = ifnull((select sum(base_grand_total) - from `tabSales Order` where project=p.name and docstatus=1), 0) - """) \ No newline at end of file diff --git a/erpnext/patches/v8_0/update_status_as_paid_for_completed_expense_claim.py b/erpnext/patches/v8_0/update_status_as_paid_for_completed_expense_claim.py deleted file mode 100644 index 19d27b206b..0000000000 --- a/erpnext/patches/v8_0/update_status_as_paid_for_completed_expense_claim.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - """ set status as Paid in Expense Claim if total_sactioned_amount - and total_amount_reimbursed is equal """ - - frappe.reload_doctype('Expense Claim') - - frappe.db.sql(""" - update - `tabExpense Claim` - set status = 'Paid' - where - total_sanctioned_amount = total_amount_reimbursed - """) diff --git a/erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py b/erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py deleted file mode 100644 index 1f937bb8af..0000000000 --- a/erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('manufacturing', 'doctype', 'bom_item') - frappe.reload_doc('manufacturing', 'doctype', 'bom_explosion_item') - frappe.reload_doc('manufacturing', 'doctype', 'bom_scrap_item') - frappe.db.sql("update `tabBOM Item` set stock_qty = qty, uom = stock_uom, conversion_factor = 1") - frappe.db.sql("update `tabBOM Explosion Item` set stock_qty = qty") - if "qty" in frappe.db.get_table_columns("BOM Scrap Item"): - frappe.db.sql("update `tabBOM Scrap Item` set stock_qty = qty") \ No newline at end of file diff --git a/erpnext/patches/v8_0/update_stock_qty_value_in_purchase_invoice.py b/erpnext/patches/v8_0/update_stock_qty_value_in_purchase_invoice.py deleted file mode 100644 index be5cf3aed7..0000000000 --- a/erpnext/patches/v8_0/update_stock_qty_value_in_purchase_invoice.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_item') - frappe.db.sql("update `tabPurchase Invoice Item` set stock_qty = qty, stock_uom = uom") \ No newline at end of file diff --git a/erpnext/patches/v8_0/update_student_groups_from_student_batches.py b/erpnext/patches/v8_0/update_student_groups_from_student_batches.py deleted file mode 100644 index ae24fe4a14..0000000000 --- a/erpnext/patches/v8_0/update_student_groups_from_student_batches.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import * -from frappe.model.mapper import get_mapped_doc - - -def execute(): - if frappe.db.table_exists("Student Batch"): - student_batches = frappe.db.sql('''select name from `tabStudent Batch`''', as_dict=1) - - for student_batch in student_batches: - if frappe.db.exists("Student Group", student_batch.get("name")): - student_group = frappe.get_doc("Student Group", student_batch.get("name")) - - if frappe.db.table_exists("Student Batch Student"): - current_student_list = frappe.db.sql_list('''select student from `tabStudent Group Student` - where parent=%s''', (student_group.name)) - batch_student_list = frappe.db.sql_list('''select student from `tabStudent Batch Student` - where parent=%s''', (student_group.name)) - - student_list = list(set(batch_student_list)-set(current_student_list)) - if student_list: - student_group.extend("students", [{"student":d} for d in student_list]) - - if frappe.db.table_exists("Student Batch Instructor"): - current_instructor_list = frappe.db.sql_list('''select instructor from `tabStudent Group Instructor` - where parent=%s''', (student_group.name)) - batch_instructor_list = frappe.db.sql_list('''select instructor from `tabStudent Batch Instructor` - where parent=%s''', (student_group.name)) - - instructor_list = list(set(batch_instructor_list)-set(current_instructor_list)) - if instructor_list: - student_group.extend("instructors", [{"instructor":d} for d in instructor_list]) - - student_group.save() diff --git a/erpnext/patches/v8_0/update_supplier_address_in_stock_entry.py b/erpnext/patches/v8_0/update_supplier_address_in_stock_entry.py deleted file mode 100644 index a2173048fd..0000000000 --- a/erpnext/patches/v8_0/update_supplier_address_in_stock_entry.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # copy supplier_address to address_display, and set supplier_address to blank - - stock_entries = frappe.db.sql(""" select name, purchase_order, supplier_address from `tabStock Entry` - where ifnull(supplier_address, '') <> ''""", as_dict=True) - - frappe.reload_doc('stock', 'doctype', 'stock_entry') - - for stock_entry in stock_entries: - # move supplier address to address_display, and fetch the supplier address from purchase order - - se = frappe.get_doc("Stock Entry", stock_entry.get("name")) - se.address_display = stock_entry.get("supplier_address") - se.supplier_address = frappe.db.get_value("Purchase Order", stock_entry.get("purchase_order"),"supplier_address") or None - - se.db_update() diff --git a/erpnext/patches/v8_1/__init__.py b/erpnext/patches/v8_1/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_1/add_hsn_sac_codes.py b/erpnext/patches/v8_1/add_hsn_sac_codes.py deleted file mode 100644 index 0fce96a8d4..0000000000 --- a/erpnext/patches/v8_1/add_hsn_sac_codes.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.regional.india.setup import setup - -def execute(): - company = frappe.get_all('Company', filters = {'country': 'India'}) - if not company: - return - - # call setup for india - setup(patch=True) \ No newline at end of file diff --git a/erpnext/patches/v8_1/add_indexes_in_transaction_doctypes.py b/erpnext/patches/v8_1/add_indexes_in_transaction_doctypes.py deleted file mode 100644 index 4631602606..0000000000 --- a/erpnext/patches/v8_1/add_indexes_in_transaction_doctypes.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for dt in ("Sales Order Item", "Purchase Order Item", - "Material Request Item", "Work Order Item", "Packed Item"): - frappe.get_doc("DocType", dt).run_module_method("on_doctype_update") \ No newline at end of file diff --git a/erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py b/erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py deleted file mode 100644 index 4c606af424..0000000000 --- a/erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - inv_copy_options = "ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nDUPLICATE FOR SUPPLIER\nTRIPLICATE FOR SUPPLIER" - - frappe.db.sql("""update `tabCustom Field` set allow_on_submit=1, options=%s - where fieldname='invoice_copy' and dt = 'Sales Invoice' - """, inv_copy_options) - - frappe.db.sql("""update `tabCustom Field` set read_only=1 - where fieldname='gst_state_number' and dt = 'Address' - """) diff --git a/erpnext/patches/v8_1/delete_deprecated_reports.py b/erpnext/patches/v8_1/delete_deprecated_reports.py deleted file mode 100644 index 3e0fdee719..0000000000 --- a/erpnext/patches/v8_1/delete_deprecated_reports.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - """ delete deprecated reports """ - - reports = [ - "Monthly Salary Register", "Customer Addresses And Contacts", - "Supplier Addresses And Contacts" - ] - - for report in reports: - if frappe.db.exists("Report", report): - check_and_update_auto_email_report(report) - frappe.db.commit() - - frappe.delete_doc("Report", report, ignore_permissions=True) - -def check_and_update_auto_email_report(report): - """ delete or update auto email report for deprecated report """ - - auto_email_report = frappe.db.get_value("Auto Email Report", {"report": report}) - if not auto_email_report: - return - - if report == "Monthly Salary Register": - frappe.delete_doc("Auto Email Report", auto_email_report) - - elif report in ["Customer Addresses And Contacts", "Supplier Addresses And Contacts"]: - frappe.db.set_value("Auto Email Report", auto_email_report, "report", report) \ No newline at end of file diff --git a/erpnext/patches/v8_1/gst_fixes.py b/erpnext/patches/v8_1/gst_fixes.py deleted file mode 100644 index 34255eb0a4..0000000000 --- a/erpnext/patches/v8_1/gst_fixes.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.custom.doctype.custom_field.custom_field import create_custom_field -from erpnext.regional.address_template.setup import set_up_address_templates - - -def execute(): - company = frappe.get_all('Company', filters = {'country': 'India'}) - if not company: - return - - update_existing_custom_fields() - add_custom_fields() - set_up_address_templates(default_country='India') - frappe.reload_doc("regional", "print_format", "gst_tax_invoice") - - -def update_existing_custom_fields(): - frappe.db.sql("""update `tabCustom Field` set label = 'HSN/SAC' - where fieldname='gst_hsn_code' and label='GST HSN Code' - """) - - frappe.db.sql("""update `tabCustom Field` set print_hide = 1 - where fieldname in ('customer_gstin', 'supplier_gstin', 'company_gstin') - """) - - frappe.db.sql("""update `tabCustom Field` set insert_after = 'address_display' - where fieldname in ('customer_gstin', 'supplier_gstin') - """) - - frappe.db.sql("""update `tabCustom Field` set insert_after = 'company_address_display' - where fieldname = 'company_gstin' - """) - - frappe.db.sql("""update `tabCustom Field` set insert_after = 'description' - where fieldname='gst_hsn_code' and dt in ('Sales Invoice Item', 'Purchase Invoice Item') - """) - - -def add_custom_fields(): - hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', - fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description') - - custom_fields = { - 'Address': [ - dict(fieldname='gst_state_number', label='GST State Number', - fieldtype='Int', insert_after='gst_state'), - ], - 'Sales Invoice': [ - dict(fieldname='invoice_copy', label='Invoice Copy', - fieldtype='Select', insert_after='project', print_hide=1, allow_on_submit=1, - options='ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nTRIPLICATE FOR SUPPLIER'), - ], - 'Sales Order Item': [hsn_sac_field], - 'Delivery Note Item': [hsn_sac_field], - 'Purchase Order Item': [hsn_sac_field], - 'Purchase Receipt Item': [hsn_sac_field] - } - - for doctype, fields in custom_fields.items(): - for df in fields: - create_custom_field(doctype, df) diff --git a/erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py b/erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py deleted file mode 100644 index 3962f8f1f2..0000000000 --- a/erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Serial No") - - frappe.db.sql(""" - update - `tabSerial No` - set - sales_invoice = NULL - where - sales_invoice in (select return_against from - `tabSales Invoice` where docstatus =1 and is_return=1) - and sales_invoice is not null and sales_invoice !='' """) \ No newline at end of file diff --git a/erpnext/patches/v8_1/removed_report_support_hours.py b/erpnext/patches/v8_1/removed_report_support_hours.py deleted file mode 100644 index 0936b2231b..0000000000 --- a/erpnext/patches/v8_1/removed_report_support_hours.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql(""" update `tabAuto Email Report` set report = %s - where name = %s""", ('Support Hour Distribution', 'Support Hours')) - - frappe.db.sql(""" update `tabCustom Role` set report = %s - where report = %s""", ('Support Hour Distribution', 'Support Hours')) - - frappe.delete_doc('Report', 'Support Hours') \ No newline at end of file diff --git a/erpnext/patches/v8_1/set_delivery_date_in_so_item.py b/erpnext/patches/v8_1/set_delivery_date_in_so_item.py deleted file mode 100644 index af2d28b857..0000000000 --- a/erpnext/patches/v8_1/set_delivery_date_in_so_item.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Sales Order") - frappe.reload_doctype("Sales Order Item") - - if "final_delivery_date" in frappe.db.get_table_columns("Sales Order"): - frappe.db.sql(""" - update `tabSales Order` - set delivery_date = final_delivery_date - where (delivery_date is null or delivery_date = '0000-00-00') - and order_type = 'Sales'""") - - frappe.db.sql(""" - update `tabSales Order` so, `tabSales Order Item` so_item - set so_item.delivery_date = so.delivery_date - where so.name = so_item.parent - and so.order_type = 'Sales' - and (so_item.delivery_date is null or so_item.delivery_date = '0000-00-00') - and (so.delivery_date is not null and so.delivery_date != '0000-00-00') - """) \ No newline at end of file diff --git a/erpnext/patches/v8_1/update_expense_claim_status.py b/erpnext/patches/v8_1/update_expense_claim_status.py deleted file mode 100644 index 4c1b85a13f..0000000000 --- a/erpnext/patches/v8_1/update_expense_claim_status.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Expense Claim') - - for data in frappe.db.sql(""" select name from `tabExpense Claim` - where (docstatus=1 and total_sanctioned_amount=0 and status = 'Paid') or - (docstatus = 1 and approval_status = 'Rejected' and total_sanctioned_amount > 0)""", as_dict=1): - doc = frappe.get_doc('Expense Claim', data.name) - if doc.approval_status == 'Rejected': - for d in doc.expenses: - d.db_set("sanctioned_amount", 0, update_modified = False) - doc.db_set("total_sanctioned_amount", 0, update_modified = False) - - frappe.db.sql(""" delete from `tabGL Entry` where voucher_type = 'Expense Claim' - and voucher_no = %s""", (doc.name)) - - doc.set_status() - doc.db_set("status", doc.status, update_modified = False) \ No newline at end of file diff --git a/erpnext/patches/v8_1/update_gst_state.py b/erpnext/patches/v8_1/update_gst_state.py deleted file mode 100644 index 7aaf2d5ff3..0000000000 --- a/erpnext/patches/v8_1/update_gst_state.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.regional.india import states - -def execute(): - company = frappe.get_all('Company', filters = {'country': 'India'}) - if not company: - return - - if not frappe.db.get_value("Custom Field", filters={'fieldname':'gst_state'}): - return - - frappe.db.sql("update `tabCustom Field` set options=%s where fieldname='gst_state'", '\n'.join(states)) - frappe.db.sql("update `tabAddress` set gst_state='Chhattisgarh' where gst_state='Chattisgarh'") - frappe.db.sql("update `tabAddress` set gst_state_number='05' where gst_state='Uttarakhand'") diff --git a/erpnext/patches/v8_10/__init__.py b/erpnext/patches/v8_10/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_10/change_default_customer_credit_days.py b/erpnext/patches/v8_10/change_default_customer_credit_days.py deleted file mode 100644 index 992be17da0..0000000000 --- a/erpnext/patches/v8_10/change_default_customer_credit_days.py +++ /dev/null @@ -1,89 +0,0 @@ -from __future__ import unicode_literals -import frappe - - -def execute(): - frappe.reload_doc("selling", "doctype", "customer") - frappe.reload_doc("buying", "doctype", "supplier") - frappe.reload_doc("setup", "doctype", "supplier_type") - frappe.reload_doc("accounts", "doctype", "payment_term") - frappe.reload_doc("accounts", "doctype", "payment_terms_template_detail") - frappe.reload_doc("accounts", "doctype", "payment_terms_template") - - payment_terms = [] - records = [] - for doctype in ("Customer", "Supplier", "Supplier Type"): - credit_days = frappe.db.sql(""" - SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name` - from `tab{0}` - where - ((credit_days_based_on='Fixed Days' or credit_days_based_on is null) - and credit_days is not null) - or credit_days_based_on='Last Day of the Next Month' - """.format(doctype)) - - credit_records = ((record[0], record[1], record[2]) for record in credit_days) - for days, based_on, party_name in credit_records: - if based_on == "Fixed Days": - pyt_template_name = 'Default Payment Term - N{0}'.format(days) - else: - pyt_template_name = 'Default Payment Term - EO2M' - - if not frappe.db.exists("Payment Terms Template", pyt_template_name): - payment_term = make_payment_term(days, based_on) - template = make_template(payment_term) - else: - template = frappe.get_doc("Payment Terms Template", pyt_template_name) - - payment_terms.append('WHEN `name`={0} THEN {1}'.format(frappe.db.escape(party_name), template.template_name)) - records.append(frappe.db.escape(party_name)) - - begin_query_str = "UPDATE `tab{0}` SET `payment_terms` = CASE ".format(doctype) - value_query_str = " ".join(payment_terms) - cond_query_str = " ELSE `payment_terms` END WHERE " - - if records: - frappe.db.sql( - begin_query_str + value_query_str + cond_query_str + '`name` IN %s', - (records,) - ) - - -def make_template(payment_term): - doc = frappe.new_doc('Payment Terms Template Detail') - doc.payment_term = payment_term.payment_term_name - doc.due_date_based_on = payment_term.due_date_based_on - doc.invoice_portion = payment_term.invoice_portion - doc.description = payment_term.description - doc.credit_days = payment_term.credit_days - doc.credit_months = payment_term.credit_months - - template = frappe.new_doc('Payment Terms Template') - template.template_name = 'Default Payment Term - {0}'.format(payment_term.payment_term_name) - template.append('terms', doc) - template.save() - - return template - - -def make_payment_term(days, based_on): - based_on_map = { - 'Fixed Days': 'Day(s) after invoice date', - 'Last Day of the Next Month': 'Month(s) after the end of the invoice month' - } - - doc = frappe.new_doc('Payment Term') - doc.due_date_based_on = based_on_map.get(based_on) - doc.invoice_portion = 100 - - if based_on == 'Fixed Days': - doc.credit_days = days - doc.description = 'Net payable within {0} days'.format(days) - doc.payment_term_name = 'N{0}'.format(days) - else: - doc.credit_months = 1 - doc.description = 'Net payable by the end of next month' - doc.payment_term_name = 'EO2M' - - doc.save() - return doc diff --git a/erpnext/patches/v8_3/__init__.py b/erpnext/patches/v8_3/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py b/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py deleted file mode 100644 index 6c4c6d5bd8..0000000000 --- a/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - """ set the restrict to domain in module def """ - pass \ No newline at end of file diff --git a/erpnext/patches/v8_3/update_company_total_sales.py b/erpnext/patches/v8_3/update_company_total_sales.py deleted file mode 100644 index 78efecb387..0000000000 --- a/erpnext/patches/v8_3/update_company_total_sales.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from erpnext.setup.doctype.company.company import update_company_current_month_sales, update_company_monthly_sales - -def execute(): - '''Update company monthly sales history based on sales invoices''' - frappe.reload_doctype("Company") - companies = [d['name'] for d in frappe.get_list("Company")] - - for company in companies: - update_company_current_month_sales(company) - update_company_monthly_sales(company) diff --git a/erpnext/patches/v8_4/__init__.py b/erpnext/patches/v8_4/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v8_4/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v8_4/make_scorecard_records.py b/erpnext/patches/v8_4/make_scorecard_records.py deleted file mode 100644 index 73afa277b4..0000000000 --- a/erpnext/patches/v8_4/make_scorecard_records.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records -def execute(): - frappe.reload_doc('buying', 'doctype', 'supplier_scorecard_variable') - frappe.reload_doc('buying', 'doctype', 'supplier_scorecard_standing') - make_default_records() \ No newline at end of file diff --git a/erpnext/patches/v8_5/__init__.py b/erpnext/patches/v8_5/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_5/fix_tax_breakup_for_non_invoice_docs.py b/erpnext/patches/v8_5/fix_tax_breakup_for_non_invoice_docs.py deleted file mode 100644 index 82beba3770..0000000000 --- a/erpnext/patches/v8_5/fix_tax_breakup_for_non_invoice_docs.py +++ /dev/null @@ -1,48 +0,0 @@ -from __future__ import unicode_literals -import frappe -from erpnext.regional.india.setup import make_custom_fields -from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html - -def execute(): - companies = [d.name for d in frappe.get_all('Company', filters = {'country': 'India'})] - if not companies: - return - - make_custom_fields() - - # update invoice copy value - values = ["Original for Recipient", "Duplicate for Transporter", - "Duplicate for Supplier", "Triplicate for Supplier"] - for d in values: - frappe.db.sql("update `tabSales Invoice` set invoice_copy=%s where invoice_copy=%s", (d, d)) - - # update tax breakup in transactions made after 1st July 2017 - doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", - "Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"] - - for doctype in doctypes: - frappe.reload_doctype(doctype) - - date_field = "posting_date" - if doctype in ["Quotation", "Sales Order", "Supplier Quotation", "Purchase Order"]: - date_field = "transaction_date" - - records = [d.name for d in frappe.get_all(doctype, filters={ - "docstatus": ["!=", 2], - date_field: [">=", "2017-07-01"], - "company": ["in", companies], - "total_taxes_and_charges": [">", 0], - "other_charges_calculation": "" - })] - if records: - frappe.db.sql(""" - update `tab%s Item` dt_item - set gst_hsn_code = (select gst_hsn_code from tabItem where name=dt_item.item_code) - where parent in (%s) - and (gst_hsn_code is null or gst_hsn_code = '') - """ % (doctype, ', '.join(['%s']*len(records))), tuple(records)) - - for record in records: - doc = frappe.get_doc(doctype, record) - html = get_itemised_tax_breakup_html(doc) - doc.db_set("other_charges_calculation", html, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v8_5/remove_project_type_property_setter.py b/erpnext/patches/v8_5/remove_project_type_property_setter.py deleted file mode 100644 index 70a08f5377..0000000000 --- a/erpnext/patches/v8_5/remove_project_type_property_setter.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - ps = frappe.db.get_value('Property Setter', dict(doc_type='Project', field_name='project_type', - property='options')) - if ps: - frappe.delete_doc('Property Setter', ps) - - project_types = frappe.db.sql_list('select distinct project_type from tabProject') - - for project_type in project_types: - if project_type and not frappe.db.exists("Project Type", project_type): - p_type = frappe.get_doc({ - "doctype": "Project Type", - "project_type": project_type - }) - p_type.insert() \ No newline at end of file diff --git a/erpnext/patches/v8_5/remove_quotations_route_in_sidebar.py b/erpnext/patches/v8_5/remove_quotations_route_in_sidebar.py deleted file mode 100644 index 2d7df4a179..0000000000 --- a/erpnext/patches/v8_5/remove_quotations_route_in_sidebar.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Portal Settings") - - frappe.db.sql(""" - delete from - `tabPortal Menu Item` - where - (route = '/quotations' and title = 'Supplier Quotation') - or (route = '/quotation' and title = 'Quotations') - """) \ No newline at end of file diff --git a/erpnext/patches/v8_5/set_default_mode_of_payment.py b/erpnext/patches/v8_5/set_default_mode_of_payment.py deleted file mode 100644 index 34ecbb0a3c..0000000000 --- a/erpnext/patches/v8_5/set_default_mode_of_payment.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("POS Profile") - frappe.reload_doctype("Sales Invoice Payment") - - frappe.db.sql(""" - update - `tabSales Invoice Payment` - set `tabSales Invoice Payment`.default = 1 - where - `tabSales Invoice Payment`.parenttype = 'POS Profile' - and `tabSales Invoice Payment`.idx=1""") \ No newline at end of file diff --git a/erpnext/patches/v8_5/update_customer_group_in_POS_profile.py b/erpnext/patches/v8_5/update_customer_group_in_POS_profile.py deleted file mode 100644 index 2661914401..0000000000 --- a/erpnext/patches/v8_5/update_customer_group_in_POS_profile.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('POS Profile') - customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group') - if customer_group: - frappe.db.sql(""" update `tabPOS Profile` - set customer_group = %s where customer_group is null """, (customer_group)) \ No newline at end of file diff --git a/erpnext/patches/v8_5/update_existing_data_in_project_type.py b/erpnext/patches/v8_5/update_existing_data_in_project_type.py deleted file mode 100644 index 497da0602e..0000000000 --- a/erpnext/patches/v8_5/update_existing_data_in_project_type.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("projects", "doctype", "project_type") - frappe.reload_doc("projects", "doctype", "project") - - project_types = ["Internal", "External", "Other"] - - for project_type in project_types: - if not frappe.db.exists("Project Type", project_type): - p_type = frappe.get_doc({ - "doctype": "Project Type", - "project_type": project_type - }) - p_type.insert() \ No newline at end of file diff --git a/erpnext/patches/v8_6/__init__.py b/erpnext/patches/v8_6/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_6/point_sms_doctype_module_to_frappe_core.py b/erpnext/patches/v8_6/point_sms_doctype_module_to_frappe_core.py deleted file mode 100644 index 014a74abe3..0000000000 --- a/erpnext/patches/v8_6/point_sms_doctype_module_to_frappe_core.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql('''UPDATE `tabDocType` SET module="Core" - WHERE name IN ("SMS Parameter", "SMS Settings");''') \ No newline at end of file diff --git a/erpnext/patches/v8_6/rename_bom_update_tool.py b/erpnext/patches/v8_6/rename_bom_update_tool.py deleted file mode 100644 index ef5f335e45..0000000000 --- a/erpnext/patches/v8_6/rename_bom_update_tool.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.delete_doc_if_exists("DocType", "BOM Replace Tool") - - frappe.reload_doctype("BOM") - frappe.db.sql("update tabBOM set conversion_rate=1 where conversion_rate is null or conversion_rate=0") - frappe.db.sql("update tabBOM set set_rate_of_sub_assembly_item_based_on_bom=1") \ No newline at end of file diff --git a/erpnext/patches/v8_6/set_write_permission_for_quotation_for_sales_manager.py b/erpnext/patches/v8_6/set_write_permission_for_quotation_for_sales_manager.py deleted file mode 100644 index db4f94748e..0000000000 --- a/erpnext/patches/v8_6/set_write_permission_for_quotation_for_sales_manager.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # Set write permission to permlevel 1 for sales manager role in Quotation doctype - frappe.db.sql(""" update `tabCustom DocPerm` set `tabCustom DocPerm`.write = 1 - where `tabCustom DocPerm`.parent = 'Quotation' and `tabCustom DocPerm`.role = 'Sales Manager' - and `tabCustom DocPerm`.permlevel = 1 """) \ No newline at end of file diff --git a/erpnext/patches/v8_6/update_timesheet_company_from_PO.py b/erpnext/patches/v8_6/update_timesheet_company_from_PO.py deleted file mode 100644 index 2d46bee7ca..0000000000 --- a/erpnext/patches/v8_6/update_timesheet_company_from_PO.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Timesheet') - company = frappe.get_all('Company') - - #Check more than one company exists - if len(company) > 1: - frappe.db.sql(""" update `tabTimesheet` set `tabTimesheet`.company = - (select company from `tabWork Order` where name = `tabTimesheet`.work_order) - where workn_order is not null and work_order !=''""") \ No newline at end of file diff --git a/erpnext/patches/v8_7/__init__.py b/erpnext/patches/v8_7/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_7/fix_purchase_receipt_status.py b/erpnext/patches/v8_7/fix_purchase_receipt_status.py deleted file mode 100644 index 99ecb44214..0000000000 --- a/erpnext/patches/v8_7/fix_purchase_receipt_status.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - # there is no more status called "Submitted", there was an old issue that used - # to set it as Submitted, fixed in this commit - frappe.db.sql(""" - update - `tabPurchase Receipt` - set - status = 'To Bill' - where - status = 'Submitted'""") \ No newline at end of file diff --git a/erpnext/patches/v8_7/make_subscription_from_recurring_data.py b/erpnext/patches/v8_7/make_subscription_from_recurring_data.py deleted file mode 100644 index 2932749116..0000000000 --- a/erpnext/patches/v8_7/make_subscription_from_recurring_data.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe.utils import today - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'subscription') - frappe.reload_doc('selling', 'doctype', 'sales_order') - frappe.reload_doc('selling', 'doctype', 'quotation') - frappe.reload_doc('buying', 'doctype', 'purchase_order') - frappe.reload_doc('buying', 'doctype', 'supplier_quotation') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice') - frappe.reload_doc('accounts', 'doctype', 'purchase_invoice') - frappe.reload_doc('stock', 'doctype', 'purchase_receipt') - frappe.reload_doc('stock', 'doctype', 'delivery_note') - frappe.reload_doc('accounts', 'doctype', 'journal_entry') - frappe.reload_doc('accounts', 'doctype', 'payment_entry') - - for doctype in ['Sales Order', 'Sales Invoice', 'Purchase Order', 'Purchase Invoice']: - date_field = "transaction_date" - if doctype in ("Sales Invoice", "Purchase Invoice"): - date_field = "posting_date" - - for data in get_data(doctype, date_field): - make_subscription(doctype, data, date_field) - -def get_data(doctype, date_field): - return frappe.db.sql(""" select name, from_date, end_date, recurring_type, recurring_id, - next_date, notify_by_email, notification_email_address, recurring_print_format, - repeat_on_day_of_month, submit_on_creation, docstatus, {0} - from `tab{1}` where is_recurring = 1 and next_date >= %s and docstatus < 2 - order by next_date desc - """.format(date_field, doctype), today(), as_dict=1) - -def make_subscription(doctype, data, date_field): - if data.name == data.recurring_id: - start_date = data.get(date_field) - else: - start_date = frappe.db.get_value(doctype, data.recurring_id, date_field) - - doc = frappe.get_doc({ - 'doctype': 'Subscription', - 'reference_doctype': doctype, - 'reference_document': data.recurring_id, - 'start_date': start_date, - 'end_date': data.end_date, - 'frequency': data.recurring_type, - 'repeat_on_day': data.repeat_on_day_of_month, - 'notify_by_email': data.notify_by_email, - 'recipients': data.notification_email_address, - 'next_schedule_date': data.next_date, - 'submit_on_creation': data.submit_on_creation - }).insert(ignore_permissions=True) - - if data.docstatus == 1: - doc.submit() \ No newline at end of file diff --git a/erpnext/patches/v8_8/__init__.py b/erpnext/patches/v8_8/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v8_8/add_new_fields_in_accounts_settings.py b/erpnext/patches/v8_8/add_new_fields_in_accounts_settings.py deleted file mode 100644 index bd25f15d78..0000000000 --- a/erpnext/patches/v8_8/add_new_fields_in_accounts_settings.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - - -def execute(): - frappe.db.sql( - "INSERT INTO `tabSingles` (`doctype`, `field`, `value`) VALUES ('Accounts Settings', 'allow_stale', '1'), " - "('Accounts Settings', 'stale_days', '1')" - ) diff --git a/erpnext/patches/v8_8/set_bom_rate_as_per_uom.py b/erpnext/patches/v8_8/set_bom_rate_as_per_uom.py deleted file mode 100644 index 5b169cdff2..0000000000 --- a/erpnext/patches/v8_8/set_bom_rate_as_per_uom.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.db.sql(""" - update `tabBOM Item` - set rate = rate * conversion_factor - where uom != stock_uom and docstatus < 2 - and conversion_factor not in (0, 1) - """) \ No newline at end of file diff --git a/erpnext/patches/v8_9/__init__.py b/erpnext/patches/v8_9/__init__.py deleted file mode 100644 index 8b13789179..0000000000 --- a/erpnext/patches/v8_9/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/erpnext/patches/v8_9/add_setup_progress_actions.py b/erpnext/patches/v8_9/add_setup_progress_actions.py deleted file mode 100644 index 77501073cf..0000000000 --- a/erpnext/patches/v8_9/add_setup_progress_actions.py +++ /dev/null @@ -1,47 +0,0 @@ - -from __future__ import unicode_literals -import frappe -from frappe import _ - -def execute(): - """Add setup progress actions""" - if not frappe.db.exists('DocType', 'Setup Progress') or not frappe.db.exists('DocType', 'Setup Progress Action'): - return - - frappe.reload_doc("setup", "doctype", "setup_progress") - frappe.reload_doc("setup", "doctype", "setup_progress_action") - - actions = [ - {"action_name": "Add Company", "action_doctype": "Company", "min_doc_count": 1, "is_completed": 1, - "domains": '[]' }, - {"action_name": "Set Sales Target", "action_doctype": "Company", "min_doc_count": 99, - "action_document": frappe.defaults.get_defaults().get("company") or '', - "action_field": "monthly_sales_target", "is_completed": 0, - "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' }, - {"action_name": "Add Customers", "action_doctype": "Customer", "min_doc_count": 1, "is_completed": 0, - "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' }, - {"action_name": "Add Suppliers", "action_doctype": "Supplier", "min_doc_count": 1, "is_completed": 0, - "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' }, - {"action_name": "Add Products", "action_doctype": "Item", "min_doc_count": 1, "is_completed": 0, - "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' }, - {"action_name": "Add Programs", "action_doctype": "Program", "min_doc_count": 1, "is_completed": 0, - "domains": '["Education"]' }, - {"action_name": "Add Instructors", "action_doctype": "Instructor", "min_doc_count": 1, "is_completed": 0, - "domains": '["Education"]' }, - {"action_name": "Add Courses", "action_doctype": "Course", "min_doc_count": 1, "is_completed": 0, - "domains": '["Education"]' }, - {"action_name": "Add Rooms", "action_doctype": "Room", "min_doc_count": 1, "is_completed": 0, - "domains": '["Education"]' }, - {"action_name": "Add Users", "action_doctype": "User", "min_doc_count": 4, "is_completed": 0, - "domains": '[]' }, - {"action_name": "Add Letterhead", "action_doctype": "Letter Head", "min_doc_count": 1, "is_completed": 0, - "domains": '[]' } - ] - - setup_progress = frappe.get_doc("Setup Progress", "Setup Progress") - setup_progress.actions = [] - for action in actions: - setup_progress.append("actions", action) - - setup_progress.save(ignore_permissions=True) - diff --git a/erpnext/patches/v8_9/delete_gst_doctypes_for_outside_india_accounts.py b/erpnext/patches/v8_9/delete_gst_doctypes_for_outside_india_accounts.py deleted file mode 100644 index f67af90555..0000000000 --- a/erpnext/patches/v8_9/delete_gst_doctypes_for_outside_india_accounts.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - company = frappe.get_all('Company', filters = {'country': 'India'}) - if not company: - if frappe.db.exists("DocType", "GST Settings"): - frappe.delete_doc("DocType", "GST Settings") - frappe.delete_doc("DocType", "GST HSN Code") - - for report_name in ('GST Sales Register', 'GST Purchase Register', - 'GST Itemised Sales Register', 'GST Itemised Purchase Register'): - - frappe.delete_doc('Report', report_name) \ No newline at end of file diff --git a/erpnext/patches/v8_9/remove_employee_from_salary_structure_parent.py b/erpnext/patches/v8_9/remove_employee_from_salary_structure_parent.py deleted file mode 100644 index 808ae6d527..0000000000 --- a/erpnext/patches/v8_9/remove_employee_from_salary_structure_parent.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if 'employee' in frappe.db.get_table_columns("Salary Structure"): - frappe.db.sql("alter table `tabSalary Structure` drop column employee") diff --git a/erpnext/patches/v8_9/rename_company_sales_target_field.py b/erpnext/patches/v8_9/rename_company_sales_target_field.py deleted file mode 100644 index 5433eb673e..0000000000 --- a/erpnext/patches/v8_9/rename_company_sales_target_field.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - frappe.reload_doc("setup", "doctype", "company") - if frappe.db.has_column('Company', 'sales_target'): - rename_field("Company", "sales_target", "monthly_sales_target") diff --git a/erpnext/patches/v8_9/set_default_customer_group.py b/erpnext/patches/v8_9/set_default_customer_group.py deleted file mode 100644 index cbbe09daf5..0000000000 --- a/erpnext/patches/v8_9/set_default_customer_group.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - selling_settings = frappe.get_single('Selling Settings') - selling_settings.set_default_customer_group_and_territory() - selling_settings.flags.ignore_mandatory = True - selling_settings.save() diff --git a/erpnext/patches/v8_9/set_default_fields_in_variant_settings.py b/erpnext/patches/v8_9/set_default_fields_in_variant_settings.py deleted file mode 100644 index a550d093fa..0000000000 --- a/erpnext/patches/v8_9/set_default_fields_in_variant_settings.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('stock', 'doctype', 'item_variant_settings') - frappe.reload_doc('stock', 'doctype', 'variant_field') - - doc = frappe.get_doc('Item Variant Settings') - doc.set_default_fields() - doc.save() \ No newline at end of file diff --git a/erpnext/patches/v8_9/set_member_party_type.py b/erpnext/patches/v8_9/set_member_party_type.py deleted file mode 100644 index 33bbc11a93..0000000000 --- a/erpnext/patches/v8_9/set_member_party_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if not frappe.db.exists("Party Type", "Member"): - frappe.reload_doc("non_profit", "doctype", "member") - party = frappe.new_doc("Party Type") - party.party_type = "Member" - party.save() diff --git a/erpnext/patches/v8_9/set_print_zero_amount_taxes.py b/erpnext/patches/v8_9/set_print_zero_amount_taxes.py deleted file mode 100644 index 3c508eaa09..0000000000 --- a/erpnext/patches/v8_9/set_print_zero_amount_taxes.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from erpnext.setup.install import create_print_zero_amount_taxes_custom_field - -def execute(): - frappe.reload_doc('printing', 'doctype', 'print_style') - frappe.reload_doc('printing', 'doctype', 'print_settings') - create_print_zero_amount_taxes_custom_field() \ No newline at end of file diff --git a/erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py b/erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py deleted file mode 100644 index 24e20409c1..0000000000 --- a/erpnext/patches/v8_9/update_billing_gstin_for_indian_account.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - company = frappe.get_all('Company', filters = {'country': 'India'}) - - if company: - for doctype in ['Sales Invoice', 'Delivery Note']: - frappe.db.sql(""" update `tab{0}` - set billing_address_gstin = (select gstin from `tabAddress` - where name = customer_address) - where customer_address is not null and customer_address != ''""".format(doctype)) \ No newline at end of file diff --git a/erpnext/patches/v9_0/__init__.py b/erpnext/patches/v9_0/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/erpnext/patches/v9_0/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v9_0/add_healthcare_domain.py b/erpnext/patches/v9_0/add_healthcare_domain.py deleted file mode 100644 index 3c0433b9d4..0000000000 --- a/erpnext/patches/v9_0/add_healthcare_domain.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - domain = 'Healthcare' - if not frappe.db.exists('Domain', domain): - frappe.get_doc({ - 'doctype': 'Domain', - 'domain': domain - }).insert(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py deleted file mode 100644 index 8a8c8064dd..0000000000 --- a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.table_exists("POS Profile User"): - frappe.reload_doc('accounts', 'doctype', 'pos_profile_user') - - frappe.db.sql(""" update `tabPOS Profile User`, - (select `tabPOS Profile User`.name from `tabPOS Profile User`, `tabPOS Profile` - where `tabPOS Profile`.name = `tabPOS Profile User`.parent - group by `tabPOS Profile User`.user, `tabPOS Profile`.company) as pfu - set - `tabPOS Profile User`.default = 1 - where `tabPOS Profile User`.name = pfu.name""") - else: - doctype = 'POS Profile' - frappe.reload_doc('accounts', 'doctype', doctype) - frappe.reload_doc('accounts', 'doctype', 'pos_profile_user') - frappe.reload_doc('accounts', 'doctype', 'pos_item_group') - frappe.reload_doc('accounts', 'doctype', 'pos_customer_group') - - for doc in frappe.get_all(doctype): - _doc = frappe.get_doc(doctype, doc.name) - user = frappe.db.get_value(doctype, doc.name, 'user') - - if not user: continue - - _doc.append('applicable_for_users', { - 'user': user, - 'default': 1 - }) - - _doc.flags.ignore_validate = True - _doc.flags.ignore_mandatory = True - _doc.save() \ No newline at end of file diff --git a/erpnext/patches/v9_0/copy_old_fees_field_data.py b/erpnext/patches/v9_0/copy_old_fees_field_data.py deleted file mode 100644 index 14278209c7..0000000000 --- a/erpnext/patches/v9_0/copy_old_fees_field_data.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # 'Schools' module changed to the 'Education' - # frappe.reload_doc("schools", "doctype", "fees") - frappe.reload_doc("education", "doctype", "fees") - - if "total_amount" not in frappe.db.get_table_columns("Fees"): - return - - frappe.db.sql("""update tabFees set grand_total=total_amount where grand_total = 0.0""") \ No newline at end of file diff --git a/erpnext/patches/v9_0/remove_non_existing_warehouse_from_stock_settings.py b/erpnext/patches/v9_0/remove_non_existing_warehouse_from_stock_settings.py deleted file mode 100644 index c685bbc681..0000000000 --- a/erpnext/patches/v9_0/remove_non_existing_warehouse_from_stock_settings.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - default_warehouse = frappe.db.get_value("Stock Settings", None, "default_warehouse") - if default_warehouse: - if not frappe.db.get_value("Warehouse", {"name": default_warehouse}): - frappe.db.set_value("Stock Settings", None, "default_warehouse", "") \ No newline at end of file diff --git a/erpnext/patches/v9_0/remove_subscription_module.py b/erpnext/patches/v9_0/remove_subscription_module.py deleted file mode 100644 index 493873f3e8..0000000000 --- a/erpnext/patches/v9_0/remove_subscription_module.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists('Module Def', 'Subscription'): - frappe.db.sql(""" delete from `tabModule Def` where name = 'Subscription'""") \ No newline at end of file diff --git a/erpnext/patches/v9_0/revert_manufacturing_user_role.py b/erpnext/patches/v9_0/revert_manufacturing_user_role.py deleted file mode 100644 index f38b7f29ce..0000000000 --- a/erpnext/patches/v9_0/revert_manufacturing_user_role.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if 'Manufacturing' in frappe.get_active_domains(): return - - role = 'Manufacturing User' - frappe.db.set_value('Role', role, 'restrict_to_domain', '') - frappe.db.set_value('Role', role, 'disabled', 0) - - users = frappe.get_all('Has Role', filters = { - 'parenttype': 'User', - 'role': ('in', ['System Manager', 'Manufacturing Manager']) - }, fields=['parent'], as_list=1) - - for user in users: - _user = frappe.get_doc('User', user[0]) - _user.append('roles', { - 'role': role - }) - _user.flags.ignore_validate = True - _user.save() diff --git a/erpnext/patches/v9_0/set_pos_profile_name.py b/erpnext/patches/v9_0/set_pos_profile_name.py deleted file mode 100644 index a3a9735215..0000000000 --- a/erpnext/patches/v9_0/set_pos_profile_name.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - doctype = 'POS Profile' - frappe.reload_doctype(doctype) - - for pos in frappe.get_all(doctype, filters={'disabled': 0}): - doc = frappe.get_doc(doctype, pos.name) - - if not doc.user: continue - - try: - pos_profile_name = doc.user + ' - ' + doc.company - doc.flags.ignore_validate = True - doc.flags.ignore_mandatory = True - doc.save() - - frappe.rename_doc(doctype, doc.name, pos_profile_name, force=True) - except frappe.LinkValidationError: - frappe.db.set_value("POS Profile", doc.name, 'disabled', 1) diff --git a/erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py b/erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py deleted file mode 100644 index 3d012978fa..0000000000 --- a/erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - for doctype in ("Material Request", "Purchase Order"): - frappe.reload_doctype(doctype) - frappe.reload_doctype(doctype + " Item") - - if not frappe.db.has_column(doctype, "schedule_date"): - continue - - #Update only submitted MR - for record in frappe.get_all(doctype, filters= [["docstatus", "=", 1]], fields=["name"]): - doc = frappe.get_doc(doctype, record) - if doc.items: - if not doc.schedule_date: - schedule_dates = [d.schedule_date for d in doc.items if d.schedule_date] - if len(schedule_dates) > 0: - min_schedule_date = min(schedule_dates) - frappe.db.set_value(doctype, record, - "schedule_date", min_schedule_date, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v9_0/set_shipping_type_for_existing_shipping_rules.py b/erpnext/patches/v9_0/set_shipping_type_for_existing_shipping_rules.py deleted file mode 100644 index 5092695b7d..0000000000 --- a/erpnext/patches/v9_0/set_shipping_type_for_existing_shipping_rules.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype("Shipping Rule") - - # default "calculate_based_on" - frappe.db.sql('''update `tabShipping Rule` - set calculate_based_on = "Net Weight" - where ifnull(calculate_based_on, '') = '' ''') - - # default "shipping_rule_type" - frappe.db.sql('''update `tabShipping Rule` - set shipping_rule_type = "Selling" - where ifnull(shipping_rule_type, '') = '' ''') diff --git a/erpnext/patches/v9_0/set_uoms_in_variant_field.py b/erpnext/patches/v9_0/set_uoms_in_variant_field.py deleted file mode 100644 index 9e783d99be..0000000000 --- a/erpnext/patches/v9_0/set_uoms_in_variant_field.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals -import frappe - - -def execute(): - doc = frappe.get_doc('Item Variant Settings') - variant_field_names = [vf.field_name for vf in doc.fields] - if 'uoms' not in variant_field_names: - doc.append( - 'fields', { - 'field_name': 'uoms' - } - ) - doc.save() diff --git a/erpnext/patches/v9_0/set_variant_item_description.py b/erpnext/patches/v9_0/set_variant_item_description.py deleted file mode 100644 index 82d6148508..0000000000 --- a/erpnext/patches/v9_0/set_variant_item_description.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import cstr - -def execute(): - ''' - Issue: - While copying data from template item to variant item, - the system appending description multiple times to the respective variant. - - Purpose: - Check variant description, - if variant have user defined description remove all system appended descriptions - else replace multiple system generated descriptions with single description - - Steps: - 1. Get all variant items - 2. Create system generated variant description - 3. If variant have user defined description, remove all system generated descriptions - 4. If variant description only contains system generated description, - replace multiple descriptions by new description. - ''' - for item in frappe.db.sql(""" select name from tabItem - where ifnull(variant_of, '') != '' """,as_dict=1): - variant = frappe.get_doc("Item", item.name) - temp_variant_description = '\n' - - if variant.attributes: - for d in variant.attributes: - temp_variant_description += "
" + d.attribute + ": " + cstr(d.attribute_value) + "
" - - variant_description = variant.description.replace(temp_variant_description, '').rstrip() - if variant_description: - splitted_desc = variant.description.strip().split(temp_variant_description) - - if len(splitted_desc) > 2: - if splitted_desc[0] == '': - variant_description = temp_variant_description + variant_description - elif splitted_desc[1] == '' or splitted_desc[1] == '\n': - variant_description += temp_variant_description - variant.db_set('description', variant_description, update_modified=False) - else: - variant.db_set('description', variant_description, update_modified=False) - - else: - variant.db_set('description', temp_variant_description, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v9_0/student_admission_childtable_migrate.py b/erpnext/patches/v9_0/student_admission_childtable_migrate.py deleted file mode 100644 index a5712c76dc..0000000000 --- a/erpnext/patches/v9_0/student_admission_childtable_migrate.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # 'Schools' module changed to the 'Education' - # frappe.reload_doc('schools', 'doctype', 'Student Admission Program') - # frappe.reload_doc('schools', 'doctype', 'student_admission') - frappe.reload_doc('education', 'doctype', 'Student Admission Program') - frappe.reload_doc('education', 'doctype', 'student_admission') - - if "program" not in frappe.db.get_table_columns("Student Admission"): - return - - student_admissions = frappe.get_all("Student Admission", fields=["name", "application_fee", \ - "naming_series_for_student_applicant", "program", "introduction", "eligibility"]) - for student_admission in student_admissions: - doc = frappe.get_doc("Student Admission", student_admission.name) - doc.append("program_details", { - "program": student_admission.get("program"), - "application_fee": student_admission.get("application_fee"), - "applicant_naming_series": student_admission.get("naming_series_for_student_applicant"), - }) - if student_admission.eligibility and student_admission.introduction: - doc.introduction = student_admission.introduction + "
" + \ - student_admission.eligibility + "
" - doc.flags.ignore_validate = True - doc.flags.ignore_mandatory = True - doc.save() diff --git a/erpnext/patches/v9_0/update_employee_loan_details.py b/erpnext/patches/v9_0/update_employee_loan_details.py deleted file mode 100644 index ef8d32855f..0000000000 --- a/erpnext/patches/v9_0/update_employee_loan_details.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc('Payroll', 'doctype', 'salary_slip_loan') - frappe.reload_doc('Payroll', 'doctype', 'salary_slip') - - for data in frappe.db.sql(""" select name, - start_date, end_date, total_loan_repayment - from - `tabSalary Slip` - where - docstatus < 2 and ifnull(total_loan_repayment, 0) > 0""", as_dict=1): - salary_slip = frappe.get_doc('Salary Slip', data.name) - salary_slip.set_loan_repayment() - - if salary_slip.total_loan_repayment == data.total_loan_repayment: - for row in salary_slip.loans: - row.db_update() - - salary_slip.db_update() diff --git a/erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py b/erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py deleted file mode 100644 index 45610ed5a7..0000000000 --- a/erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doctype('Material Request') - frappe.reload_doctype('Material Request Item') - - frappe.db.sql(""" update `tabMaterial Request Item` - set stock_uom = uom, stock_qty = qty, conversion_factor = 1.0""") \ No newline at end of file diff --git a/erpnext/patches/v9_1/__init__.py b/erpnext/patches/v9_1/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v9_1/create_issue_opportunity_type.py b/erpnext/patches/v9_1/create_issue_opportunity_type.py deleted file mode 100644 index aa8bbd1e79..0000000000 --- a/erpnext/patches/v9_1/create_issue_opportunity_type.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2017, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe -from frappe import _ - -def execute(): - # delete custom field if exists - for doctype, fieldname in (('Issue', 'issue_type'), ('Opportunity', 'opportunity_type')): - custom_field = frappe.db.get_value("Custom Field", {"fieldname": fieldname, 'dt': doctype}) - if custom_field: - frappe.delete_doc("Custom Field", custom_field, ignore_permissions=True) - - frappe.reload_doc('support', 'doctype', 'issue_type') - frappe.reload_doc('support', 'doctype', 'issue') - frappe.reload_doc('crm', 'doctype', 'opportunity_type') - frappe.reload_doc('crm', 'doctype', 'opportunity') - - # rename enquiry_type -> opportunity_type - from frappe.model.utils.rename_field import rename_field - rename_field('Opportunity', 'enquiry_type', 'opportunity_type') - - # create values if already set - for opts in (('Issue', 'issue_type', 'Issue Type'), - ('Opportunity', 'opportunity_type', 'Opportunity Type')): - for d in frappe.db.sql('select distinct {0} from `tab{1}`'.format(opts[1], opts[0])): - if d[0] and not frappe.db.exists(opts[2], d[0]): - frappe.get_doc(dict(doctype = opts[2], name=d[0])).insert() - - # fixtures - for name in ('Hub', _('Sales'), _('Support'), _('Maintenance')): - if not frappe.db.exists('Opportunity Type', name): - frappe.get_doc(dict(doctype = 'Opportunity Type', name=name)).insert() diff --git a/erpnext/patches/v9_2/__init__.py b/erpnext/patches/v9_2/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/patches/v9_2/delete_healthcare_domain_default_items.py b/erpnext/patches/v9_2/delete_healthcare_domain_default_items.py deleted file mode 100644 index 54ae18b8e2..0000000000 --- a/erpnext/patches/v9_2/delete_healthcare_domain_default_items.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.utils import getdate - -def execute(): - domain_settings = frappe.get_doc('Domain Settings') - active_domains = [d.domain for d in domain_settings.active_domains] - - if "Healthcare" not in active_domains: - items = ["TTT", "MCH", "LDL", "GTT", "HDL", "BILT", "BILD", "BP", "BS"] - for item_code in items: - try: - item = frappe.db.get_value("Item", {"item_code": item_code}, ["name", "creation"], as_dict=1) - if item and getdate(item.creation) >= getdate("2017-11-10"): - frappe.delete_doc("Item", item.name) - except: - pass \ No newline at end of file diff --git a/erpnext/patches/v9_2/delete_process_payroll.py b/erpnext/patches/v9_2/delete_process_payroll.py deleted file mode 100644 index 91c49f577f..0000000000 --- a/erpnext/patches/v9_2/delete_process_payroll.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.delete_doc("DocType", "Process Payroll") diff --git a/erpnext/patches/v9_2/remove_company_from_patient.py b/erpnext/patches/v9_2/remove_company_from_patient.py deleted file mode 100644 index 1a50088f23..0000000000 --- a/erpnext/patches/v9_2/remove_company_from_patient.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - if frappe.db.exists("DocType", "Patient"): - if 'company' in frappe.db.get_table_columns("Patient"): - frappe.db.sql("alter table `tabPatient` drop column company") diff --git a/erpnext/patches/v9_2/rename_net_weight_in_item_master.py b/erpnext/patches/v9_2/rename_net_weight_in_item_master.py deleted file mode 100644 index cad979deab..0000000000 --- a/erpnext/patches/v9_2/rename_net_weight_in_item_master.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe.model.utils.rename_field import rename_field - -def execute(): - frappe.reload_doc("stock", "doctype", "item") - if frappe.db.has_column('Item', 'net_weight'): - rename_field("Item", "net_weight", "weight_per_unit") diff --git a/erpnext/patches/v9_2/rename_translated_domains_in_en.py b/erpnext/patches/v9_2/rename_translated_domains_in_en.py deleted file mode 100644 index e5a9e2461f..0000000000 --- a/erpnext/patches/v9_2/rename_translated_domains_in_en.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import unicode_literals -import frappe -from frappe import _ -from frappe.model.rename_doc import rename_doc - -def execute(): - frappe.reload_doc('stock', 'doctype', 'item') - language = frappe.get_single("System Settings").language - - if language and language.startswith('en'): return - - frappe.local.lang = language - - all_domains = frappe.get_hooks("domains") - - for domain in all_domains: - translated_domain = _(domain, lang=language) - if frappe.db.exists("Domain", translated_domain): - #if domain already exists merged translated_domain and domain - merge = False - if frappe.db.exists("Domain", domain): - merge=True - - rename_doc("Domain", translated_domain, domain, ignore_permissions=True, merge=merge) - - domain_settings = frappe.get_single("Domain Settings") - active_domains = [d.domain for d in domain_settings.active_domains] - - try: - for domain in active_domains: - domain = frappe.get_doc("Domain", domain) - domain.setup_domain() - - if int(frappe.db.get_single_value('System Settings', 'setup_complete')): - domain.setup_sidebar_items() - domain.setup_desktop_icons() - domain.set_default_portal_role() - except frappe.LinkValidationError: - pass \ No newline at end of file diff --git a/erpnext/patches/v9_2/repost_reserved_qty_for_production.py b/erpnext/patches/v9_2/repost_reserved_qty_for_production.py deleted file mode 100644 index 040e655bd8..0000000000 --- a/erpnext/patches/v9_2/repost_reserved_qty_for_production.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - frappe.reload_doc("stock", "doctype", "bin") - bins = frappe.db.sql("select name from `tabBin` where reserved_qty_for_production > 0") - for d in bins: - bin_doc = frappe.get_doc("Bin", d[0]) - bin_doc.update_reserved_qty_for_production() diff --git a/erpnext/patches/v9_2/set_item_name_in_production_order.py b/erpnext/patches/v9_2/set_item_name_in_production_order.py deleted file mode 100644 index 1f490e62c8..0000000000 --- a/erpnext/patches/v9_2/set_item_name_in_production_order.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import unicode_literals -import frappe - -def execute(): - - frappe.db.sql(""" - update `tabBOM Item` bom, `tabWork Order Item` po_item - set po_item.item_name = bom.item_name, - po_item.description = bom.description - where po_item.item_code = bom.item_code - and (po_item.item_name is null or po_item.description is null) - """) From 3dfbfe87e9e67a3605cf6f92c05a63455fd1bff1 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 4 Jun 2021 11:47:09 +0530 Subject: [PATCH 174/180] chore: Drop < v10 patches from list v7 backup was restored and upgraded to latest v10.x.x branch. The patches run uptil the upgrade are removed in this change. This means only existing v10 sites are allowed direct upgrade to v13 and newer There are older version patches still left since they're being used in later ERPNext versions too. --- erpnext/patches.txt | 495 -------------------------------------------- 1 file changed, 495 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 93689a0ef3..ed6fefdd87 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -1,494 +1,19 @@ -execute:import unidecode # new requirement -erpnext.patches.v8_0.move_perpetual_inventory_setting -erpnext.patches.v8_9.set_print_zero_amount_taxes erpnext.patches.v12_0.update_is_cancelled_field erpnext.patches.v11_0.rename_production_order_to_work_order erpnext.patches.v11_0.refactor_naming_series erpnext.patches.v11_0.refactor_autoname_naming -erpnext.patches.v10_0.rename_schools_to_education -erpnext.patches.v4_0.validate_v3_patch -erpnext.patches.v4_0.fix_employee_user_id -erpnext.patches.v4_0.remove_employee_role_if_no_employee -erpnext.patches.v4_0.update_user_properties -erpnext.patches.v4_0.apply_user_permissions -erpnext.patches.v4_0.move_warehouse_user_to_restrictions -erpnext.patches.v4_0.global_defaults_to_system_settings -erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule execute:frappe.reload_doc("accounts", "doctype", "POS Payment Method") #2020-05-28 execute:frappe.reload_doc("HR", "doctype", "HR Settings") #2020-01-16 #2020-07-24 -execute:frappe.reload_doc('stock', 'doctype', 'warehouse') # 2017-04-24 -execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2016-08-31 -execute:frappe.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-29 -execute:frappe.reload_doc('selling', 'doctype', 'quotation') # 2014-01-29 -execute:frappe.reload_doc('stock', 'doctype', 'delivery_note') # 2014-01-29 -erpnext.patches.v4_0.reload_sales_print_format -execute:frappe.reload_doc('accounts', 'doctype', 'purchase_invoice') # 2014-01-29 -execute:frappe.reload_doc('buying', 'doctype', 'purchase_order') # 2014-01-29 -execute:frappe.reload_doc('buying', 'doctype', 'supplier_quotation') # 2014-01-29 -execute:frappe.reload_doc('stock', 'doctype', 'purchase_receipt') # 2014-01-29 -execute:frappe.reload_doc('accounts', 'doctype', 'pos_setting') # 2014-01-29 -execute:frappe.reload_doc('selling', 'doctype', 'customer') # 2014-01-29 -execute:frappe.reload_doc('buying', 'doctype', 'supplier') # 2014-01-29 -execute:frappe.reload_doc('accounts', 'doctype', 'asset_category') -execute:frappe.reload_doc('accounts', 'doctype', 'pricing_rule') -erpnext.patches.v4_0.map_charge_to_taxes_and_charges -execute:frappe.reload_doc('support', 'doctype', 'newsletter') # 2014-01-31 -execute:frappe.reload_doc('hr', 'doctype', 'employee') # 2014-02-03 -execute:frappe.db.sql("update tabPage set module='Core' where name='Setup'") -erpnext.patches.v5_2.change_item_selects_to_checks -execute:frappe.reload_doctype('Item') -erpnext.patches.v4_0.fields_to_be_renamed -erpnext.patches.v4_0.rename_sitemap_to_route -erpnext.patches.v7_0.re_route #2016-06-27 -erpnext.patches.v4_0.fix_contact_address -erpnext.patches.v4_0.customer_discount_to_pricing_rule -execute:frappe.db.sql("""delete from `tabWebsite Item Group` where ifnull(item_group, '')=''""") -erpnext.patches.v4_0.remove_module_home_pages -erpnext.patches.v4_0.split_email_settings -erpnext.patches.v4_0.import_country_codes -erpnext.patches.v4_0.countrywise_coa -execute:frappe.delete_doc("DocType", "MIS Control") -execute:frappe.delete_doc("Page", "Financial Statements") -execute:frappe.delete_doc("DocType", "Stock Ledger") -execute:frappe.delete_doc("DocType", "Grade") -execute:frappe.db.sql("delete from `tabWebsite Item Group` where ifnull(item_group, '')=''") -execute:frappe.delete_doc("Print Format", "SalesInvoice") -execute:import frappe.defaults;frappe.defaults.clear_default("price_list_currency") -erpnext.patches.v4_0.update_account_root_type -execute:frappe.delete_doc("Report", "Purchase In Transit") -erpnext.patches.v4_0.new_address_template -execute:frappe.delete_doc("DocType", "SMS Control") -execute:frappe.delete_doc_if_exists("DocType", "Bulk SMS") #2015-08-18 -erpnext.patches.v4_0.fix_case_of_hr_module_def -erpnext.patches.v4_0.fix_address_template - -# WATCHOUT: This patch reload's documents -erpnext.patches.v4_0.reset_permissions_for_masters -erpnext.patches.v6_20x.rename_project_name_to_project #2016-03-14 - -erpnext.patches.v4_0.update_tax_amount_after_discount -execute:frappe.permissions.reset_perms("GL Entry") #2014-06-09 -execute:frappe.permissions.reset_perms("Stock Ledger Entry") #2014-06-09 -erpnext.patches.v4_0.create_custom_fields_for_india_specific_fields -erpnext.patches.v4_0.save_default_letterhead -erpnext.patches.v4_0.update_custom_print_formats_for_renamed_fields -erpnext.patches.v4_0.update_other_charges_in_custom_purchase_print_formats -erpnext.patches.v4_0.create_price_list_if_missing -execute:frappe.db.sql("update `tabItem` set end_of_life=null where end_of_life='0000-00-00'") #2014-06-16 -erpnext.patches.v4_0.update_users_report_view_settings -erpnext.patches.v4_0.set_pricing_rule_for_buying_or_selling -erpnext.patches.v4_1.set_outgoing_email_footer -erpnext.patches.v4_1.fix_sales_order_delivered_status -erpnext.patches.v4_1.fix_delivery_and_billing_status -execute:frappe.db.sql("update `tabAccount` set root_type='Liability' where root_type='Income' and report_type='Balance Sheet'") -execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool") # 29-07-2014 -execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool Detail") # 29-07-2014 -execute:frappe.delete_doc("Page", "trial-balance") #2014-07-22 -erpnext.patches.v4_2.delete_old_print_formats #2014-07-29 -erpnext.patches.v4_2.toggle_rounded_total #2014-07-30 -erpnext.patches.v4_2.fix_account_master_type -erpnext.patches.v4_2.update_project_milestones -erpnext.patches.v4_2.add_currency_turkish_lira #2014-08-08 -execute:frappe.delete_doc("DocType", "Landed Cost Wizard") -erpnext.patches.v4_2.default_website_style -erpnext.patches.v4_2.set_company_country -erpnext.patches.v4_2.update_sales_order_invoice_field_name -erpnext.patches.v4_2.seprate_manufacture_and_repack -execute:frappe.delete_doc("Report", "Warehouse-Wise Stock Balance") -execute:frappe.delete_doc("DocType", "Purchase Request") -execute:frappe.delete_doc("DocType", "Purchase Request Item") -erpnext.patches.v4_2.recalculate_bom_cost -erpnext.patches.v4_2.fix_gl_entries_for_stock_transactions erpnext.patches.v4_2.update_requested_and_ordered_qty #2021-03-31 -execute:frappe.rename_doc("DocType", "Support Ticket", "Issue", force=True) -erpnext.patches.v4_4.make_email_accounts -execute:frappe.delete_doc("DocType", "Contact Control") -erpnext.patches.v4_2.discount_amount -erpnext.patches.v4_2.reset_bom_costs -erpnext.patches.v5_0.update_frozen_accounts_permission_role -erpnext.patches.v5_0.update_dn_against_doc_fields -execute:frappe.db.sql("update `tabMaterial Request` set material_request_type = 'Material Transfer' where material_request_type = 'Transfer'") -execute:frappe.reload_doc('stock', 'doctype', 'item') -erpnext.patches.v5_0.set_default_company_in_bom -execute:frappe.reload_doc('crm', 'doctype', 'lead') -execute:frappe.reload_doc('crm', 'doctype', 'opportunity') -erpnext.patches.v5_0.rename_taxes_and_charges_master -erpnext.patches.v5_1.sales_bom_rename -erpnext.patches.v5_0.rename_table_fieldnames -execute:frappe.db.sql("update `tabJournal Entry` set voucher_type='Journal Entry' where ifnull(voucher_type, '')=''") -erpnext.patches.v5_0.is_group -erpnext.patches.v4_2.party_model -erpnext.patches.v5_0.party_model_patch_fix -erpnext.patches.v4_1.fix_jv_remarks -erpnext.patches.v4_2.update_landed_cost_voucher -erpnext.patches.v4_2.set_item_has_batch -erpnext.patches.v4_2.update_stock_uom_for_dn_in_sle -erpnext.patches.v5_0.recalculate_total_amount_in_jv -erpnext.patches.v5_0.update_companywise_payment_account -erpnext.patches.v5_0.remove_birthday_events -erpnext.patches.v5_0.update_item_name_in_bom -erpnext.patches.v5_0.rename_customer_issue -erpnext.patches.v5_0.rename_total_fields -erpnext.patches.v5_0.new_crm_module -erpnext.patches.v5_0.rename_customer_issue -erpnext.patches.v5_0.update_material_transfer_for_manufacture -execute:frappe.reload_doc('crm', 'doctype', 'opportunity_item') -erpnext.patches.v5_0.update_item_description_and_image -erpnext.patches.v5_0.update_material_transferred_for_manufacturing -erpnext.patches.v5_0.stock_entry_update_value -erpnext.patches.v5_0.convert_stock_reconciliation -erpnext.patches.v5_0.update_projects -erpnext.patches.v5_0.item_patches -erpnext.patches.v5_0.update_journal_entry_title -erpnext.patches.v5_0.taxes_and_totals_in_party_currency -erpnext.patches.v5_0.replace_renamed_fields_in_custom_scripts_and_print_formats -erpnext.patches.v5_0.update_from_bom -erpnext.patches.v5_0.update_account_types -erpnext.patches.v5_0.update_sms_sender -erpnext.patches.v5_0.set_appraisal_remarks -erpnext.patches.v5_0.update_time_log_title -erpnext.patches.v7_0.create_warehouse_nestedset -erpnext.patches.v7_0.merge_account_type_stock_and_warehouse_to_stock -erpnext.patches.v7_0.set_is_group_for_warehouse -erpnext.patches.v7_2.stock_uom_in_selling -erpnext.patches.v4_2.repost_sle_for_si_with_no_warehouse -erpnext.patches.v5_0.newsletter -execute:frappe.delete_doc("DocType", "Chart of Accounts") -execute:frappe.delete_doc("DocType", "Style Settings") -erpnext.patches.v5_0.update_opportunity -erpnext.patches.v5_0.opportunity_not_submittable -execute:frappe.permissions.reset_perms("Purchase Taxes and Charges Template") #2014-06-09 -execute:frappe.permissions.reset_perms("Expense Claim Type") #2014-06-19 -erpnext.patches.v5_0.execute_on_doctype_update -erpnext.patches.v4_2.fix_recurring_orders -erpnext.patches.v4_2.delete_gl_entries_for_cancelled_invoices -erpnext.patches.v5_0.project_costing -erpnext.patches.v5_0.update_temporary_account -erpnext.patches.v5_0.update_advance_paid -erpnext.patches.v5_0.link_warehouse_with_account -execute:frappe.delete_doc("Page", "stock-ledger") -execute:frappe.delete_doc("Page","stock-level") -erpnext.patches.v5_0.reclculate_planned_operating_cost_in_production_order -erpnext.patches.v5_0.repost_requested_qty -erpnext.patches.v5_0.fix_taxes_and_totals_in_party_currency -erpnext.patches.v5_0.update_tax_amount_after_discount_in_purchase_cycle -erpnext.patches.v5_0.rename_pos_setting -erpnext.patches.v5_0.update_operation_description -erpnext.patches.v5_0.set_footer_address -execute:frappe.db.set_value("Backup Manager", None, "send_backups_to_dropbox", 1 if frappe.db.get_value("Backup Manager", None, "upload_backups_to_dropbox") in ("Daily", "Weekly") else 0) -execute:frappe.db.sql_list("delete from `tabDocPerm` where parent='Issue' and modified_by='Administrator' and role='Guest'") -erpnext.patches.v5_0.update_item_and_description_again -erpnext.patches.v6_0.multi_currency -erpnext.patches.v7_0.create_budget_record -erpnext.patches.v5_0.repost_gle_for_jv_with_multiple_party -erpnext.patches.v5_0.portal_fixes -erpnext.patches.v5_0.reset_values_in_tools # 02-05-2016 -execute:frappe.delete_doc("Page", "users") -erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again -erpnext.patches.v5_0.index_on_account_and_gl_entry -execute:frappe.db.sql("""delete from `tabProject Task`""") -erpnext.patches.v5_0.update_item_desc_in_invoice -erpnext.patches.v5_1.fix_against_account -execute:frappe.rename_doc("DocType", "Salary Manager", "Process Payroll", force=True) -erpnext.patches.v5_1.rename_roles -erpnext.patches.v5_1.default_bom -execute:frappe.delete_doc("DocType", "Party Type") -execute:frappe.delete_doc("Module Def", "Contacts") -erpnext.patches.v5_4.fix_reserved_qty_and_sle_for_packed_items # 30-07-2015 -execute:frappe.reload_doctype("Leave Type") -execute:frappe.db.sql("update `tabLeave Type` set include_holiday=0") -erpnext.patches.v5_4.set_root_and_report_type -erpnext.patches.v5_4.notify_system_managers_regarding_wrong_tax_calculation -erpnext.patches.v5_4.fix_invoice_outstanding -execute:frappe.db.sql("update `tabStock Ledger Entry` set stock_queue = '[]' where voucher_type = 'Stock Reconciliation' and ifnull(qty_after_transaction, 0) = 0") -erpnext.patches.v5_4.fix_missing_item_images -erpnext.patches.v5_4.stock_entry_additional_costs -erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14 erpnext.patches.v5_7.update_item_description_based_on_item_master -erpnext.patches.v5_7.item_template_attributes -execute:frappe.delete_doc_if_exists("DocType", "Manage Variants") -execute:frappe.delete_doc_if_exists("DocType", "Manage Variants Item") erpnext.patches.v4_2.repost_reserved_qty #2021-03-31 -erpnext.patches.v5_4.update_purchase_cost_against_project -erpnext.patches.v5_8.update_order_reference_in_return_entries -erpnext.patches.v5_8.add_credit_note_print_heading -execute:frappe.delete_doc_if_exists("Print Format", "Credit Note - Negative Invoice") - -# V6.0 -erpnext.patches.v6_0.set_default_title # 2015-09-03 -erpnext.patches.v6_0.default_activity_rate -execute:frappe.db.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1) -execute:frappe.db.sql("""update `tabProject` set percent_complete=round(percent_complete, 2) where percent_complete is not null""") -erpnext.patches.v6_0.fix_outstanding_amount -erpnext.patches.v6_0.fix_planned_qty -erpnext.patches.v6_2.remove_newsletter_duplicates -erpnext.patches.v6_2.fix_missing_default_taxes_and_lead -erpnext.patches.v6_3.convert_applicable_territory -erpnext.patches.v6_4.round_status_updater_percentages -erpnext.patches.v6_4.repost_gle_for_journal_entries_where_reference_name_missing -erpnext.patches.v6_4.fix_journal_entries_due_to_reconciliation -erpnext.patches.v6_4.fix_status_in_sales_and_purchase_order -erpnext.patches.v6_4.fix_modified_in_sales_order_and_purchase_order -erpnext.patches.v6_4.fix_duplicate_bins -erpnext.patches.v6_4.fix_sales_order_maintenance_status -erpnext.patches.v6_4.email_digest_update - -# delete shopping cart doctypes -execute:frappe.delete_doc_if_exists("DocType", "Applicable Territory") -execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Price List") -execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Taxes and Charges Master") - -erpnext.patches.v6_4.set_user_in_contact -erpnext.patches.v6_4.make_image_thumbnail #2015-10-20 -erpnext.patches.v6_5.show_in_website_for_template_item -erpnext.patches.v6_4.fix_expense_included_in_valuation -execute:frappe.delete_doc_if_exists("Report", "Item-wise Last Purchase Rate") -erpnext.patches.v6_6.fix_website_image -erpnext.patches.v6_6.remove_fiscal_year_from_leave_allocation -execute:frappe.delete_doc_if_exists("DocType", "Stock UOM Replace Utility") -erpnext.patches.v6_8.make_webform_standard #2015-11-23 -erpnext.patches.v6_8.move_drop_ship_to_po_items -erpnext.patches.v6_10.fix_ordered_received_billed -erpnext.patches.v6_10.fix_jv_total_amount #2015-11-30 -erpnext.patches.v6_10.email_digest_default_quote -erpnext.patches.v6_10.fix_billed_amount_in_drop_ship_po -erpnext.patches.v6_10.fix_delivery_status_of_drop_ship_item #2015-12-08 -erpnext.patches.v5_8.tax_rule #2015-12-08 -erpnext.patches.v6_12.set_overdue_tasks -erpnext.patches.v6_16.update_billing_status_in_dn_and_pr -erpnext.patches.v6_16.create_manufacturer_records -execute:frappe.db.sql("update `tabPricing Rule` set title=name where title='' or title is null") #2016-01-27 -erpnext.patches.v6_20.set_party_account_currency_in_orders -erpnext.patches.v6_19.comment_feed_communication -erpnext.patches.v6_21.fix_reorder_level -erpnext.patches.v6_21.rename_material_request_fields -erpnext.patches.v6_23.update_stopped_status_to_closed -erpnext.patches.v6_24.set_recurring_id -erpnext.patches.v6_20x.set_compact_print -execute:frappe.delete_doc_if_exists("Web Form", "contact") #2016-03-10 -erpnext.patches.v6_20x.remove_fiscal_year_from_holiday_list -erpnext.patches.v6_24.map_customer_address_to_shipping_address_on_po -erpnext.patches.v6_27.fix_recurring_order_status -erpnext.patches.v6_20x.update_product_bundle_description -erpnext.patches.v7_0.update_party_status #2016-09-22 -erpnext.patches.v7_0.remove_features_setup -erpnext.patches.v7_0.update_home_page -execute:frappe.delete_doc_if_exists("Page", "financial-analytics") -erpnext.patches.v7_0.update_project_in_gl_entry -execute:frappe.db.sql('update tabQuotation set status="Cancelled" where docstatus=2') -execute:frappe.rename_doc("DocType", "Payments", "Sales Invoice Payment", force=True) -erpnext.patches.v7_0.update_mins_to_first_response -erpnext.patches.v6_20x.repost_valuation_rate_for_negative_inventory -erpnext.patches.v7_0.migrate_mode_of_payments_v6_to_v7 -erpnext.patches.v7_0.system_settings_setup_complete -erpnext.patches.v7_0.set_naming_series_for_timesheet #2016-07-27 -execute:frappe.reload_doc('projects', 'doctype', 'project') -execute:frappe.reload_doc('projects', 'doctype', 'project_user') -erpnext.patches.v7_0.convert_timelogbatch_to_timesheet -erpnext.patches.v7_0.convert_timelog_to_timesheet -erpnext.patches.v7_0.move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet -erpnext.patches.v7_0.remove_doctypes_and_reports #2016-10-29 -erpnext.patches.v7_0.update_maintenance_module_in_doctype -erpnext.patches.v7_0.update_prevdoc_values_for_supplier_quotation_item -erpnext.patches.v7_0.rename_advance_table_fields -erpnext.patches.v7_0.rename_salary_components -erpnext.patches.v7_0.rename_prevdoc_fields -erpnext.patches.v7_0.rename_time_sheet_doctype -execute:frappe.delete_doc_if_exists("Report", "Customers Not Buying Since Long Time") -erpnext.patches.v7_0.make_is_group_fieldtype_as_check -execute:frappe.reload_doc('projects', 'doctype', 'timesheet') #2016-09-12 -erpnext.patches.v7_1.rename_field_timesheet -execute:frappe.delete_doc_if_exists("Report", "Employee Holiday Attendance") -execute:frappe.delete_doc_if_exists("DocType", "Payment Tool") -execute:frappe.delete_doc_if_exists("DocType", "Payment Tool Detail") -erpnext.patches.v7_0.setup_account_table_for_expense_claim_type_if_exists -erpnext.patches.v7_0.migrate_schools_to_erpnext -erpnext.patches.v7_1.update_lead_source -erpnext.patches.v6_20x.remove_customer_supplier_roles -erpnext.patches.v7_0.remove_administrator_role_in_doctypes -erpnext.patches.v7_0.rename_fee_amount_to_fee_component -erpnext.patches.v7_0.calculate_total_costing_amount -erpnext.patches.v7_0.fix_nonwarehouse_ledger_gl_entries_for_transactions -erpnext.patches.v7_0.remove_old_earning_deduction_doctypes -erpnext.patches.v7_0.make_guardian -erpnext.patches.v7_0.update_refdoc_in_landed_cost_voucher -erpnext.patches.v7_0.set_material_request_type_in_item -erpnext.patches.v7_0.rename_examination_to_assessment -erpnext.patches.v7_0.set_portal_settings -erpnext.patches.v7_0.update_change_amount_account -erpnext.patches.v7_0.fix_duplicate_icons -erpnext.patches.v7_0.repost_gle_for_pos_sales_return -erpnext.patches.v7_1.update_total_billing_hours -erpnext.patches.v7_1.update_component_type -erpnext.patches.v7_0.repost_gle_for_pos_sales_return -erpnext.patches.v7_0.update_missing_employee_in_timesheet -erpnext.patches.v7_0.update_status_for_timesheet -erpnext.patches.v7_0.set_party_name_in_payment_entry -erpnext.patches.v7_1.set_student_guardian -erpnext.patches.v7_0.update_conversion_factor_in_supplier_quotation_item -erpnext.patches.v7_1.move_sales_invoice_from_parent_to_child_timesheet -execute:frappe.db.sql("update `tabTimesheet` ts, `tabEmployee` emp set ts.employee_name = emp.employee_name where emp.name = ts.employee and ts.employee_name is null and ts.employee is not null") -erpnext.patches.v7_1.fix_link_for_customer_from_lead -execute:frappe.db.sql("delete from `tabTimesheet Detail` where NOT EXISTS (select name from `tabTimesheet` where name = `tabTimesheet Detail`.parent)") -erpnext.patches.v7_0.update_mode_of_payment_type - -execute:frappe.reload_doctype('Employee') #2016-10-18 -execute:frappe.db.sql("update `tabEmployee` set prefered_contact_email = IFNULL(prefered_contact_email,'') ") execute:frappe.reload_doc("Payroll", "doctype", "salary_slip") -execute:frappe.db.sql("update `tabSalary Slip` set posting_date=creation") -execute:frappe.reload_doc("stock", "doctype", "stock_settings") -erpnext.patches.v8_0.create_domain_docs #16-05-2017 -erpnext.patches.v7_1.update_portal_roles -erpnext.patches.v7_1.set_total_amount_currency_in_je -finally:erpnext.patches.v7_0.update_timesheet_communications -erpnext.patches.v7_0.update_status_of_zero_amount_sales_order -erpnext.patches.v7_1.add_field_for_task_dependent -erpnext.patches.v7_0.repost_bin_qty_and_item_projected_qty -erpnext.patches.v7_1.set_prefered_contact_email -execute:frappe.reload_doc('accounts', 'doctype', 'accounts_settings') -execute:frappe.db.set_value("Accounts Settings", "Accounts Settings", "unlink_payment_on_cancellation_of_invoice", 0) -execute:frappe.db.sql("update `tabStock Entry` set total_amount = 0 where purpose in('Repack', 'Manufacture')") -erpnext.patches.v7_1.save_stock_settings -erpnext.patches.v7_0.repost_gle_for_pi_with_update_stock #2016-11-01 -erpnext.patches.v7_1.add_account_user_role_for_timesheet -erpnext.patches.v7_0.set_base_amount_in_invoice_payment_table -erpnext.patches.v7_1.update_invoice_status -erpnext.patches.v7_0.po_status_issue_for_pr_return -erpnext.patches.v7_1.update_missing_salary_component_type -erpnext.patches.v7_1.rename_quality_inspection_field -erpnext.patches.v7_0.update_autoname_field -erpnext.patches.v7_1.update_bom_base_currency -erpnext.patches.v7_0.update_status_of_po_so -erpnext.patches.v7_1.set_budget_against_as_cost_center -erpnext.patches.v7_1.set_currency_exchange_date -erpnext.patches.v7_1.set_sales_person_status -erpnext.patches.v7_1.repost_stock_for_deleted_bins_for_merging_items -erpnext.patches.v7_2.update_website_for_variant -erpnext.patches.v7_2.update_assessment_modules -erpnext.patches.v7_2.update_doctype_status -erpnext.patches.v7_2.update_salary_slips -erpnext.patches.v7_2.delete_fleet_management_module_def -erpnext.patches.v7_2.contact_address_links -erpnext.patches.v7_2.mark_students_active -erpnext.patches.v7_2.set_null_value_to_fields -erpnext.patches.v7_2.update_guardian_name_in_student_master -erpnext.patches.v7_2.update_abbr_in_salary_slips -erpnext.patches.v7_2.rename_evaluation_criteria -erpnext.patches.v7_2.update_party_type -erpnext.patches.v7_2.setup_auto_close_settings -erpnext.patches.v7_2.empty_supplied_items_for_non_subcontracted -erpnext.patches.v7_2.arrear_leave_encashment_as_salary_component -erpnext.patches.v7_2.rename_att_date_attendance -erpnext.patches.v7_2.update_attendance_docstatus -erpnext.patches.v7_2.make_all_assessment_group -erpnext.patches.v8_0.repost_reserved_qty_for_multiple_sales_uom -erpnext.patches.v8_0.addresses_linked_to_lead -execute:frappe.delete_doc('DocType', 'Purchase Common') -erpnext.patches.v8_0.update_stock_qty_value_in_purchase_invoice -erpnext.patches.v8_0.update_supplier_address_in_stock_entry -erpnext.patches.v8_0.rename_is_sample_item_to_allow_zero_valuation_rate -erpnext.patches.v8_0.set_null_to_serial_nos_for_disabled_sales_invoices -erpnext.patches.v8_0.enable_booking_asset_depreciation_automatically -erpnext.patches.v8_0.set_project_copied_from -erpnext.patches.v8_0.update_status_as_paid_for_completed_expense_claim -erpnext.patches.v7_2.stock_uom_in_selling -erpnext.patches.v8_0.revert_manufacturers_table_from_item -erpnext.patches.v8_0.disable_instructor_role -erpnext.patches.v8_0.merge_student_batch_and_student_group -erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017 -erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding -erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice -erpnext.patches.v8_0.set_sales_invoice_serial_number_from_delivery_note -erpnext.patches.v8_0.delete_schools_depricated_doctypes -erpnext.patches.v8_0.update_customer_pos_id -erpnext.patches.v8_0.rename_items_in_status_field_of_material_request -erpnext.patches.v8_0.delete_bin_indexes -erpnext.patches.v8_0.move_account_head_from_account_to_warehouse_for_inventory -erpnext.patches.v8_0.change_in_words_varchar_length -erpnext.patches.v8_0.update_stock_qty_value_in_bom_item -erpnext.patches.v8_0.update_sales_cost_in_project -erpnext.patches.v8_0.save_system_settings -erpnext.patches.v8_1.delete_deprecated_reports -erpnext.patches.v9_0.remove_subscription_module -erpnext.patches.v8_7.make_subscription_from_recurring_data erpnext.patches.v8_1.setup_gst_india #2017-06-27 -execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code') erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account #16-08-2018 -erpnext.patches.v8_1.gst_fixes #2017-07-06 -erpnext.patches.v8_0.update_production_orders -erpnext.patches.v8_1.remove_sales_invoice_from_returned_serial_no -erpnext.patches.v8_1.allow_invoice_copy_to_edit_after_submit -erpnext.patches.v8_1.add_hsn_sac_codes -erpnext.patches.v8_1.update_gst_state #17-07-2017 -erpnext.patches.v8_1.removed_report_support_hours -erpnext.patches.v8_1.add_indexes_in_transaction_doctypes -erpnext.patches.v8_3.set_restrict_to_domain_for_module_def -erpnext.patches.v8_1.update_expense_claim_status -erpnext.patches.v8_3.update_company_total_sales #2017-08-16 -erpnext.patches.v8_4.make_scorecard_records -erpnext.patches.v8_1.set_delivery_date_in_so_item #2017-07-28 -erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs -erpnext.patches.v8_5.remove_quotations_route_in_sidebar -erpnext.patches.v8_5.update_existing_data_in_project_type -erpnext.patches.v8_5.set_default_mode_of_payment -erpnext.patches.v8_5.update_customer_group_in_POS_profile -erpnext.patches.v8_6.update_timesheet_company_from_PO -erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager -erpnext.patches.v8_5.remove_project_type_property_setter erpnext.patches.v8_7.sync_india_custom_fields -erpnext.patches.v8_7.fix_purchase_receipt_status -erpnext.patches.v8_6.rename_bom_update_tool -erpnext.patches.v8_9.add_setup_progress_actions #08-09-2017 #26-09-2017 #22-11-2017 #15-12-2017 -erpnext.patches.v8_9.rename_company_sales_target_field -erpnext.patches.v8_8.set_bom_rate_as_per_uom -erpnext.patches.v8_8.add_new_fields_in_accounts_settings -erpnext.patches.v8_9.set_default_customer_group -erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts -erpnext.patches.v8_9.set_default_fields_in_variant_settings -erpnext.patches.v8_9.update_billing_gstin_for_indian_account -erpnext.patches.v8_9.set_member_party_type -erpnext.patches.v9_0.add_user_to_child_table_in_pos_profile -erpnext.patches.v9_0.set_schedule_date_for_material_request_and_purchase_order -erpnext.patches.v9_0.student_admission_childtable_migrate -erpnext.patches.v9_0.add_healthcare_domain -erpnext.patches.v9_0.set_variant_item_description -erpnext.patches.v9_0.set_uoms_in_variant_field -erpnext.patches.v9_0.copy_old_fees_field_data -execute:frappe.delete_doc_if_exists("DocType", "Program Fee") -erpnext.patches.v9_0.set_pos_profile_name -erpnext.patches.v9_0.remove_non_existing_warehouse_from_stock_settings -execute:frappe.delete_doc_if_exists("DocType", "Program Fee") -erpnext.patches.v8_10.change_default_customer_credit_days -erpnext.patches.v9_0.update_employee_loan_details -erpnext.patches.v9_2.delete_healthcare_domain_default_items -erpnext.patches.v9_1.create_issue_opportunity_type -erpnext.patches.v9_2.rename_translated_domains_in_en -erpnext.patches.v9_0.set_shipping_type_for_existing_shipping_rules -erpnext.patches.v9_0.update_multi_uom_fields_in_material_request -erpnext.patches.v9_2.repost_reserved_qty_for_production -erpnext.patches.v9_2.remove_company_from_patient -erpnext.patches.v9_2.set_item_name_in_production_order -erpnext.patches.v10_0.update_lft_rgt_for_employee -erpnext.patches.v9_2.rename_net_weight_in_item_master -erpnext.patches.v9_2.delete_process_payroll -erpnext.patches.v10_0.add_agriculture_domain -erpnext.patches.v10_0.add_non_profit_domain -erpnext.patches.v10_0.setup_vat_for_uae_and_saudi_arabia #2017-12-28 -erpnext.patches.v10_0.set_primary_contact_for_customer -erpnext.patches.v10_0.copy_projects_renamed_fields -erpnext.patches.v10_0.enabled_regional_print_format_based_on_country -erpnext.patches.v10_0.update_asset_calculate_depreciation -erpnext.patches.v10_0.add_guardian_role_for_parent_portal -erpnext.patches.v10_0.set_numeric_ranges_in_template_if_blank -erpnext.patches.v10_0.update_reserved_qty_for_purchase_order erpnext.patches.v10_0.fichier_des_ecritures_comptables_for_france -erpnext.patches.v10_0.update_assessment_plan -erpnext.patches.v10_0.update_assessment_result -erpnext.patches.v10_0.set_default_payment_terms_based_on_company -erpnext.patches.v10_0.update_sales_order_link_to_purchase_order erpnext.patches.v10_0.rename_price_to_rate_in_pricing_rule erpnext.patches.v10_0.set_currency_in_pricing_rule -erpnext.patches.v10_0.set_b2c_limit erpnext.patches.v10_0.update_translatable_fields erpnext.patches.v10_0.rename_offer_letter_to_job_offer execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True) @@ -496,16 +21,6 @@ erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_ erpnext.patches.v10_0.add_default_cash_flow_mappers erpnext.patches.v11_0.rename_duplicate_item_code_values erpnext.patches.v11_0.make_quality_inspection_template -erpnext.patches.v10_0.update_status_for_multiple_source_in_po -erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry -erpnext.patches.v10_0.update_territory_and_customer_group -erpnext.patches.v10_0.update_warehouse_address_details -erpnext.patches.v10_0.update_reserved_qty_for_purchase_order -erpnext.patches.v10_0.update_hub_connector_domain -erpnext.patches.v10_0.set_student_party_type -erpnext.patches.v10_0.update_project_in_sle -erpnext.patches.v10_0.fix_reserved_qty_for_sub_contract -erpnext.patches.v10_0.repost_requested_qty_for_non_stock_uom_items erpnext.patches.v11_0.merge_land_unit_with_location erpnext.patches.v11_0.add_index_on_nestedset_doctypes erpnext.patches.v11_0.remove_modules_setup_page @@ -514,7 +29,6 @@ erpnext.patches.v11_0.update_department_lft_rgt erpnext.patches.v11_0.add_default_email_template_for_leave erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018 erpnext.patches.v11_0.uom_conversion_data #30-06-2018 -erpnext.patches.v10_0.taxes_issue_with_pos erpnext.patches.v11_0.update_account_type_in_party_type erpnext.patches.v11_0.rename_healthcare_doctype_and_fields erpnext.patches.v11_0.rename_supplier_type_to_supplier_group @@ -522,8 +36,6 @@ erpnext.patches.v10_1.transfer_subscription_to_auto_repeat erpnext.patches.v11_0.update_brand_in_item_price erpnext.patches.v11_0.create_default_success_action erpnext.patches.v11_0.add_healthcare_service_unit_tree_root -erpnext.patches.v10_0.set_qty_in_transactions_based_on_serial_no_input -erpnext.patches.v10_0.show_leaves_of_all_department_members_in_calendar erpnext.patches.v11_0.rename_field_max_days_allowed erpnext.patches.v11_0.create_salary_structure_assignments erpnext.patches.v11_0.rename_health_insurance @@ -536,7 +48,6 @@ erpnext.patches.v11_0.move_item_defaults_to_child_table_for_multicompany #02-07- erpnext.patches.v11_0.refactor_erpnext_shopify #2018-09-07 erpnext.patches.v11_0.rename_overproduction_percent_field erpnext.patches.v11_0.update_backflush_subcontract_rm_based_on_bom -erpnext.patches.v10_0.update_status_in_purchase_receipt erpnext.patches.v11_0.inter_state_field_for_gst erpnext.patches.v11_0.rename_members_with_naming_series #04-06-2018 erpnext.patches.v11_0.set_update_field_and_value_in_workflow_state @@ -550,13 +61,10 @@ erpnext.patches.v11_0.skip_user_permission_check_for_department erpnext.patches.v11_0.set_department_for_doctypes erpnext.patches.v11_0.update_allow_transfer_for_manufacture erpnext.patches.v11_0.add_item_group_defaults -erpnext.patches.v10_0.update_address_template_for_india erpnext.patches.v11_0.add_expense_claim_default_account execute:frappe.delete_doc("Page", "hub") erpnext.patches.v11_0.reset_publish_in_hub_for_all_items erpnext.patches.v11_0.update_hub_url # 2018-08-31 # 2018-09-03 -erpnext.patches.v10_0.set_discount_amount -erpnext.patches.v10_0.recalculate_gross_margin_for_project erpnext.patches.v11_0.make_job_card erpnext.patches.v11_0.redesign_healthcare_billing_work_flow erpnext.patches.v10_0.delete_hub_documents # 12-08-2018 @@ -570,9 +78,6 @@ execute:frappe.delete_doc_if_exists("Page", "stock-analytics") execute:frappe.delete_doc_if_exists("Page", "production-analytics") erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01 #2019-04-26 #2019-05-03 erpnext.patches.v11_0.drop_column_max_days_allowed -erpnext.patches.v10_0.update_user_image_in_employee -erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items -erpnext.patches.v10_0.allow_operators_in_supplier_scorecard erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 erpnext.patches.v11_0.update_delivery_trip_status erpnext.patches.v11_0.set_missing_gst_hsn_code From 43a24f2aa87eef372cf2fddf1b99ef68245cb643 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 3 Jun 2021 20:05:00 +0530 Subject: [PATCH 175/180] ci: Update ERPNext backup patch test >= v10 * Generated v10 backup archive * used old v7 erpnext backup hosted via build.erpnext.com * upgraded to v10 frappe + erpnext * Hosted backup on https://erpnext.com/files/v10-erpnext.sql.gz --- .github/workflows/patch.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml index 7c9e0272c9..b96a3d6bbe 100644 --- a/.github/workflows/patch.yml +++ b/.github/workflows/patch.yml @@ -66,4 +66,8 @@ jobs: run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh - name: Run Patch Tests - run: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate + run: | + cd ~/frappe-bench/ + wget https://erpnext.com/files/v10-erpnext.sql.gz + bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz + bench --site test_site migrate From 96f8ebc308ba2ceada92ab5a46ec582a7a9ba15f Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 4 Jun 2021 17:07:45 +0530 Subject: [PATCH 176/180] fix(patch): Handle NULL values from fieldtype change --- erpnext/patches/v11_0/rename_bom_wo_fields.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py index b4a740fabb..882ec84e64 100644 --- a/erpnext/patches/v11_0/rename_bom_wo_fields.py +++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py @@ -6,6 +6,10 @@ import frappe from frappe.model.utils.rename_field import rename_field def execute(): + # updating column value to handle field change from Data to Currency + changed_field = "base_scrap_material_cost" + frappe.db.sql(f"update `tabBOM` set {changed_field} = '0' where trim(coalesce({changed_field}, ''))= ''") + for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']: if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'): if doctype != 'Item': From 137d08a9d7bddb5903e5b01612a07c5a1223c378 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 4 Jun 2021 20:11:34 +0530 Subject: [PATCH 177/180] fix: Manually link_fields from flags before rename_doc --- .../v13_0/healthcare_lab_module_rename_doctypes.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py b/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py index 9af0a8dbef..2549a1e91e 100644 --- a/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py +++ b/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field + def execute(): if frappe.db.exists('DocType', 'Lab Test') and frappe.db.exists('DocType', 'Lab Test Template'): # rename child doctypes @@ -17,7 +18,12 @@ def execute(): frappe.reload_doc('healthcare', 'doctype', 'lab_test_template') for old_dt, new_dt in doctypes.items(): - if not frappe.db.table_exists(new_dt) and frappe.db.table_exists(old_dt): + frappe.flags.link_fields = {} + should_rename = ( + frappe.db.table_exists(old_dt) + and not frappe.db.table_exists(new_dt) + ) + if should_rename: frappe.reload_doc('healthcare', 'doctype', frappe.scrub(old_dt)) frappe.rename_doc('DocType', old_dt, new_dt, force=True) frappe.reload_doc('healthcare', 'doctype', frappe.scrub(new_dt)) From a5c3427293a8bfeb38bd83c08fe155b9d33179a4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 10 Jun 2021 18:09:49 +0530 Subject: [PATCH 178/180] fix: Sort account balances by account name --- .../report/account_balance/account_balance.py | 4 +--- .../account_balance/test_account_balance.py | 22 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/report/account_balance/account_balance.py b/erpnext/accounts/report/account_balance/account_balance.py index 65e7d789bb..be64c327fd 100644 --- a/erpnext/accounts/report/account_balance/account_balance.py +++ b/erpnext/accounts/report/account_balance/account_balance.py @@ -58,11 +58,9 @@ def get_conditions(filters): def get_data(filters): data = [] - conditions = get_conditions(filters) - accounts = frappe.db.get_all("Account", fields=["name", "account_currency"], - filters=conditions) + filters=conditions, order_by='name') for d in accounts: balance = get_balance_on(d.name, date=filters.report_date) diff --git a/erpnext/accounts/report/account_balance/test_account_balance.py b/erpnext/accounts/report/account_balance/test_account_balance.py index b6ced312d0..14ddf4a30f 100644 --- a/erpnext/accounts/report/account_balance/test_account_balance.py +++ b/erpnext/accounts/report/account_balance/test_account_balance.py @@ -23,7 +23,7 @@ class TestAccountBalance(unittest.TestCase): expected_data = [ { - "account": 'Sales - _TC2', + "account": 'Direct Income - _TC2', "currency": 'EUR', "balance": -100.0, }, @@ -32,21 +32,21 @@ class TestAccountBalance(unittest.TestCase): "currency": 'EUR', "balance": -100.0, }, - { - "account": 'Service - _TC2', - "currency": 'EUR', - "balance": 0.0, - }, - { - "account": 'Direct Income - _TC2', - "currency": 'EUR', - "balance": -100.0, - }, { "account": 'Indirect Income - _TC2', "currency": 'EUR', "balance": 0.0, }, + { + "account": 'Sales - _TC2', + "currency": 'EUR', + "balance": -100.0, + }, + { + "account": 'Service - _TC2', + "currency": 'EUR', + "balance": 0.0, + } ] self.assertEqual(expected_data, report[1]) From 9a243ed4699f2ae9e96397b221193f1fe40a2cb0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 10 Jun 2021 18:09:49 +0530 Subject: [PATCH 179/180] fix: Sort account balances by account name --- .../report/account_balance/account_balance.py | 4 +--- .../account_balance/test_account_balance.py | 22 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/report/account_balance/account_balance.py b/erpnext/accounts/report/account_balance/account_balance.py index 65e7d789bb..be64c327fd 100644 --- a/erpnext/accounts/report/account_balance/account_balance.py +++ b/erpnext/accounts/report/account_balance/account_balance.py @@ -58,11 +58,9 @@ def get_conditions(filters): def get_data(filters): data = [] - conditions = get_conditions(filters) - accounts = frappe.db.get_all("Account", fields=["name", "account_currency"], - filters=conditions) + filters=conditions, order_by='name') for d in accounts: balance = get_balance_on(d.name, date=filters.report_date) diff --git a/erpnext/accounts/report/account_balance/test_account_balance.py b/erpnext/accounts/report/account_balance/test_account_balance.py index b6ced312d0..14ddf4a30f 100644 --- a/erpnext/accounts/report/account_balance/test_account_balance.py +++ b/erpnext/accounts/report/account_balance/test_account_balance.py @@ -23,7 +23,7 @@ class TestAccountBalance(unittest.TestCase): expected_data = [ { - "account": 'Sales - _TC2', + "account": 'Direct Income - _TC2', "currency": 'EUR', "balance": -100.0, }, @@ -32,21 +32,21 @@ class TestAccountBalance(unittest.TestCase): "currency": 'EUR', "balance": -100.0, }, - { - "account": 'Service - _TC2', - "currency": 'EUR', - "balance": 0.0, - }, - { - "account": 'Direct Income - _TC2', - "currency": 'EUR', - "balance": -100.0, - }, { "account": 'Indirect Income - _TC2', "currency": 'EUR', "balance": 0.0, }, + { + "account": 'Sales - _TC2', + "currency": 'EUR', + "balance": -100.0, + }, + { + "account": 'Service - _TC2', + "currency": 'EUR', + "balance": 0.0, + } ] self.assertEqual(expected_data, report[1]) From 9a67141bfb0069d9254a902dd2f366d7a22b36be Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 10 Jun 2021 18:48:55 +0530 Subject: [PATCH 180/180] fix(einvoicing): service item check (#26010) --- erpnext/regional/india/e_invoice/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index a1179ff9b6..0eaf790538 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -199,7 +199,7 @@ def get_item_list(invoice): item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None - item.is_service_item = 'Y' if item.gst_hsn_code[:2] == "99" else 'N' + item.is_service_item = 'Y' if item.gst_hsn_code and item.gst_hsn_code[:2] == "99" else 'N' item.serial_no = "" item = update_item_taxes(invoice, item)