Merge pull request #7657 from rmehta/po-from-so
[enhance] production order from sales order
This commit is contained in:
commit
259489572d
File diff suppressed because it is too large
Load Diff
@ -249,7 +249,7 @@ class ProductionPlanningTool(Document):
|
|||||||
"wip_warehouse" : "",
|
"wip_warehouse" : "",
|
||||||
"fg_warehouse" : d.warehouse,
|
"fg_warehouse" : d.warehouse,
|
||||||
"status" : "Draft",
|
"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 """
|
""" 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):
|
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("""
|
items = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
bom_item.item_code,
|
bom_item.item_code,
|
||||||
default_material_request_type,
|
default_material_request_type,
|
||||||
ifnull(%(parent_qty)s * sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
|
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,
|
item.default_bom as default_bom,
|
||||||
bom_item.description as description,
|
bom_item.description as description,
|
||||||
bom_item.stock_uom as stock_uom,
|
bom_item.stock_uom as stock_uom,
|
||||||
item.min_order_qty as min_order_qty
|
item.min_order_qty as min_order_qty
|
||||||
FROM
|
FROM
|
||||||
`tabBOM Item` bom_item,
|
`tabBOM Item` bom_item,
|
||||||
`tabBOM` bom,
|
`tabBOM` bom,
|
||||||
tabItem item
|
tabItem item
|
||||||
where
|
where
|
||||||
bom.name = bom_item.parent
|
bom.name = bom_item.parent
|
||||||
and bom.name = %(bom)s
|
and bom.name = %(bom)s
|
||||||
and bom_item.docstatus < 2
|
and bom_item.docstatus < 2
|
||||||
and bom_item.item_code = item.name
|
and bom_item.item_code = item.name
|
||||||
""" + ("and item.is_stock_item = 1", "")[non_stock_item] + """
|
""" + ("and item.is_stock_item = 1", "")[non_stock_item] + """
|
||||||
group by bom_item.item_code""", {"bom": bom, "parent_qty": parent_qty}, as_dict=1)
|
group by bom_item.item_code""", {"bom": bom, "parent_qty": parent_qty}, as_dict=1)
|
||||||
|
|
||||||
for d in items:
|
for d in items:
|
||||||
if ((d.default_material_request_type == "Purchase"
|
if ((d.default_material_request_type == "Purchase"
|
||||||
and not (d.is_sub_contracted and only_raw and include_sublevel))
|
and not (d.is_sub_contracted and only_raw and include_sublevel))
|
||||||
or (d.default_material_request_type == "Manufacture" and not only_raw)):
|
or (d.default_material_request_type == "Manufacture" and not only_raw)):
|
||||||
|
|
||||||
if d.item_code in bom_wise_item_details:
|
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
|
bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty
|
||||||
else:
|
else:
|
||||||
bom_wise_item_details[d.item_code] = d
|
bom_wise_item_details[d.item_code] = d
|
||||||
|
|
||||||
if include_sublevel:
|
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")):
|
or (d.default_material_request_type == "Manufacture")):
|
||||||
|
|
||||||
my_qty = 0
|
my_qty = 0
|
||||||
projected_qty = self.get_item_projected_qty(d.item_code)
|
projected_qty = self.get_item_projected_qty(d.item_code)
|
||||||
|
|
||||||
if self.create_material_requests_for_all_required_qty:
|
if self.create_material_requests_for_all_required_qty:
|
||||||
my_qty = d.qty
|
my_qty = d.qty
|
||||||
elif (bom_wise_item_details[d.item_code].qty - d.qty) < projected_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
|
my_qty = bom_wise_item_details[d.item_code].qty - projected_qty
|
||||||
else:
|
else:
|
||||||
my_qty = d.qty
|
my_qty = d.qty
|
||||||
|
|
||||||
if my_qty > 0:
|
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)
|
d.default_bom, my_qty, include_sublevel, only_raw, supply_subs)
|
||||||
|
|
||||||
return bom_wise_item_details
|
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_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
|
item_qty = frappe.db.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
|
||||||
from `tabBin` where item_code = %s""", item, as_dict=1)
|
from `tabBin` where item_code = %s""", item, as_dict=1)
|
||||||
|
|
||||||
i_qty, o_qty, a_qty = 0, 0, 0
|
i_qty, o_qty, a_qty = 0, 0, 0
|
||||||
for w in item_qty:
|
for w in item_qty:
|
||||||
i_qty, o_qty, a_qty = i_qty + flt(w.indented_qty), o_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)
|
flt(w.ordered_qty), a_qty + flt(w.actual_qty)
|
||||||
|
|
||||||
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
|
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
|
||||||
flt(w.ordered_qty), flt(w.actual_qty)])
|
flt(w.ordered_qty), flt(w.actual_qty)])
|
||||||
if item_qty:
|
if item_qty:
|
||||||
@ -485,15 +485,15 @@ class ProductionPlanningTool(Document):
|
|||||||
def get_item_projected_qty(self,item):
|
def get_item_projected_qty(self,item):
|
||||||
item_projected_qty = frappe.db.sql("""
|
item_projected_qty = frappe.db.sql("""
|
||||||
select ifnull(sum(projected_qty),0) as qty
|
select ifnull(sum(projected_qty),0) as qty
|
||||||
from `tabBin`
|
from `tabBin`
|
||||||
where item_code = %(item_code)s and warehouse=%(warehouse)s
|
where item_code = %(item_code)s and warehouse=%(warehouse)s
|
||||||
""", {
|
""", {
|
||||||
"item_code": item,
|
"item_code": item,
|
||||||
"warehouse": self.purchase_request_for_warehouse
|
"warehouse": self.purchase_request_for_warehouse
|
||||||
}, as_dict=1)
|
}, as_dict=1)
|
||||||
|
|
||||||
return item_projected_qty[0].qty
|
return item_projected_qty[0].qty
|
||||||
|
|
||||||
def get_projected_qty(self):
|
def get_projected_qty(self):
|
||||||
items = self.item_dict.keys()
|
items = self.item_dict.keys()
|
||||||
item_projected_qty = frappe.db.sql("""select item_code, sum(projected_qty)
|
item_projected_qty = frappe.db.sql("""select item_code, sum(projected_qty)
|
||||||
|
|||||||
@ -4,11 +4,23 @@
|
|||||||
{% include 'erpnext/selling/sales_common.js' %}
|
{% include 'erpnext/selling/sales_common.js' %}
|
||||||
|
|
||||||
frappe.ui.form.on("Sales Order", {
|
frappe.ui.form.on("Sales Order", {
|
||||||
|
setup: function(frm) {
|
||||||
|
$.extend(frm.cscript, new erpnext.selling.SalesOrderController({frm: frm}));
|
||||||
|
},
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||||
return erpnext.queries.warehouse(frm.doc);
|
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
|
// formatter for material request item
|
||||||
frm.set_indicator_formatter('item_code',
|
frm.set_indicator_formatter('item_code',
|
||||||
function(doc) { return (doc.qty<=doc.delivered_qty) ? "green" : "orange" })
|
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({
|
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
|
||||||
refresh: function(doc, dt, dn) {
|
refresh: function(doc, dt, dn) {
|
||||||
|
var me = this;
|
||||||
this._super();
|
this._super();
|
||||||
var allow_purchase = false;
|
var allow_purchase = false;
|
||||||
var allow_delivery = false;
|
var allow_delivery = false;
|
||||||
@ -24,8 +37,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
if(doc.docstatus==1) {
|
if(doc.docstatus==1) {
|
||||||
if(doc.status != 'Closed') {
|
if(doc.status != 'Closed') {
|
||||||
|
|
||||||
for (var i in cur_frm.doc.items) {
|
for (var i in this.frm.doc.items) {
|
||||||
var item = cur_frm.doc.items[i];
|
var item = this.frm.doc.items[i];
|
||||||
if(item.delivered_by_supplier === 1 || item.supplier){
|
if(item.delivered_by_supplier === 1 || item.supplier){
|
||||||
if(item.qty > flt(item.ordered_qty)
|
if(item.qty > flt(item.ordered_qty)
|
||||||
&& item.qty > flt(item.delivered_qty)) {
|
&& item.qty > flt(item.delivered_qty)) {
|
||||||
@ -47,55 +60,69 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
if (this.frm.has_perm("submit")) {
|
if (this.frm.has_perm("submit")) {
|
||||||
// close
|
// close
|
||||||
if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed) < 100) {
|
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
|
// delivery note
|
||||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
|
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"));
|
this.frm.add_custom_button(__('Delivery'),
|
||||||
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
|
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
|
// sales invoice
|
||||||
if(flt(doc.per_billed, 2) < 100) {
|
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
|
// material request
|
||||||
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1
|
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1
|
||||||
&& flt(doc.per_delivered, 2) < 100) {
|
&& 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
|
// make purchase order
|
||||||
if(flt(doc.per_delivered, 2) < 100 && allow_purchase) {
|
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) {
|
if(flt(doc.per_billed)==0) {
|
||||||
cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
|
this.frm.add_custom_button(__('Payment Request'),
|
||||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __("Make"));
|
function() { me.make_payment_request() }, __("Make"));
|
||||||
|
this.frm.add_custom_button(__('Payment'),
|
||||||
|
function() { me.make_payment_entry() }, __("Make"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// maintenance
|
// maintenance
|
||||||
if(flt(doc.per_delivered, 2) < 100 &&
|
if(flt(doc.per_delivered, 2) < 100 &&
|
||||||
["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
|
["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
|
||||||
cur_frm.add_custom_button(__('Maintenance Visit'), this.make_maintenance_visit, __("Make"));
|
this.frm.add_custom_button(__('Maintenance Visit'),
|
||||||
cur_frm.add_custom_button(__('Maintenance Schedule'), this.make_maintenance_schedule, __("Make"));
|
function() { me.make_maintenance_visit() }, __("Make"));
|
||||||
|
this.frm.add_custom_button(__('Maintenance Schedule'),
|
||||||
|
function() { me.make_maintenance_schedule() }, __("Make"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (this.frm.has_perm("submit")) {
|
if (this.frm.has_perm("submit")) {
|
||||||
// un-close
|
// 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) {
|
if (this.frm.doc.docstatus===0) {
|
||||||
cur_frm.add_custom_button(__('Quotation'),
|
this.frm.add_custom_button(__('Quotation'),
|
||||||
function() {
|
function() {
|
||||||
erpnext.utils.map_current_doc({
|
erpnext.utils.map_current_doc({
|
||||||
method: "erpnext.selling.doctype.quotation.quotation.make_sales_order",
|
method: "erpnext.selling.doctype.quotation.quotation.make_sales_order",
|
||||||
@ -103,9 +130,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
get_query_filters: {
|
get_query_filters: {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Lost"],
|
status: ["!=", "Lost"],
|
||||||
order_type: cur_frm.doc.order_type,
|
order_type: me.frm.doc.order_type,
|
||||||
customer: cur_frm.doc.customer || undefined,
|
customer: me.frm.doc.customer || undefined,
|
||||||
company: cur_frm.doc.company
|
company: me.frm.doc.company
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get items from"));
|
||||||
@ -114,6 +141,82 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
this.order_type(doc);
|
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() {
|
order_type: function() {
|
||||||
this.frm.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
|
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() {
|
make_material_request: function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
|
||||||
frm: cur_frm
|
frm: this.frm
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
make_delivery_note: function() {
|
make_delivery_note: function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
||||||
frm: cur_frm
|
frm: this.frm
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
make_sales_invoice: function() {
|
make_sales_invoice: function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
|
||||||
frm: cur_frm
|
frm: this.frm
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
make_maintenance_schedule: function() {
|
make_maintenance_schedule: function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
|
||||||
frm: cur_frm
|
frm: this.frm
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
make_maintenance_visit: function() {
|
make_maintenance_visit: function() {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
|
||||||
frm: cur_frm
|
frm: this.frm
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
make_purchase_order: function(){
|
make_purchase_order: function(){
|
||||||
|
var me = this;
|
||||||
var dialog = new frappe.ui.Dialog({
|
var dialog = new frappe.ui.Dialog({
|
||||||
title: __("For Supplier"),
|
title: __("For Supplier"),
|
||||||
fields: [
|
fields: [
|
||||||
@ -165,7 +269,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
"get_query": function () {
|
"get_query": function () {
|
||||||
return {
|
return {
|
||||||
query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
|
query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
|
||||||
filters: {'parent': cur_frm.doc.name}
|
filters: {'parent': me.frm.doc.name}
|
||||||
}
|
}
|
||||||
}, "reqd": 1 },
|
}, "reqd": 1 },
|
||||||
{"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
|
{"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",
|
type: "GET",
|
||||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
|
method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
|
||||||
args: {
|
args: {
|
||||||
"source_name": cur_frm.doc.name,
|
"source_name": me.frm.doc.name,
|
||||||
"for_supplier": args.supplier
|
"for_supplier": args.supplier
|
||||||
},
|
},
|
||||||
freeze: true,
|
freeze: true,
|
||||||
@ -195,44 +299,25 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
dialog.show();
|
dialog.show();
|
||||||
},
|
},
|
||||||
close_sales_order: function(){
|
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_color = "green"
|
||||||
self.indicator_title = _("Paid")
|
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):
|
def on_recurring(self, reference_doc):
|
||||||
mcount = month_map[reference_doc.recurring_type]
|
mcount = month_map[reference_doc.recurring_type]
|
||||||
self.set("delivery_date", get_next_date(reference_doc.delivery_date, mcount,
|
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.amount = flt(source.amount) - flt(source.billed_amt)
|
||||||
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
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
|
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)
|
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") \
|
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center") \
|
||||||
or item.selling_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')
|
'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()
|
@frappe.whitelist()
|
||||||
def update_status(status, name):
|
def update_status(status, name):
|
||||||
so = frappe.get_doc("Sales Order", 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() {
|
onload_post_render: function() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user