Merge pull request #2195 from neilLasrado/manufacture-and-repack

[fix] Issue #2183 - Manufacturing and repack seprated in stock entry
This commit is contained in:
Nabin Hait 2014-09-30 15:11:05 +05:30
commit 4f614b4030
13 changed files with 617 additions and 603 deletions

View File

@ -96,7 +96,7 @@ cur_frm.cscript['Transfer Raw Materials'] = function() {
}
cur_frm.cscript['Update Finished Goods'] = function() {
cur_frm.cscript.make_se('Manufacture/Repack');
cur_frm.cscript.make_se('Manufacture');
}
cur_frm.fields_dict['production_item'].get_query = function(doc) {

View File

@ -109,15 +109,15 @@
"permlevel": 0
},
{
"depends_on": "eval:doc.docstatus==1",
"description": "Automatically updated via Stock Entry of type Manufacture/Repack",
"fieldname": "produced_qty",
"fieldtype": "Float",
"label": "Manufactured Qty",
"no_copy": 1,
"oldfieldname": "produced_qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"depends_on": "eval:doc.docstatus==1",
"description": "Automatically updated via Stock Entry of type Manufacture or Repack",
"fieldname": "produced_qty",
"fieldtype": "Float",
"label": "Manufactured Qty",
"no_copy": 1,
"oldfieldname": "produced_qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 1
},
{

View File

@ -103,7 +103,7 @@ class ProductionOrder(Document):
status = "Submitted"
if stock_entries:
status = "In Process"
produced_qty = stock_entries.get("Manufacture/Repack")
produced_qty = stock_entries.get("Manufacture")
if flt(produced_qty) == flt(self.qty):
status = "Completed"
@ -113,7 +113,7 @@ class ProductionOrder(Document):
def update_produced_qty(self):
produced_qty = frappe.db.sql("""select sum(fg_completed_qty)
from `tabStock Entry` where production_order=%s and docstatus=1
and purpose='Manufacture/Repack'""", self.name)
and purpose='Manufacture'""", self.name)
produced_qty = flt(produced_qty[0][0]) if produced_qty else 0
if produced_qty > self.qty:

View File

@ -31,7 +31,7 @@ class TestProductionOrder(unittest.TestCase):
s.submit()
# from wip to fg
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture/Repack", 4))
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture", 4))
s.insert()
s.submit()
@ -49,7 +49,7 @@ class TestProductionOrder(unittest.TestCase):
test_stock_entry.make_stock_entry("_Test Item", None, "_Test Warehouse - _TC", 100, 100)
test_stock_entry.make_stock_entry("_Test Item Home Desktop 100", None, "_Test Warehouse - _TC", 100, 100)
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture/Repack", 7))
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture", 7))
s.insert()
self.assertRaises(StockOverProductionError, s.submit)

View File

@ -6,12 +6,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2014-06-03 07:18:17.082436",
"modified": "2014-09-17 12:41:55.740299",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Issued Items Against Production Order",
"owner": "Administrator",
"query": "select\n ste.production_order as \"Production Order:Link/Production Order:120\",\n ste.posting_date as \"Issue Date:Date:140\",\n ste_item.item_code as \"Item Code:Link/Item:120\",\n\tste_item.description as \"Description::150\",\n\tste_item.transfer_qty as \"Qty:Float:100\",\n\tste_item.stock_uom as \"UOM:Link/UOM:80\",\n\tste_item.amount as \"Amount:Currency:120\",\n\tste_item.serial_no as \"Serial No:Link/Serial No:80\",\n\tste_item.s_warehouse as \"Source Warehouse:Link/Warehouse:120\",\n\tste_item.t_warehouse as \"Target Warehouse:Link/Warehouse:120\",\n\tpro.production_item as \"Finished Goods:Link/Item:120\", \n\tste.name as \"Stock Entry:Link/Stock Entry:120\"\nfrom\n\t`tabStock Entry` ste, `tabStock Entry Detail` ste_item, `tabProduction Order` pro\nwhere\n\tifnull(ste.production_order, '') != '' and ste.name = ste_item.parent \n\tand ste.production_order = pro.name and ste.docstatus = 1 \n\tand ste.purpose = 'Manufacture/Repack'\norder by ste.posting_date, ste.production_order, ste_item.item_code",
"query": "select\n ste.production_order as \"Production Order:Link/Production Order:120\",\n ste.posting_date as \"Issue Date:Date:140\",\n ste_item.item_code as \"Item Code:Link/Item:120\",\n\tste_item.description as \"Description::150\",\n\tste_item.transfer_qty as \"Qty:Float:100\",\n\tste_item.stock_uom as \"UOM:Link/UOM:80\",\n\tste_item.amount as \"Amount:Currency:120\",\n\tste_item.serial_no as \"Serial No:Link/Serial No:80\",\n\tste_item.s_warehouse as \"Source Warehouse:Link/Warehouse:120\",\n\tste_item.t_warehouse as \"Target Warehouse:Link/Warehouse:120\",\n\tpro.production_item as \"Finished Goods:Link/Item:120\", \n\tste.name as \"Stock Entry:Link/Stock Entry:120\"\nfrom\n\t`tabStock Entry` ste, `tabStock Entry Detail` ste_item, `tabProduction Order` pro\nwhere\n\tifnull(ste.production_order, '') != '' and ste.name = ste_item.parent \n\tand ste.production_order = pro.name and ste.docstatus = 1 \n\tand ste.purpose = 'Manufacture' or 'Repack'\norder by ste.posting_date, ste.production_order, ste_item.item_code",
"ref_doctype": "Production Order",
"report_name": "Issued Items Against Production Order",
"report_type": "Query Report"

View File

@ -80,4 +80,5 @@ execute:frappe.delete_doc("DocType", "Landed Cost Wizard")
erpnext.patches.v4_2.default_website_style
erpnext.patches.v4_2.set_company_country
erpnext.patches.v4_2.update_sales_order_invoice_field_name
erpnext.patches.v4_2.cost_of_production_cycle
erpnext.patches.v4_2.cost_of_production_cycle
erpnext.patches.v4_2.seprate_manufacture_and_repack

View File

@ -0,0 +1,9 @@
# 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
def execute():
frappe.db.sql("""update `tabStock Entry` set purpose='Manufacture' where purpose='Manufacture/Repack' and ifnull(production_order,"")!="" """)
frappe.db.sql("""update `tabStock Entry` set purpose='Repack' where purpose='Manufacture/Repack' and ifnull(production_order,"")="" """)

View File

@ -120,7 +120,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
clean_up: function() {
// Clear Production Order record from locals, because it is updated via Stock Entry
if(this.frm.doc.production_order &&
this.frm.doc.purpose == "Manufacture/Repack") {
this.frm.doc.purpose == "Manufacture") {
frappe.model.remove_from_locals("Production Order",
this.frm.doc.production_order);
}
@ -162,7 +162,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
},
toggle_enable_bom: function() {
this.frm.toggle_enable("bom_no", !this.frm.doc.production_order);
this.frm.toggle_enable("bom_no", this.frm.doc.purpose!="Manufacture");
},
get_doctype_docname: function() {
@ -339,6 +339,8 @@ cur_frm.cscript.toggle_related_fields = function(doc) {
cur_frm.fields_dict["mtn_details"].grid.set_column_disp("s_warehouse", !disable_from_warehouse);
cur_frm.fields_dict["mtn_details"].grid.set_column_disp("t_warehouse", !disable_to_warehouse);
cur_frm.cscript.toggle_enable_bom();
if(doc.purpose == 'Purchase Return') {
doc.customer = doc.customer_name = doc.customer_address =
doc.delivery_note_no = doc.sales_invoice_no = null;
@ -351,6 +353,8 @@ cur_frm.cscript.toggle_related_fields = function(doc) {
doc.delivery_note_no = doc.sales_invoice_no = doc.supplier =
doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = null;
}
}
cur_frm.fields_dict['production_order'].get_query = function(doc) {
@ -457,4 +461,5 @@ cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) {
cur_frm.fields_dict.supplier.get_query = function(doc, cdt, cdn) {
return { query: "erpnext.controllers.queries.supplier_query" }
}
cur_frm.add_fetch('production_order', 'total_fixed_cost', 'total_fixed_cost');
cur_frm.add_fetch('production_order', 'total_fixed_cost', 'total_fixed_cost');
cur_frm.add_fetch('bom_no', 'total_fixed_cost', 'total_fixed_cost');

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@ class StockEntry(StockController):
self.validate_uom_is_integer("uom", "qty")
self.validate_uom_is_integer("stock_uom", "transfer_qty")
self.validate_warehouse(pro_obj)
self.validate_production_order(pro_obj)
self.validate_production_order()
self.get_stock_and_rate()
self.validate_incoming_rate()
self.validate_bom()
@ -54,6 +54,7 @@ class StockEntry(StockController):
self.validate_valuation_rate()
self.set_total_amount()
def on_submit(self):
self.update_stock_ledger()
@ -74,7 +75,7 @@ class StockEntry(StockController):
def validate_purpose(self):
valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer",
"Manufacture/Repack", "Subcontract", "Sales Return", "Purchase Return"]
"Manufacture", "Repack", "Subcontract", "Sales Return", "Purchase Return"]
if self.purpose not in valid_purposes:
frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
@ -137,7 +138,7 @@ class StockEntry(StockController):
if self.purpose in target_mandatory and not d.t_warehouse:
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
if self.purpose == "Manufacture/Repack":
if self.purpose in ["Manufacture", "Repack"]:
if validate_for_manufacture_repack:
if d.bom_no:
d.s_warehouse = None
@ -156,14 +157,11 @@ class StockEntry(StockController):
if cstr(d.s_warehouse) == cstr(d.t_warehouse):
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
def validate_production_order(self, pro_obj=None):
if not pro_obj:
if self.production_order:
pro_obj = frappe.get_doc('Production Order', self.production_order)
else:
return
if self.purpose == "Manufacture/Repack":
def validate_production_order(self):
if self.purpose == "Manufacture":
# check if production order is entered
if not self.production_order:
frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture"))
# check for double entry
self.check_duplicate_entry_for_production_order()
elif self.purpose != "Material Transfer":
@ -192,7 +190,7 @@ class StockEntry(StockController):
+ self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError)
def validate_valuation_rate(self):
if self.purpose == "Manufacture/Repack":
if self.purpose in ["Manufacture", "Repack"]:
valuation_at_source, valuation_at_target = 0, 0
for d in self.get("mtn_details"):
if d.s_warehouse and not d.t_warehouse:
@ -248,7 +246,7 @@ class StockEntry(StockController):
raw_material_cost += flt(d.amount)
# set incoming rate for fg item
if self.purpose == "Manufacture/Repack":
if self.purpose in ["Manufacture", "Repack"]:
number_of_fg_items = len([t.t_warehouse for t in self.get("mtn_details") if t.t_warehouse])
for d in self.get("mtn_details"):
if d.bom_no or (d.t_warehouse and number_of_fg_items == 1):
@ -391,7 +389,7 @@ class StockEntry(StockController):
pro_doc = frappe.get_doc("Production Order", self.production_order)
_validate_production_order(pro_doc)
pro_doc.run_method("update_status")
if self.purpose == "Manufacture/Repack":
if self.purpose == "Manufacture":
pro_doc.run_method("update_produced_qty")
self.update_planned_qty(pro_doc)
@ -463,20 +461,20 @@ class StockEntry(StockController):
def get_items(self):
self.set('mtn_details', [])
self.validate_production_order()
pro_obj = None
if self.production_order:
# common validations
pro_obj = frappe.get_doc('Production Order', self.production_order)
if pro_obj:
self.validate_production_order(pro_obj)
self.bom_no = pro_obj.bom_no
else:
# invalid production order
self.production_order = None
if self.bom_no:
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture/Repack",
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
"Subcontract"]:
if self.production_order and self.purpose == "Material Transfer":
item_dict = self.get_pending_raw_materials(pro_obj)
@ -493,7 +491,7 @@ class StockEntry(StockController):
self.add_to_stock_entry_detail(item_dict)
# add finished good item to Stock Entry Detail table -- along with bom_no
if self.production_order and self.purpose == "Manufacture/Repack":
if self.production_order and self.purpose == "Manufacture":
item = frappe.db.get_value("Item", pro_obj.production_item, ["item_name",
"description", "stock_uom", "expense_account", "buying_cost_center"], as_dict=1)
self.add_to_stock_entry_detail({
@ -509,7 +507,7 @@ class StockEntry(StockController):
}
}, bom_no=pro_obj.bom_no)
elif self.purpose in ["Material Receipt", "Manufacture/Repack"]:
elif self.purpose in ["Material Receipt", "Repack"]:
if self.purpose=="Material Receipt":
self.from_warehouse = ""

View File

@ -6,7 +6,8 @@
"Material Issue": "icon-arrow-right",
"Material Receipt": "icon-arrow-left",
"Material Transfer": "icon-resize-horizontal",
"Manufacture/Repack": "icon-wrench",
"Manufacture": "icon-wrench",
"Repack": "icon-wrench",
"Sales Return": "icon-warning-sign",
"Purchase Return": "icon-warning-sign",
"Subcontract": "icon-truck"

View File

@ -108,6 +108,6 @@
],
"posting_date": "2013-01-25",
"posting_time": "17:14:24",
"purpose": "Manufacture/Repack"
"purpose": "Repack"
}
]

View File

@ -843,7 +843,7 @@ class TestStockEntry(unittest.TestCase):
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.update({
"purpose": "Manufacture/Repack",
"purpose": "Manufacture",
"production_order": production_order.name,
"bom_no": bom_no,
"fg_completed_qty": "1",