From c865f229fbba691b46eb2d86edebf2d6d8e6c554 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 21 Sep 2015 09:18:43 +0530 Subject: [PATCH] Target Warehouse in Delivery Note and Sales Invoice and removed Serial No status --- .../doctype/sales_invoice/sales_invoice.py | 2 +- .../sales_invoice/test_sales_invoice.py | 7 +- .../sales_invoice_item.json | 25 ++- erpnext/controllers/selling_controller.py | 6 +- erpnext/controllers/stock_controller.py | 67 +++++-- .../doctype/sales_order/sales_order.py | 2 +- .../sales_order_item/sales_order_item.json | 25 ++- .../doctype/delivery_note/delivery_note.py | 2 +- .../delivery_note/test_delivery_note.py | 12 +- .../delivery_note_item.json | 25 ++- .../doctype/packed_item/packed_item.json | 165 ++++++++++++------ .../stock/doctype/packed_item/packed_item.py | 56 +++--- .../purchase_receipt/test_purchase_receipt.py | 2 - .../stock/doctype/serial_no/serial_no.json | 30 +--- erpnext/stock/doctype/serial_no/serial_no.py | 37 +--- .../serial_no_status/serial_no_status.json | 6 +- erpnext/stock/stock_balance.py | 5 +- 17 files changed, 291 insertions(+), 183 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 33fa4e340b..940f754262 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -422,7 +422,7 @@ class SalesInvoice(SellingController): def update_packing_list(self): if cint(self.update_stock) == 1: from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self, 'items') + make_packing_list(self) else: self.set('packed_items', []) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 0eae7cbcfb..20c734ce5c 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -688,7 +688,6 @@ class TestSalesInvoice(unittest.TestCase): si.insert() si.submit() - self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Delivered") self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "warehouse")) self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "delivery_document_no"), si.name) @@ -702,20 +701,18 @@ class TestSalesInvoice(unittest.TestCase): serial_nos = get_serial_nos(si.get("items")[0].serial_no) - self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "status"), "Available") self.assertEquals(frappe.db.get_value("Serial No", serial_nos[0], "warehouse"), "_Test Warehouse - _TC") self.assertFalse(frappe.db.get_value("Serial No", serial_nos[0], "delivery_document_no")) def test_serialize_status(self): - from erpnext.stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos, SerialNoDuplicateError + from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError, get_serial_nos, SerialNoDuplicateError from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item se = make_serialized_item() serial_nos = get_serial_nos(se.get("items")[0].serial_no) sr = frappe.get_doc("Serial No", serial_nos[0]) - sr.status = "Not Available" sr.save() si = frappe.copy_doc(test_records[0]) @@ -725,7 +722,7 @@ class TestSalesInvoice(unittest.TestCase): si.get("items")[0].serial_no = serial_nos[0] si.insert() - self.assertRaises(SerialNoStatusError, si.submit) + self.assertRaises(SerialNoWarehouseError, si.submit) # hack! because stock ledger entires are already inserted and are not rolled back! self.assertRaises(SerialNoDuplicateError, si.cancel) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 2a14b8cb57..49b5b1052e 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -843,6 +843,29 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "target_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Target Warehouse", + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1259,7 +1282,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-20 17:18:52.752064", + "modified": "2015-09-20 21:26:46.279615", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 4b44932a88..75be4d684c 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -173,7 +173,8 @@ class SellingController(StockController): 'uom': p.uom, 'batch_no': cstr(p.batch_no).strip(), 'serial_no': cstr(p.serial_no).strip(), - 'name': d.name + 'name': d.name, + 'target_warehouse': p.target_warehouse })) else: il.append(frappe._dict({ @@ -184,7 +185,8 @@ class SellingController(StockController): 'stock_uom': d.stock_uom, 'batch_no': cstr(d.get("batch_no")).strip(), 'serial_no': cstr(d.get("serial_no")).strip(), - 'name': d.name + 'name': d.name, + 'target_warehouse': p.target_warehouse })) return il diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index eccceb0ad3..4b58b3c046 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -7,6 +7,7 @@ from frappe.utils import cint, flt, cstr from frappe import msgprint, _ import frappe.defaults from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map +from erpnext.stock.utils import get_incoming_rate from erpnext.controllers.accounts_controller import AccountsController @@ -184,7 +185,7 @@ class StockController(AccountsController): "voucher_no": self.name, "voucher_detail_no": d.name, "actual_qty": (self.docstatus==1 and 1 or -1)*flt(d.get("stock_qty")), - "stock_uom": d.get("stock_uom"), + "stock_uom": frappe.db.get_value("Item", args.get("item_code") or d.get("item_code"), "stock_uom"), "incoming_rate": 0, "company": self.company, "fiscal_year": self.fiscal_year, @@ -217,13 +218,14 @@ class StockController(AccountsController): return serialized_items - def get_incoming_rate_for_sales_return(self, item_code, against_document): + def get_incoming_rate_for_sales_return(self, item_code, warehouse, against_document): incoming_rate = 0.0 if against_document and item_code: incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty) from `tabStock Ledger Entry` - where voucher_type = %s and voucher_no = %s and item_code = %s limit 1""", - (self.doctype, against_document, item_code)) + where voucher_type = %s and voucher_no = %s + and item_code = %s and warehouse=%s limit 1""", + (self.doctype, against_document, item_code, warehouse)) incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0 return incoming_rate @@ -252,19 +254,54 @@ class StockController(AccountsController): sl_entries = [] for d in self.get_item_list(): - if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 \ - and d.warehouse and flt(d['qty']): - - incoming_rate = 0 + if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty): + return_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']), - "stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"), - "incoming_rate": incoming_rate - })) + return_rate = self.get_incoming_rate_for_sales_return(d.item_code, + d.warehouse, self.return_against) + + # On cancellation or if return entry submission, make stock ledger entry for + # target warehouse first, to update serial no values properly + if d.warehouse and ((not cint(self.is_return) and self.docstatus==1) + or (cint(self.is_return) and self.docstatus==2)): + sl_entries.append(self.get_sl_entries(d, { + "actual_qty": -1*flt(d.qty), + "incoming_rate": return_rate + })) + + if d.target_warehouse: + target_warehouse_sle = self.get_sl_entries(d, { + "actual_qty": flt(d.qty), + "warehouse": d.target_warehouse + }) + + if self.docstatus == 1: + if not cint(self.is_return): + args = frappe._dict({ + "item_code": d.item_code, + "warehouse": d.warehouse, + "posting_date": self.posting_date, + "posting_time": self.posting_time, + "qty": -1*flt(d.qty), + "serial_no": d.serial_no + }) + target_warehouse_sle.update({ + "incoming_rate": get_incoming_rate(args) + }) + else: + target_warehouse_sle.update({ + "outgoing_rate": return_rate + }) + sl_entries.append(target_warehouse_sle) + + if d.warehouse and ((not cint(self.is_return) and self.docstatus==2) + or (cint(self.is_return) and self.docstatus==1)): + sl_entries.append(self.get_sl_entries(d, { + "actual_qty": -1*flt(d.qty), + "incoming_rate": return_rate + })) + self.make_sl_entries(sl_entries) def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 732867ff01..6cc12c53a9 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -33,7 +33,7 @@ class SalesOrder(SellingController): self.validate_warehouse() from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self,'items') + make_packing_list(self) self.validate_with_previous_doc() self.set_status() diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 8533ffaf75..a699a265b9 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -730,6 +730,29 @@ "unique": 0, "width": "150px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "target_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Target Warehouse", + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1072,7 +1095,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-27 02:29:20.603580", + "modified": "2015-09-20 21:26:22.732109", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 51d4e403fc..6339752634 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -113,7 +113,7 @@ class DeliveryNote(SellingController): self.validate_with_previous_doc() from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self, 'items') + make_packing_list(self) self.update_current_stock() diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index e41aab7324..d233d6b74a 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -15,7 +15,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice from erpnext.stock.doctype.stock_entry.test_stock_entry \ import make_stock_entry, make_serialized_item, get_qty_after_transaction -from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoStatusError +from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWarehouseError from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation class TestDeliveryNote(unittest.TestCase): @@ -152,7 +152,6 @@ class TestDeliveryNote(unittest.TestCase): dn = create_delivery_note(item_code="_Test Serialized Item With Series", serial_no=serial_no) self.check_serial_no_values(serial_no, { - "status": "Delivered", "warehouse": "", "delivery_document_no": dn.name }) @@ -160,7 +159,6 @@ class TestDeliveryNote(unittest.TestCase): dn.cancel() self.check_serial_no_values(serial_no, { - "status": "Available", "warehouse": "_Test Warehouse - _TC", "delivery_document_no": "" }) @@ -169,12 +167,10 @@ class TestDeliveryNote(unittest.TestCase): se = make_serialized_item() serial_no = get_serial_nos(se.get("items")[0].serial_no)[0] - frappe.db.set_value("Serial No", serial_no, "status", "Not Available") - dn = create_delivery_note(item_code="_Test Serialized Item With Series", serial_no=serial_no, do_not_submit=True) - self.assertRaises(SerialNoStatusError, dn.submit) + self.assertRaises(SerialNoWarehouseError, dn.submit) def check_serial_no_values(self, serial_no, field_values): serial_no = frappe.get_doc("Serial No", serial_no) @@ -295,7 +291,6 @@ class TestDeliveryNote(unittest.TestCase): dn = create_delivery_note(item_code="_Test Serialized Item With Series", rate=500, serial_no=serial_no) self.check_serial_no_values(serial_no, { - "status": "Delivered", "warehouse": "", "delivery_document_no": dn.name }) @@ -305,7 +300,6 @@ class TestDeliveryNote(unittest.TestCase): is_return=1, return_against=dn.name, qty=-1, rate=500, serial_no=serial_no) self.check_serial_no_values(serial_no, { - "status": "Sales Returned", "warehouse": "_Test Warehouse - _TC", "delivery_document_no": "" }) @@ -313,7 +307,6 @@ class TestDeliveryNote(unittest.TestCase): dn1.cancel() self.check_serial_no_values(serial_no, { - "status": "Delivered", "warehouse": "", "delivery_document_no": dn.name }) @@ -321,7 +314,6 @@ class TestDeliveryNote(unittest.TestCase): dn.cancel() self.check_serial_no_values(serial_no, { - "status": "Available", "warehouse": "_Test Warehouse - _TC", "delivery_document_no": "", "purchase_document_no": se.name diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index bdf771e54a..ea2e9a378d 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -751,6 +751,29 @@ "unique": 0, "width": "100px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "target_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Target Warehouse", + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1137,7 +1160,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-26 08:33:03.676574", + "modified": "2015-09-20 21:26:33.043965", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json index 330e6cf24a..0250c30606 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.json +++ b/erpnext/stock/doctype/packed_item/packed_item.json @@ -64,7 +64,7 @@ "hidden": 0, "ignore_user_permissions": 0, "in_filter": 1, - "in_list_view": 1, + "in_list_view": 0, "label": "Item Name", "no_copy": 0, "oldfieldname": "item_name", @@ -78,29 +78,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "parent_detail_docname", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Parent Detail docname", - "no_copy": 1, - "oldfieldname": "parent_detail_docname", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 1, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -147,6 +124,27 @@ "unique": 0, "width": "300px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "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, "bold": 0, @@ -156,7 +154,7 @@ "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, - "in_list_view": 1, + "in_list_view": 0, "label": "Warehouse", "no_copy": 0, "oldfieldname": "warehouse", @@ -171,6 +169,50 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "target_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Target Warehouse", + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break_9", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "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, "bold": 0, @@ -324,20 +366,19 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, - "fieldname": "uom", - "fieldtype": "Link", + "fieldname": "projected_qty", + "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "UOM", - "no_copy": 0, - "oldfieldname": "uom", - "oldfieldtype": "Link", - "options": "UOM", + "label": "Projected Qty", + "no_copy": 1, + "oldfieldname": "projected_qty", + "oldfieldtype": "Currency", "permlevel": 0, "print_hide": 0, "read_only": 1, @@ -369,19 +410,43 @@ "unique": 0 }, { - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "projected_qty", - "fieldtype": "Float", + "fieldname": "uom", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Projected Qty", - "no_copy": 1, - "oldfieldname": "projected_qty", - "oldfieldtype": "Currency", + "label": "UOM", + "no_copy": 0, + "oldfieldname": "uom", + "oldfieldtype": "Link", + "options": "UOM", + "permlevel": 0, + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "fieldname": "page_break", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Page Break", + "no_copy": 0, + "oldfieldname": "page_break", + "oldfieldtype": "Check", "permlevel": 0, "print_hide": 0, "read_only": 1, @@ -415,21 +480,21 @@ "unique": 0 }, { - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "page_break", - "fieldtype": "Check", - "hidden": 0, + "fieldname": "parent_detail_docname", + "fieldtype": "Data", + "hidden": 1, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Page Break", - "no_copy": 0, - "oldfieldname": "page_break", - "oldfieldtype": "Check", + "label": "Parent Detail docname", + "no_copy": 1, + "oldfieldname": "parent_detail_docname", + "oldfieldtype": "Data", "permlevel": 0, - "print_hide": 0, + "print_hide": 1, "read_only": 1, "report_hide": 0, "reqd": 0, @@ -446,7 +511,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-19 12:45:53.583367", + "modified": "2015-09-21 08:29:43.704286", "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 e7a75fe422..4d0d7c5955 100644 --- a/erpnext/stock/doctype/packed_item/packed_item.py +++ b/erpnext/stock/doctype/packed_item/packed_item.py @@ -25,67 +25,67 @@ def get_packing_item_details(item): def get_bin_qty(item, warehouse): det = frappe.db.sql("""select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s""", (item, warehouse), as_dict = 1) - return det and det[0] or '' + return det and det[0] or frappe._dict() -def update_packing_list_item(obj, packing_item_code, qty, warehouse, line): - bin = get_bin_qty(packing_item_code, warehouse) +def update_packing_list_item(doc, packing_item_code, qty, main_item_row): + bin = get_bin_qty(packing_item_code, main_item_row.warehouse) item = get_packing_item_details(packing_item_code) # check if exists exists = 0 - for d in obj.get("packed_items"): - if d.parent_item == line.item_code and d.item_code == packing_item_code and d.parent_detail_docname == line.name: + for d in doc.get("packed_items"): + if d.parent_item == main_item_row.item_code and d.item_code == packing_item_code and d.parent_detail_docname == main_item_row.name: pi, exists = d, 1 break if not exists: - pi = obj.append('packed_items', {}) + pi = doc.append('packed_items', {}) - pi.parent_item = line.item_code + pi.parent_item = main_item_row.item_code pi.item_code = packing_item_code - pi.item_name = item['item_name'] - pi.parent_detail_docname = line.name - pi.description = item['description'] - pi.uom = item['stock_uom'] + pi.item_name = item.item_name + pi.parent_detail_docname = main_item_row.name + pi.description = item.description + pi.uom = item.stock_uom pi.qty = flt(qty) - pi.actual_qty = bin and flt(bin['actual_qty']) or 0 - pi.projected_qty = bin and flt(bin['projected_qty']) or 0 + pi.actual_qty = flt(bin.get("actual_qty")) + pi.projected_qty = flt(bin.get("projected_qty")) if not pi.warehouse: - pi.warehouse = warehouse + pi.warehouse = main_item_row.warehouse if not pi.batch_no: - pi.batch_no = cstr(line.get("batch_no")) + pi.batch_no = cstr(main_item_row.get("batch_no")) + if not pi.target_warehouse: + pi.target_warehouse = main_item_row.get("target_warehouse") - - -def make_packing_list(obj, item_table_fieldname): +def make_packing_list(doc): """make packing list for Product Bundle item""" - if obj.get("_action") and obj._action == "update_after_submit": return + if doc.get("_action") and doc._action == "update_after_submit": return parent_items = [] - for d in obj.get(item_table_fieldname): + for d in doc.get("items"): if frappe.db.get_value("Product Bundle", {"new_item_code": d.item_code}): for i in get_product_bundle_items(d.item_code): - update_packing_list_item(obj, i['item_code'], flt(i['qty'])*flt(d.qty), d.warehouse, d) + update_packing_list_item(doc, i.item_code, flt(i.qty)*flt(d.qty), d) if [d.item_code, d.name] not in parent_items: parent_items.append([d.item_code, d.name]) - cleanup_packing_list(obj, parent_items) + cleanup_packing_list(doc, parent_items) -def cleanup_packing_list(obj, parent_items): +def cleanup_packing_list(doc, parent_items): """Remove all those child items which are no longer present in main item table""" delete_list = [] - for d in obj.get("packed_items"): + for d in doc.get("packed_items"): if [d.parent_item, d.parent_detail_docname] not in parent_items: # mark for deletion from doclist delete_list.append(d) if not delete_list: - return obj + return doc - packed_items = obj.get("packed_items") - obj.set("packed_items", []) + packed_items = doc.get("packed_items") + doc.set("packed_items", []) for d in packed_items: if d not in delete_list: - obj.append("packed_items", d) + doc.append("packed_items", d) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 50179646cb..7ad6489295 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -163,7 +163,6 @@ class TestPurchaseReceipt(unittest.TestCase): serial_no = get_serial_nos(pr.get("items")[0].serial_no)[0] _check_serial_no_values(serial_no, { - "status": "Available", "warehouse": "_Test Warehouse - _TC", "purchase_document_no": pr.name }) @@ -172,7 +171,6 @@ class TestPurchaseReceipt(unittest.TestCase): is_return=1, return_against=pr.name, serial_no=serial_no) _check_serial_no_values(serial_no, { - "status": "Purchase Returned", "warehouse": "", "purchase_document_no": pr.name, "delivery_document_no": return_pr.name diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json index 2823e39a51..78f1fecb8e 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.json +++ b/erpnext/stock/doctype/serial_no/serial_no.json @@ -99,32 +99,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "default": "Not Available", - "description": "Only Serial Nos with status \"Available\" can be delivered.", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 1, - "in_list_view": 1, - "label": "Status", - "no_copy": 1, - "oldfieldname": "status", - "oldfieldtype": "Select", - "options": "Not Available\nAvailable\nDelivered\nPurchase Returned\nSales Returned", - "permlevel": 0, - "print_hide": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -917,7 +891,7 @@ "is_submittable": 0, "issingle": 0, "istable": 0, - "modified": "2015-09-07 15:51:26", + "modified": "2015-09-20 20:39:40.751888", "modified_by": "Administrator", "module": "Stock", "name": "Serial No", @@ -986,7 +960,7 @@ ], "read_only": 0, "read_only_onload": 0, - "search_fields": "item_code,status", + "search_fields": "item_code", "sort_field": "modified", "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 0df0ba2a52..0edd8e30a3 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -16,7 +16,6 @@ class SerialNoRequiredError(ValidationError): pass class SerialNoQtyError(ValidationError): pass class SerialNoItemError(ValidationError): pass class SerialNoWarehouseError(ValidationError): pass -class SerialNoStatusError(ValidationError): pass class SerialNoNotExistsError(ValidationError): pass class SerialNoDuplicateError(ValidationError): pass @@ -75,28 +74,6 @@ class SerialNo(StockController): self.brand = item.brand self.warranty_period = item.warranty_period - def set_status(self, last_sle): - if last_sle: - if last_sle.voucher_type == "Stock Entry": - document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no, "purpose") - else: - document_type = last_sle.voucher_type - - if last_sle.actual_qty > 0: - if document_type in ("Delivery Note", "Sales Invoice", "Sales Return"): - self.status = "Sales Returned" - else: - self.status = "Available" - else: - if document_type in ("Purchase Receipt", "Purchase Invoice", "Purchase Return"): - self.status = "Purchase Returned" - elif document_type in ("Delivery Note", "Sales Invoice"): - self.status = "Delivered" - else: - self.status = "Not Available" - else: - self.status = "Not Available" - def set_purchase_details(self, purchase_sle): if purchase_sle: self.purchase_document_type = purchase_sle.voucher_type @@ -162,10 +139,10 @@ class SerialNo(StockController): return sle_dict def on_trash(self): - if self.status == 'Delivered': - frappe.throw(_("Delivered Serial No {0} cannot be deleted").format(self.name)) if self.warehouse: frappe.throw(_("Cannot delete Serial No {0} in stock. First remove from stock, then delete.").format(self.name)) + elif self.delivery_document_no: + frappe.throw(_("Delivered Serial No {0} cannot be deleted").format(self.name)) def before_rename(self, old, new, merge=False): if merge: @@ -187,7 +164,6 @@ class SerialNo(StockController): def on_stock_ledger_entry(self): if self.via_stock_ledger and not self.get("__islocal"): last_sle = self.get_last_sle() - self.set_status(last_sle.get("last_sle")) self.set_purchase_details(last_sle.get("purchase_sle")) self.set_sales_details(last_sle.get("delivery_sle")) self.set_maintenance_status() @@ -232,10 +208,10 @@ def validate_serial_no(sle, item_det): frappe.throw(_("Serial No {0} does not belong to Warehouse {1}").format(serial_no, sle.warehouse), SerialNoWarehouseError) - if sle.voucher_type in ("Delivery Note", "Sales Invoice") and sle.is_cancelled=="No" \ - and sr.status != "Available": - frappe.throw(_("Serial No {0} status must be 'Available' to Deliver").format(serial_no), - SerialNoStatusError) + if sle.voucher_type in ("Delivery Note", "Sales Invoice") \ + and sle.is_cancelled=="No" and not sr.warehouse: + frappe.throw(_("Serial No {0} does not belong to any Warehouse") + .format(serial_no), SerialNoWarehouseError) elif sle.actual_qty < 0: # transfer out @@ -287,7 +263,6 @@ def make_serial_no(serial_no, sle): sr.insert() sr.warehouse = sle.warehouse - sr.status = "Available" sr.save() frappe.msgprint(_("Serial No {0} created").format(sr.name)) return sr.name diff --git a/erpnext/stock/report/serial_no_status/serial_no_status.json b/erpnext/stock/report/serial_no_status/serial_no_status.json index ecfa3a0669..917d26f9e6 100644 --- a/erpnext/stock/report/serial_no_status/serial_no_status.json +++ b/erpnext/stock/report/serial_no_status/serial_no_status.json @@ -1,12 +1,14 @@ { + "add_total_row": 0, "apply_user_permissions": 1, "creation": "2013-01-14 10:52:58", + "disabled": 0, "docstatus": 0, "doctype": "Report", "idx": 1, "is_standard": "Yes", - "json": "{\"sort_by\": \"Serial No.name\", \"sort_order\": \"desc\", \"sort_by_next\": \"\", \"filters\": [], \"sort_order_next\": \"desc\", \"columns\": [[\"name\", \"Serial No\"], [\"item_code\", \"Serial No\"], [\"warehouse\", \"Serial No\"], [\"status\", \"Serial No\"], [\"item_name\", \"Serial No\"], [\"description\", \"Serial No\"], [\"item_group\", \"Serial No\"], [\"brand\", \"Serial No\"], [\"purchase_document_no\", \"Serial No\"], [\"purchase_date\", \"Serial No\"], [\"customer\", \"Serial No\"], [\"customer_name\", \"Serial No\"], [\"purchase_rate\", \"Serial No\"], [\"delivery_document_no\", \"Serial No\"], [\"delivery_date\", \"Serial No\"], [\"supplier\", \"Serial No\"], [\"supplier_name\", \"Serial No\"]]}", - "modified": "2014-06-03 07:18:17.327622", + "json": "{\"filters\":[],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"warehouse\",\"Serial No\"],[\"status\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"],[\"purchase_document_no\",\"Serial No\"],[\"purchase_date\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"purchase_rate\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"delivery_date\",\"Serial No\"],[\"supplier\",\"Serial No\"],[\"supplier_name\",\"Serial No\"]],\"sort_by\":\"Serial No.name\",\"sort_order\":\"desc\",\"sort_by_next\":null,\"sort_order_next\":\"desc\"}", + "modified": "2015-09-20 21:09:49.441973", "modified_by": "Administrator", "module": "Stock", "name": "Serial No Status", diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index cba2464efd..dd62e15c04 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -214,8 +214,7 @@ def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, postin def reset_serial_no_status_and_warehouse(serial_nos=None): if not serial_nos: - serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where status != 'Not in Use' - and docstatus = 0""") + serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where docstatus = 0""") for serial_no in serial_nos: try: sr = frappe.get_doc("Serial No", serial_no) @@ -228,8 +227,6 @@ def reset_serial_no_status_and_warehouse(serial_nos=None): except: pass - frappe.db.sql("""update `tabSerial No` set warehouse='' where status in ('Delivered', 'Purchase Returned')""") - def repost_all_stock_vouchers(): warehouses_with_account = frappe.db.sql_list("""select master_name from tabAccount where ifnull(account_type, '') = 'Warehouse'""")