Contract Manufacturing : Customer Provided Items (#15828)
* Material Request from Production Plan for Customer provided parts * Test cases * Customer web portal for their material requests
This commit is contained in:
parent
35b2627112
commit
2b14d6a058
@ -133,6 +133,13 @@ website_route_rules = [
|
||||
{"from_route": "/admissions", "to_route": "Student Admission"},
|
||||
{"from_route": "/boms", "to_route": "BOM"},
|
||||
{"from_route": "/timesheets", "to_route": "Timesheet"},
|
||||
{"from_route": "/material-requests", "to_route": "Material Request"},
|
||||
{"from_route": "/material-requests/<path:name>", "to_route": "material_request_info",
|
||||
"defaults": {
|
||||
"doctype": "Material Request",
|
||||
"parents": [{"label": _("Material Request"), "route": "material-requests"}]
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
standard_portal_menu_items = [
|
||||
@ -155,6 +162,7 @@ standard_portal_menu_items = [
|
||||
{"title": _("Newsletter"), "route": "/newsletters", "reference_doctype": "Newsletter"},
|
||||
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission"},
|
||||
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application"},
|
||||
{"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"},
|
||||
]
|
||||
|
||||
default_roles = [
|
||||
@ -168,6 +176,7 @@ has_website_permission = {
|
||||
"Quotation": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Sales Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Supplier Quotation": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Material Request": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Issue": "erpnext.support.doctype.issue.issue.has_website_permission",
|
||||
"Timesheet": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
|
@ -159,28 +159,30 @@ class BOM(WebsiteGenerator):
|
||||
if arg.get('scrap_items'):
|
||||
rate = self.get_valuation_rate(arg)
|
||||
elif arg:
|
||||
if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom:
|
||||
rate = self.get_bom_unitcost(arg['bom_no'])
|
||||
else:
|
||||
if self.rm_cost_as_per == 'Valuation Rate':
|
||||
rate = self.get_valuation_rate(arg)
|
||||
elif self.rm_cost_as_per == 'Last Purchase Rate':
|
||||
rate = arg.get('last_purchase_rate') \
|
||||
or frappe.db.get_value("Item", arg['item_code'], "last_purchase_rate")
|
||||
elif self.rm_cost_as_per == "Price List":
|
||||
if not self.buying_price_list:
|
||||
frappe.throw(_("Please select Price List"))
|
||||
rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list,
|
||||
"item_code": arg["item_code"]}, "price_list_rate") or 0.0
|
||||
#Customer Provided parts will have zero rate
|
||||
if not frappe.db.get_value('Item', arg["item_code"], 'is_customer_provided_item'):
|
||||
if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom:
|
||||
rate = self.get_bom_unitcost(arg['bom_no'])
|
||||
else:
|
||||
if self.rm_cost_as_per == 'Valuation Rate':
|
||||
rate = self.get_valuation_rate(arg)
|
||||
elif self.rm_cost_as_per == 'Last Purchase Rate':
|
||||
rate = arg.get('last_purchase_rate') \
|
||||
or frappe.db.get_value("Item", arg['item_code'], "last_purchase_rate")
|
||||
elif self.rm_cost_as_per == "Price List":
|
||||
if not self.buying_price_list:
|
||||
frappe.throw(_("Please select Price List"))
|
||||
rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list,
|
||||
"item_code": arg["item_code"]}, "price_list_rate") or 0.0
|
||||
|
||||
price_list_currency = frappe.db.get_value("Price List",
|
||||
self.buying_price_list, "currency")
|
||||
if price_list_currency != self.company_currency():
|
||||
rate = flt(rate * self.conversion_rate)
|
||||
price_list_currency = frappe.db.get_value("Price List",
|
||||
self.buying_price_list, "currency")
|
||||
if price_list_currency != self.company_currency():
|
||||
rate = flt(rate * self.conversion_rate)
|
||||
|
||||
if not rate:
|
||||
frappe.msgprint(_("{0} not found for Item {1}")
|
||||
.format(self.rm_cost_as_per, arg["item_code"]), alert=True)
|
||||
if not rate:
|
||||
frappe.msgprint(_("{0} not found for Item {1}")
|
||||
.format(self.rm_cost_as_per, arg["item_code"]), alert=True)
|
||||
|
||||
return flt(rate)
|
||||
|
||||
|
@ -131,4 +131,4 @@ class TestBOM(unittest.TestCase):
|
||||
self.assertEqual(bom.base_total_cost, 33000)
|
||||
|
||||
def get_default_bom(item_code="_Test FG Item 2"):
|
||||
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
|
||||
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
|
@ -419,8 +419,8 @@ class ProductionPlan(Document):
|
||||
for item in self.mr_items:
|
||||
item_doc = frappe.get_cached_doc('Item', item.item_code)
|
||||
|
||||
# key for Sales Order:Material Request Type
|
||||
key = '{}:{}'.format(item.sales_order, item_doc.default_material_request_type)
|
||||
# key for Sales Order:Material Request Type:Customer
|
||||
key = '{}:{}:{}'.format(item.sales_order, item_doc.default_material_request_type,item_doc.customer or '')
|
||||
schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days))
|
||||
|
||||
if not key in material_request_map:
|
||||
@ -432,7 +432,8 @@ class ProductionPlan(Document):
|
||||
"status": "Draft",
|
||||
"company": self.company,
|
||||
"requested_by": frappe.session.user,
|
||||
'material_request_type': item_doc.default_material_request_type
|
||||
'material_request_type': item_doc.default_material_request_type,
|
||||
'customer': item_doc.customer or ''
|
||||
})
|
||||
material_request_list.append(material_request)
|
||||
else:
|
||||
|
@ -142,12 +142,27 @@ class TestProductionPlan(unittest.TestCase):
|
||||
|
||||
self.assertEqual(sales_orders, [])
|
||||
|
||||
def test_pp_to_mr_customer_provided(self):
|
||||
#Material Request from Production Plan for Customer Provided
|
||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||
create_item('Production Item CUST')
|
||||
for item, raw_materials in {'Production Item CUST': ['Raw Material Item 1', 'CUST-0987']}.items():
|
||||
if not frappe.db.get_value('BOM', {'item': item}):
|
||||
make_bom(item = item, raw_materials = raw_materials)
|
||||
production_plan = create_production_plan(item_code = 'Production Item CUST')
|
||||
production_plan.make_material_request()
|
||||
material_request = frappe.get_value('Material Request Item', {'production_plan': production_plan.name}, 'parent')
|
||||
mr = frappe.get_doc('Material Request', material_request)
|
||||
self.assertTrue(mr.material_request_type, 'Customer Provided')
|
||||
self.assertTrue(mr.customer, '_Test Customer')
|
||||
|
||||
def create_production_plan(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
pln = frappe.get_doc({
|
||||
'doctype': 'Production Plan',
|
||||
'company': args.company or '_Test Company',
|
||||
'customer': args.customer or '_Test Customer',
|
||||
'posting_date': nowdate(),
|
||||
'include_non_stock_items': args.include_non_stock_items or 1,
|
||||
'include_subcontracted_items': args.include_subcontracted_items or 1,
|
||||
|
@ -68,12 +68,19 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
}
|
||||
|
||||
this.frm.set_query("item_code", "items", function() {
|
||||
if(me.frm.doc.is_subcontracted == "Yes") {
|
||||
if (me.frm.doc.is_subcontracted == "Yes") {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{ 'is_sub_contracted_item': 1 }
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if (me.frm.doc.material_request_type == "Customer Provided") {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{ 'customer': me.frm.doc.customer }
|
||||
}
|
||||
}
|
||||
else {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters: {'is_purchase_item': 1}
|
||||
|
@ -177,6 +177,9 @@ class DeliveryNote(SellingController):
|
||||
frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
|
||||
else:
|
||||
chk_dupl_itm.append(f)
|
||||
#Customer Provided parts will have zero valuation rate
|
||||
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
|
||||
d.allow_zero_valuation_rate = 1
|
||||
|
||||
def validate_warehouse(self):
|
||||
super(DeliveryNote, self).validate_warehouse()
|
||||
|
@ -115,6 +115,8 @@ frappe.ui.form.on("Item", {
|
||||
['is_stock_item', 'has_serial_no', 'has_batch_no'].forEach((fieldname) => {
|
||||
frm.set_df_property(fieldname, 'read_only', stock_exists);
|
||||
});
|
||||
|
||||
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
|
||||
},
|
||||
|
||||
validate: function(frm){
|
||||
@ -124,6 +126,10 @@ frappe.ui.form.on("Item", {
|
||||
image: function() {
|
||||
refresh_field("image_view");
|
||||
},
|
||||
|
||||
is_customer_provided_item: function(frm) {
|
||||
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
|
||||
},
|
||||
|
||||
is_fixed_asset: function(frm) {
|
||||
frm.call({
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -124,6 +124,7 @@ class Item(WebsiteGenerator):
|
||||
self.validate_uom_conversion_factor()
|
||||
self.validate_item_defaults()
|
||||
self.update_defaults_from_item_group()
|
||||
self.validate_customer_provided_part()
|
||||
|
||||
if not self.get("__islocal"):
|
||||
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
|
||||
@ -143,6 +144,14 @@ class Item(WebsiteGenerator):
|
||||
if cint(frappe.db.get_single_value('Stock Settings', 'clean_description_html')):
|
||||
self.description = clean_html(self.description)
|
||||
|
||||
def validate_customer_provided_part(self):
|
||||
if self.is_customer_provided_item:
|
||||
if self.is_purchase_item:
|
||||
frappe.throw(_('"Customer Provided Item" cannot be Purchase Item also'))
|
||||
if self.valuation_rate:
|
||||
frappe.throw(_('"Customer Provided Item" cannot have Valuation Rate'))
|
||||
self.default_material_request_type = "Customer Provided"
|
||||
|
||||
def add_price(self, price_list=None):
|
||||
'''Add a new price'''
|
||||
if not price_list:
|
||||
|
@ -319,7 +319,7 @@ def make_item_variant():
|
||||
|
||||
test_records = frappe.get_test_records('Item')
|
||||
|
||||
def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None):
|
||||
def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, is_customer_provided_item=None, customer=None, is_purchase_item=None):
|
||||
if not frappe.db.exists("Item", item_code):
|
||||
item = frappe.new_doc("Item")
|
||||
item.item_code = item_code
|
||||
@ -328,6 +328,9 @@ def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None)
|
||||
item.item_group = "All Item Groups"
|
||||
item.is_stock_item = is_stock_item or 1
|
||||
item.valuation_rate = valuation_rate or 0.0
|
||||
item.is_purchase_item = is_purchase_item
|
||||
item.is_customer_provided_item = is_customer_provided_item
|
||||
item.customer = customer or ''
|
||||
item.append("item_defaults", {
|
||||
"default_warehouse": warehouse or '_Test Warehouse - _TC',
|
||||
"company": "_Test Company"
|
||||
|
@ -40,6 +40,7 @@ frappe.ui.form.on('Material Request', {
|
||||
|
||||
refresh: function(frm) {
|
||||
frm.events.make_custom_buttons(frm);
|
||||
frm.toggle_reqd('customer', frm.doc.material_request_type=="Customer Provided");
|
||||
},
|
||||
|
||||
make_custom_buttons: function(frm) {
|
||||
@ -61,6 +62,11 @@ frappe.ui.form.on('Material Request', {
|
||||
() => frm.events.make_stock_entry(frm), __("Make"));
|
||||
}
|
||||
|
||||
if (frm.doc.material_request_type === "Customer Provided") {
|
||||
frm.add_custom_button(__("Material Receipt"),
|
||||
() => frm.events.make_stock_entry(frm), __("Make"));
|
||||
}
|
||||
|
||||
if (frm.doc.material_request_type === "Purchase") {
|
||||
frm.add_custom_button(__('Purchase Order'),
|
||||
() => frm.events.make_purchase_order(frm), __("Make"));
|
||||
@ -259,6 +265,9 @@ frappe.ui.form.on('Material Request', {
|
||||
}
|
||||
});
|
||||
},
|
||||
material_request_type: function(frm) {
|
||||
frm.toggle_reqd('customer', frm.doc.material_request_type=="Customer Provided");
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -70,7 +70,7 @@ class MaterialRequest(BuyingController):
|
||||
from erpnext.controllers.status_updater import validate_status
|
||||
validate_status(self.status,
|
||||
["Draft", "Submitted", "Stopped", "Cancelled", "Pending",
|
||||
"Partially Ordered", "Ordered", "Issued", "Transferred"])
|
||||
"Partially Ordered", "Ordered", "Issued", "Transferred", "Received"])
|
||||
|
||||
validate_for_items(self)
|
||||
|
||||
@ -154,7 +154,7 @@ class MaterialRequest(BuyingController):
|
||||
|
||||
for d in self.get("items"):
|
||||
if d.name in mr_items:
|
||||
if self.material_request_type in ("Material Issue", "Material Transfer"):
|
||||
if self.material_request_type in ("Material Issue", "Material Transfer", "Customer Provided"):
|
||||
d.ordered_qty = flt(frappe.db.sql("""select sum(transfer_qty)
|
||||
from `tabStock Entry Detail` where material_request = %s
|
||||
and material_request_item = %s and docstatus = 1""",
|
||||
@ -239,6 +239,18 @@ def update_item(obj, target, source_parent):
|
||||
target.qty = flt(flt(obj.stock_qty) - flt(obj.ordered_qty))/ target.conversion_factor
|
||||
target.stock_qty = (target.qty * target.conversion_factor)
|
||||
|
||||
def get_list_context(context=None):
|
||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||
list_context = get_list_context(context)
|
||||
list_context.update({
|
||||
'show_sidebar': True,
|
||||
'show_search': True,
|
||||
'no_breadcrumbs': True,
|
||||
'title': _('Material Request'),
|
||||
})
|
||||
|
||||
return list_context
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_status(name, status):
|
||||
material_request = frappe.get_doc('Material Request', name)
|
||||
@ -400,7 +412,7 @@ def make_stock_entry(source_name, target_doc=None):
|
||||
target.transfer_qty = qty * obj.conversion_factor
|
||||
target.conversion_factor = obj.conversion_factor
|
||||
|
||||
if source_parent.material_request_type == "Material Transfer":
|
||||
if source_parent.material_request_type == "Material Transfer" or source_parent.material_request_type == "Customer Provided":
|
||||
target.t_warehouse = obj.warehouse
|
||||
else:
|
||||
target.s_warehouse = obj.warehouse
|
||||
@ -410,6 +422,9 @@ def make_stock_entry(source_name, target_doc=None):
|
||||
if source.job_card:
|
||||
target.purpose = 'Material Transfer for Manufacture'
|
||||
|
||||
if source.material_request_type == "Customer Provided":
|
||||
target.purpose = "Material Receipt"
|
||||
|
||||
target.run_method("calculate_rate_and_amount")
|
||||
target.set_job_card_data()
|
||||
|
||||
|
@ -14,6 +14,8 @@ frappe.listview_settings['Material Request'] = {
|
||||
return [__("Transfered"), "green", "per_ordered,=,100"];
|
||||
} else if (doc.material_request_type == "Material Issue") {
|
||||
return [__("Issued"), "green", "per_ordered,=,100"];
|
||||
} else if (doc.material_request_type == "Customer Provided") {
|
||||
return [__("Received"), "green", "per_ordered,=,100"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ from __future__ import unicode_literals
|
||||
import frappe, unittest, erpnext
|
||||
from frappe.utils import flt, today
|
||||
from erpnext.stock.doctype.material_request.material_request import raise_work_orders
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
|
||||
class TestMaterialRequest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@ -601,11 +602,25 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
mr = frappe.get_doc("Material Request", mr.name)
|
||||
self.assertEqual(mr.per_ordered, 100)
|
||||
|
||||
def test_customer_provided_parts_mr(self):
|
||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||
mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided')
|
||||
se = make_stock_entry(mr.name)
|
||||
se.insert()
|
||||
se.submit()
|
||||
self.assertEqual(se.get("items")[0].amount, 0)
|
||||
self.assertEqual(se.get("items")[0].material_request, mr.name)
|
||||
mr = frappe.get_doc("Material Request", mr.name)
|
||||
mr.submit()
|
||||
self.assertEqual(mr.per_ordered, 100)
|
||||
|
||||
def make_material_request(**args):
|
||||
args = frappe._dict(args)
|
||||
mr = frappe.new_doc("Material Request")
|
||||
mr.material_request_type = args.material_request_type or "Purchase"
|
||||
mr.company = args.company or "_Test Company"
|
||||
mr.customer = args.customer or '_Test Customer'
|
||||
mr.append("items", {
|
||||
"item_code": args.item_code or "_Test Item",
|
||||
"qty": args.qty or 10,
|
||||
|
@ -179,6 +179,10 @@ class StockEntry(StockController):
|
||||
frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
|
||||
frappe.MandatoryError)
|
||||
|
||||
#Customer Provided parts will have zero valuation rate
|
||||
if frappe.db.get_value('Item', item.item_code, 'is_customer_provided_item'):
|
||||
item.allow_zero_valuation_rate = 1
|
||||
|
||||
def validate_qty(self):
|
||||
manufacture_purpose = ["Manufacture", "Material Consumption for Manufacture"]
|
||||
|
||||
|
@ -720,6 +720,13 @@ class TestStockEntry(unittest.TestCase):
|
||||
for d in stock_entry.get('items'):
|
||||
self.assertEqual(item_quantity.get(d.item_code), d.qty)
|
||||
|
||||
def test_customer_provided_parts_se(self):
|
||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||
se = make_stock_entry(item_code='CUST-0987', purporse = 'Material Receipt', qty=4, to_warehouse = "_Test Warehouse - _TC")
|
||||
self.assertEqual(se.get("items")[0].allow_zero_valuation_rate, 1)
|
||||
self.assertEqual(se.get("items")[0].amount, 0)
|
||||
|
||||
|
||||
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
||||
se = frappe.copy_doc(test_records[0])
|
||||
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
|
||||
|
74
erpnext/templates/pages/material_request_info.html
Normal file
74
erpnext/templates/pages/material_request_info.html
Normal file
@ -0,0 +1,74 @@
|
||||
{% extends "templates/web.html" %}
|
||||
{% from "erpnext/templates/includes/order/order_macros.html" import item_name_and_description %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{% include "templates/includes/breadcrumbs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ doc.name }}{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h1>{{ doc.name }}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block header_actions %}
|
||||
<a class='btn btn-xs btn-default' href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' target="_blank" rel="noopener noreferrer">{{ _("Print") }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
|
||||
<div class="row transaction-subheading">
|
||||
<div class="col-xs-6">
|
||||
|
||||
<span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
|
||||
{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-xs-6 text-muted text-right small">
|
||||
{{ frappe.utils.formatdate(doc.transaction_date, 'medium') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if doc._header %}
|
||||
{{ doc._header }}
|
||||
{% endif %}
|
||||
|
||||
<div class="order-container">
|
||||
|
||||
<!-- items -->
|
||||
<div class="order-item-table">
|
||||
<div class="row order-items order-item-header text-muted">
|
||||
<div class="col-sm-6 col-xs-6 h6 text-uppercase">
|
||||
{{ _("Item") }}
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-3 text-right h6 text-uppercase">
|
||||
{{ _("Work Order") }}
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-3 text-right h6 text-uppercase">
|
||||
{{ _("Quantity") }}
|
||||
</div>
|
||||
</div>
|
||||
{% for d in doc.items %}
|
||||
{% if d.customer_provided %}
|
||||
<div class="row order-items">
|
||||
<div class="col-sm-6 col-xs-6">
|
||||
{{ item_name_and_description(d) }}
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-3 text-right">
|
||||
{% for wo in d.work_orders %}
|
||||
<p class="text-muted small">{{_(wo.name) }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-3 text-right">
|
||||
{{ d.qty }}
|
||||
{% if d.delivered_qty is defined and d.delivered_qty != None %}
|
||||
<p class="text-muted small">{{
|
||||
_("Delivered: {0}").format(d.delivered_qty) }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
49
erpnext/templates/pages/material_request_info.py
Normal file
49
erpnext/templates/pages/material_request_info.py
Normal file
@ -0,0 +1,49 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
from frappe.utils import flt
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.show_sidebar = True
|
||||
context.doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name)
|
||||
if hasattr(context.doc, "set_indicator"):
|
||||
context.doc.set_indicator()
|
||||
|
||||
context.parents = frappe.form_dict.parents
|
||||
context.title = frappe.form_dict.name
|
||||
|
||||
if not frappe.has_website_permission(context.doc):
|
||||
frappe.throw(_("Not Permitted"), frappe.PermissionError)
|
||||
|
||||
default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=frappe.form_dict.doctype), "value")
|
||||
if default_print_format:
|
||||
context.print_format = default_print_format
|
||||
else:
|
||||
context.print_format = "Standard"
|
||||
context.doc.items = get_more_items_info(context.doc.items, context.doc.name)
|
||||
|
||||
def get_more_items_info(items, material_request):
|
||||
for item in items:
|
||||
item.customer_provided = frappe.get_value('Item', item.item_code, 'is_customer_provided_item')
|
||||
item.work_orders = frappe.db.sql("""
|
||||
select
|
||||
wo.name, wo.status, wo_item.consumed_qty
|
||||
from
|
||||
`tabWork Order Item` wo_item, `tabWork Order` wo
|
||||
where
|
||||
wo_item.item_code=%s
|
||||
and wo_item.consumed_qty=0
|
||||
and wo_item.parent=wo.name
|
||||
and wo.status not in ('Completed', 'Cancelled', 'Stopped')
|
||||
order by
|
||||
wo.name asc""", item.item_code, as_dict=1)
|
||||
item.delivered_qty = flt(frappe.db.sql("""select sum(transfer_qty)
|
||||
from `tabStock Entry Detail` where material_request = %s
|
||||
and item_code = %s and docstatus = 1""",
|
||||
(material_request, item.item_code))[0][0])
|
||||
return items
|
Loading…
x
Reference in New Issue
Block a user