Update Items in Submit state can add new row (#15644)
* Update Items in Sumbit state can add new row In Sales Order and Purchase Order when docstatus is submitted user can use Update Item btn to add new child Items * Remove unused code line * Remove blocking db save thread line * Remove Company as not standard Field in Purchase Order Item * Minor indentation fix * Add Unit Test, add new row in update_child_qty_rate * Codacy fix
This commit is contained in:
committed by
Rushabh Mehta
parent
7c2a5bddb1
commit
3d82b74ea4
@@ -42,6 +42,7 @@ frappe.ui.form.on("Purchase Order", {
|
|||||||
frm: frm,
|
frm: frm,
|
||||||
child_docname: "items",
|
child_docname: "items",
|
||||||
child_doctype: "Purchase Order Detail",
|
child_doctype: "Purchase Order Detail",
|
||||||
|
cannot_add_row: false,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import frappe, erpnext
|
|||||||
import json
|
import json
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate, add_days, add_months, get_last_day, nowdate
|
from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate, add_days, add_months, get_last_day, nowdate
|
||||||
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
from erpnext.setup.utils import get_exchange_rate
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
|
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
@@ -1067,24 +1068,68 @@ def get_supplier_block_status(party_name):
|
|||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
|
||||||
|
"""
|
||||||
|
Returns a Sales Order Item child item containing the default values
|
||||||
|
"""
|
||||||
|
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
|
child_item = frappe.new_doc('Sales Order Item', p_doctype, child_docname)
|
||||||
|
item = frappe.get_doc("Item", item_code)
|
||||||
|
child_item.item_code = item.item_code
|
||||||
|
child_item.item_name = item.item_name
|
||||||
|
child_item.description = item.description
|
||||||
|
child_item.reqd_by_date = p_doctype.delivery_date
|
||||||
|
child_item.uom = item.stock_uom
|
||||||
|
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||||
|
return child_item
|
||||||
|
|
||||||
|
|
||||||
|
def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
|
||||||
|
"""
|
||||||
|
Returns a Purchase Order Item child item containing the default values
|
||||||
|
"""
|
||||||
|
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
|
child_item = frappe.new_doc('Purchase Order Item', p_doctype, child_docname)
|
||||||
|
item = frappe.get_doc("Item", item_code)
|
||||||
|
child_item.item_code = item.item_code
|
||||||
|
child_item.item_name = item.item_name
|
||||||
|
child_item.description = item.description
|
||||||
|
child_item.schedule_date = p_doctype.schedule_date
|
||||||
|
child_item.uom = item.stock_uom
|
||||||
|
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||||
|
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
||||||
|
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
||||||
|
return child_item
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
|
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
|
||||||
data = json.loads(trans_items)
|
data = json.loads(trans_items)
|
||||||
for d in data:
|
|
||||||
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
|
||||||
child_item.qty = flt(d.get("qty"))
|
|
||||||
|
|
||||||
|
for d in data:
|
||||||
|
new_child_flag = False
|
||||||
|
if not d.get("docname"):
|
||||||
|
new_child_flag = True
|
||||||
|
if parent_doctype == "Sales Order":
|
||||||
|
child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code"))
|
||||||
|
if parent_doctype == "Purchase Order":
|
||||||
|
child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code"))
|
||||||
|
else:
|
||||||
|
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
||||||
|
|
||||||
|
child_item.qty = flt(d.get("qty"))
|
||||||
if child_item.billed_amt > (flt(d.get("rate")) * flt(d.get("qty"))):
|
if child_item.billed_amt > (flt(d.get("rate")) * flt(d.get("qty"))):
|
||||||
frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
|
frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
|
||||||
.format(child_item.idx, child_item.item_code))
|
.format(child_item.idx, child_item.item_code))
|
||||||
else:
|
else:
|
||||||
child_item.rate = flt(d.get("rate"))
|
child_item.rate = flt(d.get("rate"))
|
||||||
child_item.flags.ignore_validate_update_after_submit = True
|
child_item.flags.ignore_validate_update_after_submit = True
|
||||||
|
if new_child_flag:
|
||||||
|
child_item.insert()
|
||||||
|
else:
|
||||||
child_item.save()
|
child_item.save()
|
||||||
|
|
||||||
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
|
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
|
|
||||||
p_doctype.flags.ignore_validate_update_after_submit = True
|
p_doctype.flags.ignore_validate_update_after_submit = True
|
||||||
p_doctype.set_qty_as_per_stock_uom()
|
p_doctype.set_qty_as_per_stock_uom()
|
||||||
p_doctype.calculate_taxes_and_totals()
|
p_doctype.calculate_taxes_and_totals()
|
||||||
|
|||||||
@@ -406,15 +406,19 @@ erpnext.utils.select_alternate_items = function(opts) {
|
|||||||
|
|
||||||
erpnext.utils.update_child_items = function(opts) {
|
erpnext.utils.update_child_items = function(opts) {
|
||||||
const frm = opts.frm;
|
const frm = opts.frm;
|
||||||
|
const cannot_add_row = (typeof opts.cannot_add_row === 'undefined') ? true : opts.cannot_add_row;
|
||||||
|
const child_docname = (typeof opts.cannot_add_row === 'undefined') ? "items" : opts.child_docname;
|
||||||
this.data = [];
|
this.data = [];
|
||||||
const dialog = new frappe.ui.Dialog({
|
const dialog = new frappe.ui.Dialog({
|
||||||
title: __("Update Items"),
|
title: __("Update Items"),
|
||||||
fields: [
|
fields: [
|
||||||
{fieldtype:'Section Break', label: __('Items')},
|
{fieldtype:'Section Break', label: __('Items')},
|
||||||
{
|
{
|
||||||
fieldname: "trans_items", fieldtype: "Table", cannot_add_rows: true,
|
fieldname: "trans_items",
|
||||||
in_place_edit: true, data: this.data,
|
fieldtype: "Table",
|
||||||
|
cannot_add_rows: cannot_add_row,
|
||||||
|
in_place_edit: true,
|
||||||
|
data: this.data,
|
||||||
get_data: () => {
|
get_data: () => {
|
||||||
return this.data;
|
return this.data;
|
||||||
},
|
},
|
||||||
@@ -450,10 +454,12 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
const trans_items = this.get_values()["trans_items"];
|
const trans_items = this.get_values()["trans_items"];
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
|
method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
|
||||||
|
freeze: true,
|
||||||
args: {
|
args: {
|
||||||
'parent_doctype': frm.doc.doctype,
|
'parent_doctype': frm.doc.doctype,
|
||||||
'trans_items': trans_items,
|
'trans_items': trans_items,
|
||||||
'parent_doctype_name': frm.doc.name
|
'parent_doctype_name': frm.doc.name,
|
||||||
|
'child_docname': child_docname
|
||||||
},
|
},
|
||||||
callback: function() {
|
callback: function() {
|
||||||
frm.reload_doc();
|
frm.reload_doc();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
frm: frm,
|
frm: frm,
|
||||||
child_docname: "items",
|
child_docname: "items",
|
||||||
child_doctype: "Sales Order Detail",
|
child_doctype: "Sales Order Detail",
|
||||||
|
cannot_add_row: false,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ from erpnext.selling.doctype.sales_order.sales_order import make_work_orders
|
|||||||
from erpnext.controllers.accounts_controller import update_child_qty_rate
|
from erpnext.controllers.accounts_controller import update_child_qty_rate
|
||||||
import json
|
import json
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
||||||
|
|
||||||
|
|
||||||
class TestSalesOrder(unittest.TestCase):
|
class TestSalesOrder(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
@@ -268,6 +270,22 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),
|
self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),
|
||||||
existing_reserved_qty_item2 + 20)
|
existing_reserved_qty_item2 + 20)
|
||||||
|
|
||||||
|
def test_add_new_item_in_update_child_qty_rate(self):
|
||||||
|
so = make_sales_order(item_code= "_Test Item", qty=4)
|
||||||
|
create_dn_against_so(so.name, 4)
|
||||||
|
make_sales_invoice(so.name)
|
||||||
|
|
||||||
|
trans_item = json.dumps([{'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}])
|
||||||
|
update_child_qty_rate('Sales Order', trans_item, so.name)
|
||||||
|
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(so.get("items")[-1].item_code, '_Test Item 2')
|
||||||
|
self.assertEqual(so.get("items")[-1].rate, 200)
|
||||||
|
self.assertEqual(so.get("items")[-1].qty, 7)
|
||||||
|
self.assertEqual(so.get("items")[-1].amount, 1400)
|
||||||
|
self.assertEqual(so.status, 'To Deliver and Bill')
|
||||||
|
|
||||||
|
|
||||||
def test_update_child_qty_rate(self):
|
def test_update_child_qty_rate(self):
|
||||||
so = make_sales_order(item_code= "_Test Item", qty=4)
|
so = make_sales_order(item_code= "_Test Item", qty=4)
|
||||||
create_dn_against_so(so.name, 4)
|
create_dn_against_so(so.name, 4)
|
||||||
|
|||||||
Reference in New Issue
Block a user