From e321fbb0d5c46416da2e65e3dc14111866a9af87 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 16 Jan 2020 13:37:25 +0530 Subject: [PATCH] fix: Multiple fixes based on testing on pre-release branch (#20301) * fix: Multiple fixes based on testing on pre-release branch * fix: reload hr settings --- .../purchase_order/purchase_order.json | 6 +-- .../employee_advance/employee_advance.js | 8 ++-- .../employee_advance/employee_advance.py | 7 +-- .../hr/doctype/expense_claim/expense_claim.js | 16 +++---- .../hr/doctype/expense_claim/expense_claim.py | 1 + .../expense_claim_advance.json | 9 ++-- erpnext/manufacturing/doctype/bom/bom.py | 44 ++++++++++++++++--- .../doctype/work_order/work_order.py | 7 +-- erpnext/patches.txt | 2 +- .../stock/doctype/stock_entry/stock_entry.py | 40 ++++------------- erpnext/stock/get_item_details.py | 9 ++-- 11 files changed, 75 insertions(+), 74 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 9201eef9b49..d82e128735e 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1,5 +1,4 @@ { - "actions": [], "allow_import": 1, "autoname": "naming_series:", "creation": "2013-05-21 16:16:39", @@ -48,7 +47,6 @@ "ignore_pricing_rule", "sec_warehouse", "set_warehouse", - "set_reserve_warehouse", "col_break_warehouse", "is_subcontracted", "supplier_warehouse", @@ -58,6 +56,7 @@ "section_break_48", "pricing_rules", "raw_material_details", + "set_reserve_warehouse", "supplied_items", "sb_last_purchase", "total_qty", @@ -1054,8 +1053,7 @@ "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, - "links": [], - "modified": "2019-12-30 19:11:54.122264", + "modified": "2020-01-14 18:54:39.694448", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js index ba62853336d..389660387b7 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.js +++ b/erpnext/hr/doctype/employee_advance/employee_advance.js @@ -47,7 +47,7 @@ frappe.ui.form.on('Employee Advance', { } if (frm.doc.docstatus === 1 - && (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount)) + && (flt(frm.doc.claimed_amount) + flt(frm.doc.return_amount) < flt(frm.doc.paid_amount)) && frappe.model.can_create("Journal Entry")) { frm.add_custom_button(__("Return"), function() { @@ -96,12 +96,12 @@ frappe.ui.form.on('Employee Advance', { frappe.call({ method: 'erpnext.hr.doctype.employee_advance.employee_advance.make_return_entry', args: { - 'employee_name': frm.doc.employee, + 'employee': frm.doc.employee, 'company': frm.doc.company, 'employee_advance_name': frm.doc.name, 'return_amount': flt(frm.doc.paid_amount - frm.doc.claimed_amount), - 'mode_of_payment': frm.doc.mode_of_payment, - 'advance_account': frm.doc.advance_account + 'advance_account': frm.doc.advance_account, + 'mode_of_payment': frm.doc.mode_of_payment }, callback: function(r) { const doclist = frappe.model.sync(r.message); diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index 7fe2ebc79e0..f10e3b6ce26 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -133,7 +133,8 @@ def make_bank_entry(dt, dn): return je.as_dict() @frappe.whitelist() -def make_return_entry(employee_name, company, employee_advance_name, return_amount, mode_of_payment, advance_account): +def make_return_entry(employee, company, employee_advance_name, + return_amount, advance_account, mode_of_payment=None): return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment) je = frappe.new_doc('Journal Entry') je.posting_date = nowdate() @@ -147,7 +148,7 @@ def make_return_entry(employee_name, company, employee_advance_name, return_amou 'reference_type': 'Employee Advance', 'reference_name': employee_advance_name, 'party_type': 'Employee', - 'party': employee_name, + 'party': employee, 'is_advance': 'Yes' }) @@ -159,5 +160,5 @@ def make_return_entry(employee_name, company, employee_advance_name, return_amou }) return je.as_dict() - + diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index e0bfc83a9bc..88f3865434b 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -242,13 +242,14 @@ frappe.ui.form.on("Expense Claim", { }, update_employee_advance_claimed_amount: function(frm) { + console.log("update_employee_advance_claimed_amount") let amount_to_be_allocated = frm.doc.grand_total; - $.each(frm.doc.advances || [], function(i, advance) { - if (amount_to_be_allocated >= advance.unclaimed_amount) { - frm.doc.advances[i].allocated_amount = frm.doc.advances[i].unclaimed_amount; + $.each(frm.doc.advances || [], function(i, advance){ + if (amount_to_be_allocated >= advance.unclaimed_amount){ + advance.allocated_amount = frm.doc.advances[i].unclaimed_amount; amount_to_be_allocated -= advance.allocated_amount; } else { - frm.doc.advances[i].allocated_amount = amount_to_be_allocated; + advance.allocated_amount = amount_to_be_allocated; amount_to_be_allocated = 0; } frm.refresh_field("advances"); @@ -300,6 +301,7 @@ frappe.ui.form.on("Expense Claim", { doc: frm.doc, callback: () => { refresh_field("taxes"); + frm.trigger("update_employee_advance_claimed_amount"); } }); } @@ -340,16 +342,12 @@ frappe.ui.form.on("Expense Claim Detail", { }, amount: function(frm, cdt, cdn) { var child = locals[cdt][cdn]; - var doc = frm.doc; frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.amount); - cur_frm.cscript.calculate_total(doc,cdt,cdn); }, sanctioned_amount: function(frm, cdt, cdn) { - var doc = frm.doc; - cur_frm.cscript.calculate_total(doc,cdt,cdn); + cur_frm.cscript.calculate_total(frm.doc, cdt, cdn); frm.trigger("get_taxes"); - frm.trigger("calculate_grand_total"); }, cost_center: function(frm, cdt, cdn) { erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "expenses", "cost_center"); diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index e01e7a4c7bb..fe8afdf8734 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -244,6 +244,7 @@ class ExpenseClaim(AccountsController): precision = self.precision("total_advance_amount") if flt(self.total_advance_amount, precision) > flt(self.total_claimed_amount, precision): frappe.throw(_("Total advance amount cannot be greater than total claimed amount")) + if self.total_sanctioned_amount \ and flt(self.total_advance_amount, precision) > flt(self.total_sanctioned_amount, precision): frappe.throw(_("Total advance amount cannot be greater than total sanctioned amount")) diff --git a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json index db47d1844f6..45509257c11 100644 --- a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json +++ b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json @@ -1,5 +1,4 @@ { - "actions": [], "creation": "2017-10-09 16:53:26.410762", "doctype": "DocType", "document_type": "Document", @@ -43,7 +42,7 @@ "fieldtype": "Currency", "in_list_view": 1, "label": "Advance Paid", - "options": "Company:company.default_currency", + "options": "Company:company:default_currency", "read_only": 1 }, { @@ -55,7 +54,7 @@ "no_copy": 1, "oldfieldname": "advance_amount", "oldfieldtype": "Currency", - "options": "Company:company.default_currency", + "options": "Company:company:default_currency", "print_width": "120px", "read_only": 1, "reqd": 1, @@ -70,7 +69,7 @@ "no_copy": 1, "oldfieldname": "allocated_amount", "oldfieldtype": "Currency", - "options": "Company:company.default_currency", + "options": "Company:company:default_currency", "print_width": "120px", "width": "120px" }, @@ -88,7 +87,7 @@ ], "istable": 1, "links": [], - "modified": "2019-12-11 13:53:22.111766", + "modified": "2019-12-17 13:53:22.111766", "modified_by": "Administrator", "module": "HR", "name": "Expense Claim Advance", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 7000d30eff0..6bda802d89d 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -634,7 +634,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite is_stock_item=is_stock_item, qty_field="stock_qty", select_columns = """, bom_item.source_warehouse, bom_item.operation, - bom_item.include_item_in_manufacturing, bom_item.description, + bom_item.include_item_in_manufacturing, bom_item.description, bom_item.rate, (Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s limit 1) as idx""") items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True) @@ -648,7 +648,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite qty_field="stock_qty" if fetch_qty_in_stock_uom else "qty", select_columns = """, bom_item.uom, bom_item.conversion_factor, bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing, - bom_item.description """) + bom_item.description, bom_item.base_rate as rate """) items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True) for item in items: @@ -761,11 +761,17 @@ def get_boms_in_bottom_up_order(bom_no=None): def add_additional_cost(stock_entry, work_order): # Add non stock items cost in the additional cost - bom = frappe.get_doc('BOM', work_order.bom_no) - table = 'exploded_items' if work_order.get('use_multi_level_bom') else 'items' + stock_entry.additional_costs = [] expenses_included_in_valuation = frappe.get_cached_value("Company", work_order.company, "expenses_included_in_valuation") + add_non_stock_items_cost(stock_entry, work_order, expenses_included_in_valuation) + add_operations_cost(stock_entry, work_order, expenses_included_in_valuation) + +def add_non_stock_items_cost(stock_entry, work_order, expense_account): + bom = frappe.get_doc('BOM', work_order.bom_no) + table = 'exploded_items' if work_order.get('use_multi_level_bom') else 'items' + items = {} for d in bom.get(table): items.setdefault(d.item_code, d.amount) @@ -773,11 +779,35 @@ def add_additional_cost(stock_entry, work_order): non_stock_items = frappe.get_all('Item', fields="name", filters={'name': ('in', list(items.keys())), 'ifnull(is_stock_item, 0)': 0}, as_list=1) + non_stock_items_cost = 0.0 for name in non_stock_items: + non_stock_items_cost += flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity) + + stock_entry.append('additional_costs', { + 'expense_account': expense_account, + 'description': _("Non stock items"), + 'amount': non_stock_items_cost + }) + +def add_operations_cost(stock_entry, work_order=None, expense_account=None): + from erpnext.stock.doctype.stock_entry.stock_entry import get_operating_cost_per_unit + operating_cost_per_unit = get_operating_cost_per_unit(work_order, stock_entry.bom_no) + + if operating_cost_per_unit: stock_entry.append('additional_costs', { - 'expense_account': expenses_included_in_valuation, - 'description': name[0], - 'amount': flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity) + "expense_account": expense_account, + "description": _("Operating Cost as per Work Order / BOM"), + "amount": operating_cost_per_unit * flt(stock_entry.fg_completed_qty) + }) + + if work_order and work_order.additional_operating_cost and work_order.qty: + additional_operating_cost_per_unit = \ + flt(work_order.additional_operating_cost) / flt(work_order.qty) + + stock_entry.append('additional_costs', { + "expense_account": expense_account, + "description": "Additional Operating Cost", + "amount": additional_operating_cost_per_unit * flt(stock_entry.fg_completed_qty) }) @frappe.whitelist() diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 914260b6a35..619b21a5ac1 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -12,8 +12,7 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items from dateutil.relativedelta import relativedelta from erpnext.stock.doctype.item.item import validate_end_of_life from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError -from erpnext.manufacturing.doctype.job_card.job_card import OverlapError -from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs +from erpnext.projects.doctype.timesheet.timesheet import OverlapError from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty from frappe.utils.csvutils import getlink @@ -709,10 +708,6 @@ def make_stock_entry(work_order_id, purpose, qty=None): stock_entry.from_warehouse = wip_warehouse stock_entry.to_warehouse = work_order.fg_warehouse stock_entry.project = work_order.project - if purpose=="Manufacture": - additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty, - company=work_order.company) - stock_entry.set("additional_costs", additional_costs) stock_entry.set_stock_entry_type() stock_entry.get_items() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1989f4d8143..03f6c93e35c 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -13,6 +13,7 @@ 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("HR", "doctype", "HR Settings") #2020-01-16 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 @@ -513,7 +514,6 @@ erpnext.patches.v11_0.rename_employee_loan_to_loan erpnext.patches.v11_0.move_leave_approvers_from_employee #13-06-2018 erpnext.patches.v11_0.update_department_lft_rgt erpnext.patches.v11_0.add_default_email_template_for_leave -execute:frappe.reload_doc("HR", "doctype", "HR Settings") 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 diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 1c9d4c0cdfc..1f2ccb075b5 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -478,15 +478,17 @@ class StockEntry(StockController): def set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost): if self.purpose in ["Manufacture", "Repack"]: for d in self.get("items"): - if (d.transfer_qty and (d.bom_no or d.t_warehouse) and raw_material_cost + if (d.transfer_qty and (d.bom_no or d.t_warehouse) and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)): - d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate")) - d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount")) - if (not d.basic_rate and self.work_order and - frappe.db.get_single_value("Manufacturing Settings", "material_consumption")): - d.basic_rate = get_valuation_rate_for_finished_good_entry(self.work_order) or 0 - d.basic_amount = d.basic_rate * d.qty + if self.work_order \ + and frappe.db.get_single_value("Manufacturing Settings", "material_consumption"): + bom_items = self.get_bom_raw_materials(d.transfer_qty) + raw_material_cost = sum([flt(d.qty)*flt(d.rate) for d in bom_items.values()]) + + if raw_material_cost: + d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate")) + d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount")) def distribute_additional_costs(self): if self.purpose == "Material Issue": @@ -1403,30 +1405,6 @@ def get_work_order_details(work_order, company): "additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce, company=company) } -def get_additional_costs(work_order=None, bom_no=None, fg_qty=None, company=None): - additional_costs = [] - operating_cost_per_unit = get_operating_cost_per_unit(work_order, bom_no) - expenses_included_in_valuation = frappe.get_cached_value("Company", company, "expenses_included_in_valuation") - - if operating_cost_per_unit: - additional_costs.append({ - "expense_account": expenses_included_in_valuation, - "description": "Operating Cost as per Work Order / BOM", - "amount": operating_cost_per_unit * flt(fg_qty) - }) - - if work_order and work_order.additional_operating_cost and work_order.qty: - additional_operating_cost_per_unit = \ - flt(work_order.additional_operating_cost) / flt(work_order.qty) - - additional_costs.append({ - "expense_account": expenses_included_in_valuation, - "description": "Additional Operating Cost", - "amount": additional_operating_cost_per_unit * flt(fg_qty) - }) - - return additional_costs - def get_operating_cost_per_unit(work_order=None, bom_no=None): operating_cost_per_unit = 0 if work_order: diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index b80f99d5514..2975f936948 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -610,7 +610,7 @@ def get_item_price(args, item_code, ignore_party=False): return frappe.db.sql(""" select name, price_list_rate, uom from `tabItem Price` {conditions} - order by uom desc, min_qty desc, valid_from desc """.format(conditions=conditions), args) + order by valid_from desc, min_qty desc, uom desc """.format(conditions=conditions), args) def get_price_list_rate_for(args, item_code): """ @@ -632,7 +632,8 @@ def get_price_list_rate_for(args, item_code): "customer": args.get('customer'), "supplier": args.get('supplier'), "uom": args.get('uom'), - "min_qty": args.get('qty'), + "min_qty": args.get('qty') if args.get('price_list_uom_dependant')\ + else flt(args.get('qty')) * flt(args.get("conversion_factor", 1)), "transaction_date": args.get('transaction_date'), } @@ -646,8 +647,8 @@ def get_price_list_rate_for(args, item_code): for field in ["customer", "supplier"]: del item_price_args[field] - general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party")) - + general_price_list_rate = get_item_price(item_price_args, item_code, + ignore_party=args.get("ignore_party")) if not general_price_list_rate: del item_price_args["min_qty"] general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))