Merge pull request #21122 from deepeshgarg007/quotation_blanket_order
feat: Link blanket order and quotation
This commit is contained in:
commit
13712c45e0
@ -14,27 +14,37 @@ frappe.ui.form.on('Blanket Order', {
|
|||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
erpnext.hide_company();
|
erpnext.hide_company();
|
||||||
if (frm.doc.customer && frm.doc.docstatus === 1) {
|
if (frm.doc.customer && frm.doc.docstatus === 1) {
|
||||||
frm.add_custom_button(__('View Orders'), function() {
|
frm.add_custom_button(__("Sales Order"), function() {
|
||||||
frappe.set_route('List', 'Sales Order', {blanket_order: frm.doc.name});
|
|
||||||
});
|
|
||||||
frm.add_custom_button(__("Create Sales Order"), function(){
|
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_sales_order",
|
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order",
|
||||||
frm: frm
|
frm: frm,
|
||||||
|
args: {
|
||||||
|
doctype: 'Sales Order'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}).addClass("btn-primary");
|
}, __('Create'));
|
||||||
|
|
||||||
|
frm.add_custom_button(__("Quotation"), function() {
|
||||||
|
frappe.model.open_mapped_doc({
|
||||||
|
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order",
|
||||||
|
frm: frm,
|
||||||
|
args: {
|
||||||
|
doctype: 'Quotation'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, __('Create'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frm.doc.supplier && frm.doc.docstatus === 1) {
|
if (frm.doc.supplier && frm.doc.docstatus === 1) {
|
||||||
frm.add_custom_button(__('View Orders'), function() {
|
frm.add_custom_button(__("Purchase Order"), function(){
|
||||||
frappe.set_route('List', 'Purchase Order', {blanket_order: frm.doc.name});
|
|
||||||
});
|
|
||||||
frm.add_custom_button(__("Create Purchase Order"), function(){
|
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_purchase_order",
|
method: "erpnext.manufacturing.doctype.blanket_order.blanket_order.make_order",
|
||||||
frm: frm
|
frm: frm,
|
||||||
|
args: {
|
||||||
|
doctype: 'Purchase Order'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}).addClass("btn-primary");
|
}, __('Create'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -14,10 +14,18 @@ from erpnext.stock.doctype.item.item import get_item_defaults
|
|||||||
class BlanketOrder(Document):
|
class BlanketOrder(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
|
self.validate_duplicate_items()
|
||||||
|
|
||||||
def validate_dates(self):
|
def validate_dates(self):
|
||||||
if getdate(self.from_date) > getdate(self.to_date):
|
if getdate(self.from_date) > getdate(self.to_date):
|
||||||
frappe.throw(_("From date cannot be greater than To date"))
|
frappe.throw(_("From date cannot be greater than To date"))
|
||||||
|
|
||||||
|
def validate_duplicate_items(self):
|
||||||
|
item_list = []
|
||||||
|
for item in self.items:
|
||||||
|
if item.item_code in item_list:
|
||||||
|
frappe.throw(_("Note: Item {0} added multiple times").format(frappe.bold(item.item_code)))
|
||||||
|
item_list.append(item.item_code)
|
||||||
|
|
||||||
def update_ordered_qty(self):
|
def update_ordered_qty(self):
|
||||||
ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order"
|
ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order"
|
||||||
@ -35,7 +43,14 @@ class BlanketOrder(Document):
|
|||||||
d.db_set("ordered_qty", item_ordered_qty.get(d.item_code, 0))
|
d.db_set("ordered_qty", item_ordered_qty.get(d.item_code, 0))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_sales_order(source_name):
|
def make_order(source_name):
|
||||||
|
doctype = frappe.flags.args.doctype
|
||||||
|
|
||||||
|
def update_doc(source_doc, target_doc, source_parent):
|
||||||
|
if doctype == 'Quotation':
|
||||||
|
target_doc.quotation_to = 'Customer'
|
||||||
|
target_doc.party_name = source_doc.customer
|
||||||
|
|
||||||
def update_item(source, target, source_parent):
|
def update_item(source, target, source_parent):
|
||||||
target_qty = source.get("qty") - source.get("ordered_qty")
|
target_qty = source.get("qty") - source.get("ordered_qty")
|
||||||
target.qty = target_qty if not flt(target_qty) < 0 else 0
|
target.qty = target_qty if not flt(target_qty) < 0 else 0
|
||||||
@ -49,39 +64,11 @@ def make_sales_order(source_name):
|
|||||||
|
|
||||||
target_doc = get_mapped_doc("Blanket Order", source_name, {
|
target_doc = get_mapped_doc("Blanket Order", source_name, {
|
||||||
"Blanket Order": {
|
"Blanket Order": {
|
||||||
"doctype": "Sales Order"
|
"doctype": doctype,
|
||||||
|
"postprocess": update_doc
|
||||||
},
|
},
|
||||||
"Blanket Order Item": {
|
"Blanket Order Item": {
|
||||||
"doctype": "Sales Order Item",
|
"doctype": doctype + " Item",
|
||||||
"field_map": {
|
|
||||||
"rate": "blanket_order_rate",
|
|
||||||
"parent": "blanket_order"
|
|
||||||
},
|
|
||||||
"postprocess": update_item
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return target_doc
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def make_purchase_order(source_name):
|
|
||||||
def update_item(source, target, source_parent):
|
|
||||||
target_qty = source.get("qty") - source.get("ordered_qty")
|
|
||||||
target.qty = target_qty if not flt(target_qty) < 0 else 0
|
|
||||||
item = get_item_defaults(target.item_code, source_parent.company)
|
|
||||||
if item:
|
|
||||||
target.item_name = item.get("item_name")
|
|
||||||
target.description = item.get("description")
|
|
||||||
target.uom = item.get("stock_uom")
|
|
||||||
target.warehouse = item.get("default_warehouse")
|
|
||||||
target.against_blanket_order = 1
|
|
||||||
target.blanket_order = source_name
|
|
||||||
|
|
||||||
target_doc = get_mapped_doc("Blanket Order", source_name, {
|
|
||||||
"Blanket Order": {
|
|
||||||
"doctype": "Purchase Order"
|
|
||||||
},
|
|
||||||
"Blanket Order Item": {
|
|
||||||
"doctype": "Purchase Order Item",
|
|
||||||
"field_map": {
|
"field_map": {
|
||||||
"rate": "blanket_order_rate",
|
"rate": "blanket_order_rate",
|
||||||
"parent": "blanket_order"
|
"parent": "blanket_order"
|
||||||
|
|||||||
@ -6,7 +6,7 @@ def get_data():
|
|||||||
'fieldname': 'blanket_order',
|
'fieldname': 'blanket_order',
|
||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'items': ['Purchase Order', 'Sales Order']
|
'items': ['Purchase Order', 'Sales Order', 'Quotation']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,17 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import add_months, today
|
from frappe.utils import add_months, today
|
||||||
from erpnext import get_company_currency
|
from erpnext import get_company_currency
|
||||||
from .blanket_order import make_sales_order, make_purchase_order
|
from .blanket_order import make_order
|
||||||
|
|
||||||
class TestBlanketOrder(unittest.TestCase):
|
class TestBlanketOrder(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
frappe.flags.args = frappe._dict()
|
||||||
|
|
||||||
def test_sales_order_creation(self):
|
def test_sales_order_creation(self):
|
||||||
bo = make_blanket_order(blanket_order_type="Selling")
|
bo = make_blanket_order(blanket_order_type="Selling")
|
||||||
|
|
||||||
so = make_sales_order(bo.name)
|
frappe.flags.args.doctype = 'Sales Order'
|
||||||
|
so = make_order(bo.name)
|
||||||
so.currency = get_company_currency(so.company)
|
so.currency = get_company_currency(so.company)
|
||||||
so.delivery_date = today()
|
so.delivery_date = today()
|
||||||
so.items[0].qty = 10
|
so.items[0].qty = 10
|
||||||
@ -29,7 +33,8 @@ class TestBlanketOrder(unittest.TestCase):
|
|||||||
self.assertEqual(so.items[0].qty, bo.items[0].ordered_qty)
|
self.assertEqual(so.items[0].qty, bo.items[0].ordered_qty)
|
||||||
|
|
||||||
# test the quantity
|
# test the quantity
|
||||||
so1 = make_sales_order(bo.name)
|
frappe.flags.args.doctype = 'Sales Order'
|
||||||
|
so1 = make_order(bo.name)
|
||||||
so1.currency = get_company_currency(so1.company)
|
so1.currency = get_company_currency(so1.company)
|
||||||
self.assertEqual(so1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty))
|
self.assertEqual(so1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty))
|
||||||
|
|
||||||
@ -37,7 +42,8 @@ class TestBlanketOrder(unittest.TestCase):
|
|||||||
def test_purchase_order_creation(self):
|
def test_purchase_order_creation(self):
|
||||||
bo = make_blanket_order(blanket_order_type="Purchasing")
|
bo = make_blanket_order(blanket_order_type="Purchasing")
|
||||||
|
|
||||||
po = make_purchase_order(bo.name)
|
frappe.flags.args.doctype = 'Purchase Order'
|
||||||
|
po = make_order(bo.name)
|
||||||
po.currency = get_company_currency(po.company)
|
po.currency = get_company_currency(po.company)
|
||||||
po.schedule_date = today()
|
po.schedule_date = today()
|
||||||
po.items[0].qty = 10
|
po.items[0].qty = 10
|
||||||
@ -53,7 +59,8 @@ class TestBlanketOrder(unittest.TestCase):
|
|||||||
self.assertEqual(po.items[0].qty, bo.items[0].ordered_qty)
|
self.assertEqual(po.items[0].qty, bo.items[0].ordered_qty)
|
||||||
|
|
||||||
# test the quantity
|
# test the quantity
|
||||||
po1 = make_sales_order(bo.name)
|
frappe.flags.args.doctype = 'Purchase Order'
|
||||||
|
po1 = make_order(bo.name)
|
||||||
po1.currency = get_company_currency(po1.company)
|
po1.currency = get_company_currency(po1.company)
|
||||||
self.assertEqual(po1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty))
|
self.assertEqual(po1.items[0].qty, (bo.items[0].qty-bo.items[0].ordered_qty))
|
||||||
|
|
||||||
@ -78,7 +85,7 @@ def make_blanket_order(**args):
|
|||||||
"qty": args.quantity or 1000,
|
"qty": args.quantity or 1000,
|
||||||
"rate": args.rate or 100
|
"rate": args.rate or 100
|
||||||
})
|
})
|
||||||
|
|
||||||
bo.insert()
|
bo.insert()
|
||||||
bo.submit()
|
bo.submit()
|
||||||
return bo
|
return bo
|
||||||
@ -6,7 +6,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
|
|
||||||
apply_pricing_rule_on_item: function(item){
|
apply_pricing_rule_on_item: function(item){
|
||||||
let effective_item_rate = item.price_list_rate;
|
let effective_item_rate = item.price_list_rate;
|
||||||
if (item.parenttype === "Sales Order" && item.blanket_order_rate) {
|
if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) {
|
||||||
effective_item_rate = item.blanket_order_rate;
|
effective_item_rate = item.blanket_order_rate;
|
||||||
}
|
}
|
||||||
if(item.margin_type == "Percentage"){
|
if(item.margin_type == "Percentage"){
|
||||||
|
|||||||
@ -155,6 +155,11 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
def update_item(obj, target, source_parent):
|
def update_item(obj, target, source_parent):
|
||||||
target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor)
|
target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor)
|
||||||
|
|
||||||
|
if obj.against_blanket_order:
|
||||||
|
target.against_blanket_order = obj.against_blanket_order
|
||||||
|
target.blanket_order = obj.blanket_order
|
||||||
|
target.blanket_order_rate = obj.blanket_order_rate
|
||||||
|
|
||||||
doclist = get_mapped_doc("Quotation", source_name, {
|
doclist = get_mapped_doc("Quotation", source_name, {
|
||||||
"Quotation": {
|
"Quotation": {
|
||||||
"doctype": "Sales Order",
|
"doctype": "Sales Order",
|
||||||
|
|||||||
@ -55,6 +55,9 @@
|
|||||||
"weight_uom",
|
"weight_uom",
|
||||||
"reference",
|
"reference",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
|
"against_blanket_order",
|
||||||
|
"blanket_order",
|
||||||
|
"blanket_order_rate",
|
||||||
"column_break_30",
|
"column_break_30",
|
||||||
"prevdoc_doctype",
|
"prevdoc_doctype",
|
||||||
"prevdoc_docname",
|
"prevdoc_docname",
|
||||||
@ -573,12 +576,38 @@
|
|||||||
"fieldname": "image_section",
|
"fieldname": "image_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Image"
|
"label": "Image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.against_blanket_order",
|
||||||
|
"fieldname": "blanket_order",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Blanket Order",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Blanket Order",
|
||||||
|
"print_hide": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.against_blanket_order",
|
||||||
|
"fieldname": "blanket_order_rate",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Blanket Order Rate",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "against_blanket_order",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Against Blanket Order",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-05 14:18:58.783751",
|
"modified": "2020-03-30 18:40:28.782720",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Quotation Item",
|
"name": "Quotation Item",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user