From 3c107cdbf8f2a3493254d0c72bdee91df42a59e2 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 25 Aug 2015 14:26:42 +0530 Subject: [PATCH 1/2] [enhancement] allow user to set warning for multiple items and sales order against multiple purchase orders #3699 --- .../buying_settings/buying_settings.json | 161 ++++++++++++++++-- .../purchase_common/purchase_common.py | 5 +- .../doctype/sales_order/sales_order.py | 10 +- .../selling_settings/selling_settings.json | 42 ++++- .../doctype/delivery_note/delivery_note.py | 11 +- 5 files changed, 205 insertions(+), 24 deletions(-) diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index 0ffe121285..f6c38b6e19 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.json +++ b/erpnext/buying/doctype/buying_settings/buying_settings.json @@ -1,76 +1,209 @@ { + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, "creation": "2013-06-25 11:04:03", + "custom": 0, "description": "Settings for Buying Module", "docstatus": 0, "doctype": "DocType", "document_type": "Other", "fields": [ { + "allow_on_submit": 0, "default": "Supplier Name", "fieldname": "supp_master_name", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Supplier Naming By", + "no_copy": 0, "options": "Supplier Name\nNaming Series", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "supplier_type", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Default Supplier Type", + "no_copy": 0, "options": "Supplier Type", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "buying_price_list", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Default Buying Price List", + "no_copy": 0, "options": "Price List", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_3", "fieldtype": "Column Break", - "permlevel": 0 - }, - { - "fieldname": "maintain_same_rate", - "fieldtype": "Check", - "label": "Maintain same rate throughout purchase cycle", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "po_required", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Purchase Order Required", + "no_copy": 0, "options": "No\nYes", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "pr_required", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Purchase Receipt Required", + "no_copy": 0, "options": "No\nYes", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "maintain_same_rate", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Maintain same rate throughout purchase cycle", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "allow_multiple_items", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Allow Item to be added multiple times in a transaction", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], + "hide_heading": 0, + "hide_toolbar": 0, "icon": "icon-cog", "idx": 1, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, "issingle": 1, - "modified": "2015-02-05 05:11:35.373253", + "istable": 0, + "modified": "2015-08-25 04:55:06.052342", "modified_by": "Administrator", "module": "Buying", "name": "Buying Settings", "owner": "Administrator", "permissions": [ { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, "create": 1, + "delete": 0, "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, "permlevel": 0, "print": 1, "read": 1, + "report": 0, "role": "System Manager", + "set_user_permissions": 0, "share": 1, + "submit": 0, "write": 1 } - ] + ], + "read_only": 0, + "read_only_onload": 0 } \ No newline at end of file diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py index 7c55d59350..28ea23ce9a 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.py +++ b/erpnext/buying/doctype/purchase_common/purchase_common.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import flt, cstr +from frappe.utils import flt, cstr, cint from frappe import _ from erpnext.stock.doctype.item.item import get_last_purchase_details @@ -72,7 +72,8 @@ class PurchaseCommon(BuyingController): frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx)) items.append(cstr(d.item_code)) - if items and len(items) != len(set(items)): + if items and len(items) != len(set(items)) and \ + not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0): frappe.msgprint(_("Warning: Same item has been entered multiple times.")) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b05c009fa0..720255a5c1 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe import json import frappe.utils -from frappe.utils import cstr, flt, getdate, comma_and +from frappe.utils import cstr, flt, getdate, comma_and, cint from frappe import _ from frappe.model.mapper import get_mapped_doc @@ -33,7 +33,8 @@ class SalesOrder(SellingController): so = frappe.db.sql("select name from `tabSales Order` \ where ifnull(po_no, '') = %s and name != %s and docstatus < 2\ and customer = %s", (self.po_no, self.name, self.customer)) - if so and so[0][0]: + if so and so[0][0] and not \ + cint(frappe.db.get_single_value("Selling Settings", "allow_against_multiple_purchase_orders")): frappe.msgprint(_("Warning: Sales Order {0} already exists against same Purchase Order number").format(so[0][0])) def validate_for_items(self): @@ -53,8 +54,11 @@ class SalesOrder(SellingController): tot_avail_qty = frappe.db.sql("select projected_qty from `tabBin` \ where item_code = %s and warehouse = %s", (d.item_code,d.warehouse)) d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0 + + # check for same entry multiple times unique_chk_list = set(check_list) - if len(unique_chk_list) != len(check_list): + if len(unique_chk_list) != len(check_list) and \ + not cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")): frappe.msgprint(_("Warning: Same item has been entered multiple times.")) def product_bundle_has_stock_item(self, product_bundle): diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index fb239d61ff..30d7e51544 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -207,6 +207,46 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "allow_multiple_items", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Allow Item to be added multiple times in a transaction", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "allow_against_multiple_purchase_orders", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Allow multiple Sales Orders against a Supplier Purchase Order", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "hide_heading": 0, @@ -218,7 +258,7 @@ "is_submittable": 0, "issingle": 1, "istable": 0, - "modified": "2015-08-03 12:59:51.829458", + "modified": "2015-08-25 04:52:06.879614", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 5e11962ea5..a17ee63218 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -133,6 +133,9 @@ class DeliveryNote(SellingController): def validate_for_items(self): check_list, chk_dupl_itm = [], [] + if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")): + return + for d in self.get('items'): e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or ''] f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice] @@ -249,11 +252,11 @@ class DeliveryNote(SellingController): if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 \ and d.warehouse and flt(d['qty']): self.update_reserved_qty(d) - + incoming_rate = 0 if cint(self.is_return) and self.return_against and self.docstatus==1: incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against) - + sl_entries.append(self.get_sl_entries(d, { "actual_qty": -1*flt(d['qty']), "incoming_rate": incoming_rate @@ -374,8 +377,8 @@ def make_packing_slip(source_name, target_doc=None): return doclist - + @frappe.whitelist() def make_sales_return(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc - return make_return_doc("Delivery Note", source_name, target_doc) \ No newline at end of file + return make_return_doc("Delivery Note", source_name, target_doc) From 6cf193d4324aba9fa4cc810fedad12dc8361f5e1 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 27 Aug 2015 12:21:17 +0530 Subject: [PATCH 2/2] [minor] In Sales Order, changed label from PO No. to Customer's Purchase Order --- .../doctype/sales_order/sales_order.json | 10 +++---- .../doctype/sales_order/sales_order.py | 8 +++--- .../selling_settings/selling_settings.json | 28 +++++++++++++++++-- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index a9734bf18a..f7497072c4 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -381,14 +381,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "description": "Customer's Purchase Order Number", + "description": "", "fieldname": "po_no", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "PO No", + "label": "Customer's Purchase Order", "no_copy": 0, "oldfieldname": "po_no", "oldfieldtype": "Data", @@ -407,14 +407,14 @@ "bold": 0, "collapsible": 0, "depends_on": "eval:doc.po_no", - "description": "Customer's Purchase Order Date", + "description": "", "fieldname": "po_date", "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "PO Date", + "label": "Customer's Purchase Order Date", "no_copy": 0, "oldfieldname": "po_date", "oldfieldtype": "Date", @@ -2553,7 +2553,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-08-26 08:31:08.753604", + "modified": "2015-08-27 02:44:24.437994", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 53969e810f..44ea6649ff 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -36,7 +36,7 @@ class SalesOrder(SellingController): and customer = %s", (self.po_no, self.name, self.customer)) if so and so[0][0] and not \ cint(frappe.db.get_single_value("Selling Settings", "allow_against_multiple_purchase_orders")): - frappe.msgprint(_("Warning: Sales Order {0} already exists against same Purchase Order number").format(so[0][0])) + frappe.msgprint(_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(so[0][0], self.po_no)) def validate_for_items(self): check_list = [] @@ -228,7 +228,7 @@ class SalesOrder(SellingController): frappe.db.set(self, 'status', 'Submitted') self.update_reserved_qty() frappe.msgprint(_("{0} {1} status is Unstopped").format(self.doctype, self.name)) - + def update_reserved_qty(self, so_item_rows=None): """update requested qty (before ordered_qty is updated)""" item_wh_list = [] @@ -236,11 +236,11 @@ class SalesOrder(SellingController): if item_code and warehouse and [item_code, warehouse] not in item_wh_list \ and frappe.db.get_value("Item", item_code, "is_stock_item"): item_wh_list.append([item_code, warehouse]) - + for d in self.get("items"): if (not so_item_rows or d.name in so_item_rows): _valid_for_reserve(d.item_code, d.warehouse) - + if self.has_product_bundle(d.item_code): for p in self.get("packed_items"): if p.parent_detail_docname == d.name and p.parent_item == d.item_code: diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 30d7e51544..affa38b88b 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -11,6 +11,8 @@ "fields": [ { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "default": "Customer Name", "fieldname": "cust_master_name", "fieldtype": "Select", @@ -32,6 +34,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "campaign_naming_by", "fieldtype": "Select", "hidden": 0, @@ -52,6 +56,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "description": "", "fieldname": "customer_group", "fieldtype": "Link", @@ -73,6 +79,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "description": "", "fieldname": "territory", "fieldtype": "Link", @@ -94,6 +102,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "selling_price_list", "fieldtype": "Link", "hidden": 0, @@ -114,6 +124,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "column_break_5", "fieldtype": "Column Break", "hidden": 0, @@ -132,6 +144,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "so_required", "fieldtype": "Select", "hidden": 0, @@ -152,6 +166,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "dn_required", "fieldtype": "Select", "hidden": 0, @@ -172,6 +188,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "maintain_same_sales_rate", "fieldtype": "Check", "hidden": 0, @@ -191,6 +209,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "editable_price_list_rate", "fieldtype": "Check", "hidden": 0, @@ -210,6 +230,8 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "allow_multiple_items", "fieldtype": "Check", "hidden": 0, @@ -230,13 +252,15 @@ }, { "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "fieldname": "allow_against_multiple_purchase_orders", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Allow multiple Sales Orders against a Supplier Purchase Order", + "label": "Allow multiple Sales Orders against a Customer's Purchase Order", "no_copy": 0, "permlevel": 0, "precision": "", @@ -258,7 +282,7 @@ "is_submittable": 0, "issingle": 1, "istable": 0, - "modified": "2015-08-25 04:52:06.879614", + "modified": "2015-08-27 02:42:56.512460", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings",