[feature] Blanket Order
- Creaete Sales or Purchase order from the blanket order - If there is any blanket order for the customer/supplier rates will be fetched from that order - Manually selecting the Blanket order will change the rates accordingly - Upon submission of the order, the ordered qty will be updated in the Blanket Order
This commit is contained in:
parent
2fb63e1724
commit
e5e87f7137
@ -219,6 +219,9 @@ class PurchaseOrder(BuyingController):
|
||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||
self.company, self.base_grand_total)
|
||||
|
||||
self.update_blanket_order()
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
super(PurchaseOrder, self).on_cancel()
|
||||
|
||||
@ -241,6 +244,9 @@ class PurchaseOrder(BuyingController):
|
||||
self.update_requested_qty()
|
||||
self.update_ordered_qty()
|
||||
|
||||
self.update_blanket_order(cancel=True)
|
||||
|
||||
|
||||
def on_update(self):
|
||||
pass
|
||||
|
||||
|
@ -1594,6 +1594,37 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "delivered_by_supplier",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "To be delivered to customer",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -1611,7 +1642,7 @@
|
||||
"in_standard_filter": 0,
|
||||
"label": "Blanket Order",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Blanket Order",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@ -1632,8 +1663,8 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "delivered_by_supplier",
|
||||
"fieldtype": "Check",
|
||||
"fieldname": "blanket_order_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@ -1641,9 +1672,9 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "To be delivered to customer",
|
||||
"label": "Blanket Order Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
@ -2083,7 +2114,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-05-24 09:15:37.473332",
|
||||
"modified": "2018-05-28 08:43:23.251530",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Item",
|
||||
|
@ -342,6 +342,18 @@ class StockController(AccountsController):
|
||||
if self.docstatus==1:
|
||||
raise frappe.ValidationError
|
||||
|
||||
def update_blanket_order(self, cancel=False):
|
||||
for item in self.items:
|
||||
if item.blanket_order:
|
||||
ordered_qty, doc_name = frappe.db.get_value("Blanket Order Item", {"parent": item.blanket_order}, ["ordered_qty", "name"])
|
||||
if not cancel:
|
||||
ordered_qty = ordered_qty + item.qty
|
||||
else:
|
||||
ordered_qty = ordered_qty - item.qty
|
||||
ordered_qty = flt(ordered_qty, item.precision("qty"))
|
||||
frappe.db.set_value("Blanket Order Item", doc_name, "ordered_qty", ordered_qty)
|
||||
|
||||
|
||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||
warehouse_account=None):
|
||||
def _delete_gl_entries(voucher_type, voucher_no):
|
||||
|
@ -3,41 +3,28 @@
|
||||
|
||||
frappe.ui.form.on('Blanket Order', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.customer) {
|
||||
if (frm.doc.customer && frm.doc.docstatus === 1) {
|
||||
frm.add_custom_button(__('View Orders'), function() {
|
||||
frappe.set_route('List', 'Sales Order', {blanket_order: frm.doc.name});
|
||||
});
|
||||
if (frm.doc.docstatus === 1) {
|
||||
frm.add_primary_button(__("Create Sales Order"), function(){
|
||||
|
||||
frm.add_custom_button(__("Create Sales Order"), function(){
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_sales_order",
|
||||
frm: frm
|
||||
});
|
||||
}
|
||||
}).addClass("btn-primary");
|
||||
}
|
||||
|
||||
if (frm.doc.supplier) {
|
||||
if (frm.doc.supplier && frm.doc.docstatus === 1) {
|
||||
frm.add_custom_button(__('View Orders'), function() {
|
||||
frappe.set_route('List', 'Purchase Order', {blanket_order: frm.doc.name});
|
||||
});
|
||||
}
|
||||
|
||||
// if (frm.doc.project) {
|
||||
// frm.add_custom_button(__('Project'), function() {
|
||||
// frappe.set_route("Form", "Project", frm.doc.project);
|
||||
// },__("View"));
|
||||
// frm.add_custom_button(__('Task'), function() {
|
||||
// frappe.set_route('List', 'Task', {project: frm.doc.project});
|
||||
// },__("View"));
|
||||
// }
|
||||
|
||||
if ((!frm.doc.employee) && (frm.doc.docstatus === 1)) {
|
||||
frm.add_custom_button(__('Employee'), function () {
|
||||
frm.add_custom_button(__("Create Purchase Order"), function(){
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.hr.doctype.employee_onboarding.employee_onboarding.make_employee",
|
||||
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_purchase_order",
|
||||
frm: frm
|
||||
});
|
||||
}, __("Make"));
|
||||
frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||
}).addClass("btn-primary");
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -26,7 +26,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
@ -437,7 +437,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-05-24 07:56:37.911486",
|
||||
"modified": "2018-05-28 05:56:05.922333",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Blanket Order",
|
||||
@ -467,6 +467,7 @@
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "order_type, to_date",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
|
@ -5,6 +5,39 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
|
||||
class BlanketOrder(Document):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_order(source_name):
|
||||
return get_mapped_doc("Blanket Order", source_name, {
|
||||
"Blanket Order": {
|
||||
"doctype": "Sales Order"
|
||||
},
|
||||
"Blanket Order Item": {
|
||||
"doctype": "Sales Order Item",
|
||||
"field_map": {
|
||||
"rate": "blanket_order_rate",
|
||||
"parent": "blanket_order"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_purchase_order(source_name):
|
||||
return get_mapped_doc("Blanket Order", source_name, {
|
||||
"Blanket Order": {
|
||||
"doctype": "Purchase Order"
|
||||
},
|
||||
"Blanket Order Item": {
|
||||
"doctype": "Purchase Order Item",
|
||||
"field_map": {
|
||||
"rate": "blanket_order_rate",
|
||||
"parent": "blanket_order"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -108,8 +108,11 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
|
||||
|
||||
item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0),
|
||||
precision("rate", item));
|
||||
let item_rate = item.price_list_rate;
|
||||
if (doc.doctype == "Purchase Order" && item.blanket_order_rate) {
|
||||
item_rate = item.blanket_order_rate;
|
||||
}
|
||||
item.rate = flt(item_rate * (1 - item.discount_percentage / 100.0), precision("rate", item));
|
||||
|
||||
this.calculate_taxes_and_totals();
|
||||
},
|
||||
|
@ -4,12 +4,15 @@
|
||||
erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
setup: function() {},
|
||||
apply_pricing_rule_on_item: function(item){
|
||||
|
||||
let effective_item_rate = item.price_list_rate;
|
||||
if (item.parenttype === "Sales Order" && item.blanket_order_rate) {
|
||||
effective_item_rate = item.blanket_order_rate;
|
||||
}
|
||||
if(item.margin_type == "Percentage"){
|
||||
item.rate_with_margin = flt(item.price_list_rate)
|
||||
+ flt(item.price_list_rate) * ( flt(item.margin_rate_or_amount) / 100);
|
||||
item.rate_with_margin = flt(effective_item_rate)
|
||||
+ flt(effective_item_rate) * ( flt(item.margin_rate_or_amount) / 100);
|
||||
} else {
|
||||
item.rate_with_margin = flt(item.price_list_rate) + flt(item.margin_rate_or_amount);
|
||||
item.rate_with_margin = flt(effective_item_rate) + flt(item.margin_rate_or_amount);
|
||||
item.base_rate_with_margin = flt(item.rate_with_margin) * flt(this.frm.doc.conversion_rate);
|
||||
}
|
||||
|
||||
|
@ -1323,6 +1323,36 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
blanket_order: function(doc, cdt, cdn) {
|
||||
var me = this;
|
||||
var item = locals[cdt][cdn];
|
||||
if (item.blanket_order && (item.parenttype=="Sales Order" || item.parenttype=="Purchase Order")) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.get_item_details.get_blanket_order_details",
|
||||
args: {
|
||||
args:{
|
||||
item_code: item.item_code,
|
||||
customer: doc.customer,
|
||||
supplier: doc.supplier,
|
||||
company: doc.company,
|
||||
transaction_date: doc.transaction_date,
|
||||
blanket_order: item.blanket_order
|
||||
}
|
||||
},
|
||||
callback: function(r) {
|
||||
if (!r.message) {
|
||||
frappe.throw(__("Invalid Blanket Order for the selected Customer and Item"))
|
||||
} else {
|
||||
frappe.run_serially([
|
||||
() => frappe.model.set_value(cdt, cdn, "blanket_order_rate", r.message.blanket_order_rate),
|
||||
() => me.frm.script_manager.trigger("price_list_rate", cdt, cdn)
|
||||
]);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -176,6 +176,8 @@ class SalesOrder(SellingController):
|
||||
self.update_project()
|
||||
self.update_prevdoc_status('submit')
|
||||
|
||||
self.update_blanket_order()
|
||||
|
||||
def on_cancel(self):
|
||||
# Cannot cancel closed SO
|
||||
if self.status == 'Closed':
|
||||
@ -188,6 +190,8 @@ class SalesOrder(SellingController):
|
||||
|
||||
frappe.db.set(self, 'status', 'Cancelled')
|
||||
|
||||
self.update_blanket_order(cancel=True)
|
||||
|
||||
def update_project(self):
|
||||
project_list = []
|
||||
if self.project:
|
||||
@ -382,6 +386,7 @@ class SalesOrder(SellingController):
|
||||
d.set("delivery_date", get_next_schedule_date(reference_delivery_date,
|
||||
auto_repeat_doc.frequency, cint(auto_repeat_doc.repeat_on_day)))
|
||||
|
||||
|
||||
def get_list_context(context=None):
|
||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||
list_context = get_list_context(context)
|
||||
|
@ -1681,38 +1681,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "blanket_order",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Blanket Order",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Blanket Order",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -1875,6 +1843,69 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "blanket_order",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Blanket Order",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Blanket Order",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "blanket_order_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Blanket Order Rate",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 1,
|
||||
@ -2307,7 +2338,7 @@
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-05-24 09:14:45.810084",
|
||||
"modified": "2018-05-28 05:52:36.908884",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Item",
|
||||
|
@ -64,6 +64,8 @@ def get_item_details(args):
|
||||
else:
|
||||
out.update(get_valuation_rate(args.item_code, args.company, out.get("warehouse")))
|
||||
|
||||
update_party_blanket_order(args, out)
|
||||
|
||||
get_price_list_rate(args, item_doc, out)
|
||||
|
||||
if args.customer and cint(args.is_pos):
|
||||
@ -185,7 +187,6 @@ def get_basic_details(args, item):
|
||||
company: "",
|
||||
order_type: "",
|
||||
is_pos: "",
|
||||
ignore_pricing_rule: "",
|
||||
project: "",
|
||||
qty: "",
|
||||
stock_qty: "",
|
||||
@ -735,3 +736,32 @@ def get_serial_no(args, serial_nos=None):
|
||||
serial_no = serial_nos
|
||||
|
||||
return serial_no
|
||||
|
||||
|
||||
def update_party_blanket_order(args, out):
|
||||
blanket_order_details = get_blanket_order_details(args)
|
||||
if blanket_order_details:
|
||||
out.update(blanket_order_details)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_blanket_order_details(args):
|
||||
if isinstance(args, string_types):
|
||||
args = frappe._dict(json.loads(args))
|
||||
|
||||
blanket_order_details = None
|
||||
condition1, condition2 = ' ', ' '
|
||||
if args.item_code:
|
||||
if args.customer and args.doctype == "Sales Order":
|
||||
condition1 = ' and bo.customer=%(customer)s '
|
||||
elif args.supplier and args.doctype == "Purchase Order":
|
||||
condition1 = ' and bo.supplier=%(supplier)s '
|
||||
if args.blanket_order:
|
||||
condition2 = ' and bo.name =%(blanket_order)s '
|
||||
blanket_order_details = frappe.db.sql('''
|
||||
select boi.rate as blanket_order_rate, bo.name as blanket_order
|
||||
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
|
||||
where bo.to_date>=%(transaction_date)s and bo.company=%(company)s and boi.item_code=%(item_code)s
|
||||
and bo.docstatus=1 and bo.name = boi.parent {0} {1}
|
||||
'''.format(condition1, condition2), args, as_dict=True)
|
||||
blanket_order_details = blanket_order_details[0] if blanket_order_details else ''
|
||||
return blanket_order_details
|
||||
|
Loading…
x
Reference in New Issue
Block a user