From dcce0c86edd90b5e24d10a84e2b2da7d31ce01ef Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Aug 2014 15:37:03 +0530 Subject: [PATCH 1/5] Minimum ordered qty validation --- erpnext/buying/doctype/purchase_order/purchase_order.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index d9035f40c5..6c7c0c6d08 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -70,9 +70,14 @@ class PurchaseOrder(BuyingController): def validate_minimum_order_qty(self): itemwise_min_order_qty = frappe._dict(frappe.db.sql("select name, min_order_qty from tabItem")) + itemwise_qty = frappe._dict() for d in self.get("po_details"): - if flt(d.stock_qty) < flt(itemwise_min_order_qty.get(d.item_code)): - frappe.throw(_("Row #{0}: Ordered qty can not less than item's minimum order qty (defined in item master).").format(d.idx)) + itemwise_qty.setdefault(d.item_code, 0) + itemwise_qty[d.item_code] += flt(d.stock_qty) + + for item_code, qty in itemwise_qty.items(): + if flt(qty) < flt(itemwise_min_order_qty.get(item_code)): + frappe.throw(_("Item #{0}: Ordered qty can not less than item's minimum order qty (defined in item master).").format(item_code)) def get_schedule_dates(self): for d in self.get('po_details'): From 32a3a86a001556f1afc3383c8962dc99318a1795 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Aug 2014 15:38:04 +0530 Subject: [PATCH 2/5] General ledger report: invalid account --- erpnext/accounts/report/general_ledger/general_ledger.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index dd8052835e..fcacf7ce3d 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -20,6 +20,9 @@ def execute(filters=None): return columns, res def validate_filters(filters, account_details): + if filters.get("account") and not account_details.get(filters.account): + frappe.throw(_("Account {0} does not exists").format(filters.account)) + if filters.get("account") and filters.get("group_by_account") \ and account_details[filters.account].group_or_ledger == "Ledger": frappe.throw(_("Can not filter based on Account, if grouped by Account")) From 448c9b71c12871e5ee5c062678074b1bff7b63f1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Aug 2014 15:38:53 +0530 Subject: [PATCH 3/5] minot fix in material request --- .../material_request/material_request.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 89121e322c..10b5114f40 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -287,15 +287,18 @@ def make_purchase_order_based_on_supplier(source_name, target_doc=None): def get_material_requests_based_on_supplier(supplier): supplier_items = [d[0] for d in frappe.db.get_values("Item", {"default_supplier": supplier})] - material_requests = frappe.db.sql_list("""select distinct mr.name - from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item - where mr.name = mr_item.parent - and mr_item.item_code in (%s) - and mr.material_request_type = 'Purchase' - and ifnull(mr.per_ordered, 0) < 99.99 - and mr.docstatus = 1 - and mr.status != 'Stopped'""" % ', '.join(['%s']*len(supplier_items)), - tuple(supplier_items)) + if supplier_items: + material_requests = frappe.db.sql_list("""select distinct mr.name + from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item + where mr.name = mr_item.parent + and mr_item.item_code in (%s) + and mr.material_request_type = 'Purchase' + and ifnull(mr.per_ordered, 0) < 99.99 + and mr.docstatus = 1 + and mr.status != 'Stopped'""" % ', '.join(['%s']*len(supplier_items)), + tuple(supplier_items)) + else: + material_requests = [] return material_requests, supplier_items @frappe.whitelist() From 6394f5b1a9c66a16ae91eec4b4d21aef0671a9b9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Aug 2014 15:39:32 +0530 Subject: [PATCH 4/5] minot fix in pro order --- .../manufacturing/doctype/production_order/production_order.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index 1486d2a684..99a248bf1b 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -47,7 +47,7 @@ class ProductionOrder(Document): self.validate_production_order_against_so() else: - frappe.throw(_("Sales Order {0} is not valid") % self.sales_order) + frappe.throw(_("Sales Order {0} is not valid").format(self.sales_order)) def validate_warehouse(self): from erpnext.stock.utils import validate_warehouse_company From c41a9480b89b9e1921b40b79c91a316dacdadd3d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 18 Aug 2014 15:40:15 +0530 Subject: [PATCH 5/5] Credit limit fixes --- erpnext/accounts/doctype/account/account.py | 2 +- erpnext/controllers/selling_controller.py | 24 +++++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 2f60dca904..e067c70bf0 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -165,7 +165,7 @@ class Account(Document): # If outstanding greater than credit limit and not authorized person raise exception if credit_limit > 0 and flt(total_outstanding) > credit_limit \ and not self.get_authorized_user(): - throw(_("{0} Credit limit {0} crossed").format(_(credit_limit_from), credit_limit)) + throw(_("{0} Credit limit {1} crossed").format(_(credit_limit_from), credit_limit)) def validate_due_date(self, posting_date, due_date): credit_days = (self.credit_days or frappe.db.get_value("Company", self.company, "credit_days")) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index dd58758546..e758dd1a70 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -151,7 +151,7 @@ class SellingController(StockController): cumulated_tax_fraction += tax.tax_fraction_for_current_item - if cumulated_tax_fraction and not self.discount_amount_applied: + if cumulated_tax_fraction and not self.discount_amount_applied and item.qty: item.base_amount = flt((item.amount * self.conversion_rate) / (1 + cumulated_tax_fraction), self.precision("base_amount", item)) @@ -308,14 +308,23 @@ class SellingController(StockController): customer_account = frappe.db.get_value("Account", {"company": self.company, "master_name": self.customer}, "name") if customer_account: - total_outstanding = frappe.db.sql("""select + invoice_outstanding = frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) from `tabGL Entry` where account = %s""", customer_account) - total_outstanding = total_outstanding[0][0] if total_outstanding else 0 + invoice_outstanding = flt(invoice_outstanding[0][0]) if invoice_outstanding else 0 - outstanding_including_current = flt(total_outstanding) + flt(grand_total) - frappe.get_doc('Account', customer_account).run_method("check_credit_limit", - outstanding_including_current) + ordered_amount_to_be_billed = frappe.db.sql(""" + select sum(grand_total*(100 - ifnull(per_billed, 0))/100) + from `tabSales Order` + where customer=%s and docstatus = 1 + and ifnull(per_billed, 0) < 100 and status != 'Stopped'""", self.customer) + + ordered_amount_to_be_billed = flt(ordered_amount_to_be_billed[0][0]) \ + if ordered_amount_to_be_billed else 0.0 + + total_outstanding = invoice_outstanding + ordered_amount_to_be_billed + + frappe.get_doc('Account', customer_account).check_credit_limit(total_outstanding) def validate_max_discount(self): for d in self.get(self.fname): @@ -330,6 +339,9 @@ class SellingController(StockController): reserved_warehouse = "" reserved_qty_for_main_item = 0 + if not d.qty: + frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx)) + if self.doctype == "Sales Order": if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or self.has_sales_bom(d.item_code)) and not d.warehouse: