[enhance] production order from sales order
This commit is contained in:
parent
ed94aa4798
commit
6ede4a3809
File diff suppressed because it is too large
Load Diff
@ -249,7 +249,7 @@ class ProductionPlanningTool(Document):
|
||||
"wip_warehouse" : "",
|
||||
"fg_warehouse" : d.warehouse,
|
||||
"status" : "Draft",
|
||||
"project" : frappe.db.get_value("Sales Order", d.sales_order, "project")
|
||||
"project" : frappe.db.get_value("Sales Order", d.sales_order, "project")
|
||||
}
|
||||
|
||||
""" Club similar BOM and item for processing in case of Sales Orders """
|
||||
@ -345,53 +345,53 @@ class ProductionPlanningTool(Document):
|
||||
|
||||
def get_subitems(self,bom_wise_item_details, bom, parent_qty, include_sublevel, only_raw, supply_subs,non_stock_item=0):
|
||||
items = frappe.db.sql("""
|
||||
SELECT
|
||||
bom_item.item_code,
|
||||
SELECT
|
||||
bom_item.item_code,
|
||||
default_material_request_type,
|
||||
ifnull(%(parent_qty)s * sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
item.is_sub_contracted_item as is_sub_contracted,
|
||||
item.is_sub_contracted_item as is_sub_contracted,
|
||||
item.default_bom as default_bom,
|
||||
bom_item.description as description,
|
||||
bom_item.stock_uom as stock_uom,
|
||||
item.min_order_qty as min_order_qty
|
||||
bom_item.description as description,
|
||||
bom_item.stock_uom as stock_uom,
|
||||
item.min_order_qty as min_order_qty
|
||||
FROM
|
||||
`tabBOM Item` bom_item,
|
||||
`tabBOM` bom,
|
||||
`tabBOM Item` bom_item,
|
||||
`tabBOM` bom,
|
||||
tabItem item
|
||||
where
|
||||
bom.name = bom_item.parent
|
||||
and bom.name = %(bom)s
|
||||
bom.name = bom_item.parent
|
||||
and bom.name = %(bom)s
|
||||
and bom_item.docstatus < 2
|
||||
and bom_item.item_code = item.name
|
||||
""" + ("and item.is_stock_item = 1", "")[non_stock_item] + """
|
||||
group by bom_item.item_code""", {"bom": bom, "parent_qty": parent_qty}, as_dict=1)
|
||||
|
||||
|
||||
for d in items:
|
||||
if ((d.default_material_request_type == "Purchase"
|
||||
and not (d.is_sub_contracted and only_raw and include_sublevel))
|
||||
if ((d.default_material_request_type == "Purchase"
|
||||
and not (d.is_sub_contracted and only_raw and include_sublevel))
|
||||
or (d.default_material_request_type == "Manufacture" and not only_raw)):
|
||||
|
||||
if d.item_code in bom_wise_item_details:
|
||||
bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty
|
||||
else:
|
||||
bom_wise_item_details[d.item_code] = d
|
||||
|
||||
|
||||
if include_sublevel:
|
||||
if ((d.default_material_request_type == "Purchase" and d.is_sub_contracted and supply_subs)
|
||||
if ((d.default_material_request_type == "Purchase" and d.is_sub_contracted and supply_subs)
|
||||
or (d.default_material_request_type == "Manufacture")):
|
||||
|
||||
|
||||
my_qty = 0
|
||||
projected_qty = self.get_item_projected_qty(d.item_code)
|
||||
|
||||
|
||||
if self.create_material_requests_for_all_required_qty:
|
||||
my_qty = d.qty
|
||||
elif (bom_wise_item_details[d.item_code].qty - d.qty) < projected_qty:
|
||||
my_qty = bom_wise_item_details[d.item_code].qty - projected_qty
|
||||
else:
|
||||
my_qty = d.qty
|
||||
|
||||
|
||||
if my_qty > 0:
|
||||
self.get_subitems(bom_wise_item_details,
|
||||
self.get_subitems(bom_wise_item_details,
|
||||
d.default_bom, my_qty, include_sublevel, only_raw, supply_subs)
|
||||
|
||||
return bom_wise_item_details
|
||||
@ -408,12 +408,12 @@ class ProductionPlanningTool(Document):
|
||||
item_list.append([item, self.item_dict[item][0][1], self.item_dict[item][0][2], total_qty])
|
||||
item_qty = frappe.db.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
|
||||
from `tabBin` where item_code = %s""", item, as_dict=1)
|
||||
|
||||
|
||||
i_qty, o_qty, a_qty = 0, 0, 0
|
||||
for w in item_qty:
|
||||
i_qty, o_qty, a_qty = i_qty + flt(w.indented_qty), o_qty + \
|
||||
flt(w.ordered_qty), a_qty + flt(w.actual_qty)
|
||||
|
||||
|
||||
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
|
||||
flt(w.ordered_qty), flt(w.actual_qty)])
|
||||
if item_qty:
|
||||
@ -485,15 +485,15 @@ class ProductionPlanningTool(Document):
|
||||
def get_item_projected_qty(self,item):
|
||||
item_projected_qty = frappe.db.sql("""
|
||||
select ifnull(sum(projected_qty),0) as qty
|
||||
from `tabBin`
|
||||
from `tabBin`
|
||||
where item_code = %(item_code)s and warehouse=%(warehouse)s
|
||||
""", {
|
||||
"item_code": item,
|
||||
"item_code": item,
|
||||
"warehouse": self.purchase_request_for_warehouse
|
||||
}, as_dict=1)
|
||||
|
||||
return item_projected_qty[0].qty
|
||||
|
||||
|
||||
def get_projected_qty(self):
|
||||
items = self.item_dict.keys()
|
||||
item_projected_qty = frappe.db.sql("""select item_code, sum(projected_qty)
|
||||
|
@ -4,11 +4,23 @@
|
||||
{% include 'erpnext/selling/sales_common.js' %}
|
||||
|
||||
frappe.ui.form.on("Sales Order", {
|
||||
setup: function(frm) {
|
||||
$.extend(frm.cscript, new erpnext.selling.SalesOrderController({frm: frm}));
|
||||
},
|
||||
onload: function(frm) {
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
|
||||
frm.set_query('project', function(doc, cdt, cdn) {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_project_name",
|
||||
filters: {
|
||||
'customer': doc.customer
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// formatter for material request item
|
||||
frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.delivered_qty) ? "green" : "orange" })
|
||||
@ -17,6 +29,7 @@ frappe.ui.form.on("Sales Order", {
|
||||
|
||||
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
|
||||
refresh: function(doc, dt, dn) {
|
||||
var me = this;
|
||||
this._super();
|
||||
var allow_purchase = false;
|
||||
var allow_delivery = false;
|
||||
@ -24,8 +37,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
if(doc.docstatus==1) {
|
||||
if(doc.status != 'Closed') {
|
||||
|
||||
for (var i in cur_frm.doc.items) {
|
||||
var item = cur_frm.doc.items[i];
|
||||
for (var i in this.frm.doc.items) {
|
||||
var item = this.frm.doc.items[i];
|
||||
if(item.delivered_by_supplier === 1 || item.supplier){
|
||||
if(item.qty > flt(item.ordered_qty)
|
||||
&& item.qty > flt(item.delivered_qty)) {
|
||||
@ -47,55 +60,69 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
if (this.frm.has_perm("submit")) {
|
||||
// close
|
||||
if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed) < 100) {
|
||||
cur_frm.add_custom_button(__('Close'), this.close_sales_order, __("Status"))
|
||||
this.frm.add_custom_button(__('Close'),
|
||||
function() { me.close_sales_order() }, __("Status"))
|
||||
}
|
||||
}
|
||||
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
|
||||
cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note, __("Make"));
|
||||
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||
this.frm.add_custom_button(__('Delivery'),
|
||||
function() { me.make_delivery_note() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Production Order'),
|
||||
function() { me.make_production_order() }, __("Make"));
|
||||
|
||||
this.frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||
}
|
||||
|
||||
// sales invoice
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice, __("Make"));
|
||||
this.frm.add_custom_button(__('Invoice'),
|
||||
function() { me.make_sales_invoice() }, __("Make"));
|
||||
}
|
||||
|
||||
// material request
|
||||
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1
|
||||
&& flt(doc.per_delivered, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Material Request'), this.make_material_request, __("Make"));
|
||||
this.frm.add_custom_button(__('Material Request'),
|
||||
function() { me.make_material_request() }, __("Make"));
|
||||
}
|
||||
|
||||
// make purchase order
|
||||
if(flt(doc.per_delivered, 2) < 100 && allow_purchase) {
|
||||
cur_frm.add_custom_button(__('Purchase Order'), cur_frm.cscript.make_purchase_order, __("Make"));
|
||||
this.frm.add_custom_button(__('Purchase Order'),
|
||||
function() { me.make_purchase_order() }, __("Make"));
|
||||
}
|
||||
|
||||
// payment request
|
||||
if(flt(doc.per_billed)==0) {
|
||||
cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
|
||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __("Make"));
|
||||
this.frm.add_custom_button(__('Payment Request'),
|
||||
function() { me.make_payment_request() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Payment'),
|
||||
function() { me.make_payment_entry() }, __("Make"));
|
||||
}
|
||||
|
||||
// maintenance
|
||||
if(flt(doc.per_delivered, 2) < 100 &&
|
||||
["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
|
||||
cur_frm.add_custom_button(__('Maintenance Visit'), this.make_maintenance_visit, __("Make"));
|
||||
cur_frm.add_custom_button(__('Maintenance Schedule'), this.make_maintenance_schedule, __("Make"));
|
||||
this.frm.add_custom_button(__('Maintenance Visit'),
|
||||
function() { me.make_maintenance_visit() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Maintenance Schedule'),
|
||||
function() { me.make_maintenance_schedule() }, __("Make"));
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
if (this.frm.has_perm("submit")) {
|
||||
// un-close
|
||||
cur_frm.add_custom_button(__('Re-open'), cur_frm.cscript['Unclose Sales Order'], __("Status"));
|
||||
this.frm.add_custom_button(__('Re-open'), function() {
|
||||
me.frm.cscript.update_status('Re-open', 'Draft')
|
||||
}, __("Status"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.frm.doc.docstatus===0) {
|
||||
cur_frm.add_custom_button(__('Quotation'),
|
||||
this.frm.add_custom_button(__('Quotation'),
|
||||
function() {
|
||||
erpnext.utils.map_current_doc({
|
||||
method: "erpnext.selling.doctype.quotation.quotation.make_sales_order",
|
||||
@ -103,9 +130,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["!=", "Lost"],
|
||||
order_type: cur_frm.doc.order_type,
|
||||
customer: cur_frm.doc.customer || undefined,
|
||||
company: cur_frm.doc.company
|
||||
order_type: me.frm.doc.order_type,
|
||||
customer: me.frm.doc.customer || undefined,
|
||||
company: me.frm.doc.company
|
||||
}
|
||||
})
|
||||
}, __("Get items from"));
|
||||
@ -114,6 +141,82 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
this.order_type(doc);
|
||||
},
|
||||
|
||||
make_production_order() {
|
||||
var me = this;
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: 'get_production_order_items',
|
||||
callback: function(r) {
|
||||
if(!r.message.every(function(d) { return !!d.bom })) {
|
||||
frappe.msgprint({
|
||||
title: __('Production Order not created'),
|
||||
message: __('No Items with Bill of Materials to Manufacture'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if(!r.message.every(function(d) { return !!d.pending_qty })) {
|
||||
frappe.msgprint({
|
||||
title: __('Production Order not created'),
|
||||
message: __('Production Order already created for all items with BOM'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
var fields = [
|
||||
{fieldtype:'Table', fieldname: 'items',
|
||||
description: __('Select BOM and Qty for Production'),
|
||||
fields: [
|
||||
{fieldtype:'Read Only', fieldname:'item_code',
|
||||
label: __('Item Code'), in_list_view:1},
|
||||
{fieldtype:'Link', fieldname:'bom', options: 'BOM',
|
||||
label: __('Select BOM'), in_list_view:1, get_query: function(doc) {
|
||||
return {filters: {item: doc.item_code}};
|
||||
}},
|
||||
{fieldtype:'Float', fieldname:'pending_qty',
|
||||
label: __('Qty'), in_list_view:1},
|
||||
],
|
||||
get_data: function() {
|
||||
return r.message
|
||||
}
|
||||
}
|
||||
]
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __('Select Items to Manufacture'),
|
||||
fields: fields,
|
||||
primary_action: function() {
|
||||
data = d.get_values();
|
||||
me.frm.call({
|
||||
method: 'make_production_orders',
|
||||
args: {
|
||||
items: data,
|
||||
company: me.frm.doc.company,
|
||||
sales_order: me.frm.docname,
|
||||
project: me.frm.project
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frappe.msgprint({
|
||||
message: __('Production Orders Created: {0}',
|
||||
[r.message.map(function(d) {
|
||||
return repl('<a href="#Form/Production Order/%(name)s">%(name)s</a>', {name:d})
|
||||
}).join(', ')]),
|
||||
indicator: 'green'
|
||||
})
|
||||
}
|
||||
d.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Make')
|
||||
});
|
||||
d.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
order_type: function() {
|
||||
this.frm.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
|
||||
},
|
||||
@ -125,39 +228,40 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
make_material_request: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_delivery_note: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_sales_invoice: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_maintenance_schedule: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_maintenance_visit: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_purchase_order: function(){
|
||||
var me = this;
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: __("For Supplier"),
|
||||
fields: [
|
||||
@ -165,7 +269,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
"get_query": function () {
|
||||
return {
|
||||
query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
|
||||
filters: {'parent': cur_frm.doc.name}
|
||||
filters: {'parent': me.frm.doc.name}
|
||||
}
|
||||
}, "reqd": 1 },
|
||||
{"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
|
||||
@ -180,7 +284,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
type: "GET",
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
|
||||
args: {
|
||||
"source_name": cur_frm.doc.name,
|
||||
"source_name": me.frm.doc.name,
|
||||
"for_supplier": args.supplier
|
||||
},
|
||||
freeze: true,
|
||||
@ -195,44 +299,25 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
dialog.show();
|
||||
},
|
||||
close_sales_order: function(){
|
||||
cur_frm.cscript.update_status("Close", "Closed")
|
||||
this.frm.cscript.update_status("Close", "Closed")
|
||||
},
|
||||
update_status: function(label, status){
|
||||
var doc = this.frm.doc;
|
||||
frappe.ui.form.is_saving = true;
|
||||
frappe.call({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.update_status",
|
||||
args: {status: status, name: doc.name},
|
||||
callback: function(r){
|
||||
this.frm.reload_doc();
|
||||
},
|
||||
always: function() {
|
||||
frappe.ui.form.is_saving = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
on_submit: function(doc, cdt, cdn) {
|
||||
if(cint(frappe.boot.notification_settings.sales_order)) {
|
||||
this.frm.email_doc(frappe.boot.notification_settings.sales_order_message);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
|
||||
|
||||
cur_frm.fields_dict['project'].get_query = function(doc, cdt, cdn) {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_project_name",
|
||||
filters: {
|
||||
'customer': doc.customer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.update_status = function(label, status){
|
||||
var doc = cur_frm.doc;
|
||||
frappe.ui.form.is_saving = true;
|
||||
frappe.call({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.update_status",
|
||||
args: {status: status, name: doc.name},
|
||||
callback: function(r){
|
||||
cur_frm.reload_doc();
|
||||
},
|
||||
always: function() {
|
||||
frappe.ui.form.is_saving = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Unclose Sales Order'] = function() {
|
||||
cur_frm.cscript.update_status('Re-open', 'Draft')
|
||||
}
|
||||
|
||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
if(cint(frappe.boot.notification_settings.sales_order)) {
|
||||
cur_frm.email_doc(frappe.boot.notification_settings.sales_order_message);
|
||||
}
|
||||
};
|
||||
|
@ -304,6 +304,24 @@ class SalesOrder(SellingController):
|
||||
self.indicator_color = "green"
|
||||
self.indicator_title = _("Paid")
|
||||
|
||||
def get_production_order_items(self):
|
||||
'''Returns items with BOM that already do not have a linked production order'''
|
||||
items = []
|
||||
for i in self.packed_items or self.items:
|
||||
bom = frappe.get_all('BOM', dict(item=i.item_code, is_active=True),
|
||||
order_by='is_default desc')
|
||||
bom = bom[0].name if bom else None
|
||||
items.append(dict(
|
||||
item_code= i.item_code,
|
||||
bom = bom,
|
||||
warehouse = i.warehouse,
|
||||
pending_qty= i.qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order`
|
||||
where production_item=%s and sales_order=%s''', (i.item_code, self.name))[0][0])
|
||||
))
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def on_recurring(self, reference_doc):
|
||||
mcount = month_map[reference_doc.recurring_type]
|
||||
self.set("delivery_date", get_next_date(reference_doc.delivery_date, mcount,
|
||||
@ -442,7 +460,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
||||
target.amount = flt(source.amount) - flt(source.billed_amt)
|
||||
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
||||
target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty
|
||||
|
||||
|
||||
item = frappe.db.get_value("Item", target.item_code, ["item_group", "selling_cost_center"], as_dict=1)
|
||||
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center") \
|
||||
or item.selling_cost_center \
|
||||
@ -652,6 +670,27 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters):
|
||||
'parent': filters.get('parent')
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_production_orders(items, sales_order, company, project=None):
|
||||
'''Make Production Orders against the given Sales Order for the given `items`'''
|
||||
items = json.loads(items).get('items')
|
||||
out = []
|
||||
|
||||
for i in items:
|
||||
production_order = frappe.get_doc(dict(
|
||||
doctype='Production Order',
|
||||
production_item=i['item_code'],
|
||||
bom_no=i['bom'],
|
||||
qty=i['pending_qty'],
|
||||
company=company,
|
||||
sales_order=sales_order,
|
||||
project=project,
|
||||
fg_warehouse=i['warehouse']
|
||||
)).insert()
|
||||
out.append(production_order)
|
||||
|
||||
return [p.name for p in out]
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_status(status, name):
|
||||
so = frappe.get_doc("Sales Order", name)
|
||||
|
@ -41,6 +41,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.actual_qty) ? "green" : "orange" })
|
||||
|
||||
},
|
||||
|
||||
onload_post_render: function() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user