commit
b52c6e866f
@ -45,7 +45,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
|
|
||||||
self.validate_with_previous_doc()
|
self.validate_with_previous_doc()
|
||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
self.update_raw_materials_supplied("po_raw_material_details")
|
self.create_raw_materials_supplied("po_raw_material_details")
|
||||||
|
|
||||||
def validate_with_previous_doc(self):
|
def validate_with_previous_doc(self):
|
||||||
super(PurchaseOrder, self).validate_with_previous_doc(self.tname, {
|
super(PurchaseOrder, self).validate_with_previous_doc(self.tname, {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-02-22 01:27:42.000000",
|
"creation": "2013-02-22 01:27:42",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -35,6 +35,21 @@
|
|||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"width": "300px"
|
"width": "300px"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "batch_no",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Batch No",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Batch",
|
||||||
|
"permlevel": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "serial_no",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"label": "Serial No",
|
||||||
|
"no_copy": 1,
|
||||||
|
"permlevel": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "col_break1",
|
"fieldname": "col_break1",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
@ -57,6 +72,7 @@
|
|||||||
"oldfieldname": "consumed_qty",
|
"oldfieldname": "consumed_qty",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"read_only": 1,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -137,9 +153,12 @@
|
|||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2014-02-13 11:29:35.000000",
|
"modified": "2014-05-08 18:37:42.966473",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Receipt Item Supplied",
|
"name": "Purchase Receipt Item Supplied",
|
||||||
"owner": "wasim@webnotestech.com"
|
"owner": "wasim@webnotestech.com",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
}
|
}
|
@ -200,48 +200,82 @@ class BuyingController(StockController):
|
|||||||
and not self.supplier_warehouse:
|
and not self.supplier_warehouse:
|
||||||
frappe.throw(_("Supplier Warehouse mandatory for sub-contracted Purchase Receipt"))
|
frappe.throw(_("Supplier Warehouse mandatory for sub-contracted Purchase Receipt"))
|
||||||
|
|
||||||
def update_raw_materials_supplied(self, raw_material_table):
|
def create_raw_materials_supplied(self, raw_material_table):
|
||||||
self.set(raw_material_table, [])
|
|
||||||
if self.is_subcontracted=="Yes":
|
if self.is_subcontracted=="Yes":
|
||||||
|
parent_items = []
|
||||||
|
rm_supplied_idx = 0
|
||||||
for item in self.get(self.fname):
|
for item in self.get(self.fname):
|
||||||
if self.doctype == "Purchase Receipt":
|
if self.doctype == "Purchase Receipt":
|
||||||
item.rm_supp_cost = 0.0
|
item.rm_supp_cost = 0.0
|
||||||
if item.item_code in self.sub_contracted_items:
|
if item.item_code in self.sub_contracted_items:
|
||||||
self.add_bom_items(item, raw_material_table)
|
self.update_raw_materials_supplied(item, raw_material_table, rm_supplied_idx)
|
||||||
|
|
||||||
|
if [item.item_code, item.name] not in parent_items:
|
||||||
|
parent_items.append([item.item_code, item.name])
|
||||||
|
|
||||||
|
self.cleanup_raw_materials_supplied(parent_items, raw_material_table)
|
||||||
|
|
||||||
elif self.doctype == "Purchase Receipt":
|
elif self.doctype == "Purchase Receipt":
|
||||||
for item in self.get(self.fname):
|
for item in self.get(self.fname):
|
||||||
item.rm_supp_cost = 0.0
|
item.rm_supp_cost = 0.0
|
||||||
|
|
||||||
def add_bom_items(self, d, raw_material_table):
|
def update_raw_materials_supplied(self, item, raw_material_table, rm_supplied_idx):
|
||||||
bom_items = self.get_items_from_default_bom(d.item_code)
|
bom_items = self.get_items_from_default_bom(item.item_code)
|
||||||
raw_materials_cost = 0
|
raw_materials_cost = 0
|
||||||
for item in bom_items:
|
|
||||||
required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor)
|
|
||||||
rm_doclist = {
|
|
||||||
"doctype": self.doctype + " Item Supplied",
|
|
||||||
"reference_name": d.name,
|
|
||||||
"bom_detail_no": item.name,
|
|
||||||
"main_item_code": d.item_code,
|
|
||||||
"rm_item_code": item.item_code,
|
|
||||||
"stock_uom": item.stock_uom,
|
|
||||||
"required_qty": required_qty,
|
|
||||||
"conversion_factor": d.conversion_factor,
|
|
||||||
"rate": item.rate,
|
|
||||||
"amount": required_qty * flt(item.rate)
|
|
||||||
}
|
|
||||||
if self.doctype == "Purchase Receipt":
|
|
||||||
rm_doclist.update({
|
|
||||||
"consumed_qty": required_qty,
|
|
||||||
"description": item.description,
|
|
||||||
})
|
|
||||||
|
|
||||||
self.append(raw_material_table, rm_doclist)
|
for bom_item in bom_items:
|
||||||
|
# check if exists
|
||||||
|
exists = 0
|
||||||
|
for d in self.get(raw_material_table):
|
||||||
|
if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \
|
||||||
|
and d.reference_name == item.name:
|
||||||
|
rm, exists = d, 1
|
||||||
|
break
|
||||||
|
|
||||||
|
if not exists:
|
||||||
|
rm = self.append(raw_material_table, {})
|
||||||
|
|
||||||
|
required_qty = flt(bom_item.qty_consumed_per_unit) * flt(item.qty) * flt(item.conversion_factor)
|
||||||
|
rm.reference_name = item.name
|
||||||
|
rm.bom_detail_no = bom_item.name
|
||||||
|
rm.main_item_code = item.item_code
|
||||||
|
rm.rm_item_code = bom_item.item_code
|
||||||
|
rm.stock_uom = bom_item.stock_uom
|
||||||
|
rm.required_qty = required_qty
|
||||||
|
|
||||||
|
rm.conversion_factor = item.conversion_factor
|
||||||
|
rm.rate = bom_item.rate
|
||||||
|
rm.amount = required_qty * flt(bom_item.rate)
|
||||||
|
rm.idx = rm_supplied_idx
|
||||||
|
|
||||||
|
if self.doc.doctype == "Purchase Receipt":
|
||||||
|
rm.consumed_qty = required_qty
|
||||||
|
rm.description = bom_item.description
|
||||||
|
if item.batch_no and not rm.batch_no:
|
||||||
|
rm.batch_no = item.batch_no
|
||||||
|
|
||||||
|
rm_supplied_idx += 1
|
||||||
|
|
||||||
raw_materials_cost += required_qty * flt(item.rate)
|
raw_materials_cost += required_qty * flt(item.rate)
|
||||||
|
|
||||||
if self.doctype == "Purchase Receipt":
|
if self.doctype == "Purchase Receipt":
|
||||||
d.rm_supp_cost = raw_materials_cost
|
item.rm_supp_cost = raw_materials_cost
|
||||||
|
|
||||||
|
def cleanup_raw_materials_supplied(self, parent_items, raw_material_table):
|
||||||
|
"""Remove all those child items which are no longer present in main item table"""
|
||||||
|
delete_list = []
|
||||||
|
for d in self.get(raw_material_table):
|
||||||
|
if [d.main_item_code, d.reference_name] not in parent_items:
|
||||||
|
# mark for deletion from doclist
|
||||||
|
delete_list.append([d.main_item_code, d.reference_name])
|
||||||
|
|
||||||
|
# delete from doclist
|
||||||
|
if delete_list:
|
||||||
|
rm_supplied_details = self.get(raw_material_table)
|
||||||
|
self.set(raw_material_table, [])
|
||||||
|
for d in rm_supplied_details:
|
||||||
|
if d not in delete_list:
|
||||||
|
self.append(raw_material_table, d)
|
||||||
|
|
||||||
def get_items_from_default_bom(self, item_code):
|
def get_items_from_default_bom(self, item_code):
|
||||||
bom_items = frappe.db.sql("""select t2.item_code, t2.qty_consumed_per_unit,
|
bom_items = frappe.db.sql("""select t2.item_code, t2.qty_consumed_per_unit,
|
||||||
|
@ -106,14 +106,21 @@ class ProductionPlanningTool(Document):
|
|||||||
msgprint(_("Please enter sales order in the above table"))
|
msgprint(_("Please enter sales order in the above table"))
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
item_condition = ""
|
||||||
|
if self.fg_item:
|
||||||
|
item_condition = ' and so_item.item_code = "' + self.fg_item + '"'
|
||||||
|
|
||||||
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
|
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
|
||||||
(qty - ifnull(delivered_qty, 0)) as pending_qty
|
(qty - ifnull(delivered_qty, 0)) as pending_qty
|
||||||
from `tabSales Order Item` so_item
|
from `tabSales Order Item` so_item
|
||||||
where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0)
|
where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0)
|
||||||
and exists (select * from `tabItem` item where item.name=so_item.item_code
|
and exists (select * from `tabItem` item where item.name=so_item.item_code
|
||||||
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
|
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
|
||||||
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
|
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes')) %s""" % \
|
||||||
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
|
(", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1)
|
||||||
|
|
||||||
|
if self.fg_item:
|
||||||
|
item_condition = ' and pi.item_code = "' + self.fg_item + '"'
|
||||||
|
|
||||||
packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as reserved_warhouse,
|
packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as reserved_warhouse,
|
||||||
(((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty)
|
(((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty)
|
||||||
@ -124,8 +131,8 @@ class ProductionPlanningTool(Document):
|
|||||||
and so_item.parent in (%s) and ifnull(so_item.qty, 0) > ifnull(so_item.delivered_qty, 0)
|
and so_item.parent in (%s) and ifnull(so_item.qty, 0) > ifnull(so_item.delivered_qty, 0)
|
||||||
and exists (select * from `tabItem` item where item.name=pi.item_code
|
and exists (select * from `tabItem` item where item.name=pi.item_code
|
||||||
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
|
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
|
||||||
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
|
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes')) %s""" % \
|
||||||
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
|
(", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1)
|
||||||
|
|
||||||
return items + packed_items
|
return items + packed_items
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
# sub-contracting
|
# sub-contracting
|
||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
self.update_raw_materials_supplied("pr_raw_material_details")
|
self.create_raw_materials_supplied("pr_raw_material_details")
|
||||||
|
|
||||||
self.update_valuation_rate("purchase_receipt_details")
|
self.update_valuation_rate("purchase_receipt_details")
|
||||||
|
|
||||||
|
@ -106,6 +106,11 @@ class StockReconciliation(StockController):
|
|||||||
if item.has_serial_no == "Yes":
|
if item.has_serial_no == "Yes":
|
||||||
raise frappe.ValidationError, _("Serialized Item {0} cannot be updated using Stock Reconciliation").format(item_code)
|
raise frappe.ValidationError, _("Serialized Item {0} cannot be updated using Stock Reconciliation").format(item_code)
|
||||||
|
|
||||||
|
# item managed batch-wise not allowed
|
||||||
|
if item.has_batch_no == "Yes":
|
||||||
|
frappe.throw(_("Item: {0} managed batch-wise, can not be reconciled using \
|
||||||
|
Stock Reconciliation, instead use Stock Entry").format(item_code))
|
||||||
|
|
||||||
# docstatus should be < 2
|
# docstatus should be < 2
|
||||||
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
||||||
|
|
||||||
|
@ -79,8 +79,7 @@ def get_incoming_rate(args):
|
|||||||
if not previous_sle:
|
if not previous_sle:
|
||||||
return 0.0
|
return 0.0
|
||||||
previous_stock_queue = json.loads(previous_sle.get('stock_queue', '[]') or '[]')
|
previous_stock_queue = json.loads(previous_sle.get('stock_queue', '[]') or '[]')
|
||||||
in_rate = previous_stock_queue and \
|
in_rate = get_fifo_rate(previous_stock_queue, args.get("qty") or 0) if previous_stock_queue else 0
|
||||||
get_fifo_rate(previous_stock_queue, args.get("qty") or 0) or 0
|
|
||||||
elif valuation_method == 'Moving Average':
|
elif valuation_method == 'Moving Average':
|
||||||
in_rate = previous_sle.get('valuation_rate') or 0
|
in_rate = previous_sle.get('valuation_rate') or 0
|
||||||
|
|
||||||
@ -107,24 +106,25 @@ def get_fifo_rate(previous_stock_queue, qty):
|
|||||||
total = sum(f[0] for f in previous_stock_queue)
|
total = sum(f[0] for f in previous_stock_queue)
|
||||||
return total and sum(f[0] * f[1] for f in previous_stock_queue) / flt(total) or 0.0
|
return total and sum(f[0] * f[1] for f in previous_stock_queue) / flt(total) or 0.0
|
||||||
else:
|
else:
|
||||||
outgoing_cost = 0
|
available_qty_for_outgoing, outgoing_cost = 0, 0
|
||||||
qty_to_pop = abs(qty)
|
qty_to_pop = abs(qty)
|
||||||
while qty_to_pop and previous_stock_queue:
|
while qty_to_pop and previous_stock_queue:
|
||||||
batch = previous_stock_queue[0]
|
batch = previous_stock_queue[0]
|
||||||
if 0 < batch[0] <= qty_to_pop:
|
if 0 < batch[0] <= qty_to_pop:
|
||||||
# if batch qty > 0
|
# if batch qty > 0
|
||||||
# not enough or exactly same qty in current batch, clear batch
|
# not enough or exactly same qty in current batch, clear batch
|
||||||
|
available_qty_for_outgoing += flt(batch[0])
|
||||||
outgoing_cost += flt(batch[0]) * flt(batch[1])
|
outgoing_cost += flt(batch[0]) * flt(batch[1])
|
||||||
qty_to_pop -= batch[0]
|
qty_to_pop -= batch[0]
|
||||||
previous_stock_queue.pop(0)
|
previous_stock_queue.pop(0)
|
||||||
else:
|
else:
|
||||||
# all from current batch
|
# all from current batch
|
||||||
|
available_qty_for_outgoing += flt(qty_to_pop)
|
||||||
outgoing_cost += flt(qty_to_pop) * flt(batch[1])
|
outgoing_cost += flt(qty_to_pop) * flt(batch[1])
|
||||||
batch[0] -= qty_to_pop
|
batch[0] -= qty_to_pop
|
||||||
qty_to_pop = 0
|
qty_to_pop = 0
|
||||||
|
|
||||||
# if queue gets blank and qty_to_pop remaining, get average rate of full queue
|
return outgoing_cost / available_qty_for_outgoing
|
||||||
return outgoing_cost / (abs(qty) - qty_to_pop)
|
|
||||||
|
|
||||||
def get_valid_serial_nos(sr_nos, qty=0, item_code=''):
|
def get_valid_serial_nos(sr_nos, qty=0, item_code=''):
|
||||||
"""split serial nos, validate and return list of valid serial nos"""
|
"""split serial nos, validate and return list of valid serial nos"""
|
||||||
|
Loading…
Reference in New Issue
Block a user