From 2acbb11923da8d124dd7416cba494d396290f64f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 19 Oct 2016 12:07:23 +0530 Subject: [PATCH 1/6] [fix] print format image size --- .../print_formats/includes/item_table_description.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/templates/print_formats/includes/item_table_description.html b/erpnext/templates/print_formats/includes/item_table_description.html index 16e98e0ea4..e99d71255a 100644 --- a/erpnext/templates/print_formats/includes/item_table_description.html +++ b/erpnext/templates/print_formats/includes/item_table_description.html @@ -2,7 +2,7 @@ {%- set compact_fields = doc.flags.compact_item_fields -%} {% if doc.in_format_data("image") and doc.get("image") and not doc.is_print_hide("image")-%} -
+
{%- endif %} From afceac620c757d506fcd6f81cbd4dc7d8c3968e1 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 19 Oct 2016 12:49:37 +0530 Subject: [PATCH 2/6] [fix] calculate variance only for submitted budgets --- .../report/budget_variance_report/budget_variance_report.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py index b67e2b6ec4..0be0b3d9a9 100644 --- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py +++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py @@ -64,7 +64,7 @@ def get_cost_center_target_details(filters): return frappe.db.sql(""" select b.cost_center, b.monthly_distribution, ba.account, ba.budget_amount from `tabBudget` b, `tabBudget Account` ba - where b.name=ba.parent and b.fiscal_year=%s and b.company=%s + where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year=%s and b.company=%s """, (filters.fiscal_year, filters.company), as_dict=True) #Get target distribution details of accounts of cost center @@ -84,8 +84,9 @@ def get_actual_details(cost_center, fiscal_year): ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit, MONTHNAME(gl.posting_date) as month_name, b.cost_center from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b - where + where b.name = ba.parent + and b.docstatus = 1 and ba.account=gl.account and gl.fiscal_year=%s and b.cost_center=%s From ff183eedb91cd7377d90ae64867ec4a4aa601b4f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 19 Oct 2016 13:03:49 +0530 Subject: [PATCH 3/6] Fixes for testcases --- .../doctype/salary_slip/test_salary_slip.py | 2 +- .../production_planning_tool.py | 29 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index d90d4b2c9b..48a945e725 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -14,7 +14,7 @@ class TestSalarySlip(unittest.TestCase): for dt in ["Leave Application", "Leave Allocation", "Salary Slip"]: frappe.db.sql("delete from `tab%s`" % dt) - make_allocation_record(leave_type="_Test Leave Type LWP") + # make_allocation_record(leave_type="_Test Leave Type") frappe.db.set_value("Company", "_Test Company", "default_holiday_list", "_Test Holiday List") diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py index 1e6c48aed7..5fbcf1eb90 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -454,21 +454,20 @@ class ProductionPlanningTool(Document): material_request.update({"material_request_type": item_wrapper.default_material_request_type}) for sales_order, requested_qty in items_to_be_requested[item].items(): - if sales_order != 'No Sales Order': - material_request.append("items", { - "doctype": "Material Request Item", - "__islocal": 1, - "item_code": item, - "item_name": item_wrapper.item_name, - "description": item_wrapper.description, - "uom": item_wrapper.stock_uom, - "item_group": item_wrapper.item_group, - "brand": item_wrapper.brand, - "qty": requested_qty, - "schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)), - "warehouse": self.purchase_request_for_warehouse, - "sales_order": sales_order if sales_order!="No Sales Order" else None - }) + material_request.append("items", { + "doctype": "Material Request Item", + "__islocal": 1, + "item_code": item, + "item_name": item_wrapper.item_name, + "description": item_wrapper.description, + "uom": item_wrapper.stock_uom, + "item_group": item_wrapper.item_group, + "brand": item_wrapper.brand, + "qty": requested_qty, + "schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)), + "warehouse": self.purchase_request_for_warehouse, + "sales_order": sales_order if sales_order!="No Sales Order" else None + }) material_request.flags.ignore_permissions = 1 material_request.submit() From ac9172f6dfafb238faca38dce664b0578c92631c Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 18 Oct 2016 17:22:56 +0530 Subject: [PATCH 4/6] [Fix] total projected qty --- .../production_order/test_production_order.py | 24 ++++++++++++++++ erpnext/patches.txt | 1 + .../repost_bin_qty_and_item_projected_qty.py | 28 +++++++++++++++++++ .../doctype/sales_order/test_sales_order.py | 8 ++++++ erpnext/stock/doctype/bin/bin.py | 12 ++++---- erpnext/stock/doctype/item/test_item.py | 6 ++++ 6 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.py b/erpnext/manufacturing/doctype/production_order/test_production_order.py index d29544b75e..49db299328 100644 --- a/erpnext/manufacturing/doctype/production_order/test_production_order.py +++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py @@ -10,7 +10,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per from erpnext.manufacturing.doctype.production_order.production_order \ import make_stock_entry, ItemHasVariantError from erpnext.stock.doctype.stock_entry import test_stock_entry +from erpnext.stock.doctype.item.test_item import get_total_projected_qty from erpnext.stock.utils import get_bin +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order class TestProductionOrder(unittest.TestCase): def setUp(self): @@ -172,6 +174,28 @@ class TestProductionOrder(unittest.TestCase): self.assertEqual(self.bin1_at_start.projected_qty, cint(bin1_on_cancel.projected_qty)) + def test_projected_qty_for_production_and_sales_order(self): + before_production_order = get_bin(self.item, self.warehouse) + before_production_order.update_reserved_qty_for_production() + + self.pro_order = make_prod_order_test_record(item="_Test FG Item", qty=2, + source_warehouse=self.warehouse) + + after_production_order = get_bin(self.item, self.warehouse) + + sales_order = make_sales_order(item = self.item, qty = 2) + after_sales_order = get_bin(self.item, self.warehouse) + + self.assertEqual(cint(before_production_order.reserved_qty_for_production) + 2, + cint(after_sales_order.reserved_qty_for_production)) + self.assertEqual(cint(before_production_order.projected_qty), + cint(after_sales_order.projected_qty) + 2) + + total_projected_qty = get_total_projected_qty(self.item) + + item_doc = frappe.get_doc('Item', self.item) + self.assertEqual(total_projected_qty, item_doc.total_projected_qty) + def test_reserved_qty_for_production_on_stock_entry(self): test_stock_entry.make_stock_entry(item_code="_Test Item", target= self.warehouse, qty=100, basic_rate=100) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d9ef272dbc..3caf714ddd 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -320,3 +320,4 @@ execute:frappe.db.sql("delete from `tabTimesheet Detail` where NOT EXISTS (selec erpnext.patches.v7_0.update_mode_of_payment_type finally:erpnext.patches.v7_0.update_timesheet_communications erpnext.patches.v7_0.update_status_of_zero_amount_sales_order +erpnext.patches.v7_0.repost_bin_qty_and_item_projected_qty 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 new file mode 100644 index 0000000000..97af20abc7 --- /dev/null +++ b/erpnext/patches/v7_0/repost_bin_qty_and_item_projected_qty.py @@ -0,0 +1,28 @@ +# 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.doctype.bin.bin import update_item_projected_qty + +def execute(): + repost_bin_qty() + repost_item_projected_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) != 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) + +def repost_item_projected_qty(): + for data in frappe.db.sql(""" select + `tabBin`.item_code as item_code, + sum(`tabBin`.projected_qty) as projected_qty, + `tabItem`.total_projected_qty as total_projected_qty + from + `tabBin`, `tabItem` + where `tabBin`.item_code = `tabItem`.name + group by `tabBin`.item_code having projected_qty <> total_projected_qty """, as_dict=1): + update_item_projected_qty(data.item_code) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index f687868e30..41f4ecfe60 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -5,6 +5,7 @@ import frappe from frappe.utils import flt, add_days import frappe.permissions import unittest +from erpnext.stock.doctype.item.test_item import get_total_projected_qty from erpnext.selling.doctype.sales_order.sales_order \ import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired @@ -427,6 +428,13 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(abs(flt(reserved_qty)), existing_reserved_qty_for_dn_item) + def test_total_projected_qty_against_sales_order(self): + so = make_sales_order(item = '_Test Item') + total_projected_qty = get_total_projected_qty('_Test Item') + + item_doc = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc.total_projected_qty) + def test_reserved_qty_for_closing_so(self): bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, fields=["reserved_qty"]) diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 2378e3f3e6..ece8220812 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -14,18 +14,18 @@ class Bin(Document): self.stock_uom = frappe.db.get_value('Item', self.item_code, 'stock_uom') self.validate_mandatory() - - self.projected_qty = flt(self.actual_qty) + flt(self.ordered_qty) + \ - flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty) - + self.set_projected_qty() self.block_transactions_against_group_warehouse() + def on_update(self): + update_item_projected_qty(self.item_code) + def validate_mandatory(self): qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty'] for f in qf: if (not getattr(self, f, None)) or (not self.get(f)): self.set(f, 0.0) - + def block_transactions_against_group_warehouse(self): from erpnext.stock.utils import is_group_warehouse is_group_warehouse(self.warehouse) @@ -72,9 +72,7 @@ class Bin(Document): self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty")) self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty")) - self.set_projected_qty() self.save() - update_item_projected_qty(self.item_code) def set_projected_qty(self): self.projected_qty = (flt(self.actual_qty) + flt(self.ordered_qty) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index bd617c6b85..aceefc0ce5 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -177,4 +177,10 @@ def make_item_variant(): variant.item_name = "_Test Variant Item-S" variant.save() +def get_total_projected_qty(item): + total_qty = frappe.db.sql(""" select sum(projected_qty) as projected_qty from tabBin + where item_code = %(item)s""", {'item': item}, as_dict=1) + + return total_qty[0].projected_qty if total_qty else 0.0 + test_records = frappe.get_test_records('Item') From aa8abfa5b3ae1c11b04de84a5fd4dae9162c1cb1 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 19 Oct 2016 15:26:10 +0530 Subject: [PATCH 5/6] Test cases added in sales order to check total projected qty --- .../doctype/sales_order/test_sales_order.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 41f4ecfe60..9922a1524d 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -125,8 +125,16 @@ class TestSalesOrder(unittest.TestCase): dn = create_dn_against_so(so.name, 15) self.assertEqual(get_reserved_qty(), existing_reserved_qty) + total_projected_qty = get_total_projected_qty('_Test Item') + item_doc_before_cancel = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc_before_cancel.total_projected_qty) + dn.cancel() self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10) + + total_projected_qty = get_total_projected_qty('_Test Item') + item_doc_after_cancel = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc_after_cancel.total_projected_qty) def test_reserved_qty_for_over_delivery_via_sales_invoice(self): # set over-delivery tolerance @@ -142,6 +150,10 @@ class TestSalesOrder(unittest.TestCase): si.get("items")[0].qty = 12 si.insert() si.submit() + + total_projected_qty = get_total_projected_qty('_Test Item') + item_doc = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc.total_projected_qty) self.assertEqual(get_reserved_qty(), existing_reserved_qty) @@ -151,6 +163,9 @@ class TestSalesOrder(unittest.TestCase): si.cancel() self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10) + total_projected_qty = get_total_projected_qty('_Test Item') + item_doc = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc.total_projected_qty) so.load_from_db() self.assertEqual(so.get("items")[0].delivered_qty, 0) @@ -179,6 +194,10 @@ class TestSalesOrder(unittest.TestCase): self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1) self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"), existing_reserved_qty_item2) + total_projected_qty = get_total_projected_qty('_Test Item') + item_doc = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc.total_projected_qty) + # unclose so so.load_from_db() so.update_status('Draft') @@ -212,6 +231,10 @@ class TestSalesOrder(unittest.TestCase): dn = create_dn_against_so(so.name, 15) + total_projected_qty = get_total_projected_qty('_Test Item') + item_doc = frappe.get_doc('Item', '_Test Item') + self.assertEqual(total_projected_qty, item_doc.total_projected_qty) + self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1) self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"), existing_reserved_qty_item2) From 13a07c202963da227dd110457718dea571061d98 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 19 Oct 2016 17:18:04 +0600 Subject: [PATCH 6/6] bumped to version 7.0.62 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 920a600414..df729860b7 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '7.0.61' +__version__ = '7.0.62' def get_default_company(user=None): '''Get default company for user'''