diff --git a/erpnext/accounts/report/purchase_order_items_to_be_billed/purchase_order_items_to_be_billed.json b/erpnext/accounts/report/purchase_order_items_to_be_billed/purchase_order_items_to_be_billed.json index e3a658e5c7a..42e37fd6c75 100644 --- a/erpnext/accounts/report/purchase_order_items_to_be_billed/purchase_order_items_to_be_billed.json +++ b/erpnext/accounts/report/purchase_order_items_to_be_billed/purchase_order_items_to_be_billed.json @@ -6,12 +6,12 @@ "doctype": "Report", "idx": 1, "is_standard": "Yes", - "modified": "2014-06-03 07:18:17.244501", + "modified": "2015-03-26 11:00:48.720037", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Order Items To Be Billed", "owner": "Administrator", - "query": "select \n `tabPurchase Order`.`name` as \"Purchase Order:Link/Purchase Order:120\",\n `tabPurchase Order`.`transaction_date` as \"Date:Date:100\",\n\t`tabPurchase Order`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Order Item`.`project_name` as \"Project\",\n\t`tabPurchase Order Item`.item_code as \"Item Code:Link/Item:120\",\n\t`tabPurchase Order Item`.base_amount as \"Amount:Currency:100\",\n\t`tabPurchase Order Item`.billed_amt as \"Billed Amount:Currency:100\", \n\t(`tabPurchase Order Item`.base_amount - ifnull(`tabPurchase Order Item`.billed_amt, 0)) as \"Amount to Bill:Currency:100\",\n\t`tabPurchase Order Item`.item_name as \"Item Name::150\",\n\t`tabPurchase Order Item`.description as \"Description::200\"\nfrom\n\t`tabPurchase Order`, `tabPurchase Order Item`\nwhere\n\t`tabPurchase Order Item`.`parent` = `tabPurchase Order`.`name`\n\tand `tabPurchase Order`.docstatus = 1\n\tand `tabPurchase Order`.status != \"Stopped\"\n\tand ifnull(`tabPurchase Order Item`.billed_amt, 0) < ifnull(`tabPurchase Order Item`.base_amount, 0)\norder by `tabPurchase Order`.transaction_date asc", + "query": "select \n `tabPurchase Order`.`name` as \"Purchase Order:Link/Purchase Order:120\",\n `tabPurchase Order`.`transaction_date` as \"Date:Date:100\",\n\t`tabPurchase Order`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Order Item`.`project_name` as \"Project\",\n\t`tabPurchase Order Item`.item_code as \"Item Code:Link/Item:120\",\n\t`tabPurchase Order Item`.base_amount as \"Amount:Currency:100\",\n\t(`tabPurchase Order Item`.billed_amt * ifnull(`tabPurchase Order`.conversion_rate, 1)) as \"Billed Amount:Currency:100\", \n\t(`tabPurchase Order Item`.base_amount - (ifnull(`tabPurchase Order Item`.billed_amt, 0) * ifnull(`tabPurchase Order`.conversion_rate, 1))) as \"Amount to Bill:Currency:100\",\n\t`tabPurchase Order Item`.item_name as \"Item Name::150\",\n\t`tabPurchase Order Item`.description as \"Description::200\"\nfrom\n\t`tabPurchase Order`, `tabPurchase Order Item`\nwhere\n\t`tabPurchase Order Item`.`parent` = `tabPurchase Order`.`name`\n\tand `tabPurchase Order`.docstatus = 1\n\tand `tabPurchase Order`.status != \"Stopped\"\n\tand (ifnull(`tabPurchase Order Item`.billed_amt, 0) * ifnull(`tabPurchase Order`.conversion_rate, 1)) < ifnull(`tabPurchase Order Item`.base_amount, 0)\norder by `tabPurchase Order`.transaction_date asc", "ref_doctype": "Purchase Invoice", "report_name": "Purchase Order Items To Be Billed", "report_type": "Query Report" diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 6e73778b055..ea1c4fe9eba 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.desk.reportview import get_match_cond from frappe.model.db_query import DatabaseQuery +from frappe.utils import nowdate def get_filters_cond(doctype, filters, conditions): if filters: @@ -154,8 +155,6 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters): return tax_accounts def item_query(doctype, txt, searchfield, start, page_len, filters): - from frappe.utils import nowdate - conditions = [] return frappe.db.sql("""select tabItem.name, @@ -230,38 +229,45 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, }, { "start": start, "page_len": page_len, "txt": ("%%%s%%" % txt) }) def get_batch_no(doctype, txt, searchfield, start, page_len, filters): - from erpnext.controllers.queries import get_match_cond + if not filters.get("posting_date"): + filters["posting_date"] = nowdate() - if filters.has_key('warehouse'): - return frappe.db.sql("""select batch_no, round(sum(actual_qty),2), stock_uom, expiry_date from `tabStock Ledger Entry` sle - INNER JOIN `tabBatch` - on sle.batch_no = `tabBatch`.batch_id - where item_code = '%(item_code)s' - and warehouse = '%(warehouse)s' - and batch_no like '%(txt)s' - and exists(select * from `tabBatch` - where name = sle.batch_no - and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s') - and docstatus != 2) - %(mcond)s - group by batch_no having sum(actual_qty) > 0 - order by expiry_date,batch_no desc - limit %(start)s, %(page_len)s """ % {'item_code': filters['item_code'], - 'warehouse': filters['warehouse'], 'posting_date': filters['posting_date'], - 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), - 'start': start, 'page_len': page_len}) + batch_nos = None + args = { + 'item_code': filters.get("item_code"), + 'warehouse': filters.get("warehouse"), + 'posting_date': filters.get('posting_date'), + 'txt': "%{0}%".format(txt), + "start": start, + "page_len": page_len + } + + if args.get('warehouse'): + batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom, batch.expiry_date + from `tabStock Ledger Entry` sle + INNER JOIN `tabBatch` batch on sle.batch_no = batch.name + where + sle.item_code = %(item_code)s + and sle.warehouse = %(warehouse)s + and sle.batch_no like %(txt)s + and batch.docstatus < 2 + and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s) + {match_conditions} + group by batch_no having sum(sle.actual_qty) > 0 + order by batch.expiry_date, sle.batch_no desc + limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args) + + if batch_nos: + return batch_nos else: - return frappe.db.sql("""select name from tabBatch - where docstatus != 2 - and item = '%(item_code)s' - and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s') - and name like '%(txt)s' - %(mcond)s - order by name desc - limit %(start)s, %(page_len)s""" % {'item_code': filters['item_code'], - 'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt, - 'mcond':get_match_cond(doctype),'start': start, - 'page_len': page_len}) + return frappe.db.sql("""select name, expiry_date from `tabBatch` + where item = %(item_code)s + and name like %(txt)s + and docstatus < 2 + and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s) + {match_conditions} + order by expiry_date, name desc + limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args) def get_account_list(doctype, txt, searchfield, start, page_len, filters): filter_list = [] diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 67a7cee90a4..c640b8b61d1 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -197,9 +197,10 @@ class StockController(AccountsController): sl_dict.update(args) return sl_dict - def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False): + def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False, + via_landed_cost_voucher=False): from erpnext.stock.stock_ledger import make_sl_entries - make_sl_entries(sl_entries, is_amended, allow_negative_stock) + make_sl_entries(sl_entries, is_amended, allow_negative_stock, via_landed_cost_voucher) def make_gl_entries_on_cancel(self): if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index f74ee7cea39..94fedcc3390 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -282,7 +282,8 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ batch_no: function(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); - if(item.item_code) { + + if(item.warehouse && item.item_code && item.batch_no) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_batch_qty", child: item, diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 4ee93281844..2b1ac94c0f7 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -23,7 +23,7 @@ class Bin(Document): if (not getattr(self, f, None)) or (not self.get(f)): self.set(f, 0.0) - def update_stock(self, args, allow_negative_stock=False): + def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False): self.update_qty(args) if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation": @@ -39,7 +39,7 @@ class Bin(Document): "posting_date": args.get("posting_date"), "posting_time": args.get("posting_time"), "voucher_no": args.get("voucher_no") - }, allow_negative_stock=allow_negative_stock) + }, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher) def update_qty(self, args): # update the stock values (for current quantities) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index b37576aff80..733821d982f 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -6,6 +6,7 @@ import frappe from frappe import _ from frappe.utils import flt from frappe.model.document import Document +from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos class LandedCostVoucher(Document): def get_items_from_purchase_receipts(self): @@ -93,12 +94,24 @@ class LandedCostVoucher(Document): # as those fields are allowed to edit after submit pr.save() + # update latest valuation rate in serial no + self.update_rate_in_serial_no(pr) + # update stock & gl entries for cancelled state of PR pr.docstatus = 2 - pr.update_stock_ledger(allow_negative_stock=True) + pr.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) pr.make_gl_entries_on_cancel() + # update stock & gl entries for submit state of PR pr.docstatus = 1 - pr.update_stock_ledger() + pr.update_stock_ledger(via_landed_cost_voucher=True) pr.make_gl_entries() + + def update_rate_in_serial_no(self, purchase_receipt): + for item in purchase_receipt.get("items"): + if item.serial_no: + serial_nos = get_serial_nos(item.serial_no) + if serial_nos: + frappe.db.sql("update `tabSerial No` set purchase_rate=%s where name in ({0})" + .format(", ".join(["%s"]*len(serial_nos))), tuple([item.valuation_rate] + serial_nos)) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 791e15e3ef7..d978116b144 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -183,6 +183,7 @@ def set_missing_values(source, target_doc): def update_item(obj, target, source_parent): target.conversion_factor = 1 target.qty = flt(obj.qty) - flt(obj.ordered_qty) + target.stock_qty = target.qty @frappe.whitelist() def make_purchase_order(source_name, target_doc=None): diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 5c54d684cbd..e7850412341 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -126,7 +126,7 @@ class PurchaseReceipt(BuyingController): if not d.prevdoc_docname: frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code)) - def update_stock_ledger(self, allow_negative_stock=False): + def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False): sl_entries = [] stock_items = self.get_stock_items() @@ -151,7 +151,8 @@ class PurchaseReceipt(BuyingController): })) self.bk_flush_supp_wh(sl_entries) - self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock) + self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock, + via_landed_cost_voucher=via_landed_cost_voucher) def update_ordered_qty(self): po_map = {} diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index b630f646a8a..c7c7aaad10d 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -132,7 +132,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ var me = this; if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no) frappe.throw(__("BOM and Manufacturing Quantity are required")); - + if(this.frm.doc.production_order || this.frm.doc.bom_no) { // if production order / bom is mentioned, get items return this.frm.call({ @@ -393,18 +393,21 @@ cur_frm.cscript.purpose = function(doc, cdt, cdn) { // Overloaded query for link batch_no cur_frm.fields_dict['items'].grid.get_field('batch_no').get_query = function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - if(d.item_code) { - return{ - query: "erpnext.stock.doctype.stock_entry.stock_entry.get_batch_no", - filters:{ - 'item_code' : d.item_code, - 's_warehouse' : d.s_warehouse, - 'posting_date' : doc.posting_date - } - } + var item = locals[cdt][cdn]; + if(!item.item_code) { + frappe.throw(__("Please enter Item Code to get batch no")); } else { - msgprint(__("Please enter Item Code to get batch no")); + var filters = { + 'item_code': item.item_code, + 'posting_date': me.frm.doc.posting_date, + } + + if(item.s_warehouse) filters["warehouse"] = item.s_warehouse + + return { + query : "erpnext.controllers.queries.get_batch_no", + filters: filters + } } } diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index e93658295e7..bd2d945ca84 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -289,8 +289,8 @@ class StockEntry(StockController): incoming_rate = flt(self.get_incoming_rate(args), self.precision("incoming_rate", d)) if incoming_rate > 0: d.incoming_rate = incoming_rate - - d.amount = flt(d.transfer_qty) * flt(d.incoming_rate) + + d.amount = flt(flt(d.transfer_qty) * flt(d.incoming_rate), d.precision("amount")) if not d.t_warehouse: raw_material_cost += flt(d.amount) @@ -386,7 +386,7 @@ class StockEntry(StockController): def validate_return_reference_doc(self): """validate item with reference doc""" ref = get_return_doc_and_details(self) - + if ref.doc: # validate docstatus if ref.doc.docstatus != 1: @@ -400,7 +400,7 @@ class StockEntry(StockController): # posting date check ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00") this_posting_datetime = "%s %s" % (self.posting_date, self.posting_time) - + if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime): from frappe.utils.dateutils import datetime_in_user_format frappe.throw(_("Posting timestamp must be after {0}") @@ -784,51 +784,6 @@ def query_return_item(doctype, txt, searchfield, start, page_len, filters): return result[start:start+page_len] -def get_batch_no(doctype, txt, searchfield, start, page_len, filters): - if not filters.get("posting_date"): - filters["posting_date"] = nowdate() - - batch_nos = None - args = { - 'item_code': filters.get("item_code"), - 's_warehouse': filters.get('s_warehouse'), - 'posting_date': filters.get('posting_date'), - 'txt': "%%%s%%" % txt, - 'mcond':get_match_cond(doctype), - "start": start, - "page_len": page_len - } - - if filters.get("s_warehouse"): - batch_nos = frappe.db.sql("""select batch_no - from `tabStock Ledger Entry` sle - where item_code = '%(item_code)s' - and warehouse = '%(s_warehouse)s' - and batch_no like '%(txt)s' - and exists(select * from `tabBatch` - where name = sle.batch_no - and (ifnull(expiry_date, '2099-12-31') >= %(posting_date)s - or expiry_date = '') - and docstatus != 2) - %(mcond)s - group by batch_no having sum(actual_qty) > 0 - order by batch_no desc - limit %(start)s, %(page_len)s """ - % args) - - if batch_nos: - return batch_nos - else: - return frappe.db.sql("""select name from `tabBatch` - where item = '%(item_code)s' - and docstatus < 2 - and (ifnull(expiry_date, '2099-12-31') >= %(posting_date)s - or expiry_date = '' or expiry_date = "0000-00-00") - %(mcond)s - order by name desc - limit %(start)s, %(page_len)s - """ % args) - def get_stock_items_for_return(ref_doc, parentfields): """return item codes filtered from doc, which are stock items""" if isinstance(parentfields, basestring): diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 812c5dfc14a..1b3dc06a959 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -27,8 +27,9 @@ class StockLedgerEntry(Document): self.check_stock_frozen_date() self.actual_amt_check() - from erpnext.stock.doctype.serial_no.serial_no import process_serial_no - process_serial_no(self) + if not self.get("via_landed_cost_voucher"): + from erpnext.stock.doctype.serial_no.serial_no import process_serial_no + process_serial_no(self) #check for item quantity available in stock def actual_amt_check(self): diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 8b2da793146..e24f67a5e80 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -305,13 +305,13 @@ def get_serial_nos_by_fifo(args, item_doc): })) def get_actual_batch_qty(batch_no,warehouse,item_code): - actual_batch_qty = 0 - if batch_no: - actual_batch_qty = flt(frappe.db.sql("""select sum(actual_qty) - from `tabStock Ledger Entry` - where warehouse=%s and item_code=%s and batch_no=%s""", - (warehouse, item_code, batch_no))[0][0]) - return actual_batch_qty + actual_batch_qty = 0 + if batch_no: + actual_batch_qty = flt(frappe.db.sql("""select sum(actual_qty) + from `tabStock Ledger Entry` + where warehouse=%s and item_code=%s and batch_no=%s""", + (warehouse, item_code, batch_no))[0][0]) + return actual_batch_qty @frappe.whitelist() def get_conversion_factor(item_code, uom): diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a554f225b83..5bb2f0c5175 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -14,7 +14,7 @@ class NegativeStockError(frappe.ValidationError): pass _exceptions = frappe.local('stockledger_exceptions') # _exceptions = [] -def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False): +def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False, via_landed_cost_voucher=False): if sl_entries: from erpnext.stock.utils import update_bin @@ -28,14 +28,14 @@ def make_sl_entries(sl_entries, is_amended=None, allow_negative_stock=False): sle['actual_qty'] = -flt(sle['actual_qty']) if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation": - sle_id = make_entry(sle, allow_negative_stock) + sle_id = make_entry(sle, allow_negative_stock, via_landed_cost_voucher) args = sle.copy() args.update({ "sle_id": sle_id, "is_amended": is_amended }) - update_bin(args, allow_negative_stock) + update_bin(args, allow_negative_stock, via_landed_cost_voucher) if cancel: delete_cancelled_entry(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no')) @@ -46,11 +46,12 @@ def set_as_cancel(voucher_type, voucher_no): where voucher_no=%s and voucher_type=%s""", (now(), frappe.session.user, voucher_type, voucher_no)) -def make_entry(args, allow_negative_stock=False): +def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False): args.update({"doctype": "Stock Ledger Entry"}) sle = frappe.get_doc(args) sle.flags.ignore_permissions = 1 sle.allow_negative_stock=allow_negative_stock + sle.via_landed_cost_voucher = via_landed_cost_voucher sle.insert() sle.submit() return sle.name @@ -73,13 +74,14 @@ class update_entries_after(object): "posting_time": "12:00" } """ - def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, verbose=1): + def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1): from frappe.model.meta import get_field_precision self.exceptions = [] self.verbose = verbose self.allow_zero_rate = allow_zero_rate self.allow_negative_stock = allow_negative_stock + self.via_landed_cost_voucher = via_landed_cost_voucher if not self.allow_negative_stock: self.allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock")) @@ -141,7 +143,7 @@ class update_entries_after(object): bin_doc.save(ignore_permissions=True) def process_sle(self, sle): - if sle.serial_no or not cint(self.allow_negative_stock): + if (sle.serial_no and not self.via_landed_cost_voucher) or not cint(self.allow_negative_stock): # validate negative stock for serialized items, fifo valuation # or when negative stock is not allowed for moving average if not self.validate_negative_stock(sle): diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index c34ba40d520..1a9e8283d82 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -79,11 +79,11 @@ def get_bin(item_code, warehouse): bin_obj.flags.ignore_permissions = True return bin_obj -def update_bin(args, allow_negative_stock=False): +def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False): is_stock_item = frappe.db.get_value('Item', args.get("item_code"), 'is_stock_item') if is_stock_item == 'Yes': bin = get_bin(args.get("item_code"), args.get("warehouse")) - bin.update_stock(args, allow_negative_stock) + bin.update_stock(args, allow_negative_stock, via_landed_cost_voucher) return bin else: frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code")))