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:
Stavros Anastasiadis 2018-12-10 13:00:55 +01:00 committed by Rushabh Mehta
parent 7c2a5bddb1
commit 3d82b74ea4
5 changed files with 82 additions and 11 deletions

View File

@ -42,6 +42,7 @@ frappe.ui.form.on("Purchase Order", {
frm: frm,
child_docname: "items",
child_doctype: "Purchase Order Detail",
cannot_add_row: false,
})
});
}

View File

@ -6,6 +6,7 @@ import frappe, erpnext
import json
from frappe import _, throw
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.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
from erpnext.utilities.transaction_base import TransactionBase
@ -1067,24 +1068,68 @@ def get_supplier_block_status(party_name):
}
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()
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)
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"))):
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))
else:
child_item.rate = flt(d.get("rate"))
child_item.flags.ignore_validate_update_after_submit = True
child_item.save()
if new_child_flag:
child_item.insert()
else:
child_item.save()
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
p_doctype.flags.ignore_validate_update_after_submit = True
p_doctype.set_qty_as_per_stock_uom()
p_doctype.calculate_taxes_and_totals()

View File

@ -406,15 +406,19 @@ erpnext.utils.select_alternate_items = function(opts) {
erpnext.utils.update_child_items = function(opts) {
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 = [];
const dialog = new frappe.ui.Dialog({
title: __("Update Items"),
fields: [
{fieldtype:'Section Break', label: __('Items')},
{
fieldname: "trans_items", fieldtype: "Table", cannot_add_rows: true,
in_place_edit: true, data: this.data,
fieldname: "trans_items",
fieldtype: "Table",
cannot_add_rows: cannot_add_row,
in_place_edit: true,
data: this.data,
get_data: () => {
return this.data;
},
@ -450,10 +454,12 @@ erpnext.utils.update_child_items = function(opts) {
const trans_items = this.get_values()["trans_items"];
frappe.call({
method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
freeze: true,
args: {
'parent_doctype': frm.doc.doctype,
'trans_items': trans_items,
'parent_doctype_name': frm.doc.name
'parent_doctype_name': frm.doc.name,
'child_docname': child_docname
},
callback: function() {
frm.reload_doc();

View File

@ -25,6 +25,7 @@ frappe.ui.form.on("Sales Order", {
frm: frm,
child_docname: "items",
child_doctype: "Sales Order Detail",
cannot_add_row: false,
})
});
}

View File

@ -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
import json
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
class TestSalesOrder(unittest.TestCase):
def tearDown(self):
frappe.set_user("Administrator")
@ -268,6 +270,22 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),
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):
so = make_sales_order(item_code= "_Test Item", qty=4)
create_dn_against_so(so.name, 4)
@ -760,7 +778,7 @@ def make_sales_order(**args):
})
so.delivery_date = add_days(so.transaction_date, 10)
if not args.do_not_save:
so.insert()
if not args.do_not_submit: