mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-20 03:47:11 +00:00
Merge branch 'track-changes-for-stock-settings-v12' of https://github.com/pateljannat/erpnext into track-changes-for-stock-settings-v12
This commit is contained in:
@@ -57,7 +57,7 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
|
||||
sle = frappe.get_doc("Stock Ledger Entry", {"voucher_type": "Delivery Note", "voucher_no": dn.name})
|
||||
|
||||
self.assertEqual(sle.stock_value_difference, -1*stock_queue[0][1])
|
||||
self.assertEqual(sle.stock_value_difference, flt(-1*stock_queue[0][1]))
|
||||
|
||||
self.assertFalse(get_gl_entries("Delivery Note", dn.name))
|
||||
|
||||
@@ -442,9 +442,15 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
self.assertEqual(dn.status, "To Bill")
|
||||
self.assertEqual(dn.per_billed, 0)
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(dn.po_no, so.po_no)
|
||||
|
||||
si = make_sales_invoice(dn.name)
|
||||
si.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(dn.po_no, si.po_no)
|
||||
|
||||
dn.load_from_db()
|
||||
self.assertEqual(dn.get("items")[0].billed_amt, 200)
|
||||
self.assertEqual(dn.per_billed, 100)
|
||||
@@ -461,6 +467,9 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(so.po_no, si.po_no)
|
||||
|
||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
|
||||
|
||||
dn1 = make_delivery_note(so.name)
|
||||
@@ -469,6 +478,9 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
dn1.get("items")[0].qty = 2
|
||||
dn1.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(so.po_no, dn1.po_no)
|
||||
|
||||
self.assertEqual(dn1.get("items")[0].billed_amt, 200)
|
||||
self.assertEqual(dn1.per_billed, 100)
|
||||
self.assertEqual(dn1.status, "Completed")
|
||||
@@ -479,6 +491,9 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
dn2.get("items")[0].qty = 4
|
||||
dn2.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(so.po_no, dn2.po_no)
|
||||
|
||||
dn1.load_from_db()
|
||||
self.assertEqual(dn1.get("items")[0].billed_amt, 100)
|
||||
self.assertEqual(dn1.per_billed, 50)
|
||||
@@ -502,9 +517,15 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
dn1.get("items")[0].qty = 2
|
||||
dn1.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(dn1.po_no, so.po_no)
|
||||
|
||||
si1 = make_sales_invoice(dn1.name)
|
||||
si1.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(dn1.po_no, si1.po_no)
|
||||
|
||||
dn1.load_from_db()
|
||||
self.assertEqual(dn1.per_billed, 100)
|
||||
|
||||
@@ -512,11 +533,17 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
si2.get("items")[0].qty = 4
|
||||
si2.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(si2.po_no, so.po_no)
|
||||
|
||||
dn2 = make_delivery_note(so.name)
|
||||
dn2.posting_time = "08:00"
|
||||
dn2.get("items")[0].qty = 5
|
||||
dn2.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(dn2.po_no, so.po_no)
|
||||
|
||||
dn1.load_from_db()
|
||||
self.assertEqual(dn1.get("items")[0].billed_amt, 200)
|
||||
self.assertEqual(dn1.per_billed, 100)
|
||||
@@ -536,9 +563,15 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
si = make_sales_invoice(so.name)
|
||||
si.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(so.po_no, si.po_no)
|
||||
|
||||
dn = make_delivery_note(si.name)
|
||||
dn.submit()
|
||||
|
||||
# Testing if Customer's Purchase Order No was rightly copied
|
||||
self.assertEqual(dn.po_no, si.po_no)
|
||||
|
||||
self.assertEqual(dn.get("items")[0].billed_amt, 1000)
|
||||
self.assertEqual(dn.per_billed, 100)
|
||||
self.assertEqual(dn.status, "Completed")
|
||||
|
||||
@@ -500,6 +500,8 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True):
|
||||
@frappe.whitelist()
|
||||
def make_purchase_invoice(source_name, target_doc=None):
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from erpnext.accounts.party import get_payment_terms_template
|
||||
|
||||
doc = frappe.get_doc('Purchase Receipt', source_name)
|
||||
returned_qty_map = get_returned_qty_map(source_name)
|
||||
invoiced_qty_map = get_invoiced_qty_map(source_name)
|
||||
@@ -510,6 +512,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
|
||||
doc = frappe.get_doc(target)
|
||||
doc.ignore_pricing_rule = 1
|
||||
doc.payment_terms_template = get_payment_terms_template(source.supplier, "Supplier", source.company)
|
||||
doc.run_method("onload")
|
||||
doc.run_method("set_missing_values")
|
||||
doc.run_method("calculate_taxes_and_totals")
|
||||
@@ -536,7 +539,8 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
"doctype": "Purchase Invoice",
|
||||
"field_map": {
|
||||
"supplier_warehouse":"supplier_warehouse",
|
||||
"is_return": "is_return"
|
||||
"is_return": "is_return",
|
||||
"bill_date": "bill_date"
|
||||
},
|
||||
"validation": {
|
||||
"docstatus": ["=", 1],
|
||||
|
||||
@@ -20,6 +20,30 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
|
||||
|
||||
def test_make_purchase_invoice(self):
|
||||
if not frappe.db.exists('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice'):
|
||||
frappe.get_doc({
|
||||
'doctype': 'Payment Terms Template',
|
||||
'template_name': '_Test Payment Terms Template For Purchase Invoice',
|
||||
'allocate_payment_based_on_payment_terms': 1,
|
||||
'terms': [
|
||||
{
|
||||
'doctype': 'Payment Terms Template Detail',
|
||||
'invoice_portion': 50.00,
|
||||
'credit_days_based_on': 'Day(s) after invoice date',
|
||||
'credit_days': 00
|
||||
},
|
||||
{
|
||||
'doctype': 'Payment Terms Template Detail',
|
||||
'invoice_portion': 50.00,
|
||||
'credit_days_based_on': 'Day(s) after invoice date',
|
||||
'credit_days': 30
|
||||
}]
|
||||
}).insert()
|
||||
|
||||
template = frappe.db.get_value('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice')
|
||||
old_template_in_supplier = frappe.db.get_value("Supplier", "_Test Supplier", "payment_terms")
|
||||
frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", template)
|
||||
|
||||
pr = make_purchase_receipt(do_not_save=True)
|
||||
self.assertRaises(frappe.ValidationError, make_purchase_invoice, pr.name)
|
||||
pr.submit()
|
||||
@@ -29,10 +53,23 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
self.assertEqual(pi.doctype, "Purchase Invoice")
|
||||
self.assertEqual(len(pi.get("items")), len(pr.get("items")))
|
||||
|
||||
# modify rate
|
||||
# test maintaining same rate throughout purchade cycle
|
||||
pi.get("items")[0].rate = 200
|
||||
self.assertRaises(frappe.ValidationError, frappe.get_doc(pi).submit)
|
||||
|
||||
# test if payment terms are fetched and set in PI
|
||||
self.assertEqual(pi.payment_terms_template, template)
|
||||
self.assertEqual(pi.payment_schedule[0].payment_amount, flt(pi.grand_total)/2)
|
||||
self.assertEqual(pi.payment_schedule[0].invoice_portion, 50)
|
||||
self.assertEqual(pi.payment_schedule[1].payment_amount, flt(pi.grand_total)/2)
|
||||
self.assertEqual(pi.payment_schedule[1].invoice_portion, 50)
|
||||
|
||||
# teardown
|
||||
pi.delete() # draft PI
|
||||
pr.cancel()
|
||||
frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", old_template_in_supplier)
|
||||
frappe.get_doc('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice').delete()
|
||||
|
||||
def test_purchase_receipt_no_gl_entry(self):
|
||||
company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
|
||||
|
||||
|
||||
@@ -736,6 +736,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
}
|
||||
},
|
||||
|
||||
fg_completed_qty: function() {
|
||||
this.get_items();
|
||||
},
|
||||
|
||||
get_items: function() {
|
||||
var me = this;
|
||||
if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no)
|
||||
@@ -745,6 +749,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
// if work order / bom is mentioned, get items
|
||||
return this.frm.call({
|
||||
doc: me.frm.doc,
|
||||
freeze: true,
|
||||
method: "get_items",
|
||||
callback: function(r) {
|
||||
if(!r.exc) refresh_field("items");
|
||||
|
||||
@@ -83,7 +83,7 @@ class StockEntry(StockController):
|
||||
self.set_incoming_rate()
|
||||
self.validate_serialized_batch()
|
||||
self.set_actual_qty()
|
||||
self.calculate_rate_and_amount(update_finished_item_rate=False)
|
||||
self.calculate_rate_and_amount()
|
||||
|
||||
def on_submit(self):
|
||||
|
||||
@@ -117,6 +117,7 @@ class StockEntry(StockController):
|
||||
self.update_transferred_qty()
|
||||
self.update_quality_inspection()
|
||||
self.delete_auto_created_batches()
|
||||
self.delete_linked_stock_entry()
|
||||
|
||||
def set_job_card_data(self):
|
||||
if self.job_card and not self.work_order:
|
||||
@@ -160,6 +161,12 @@ class StockEntry(StockController):
|
||||
frappe.throw(_("For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry")
|
||||
.format(self.job_card))
|
||||
|
||||
def delete_linked_stock_entry(self):
|
||||
if self.purpose == "Send to Warehouse":
|
||||
for d in frappe.get_all("Stock Entry", filters={"docstatus": 0,
|
||||
"outgoing_stock_entry": self.name, "purpose": "Receive at Warehouse"}):
|
||||
frappe.delete_doc("Stock Entry", d.name)
|
||||
|
||||
def set_transfer_qty(self):
|
||||
for item in self.get("items"):
|
||||
if not flt(item.qty):
|
||||
@@ -1003,26 +1010,22 @@ class StockEntry(StockController):
|
||||
wo = frappe.get_doc("Work Order", self.work_order)
|
||||
wo_items = frappe.get_all('Work Order Item',
|
||||
filters={'parent': self.work_order},
|
||||
fields=["item_code", "required_qty", "consumed_qty"]
|
||||
fields=["item_code", "required_qty", "consumed_qty", "transferred_qty"]
|
||||
)
|
||||
|
||||
work_order_qty = wo.material_transferred_for_manufacturing or wo.qty
|
||||
for item in wo_items:
|
||||
qty = item.required_qty
|
||||
|
||||
item_account_details = get_item_defaults(item.item_code, self.company)
|
||||
# Take into account consumption if there are any.
|
||||
if self.purpose == 'Manufacture':
|
||||
req_qty_each = flt(item.required_qty / wo.qty)
|
||||
if (flt(item.consumed_qty) != 0):
|
||||
remaining_qty = flt(item.consumed_qty) - (flt(wo.produced_qty) * req_qty_each)
|
||||
exhaust_qty = req_qty_each * wo.produced_qty
|
||||
if remaining_qty > exhaust_qty :
|
||||
if (remaining_qty/(req_qty_each * flt(self.fg_completed_qty))) >= 1:
|
||||
qty =0
|
||||
else:
|
||||
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
|
||||
else:
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
wo_item_qty = item.transferred_qty or item.required_qty
|
||||
|
||||
req_qty_each = (
|
||||
(flt(wo_item_qty) - flt(item.consumed_qty)) /
|
||||
(flt(work_order_qty) - flt(wo.produced_qty))
|
||||
)
|
||||
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
if qty > 0:
|
||||
self.add_to_stock_entry_detail({
|
||||
@@ -1108,12 +1111,17 @@ class StockEntry(StockController):
|
||||
else:
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
|
||||
elif backflushed_materials.get(item.item_code):
|
||||
for d in backflushed_materials.get(item.item_code):
|
||||
if d.get(item.warehouse):
|
||||
if (qty > req_qty):
|
||||
qty-= d.get(item.warehouse)
|
||||
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
||||
|
||||
if consumed_qty:
|
||||
qty -= consumed_qty
|
||||
|
||||
if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')):
|
||||
qty = frappe.utils.ceil(qty)
|
||||
|
||||
if qty > 0:
|
||||
self.add_to_stock_entry_detail({
|
||||
@@ -1194,8 +1202,6 @@ class StockEntry(StockController):
|
||||
return item_dict
|
||||
|
||||
def add_to_stock_entry_detail(self, item_dict, bom_no=None):
|
||||
cost_center = frappe.db.get_value("Company", self.company, 'cost_center')
|
||||
|
||||
for d in item_dict:
|
||||
stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom")
|
||||
|
||||
@@ -1206,9 +1212,10 @@ class StockEntry(StockController):
|
||||
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
|
||||
se_child.stock_uom = stock_uom
|
||||
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
|
||||
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
|
||||
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
|
||||
se_child.subcontracted_item = item_dict[d].get("main_item_code")
|
||||
se_child.cost_center = (item_dict[d].get("cost_center") or
|
||||
get_default_cost_center(item_dict[d], company = self.company))
|
||||
|
||||
for field in ["idx", "po_detail", "original_item",
|
||||
"expense_account", "description", "item_name"]:
|
||||
|
||||
@@ -191,7 +191,7 @@ class StockReconciliation(StockController):
|
||||
|
||||
sl_entries = []
|
||||
|
||||
serialized_items = False
|
||||
serialized_items = []
|
||||
for row in self.items:
|
||||
item = frappe.get_cached_doc("Item", row.item_code)
|
||||
if not (item.has_serial_no):
|
||||
@@ -229,27 +229,29 @@ class StockReconciliation(StockController):
|
||||
sl_entries.append(sle_data)
|
||||
|
||||
else:
|
||||
serialized_items = True
|
||||
serialized_items.append(row.item_code)
|
||||
|
||||
if serialized_items:
|
||||
self.get_sle_for_serialized_items(sl_entries)
|
||||
self.get_sle_for_serialized_items(sl_entries, serialized_items)
|
||||
|
||||
if sl_entries:
|
||||
allow_negative_stock = frappe.get_cached_value("Stock Settings", None, "allow_negative_stock")
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
||||
|
||||
def get_sle_for_serialized_items(self, sl_entries):
|
||||
self.issue_existing_serial_and_batch(sl_entries)
|
||||
self.add_new_serial_and_batch(sl_entries)
|
||||
self.update_valuation_rate_for_serial_no()
|
||||
def get_sle_for_serialized_items(self, sl_entries, serialized_items=[]):
|
||||
self.issue_existing_serial_and_batch(sl_entries, serialized_items)
|
||||
self.add_new_serial_and_batch(sl_entries, serialized_items)
|
||||
self.update_valuation_rate_for_serial_no(serialized_items)
|
||||
|
||||
if sl_entries:
|
||||
sl_entries = self.merge_similar_item_serial_nos(sl_entries)
|
||||
|
||||
def issue_existing_serial_and_batch(self, sl_entries):
|
||||
def issue_existing_serial_and_batch(self, sl_entries, serialized_items=[]):
|
||||
from erpnext.stock.stock_ledger import get_stock_ledger_entries
|
||||
|
||||
for row in self.items:
|
||||
if row.item_code not in serialized_items: continue
|
||||
|
||||
serial_nos = get_serial_nos(row.serial_no) or []
|
||||
|
||||
# To issue existing serial nos
|
||||
@@ -303,8 +305,10 @@ class StockReconciliation(StockController):
|
||||
|
||||
sl_entries.append(new_args)
|
||||
|
||||
def add_new_serial_and_batch(self, sl_entries):
|
||||
def add_new_serial_and_batch(self, sl_entries, serialized_items=[]):
|
||||
for row in self.items:
|
||||
if row.item_code not in serialized_items: continue
|
||||
|
||||
if row.qty:
|
||||
args = self.get_sle_for_items(row)
|
||||
|
||||
@@ -316,9 +320,9 @@ class StockReconciliation(StockController):
|
||||
|
||||
sl_entries.append(args)
|
||||
|
||||
def update_valuation_rate_for_serial_no(self):
|
||||
def update_valuation_rate_for_serial_no(self, serialized_items=[]):
|
||||
for d in self.items:
|
||||
if not d.serial_no: continue
|
||||
if d.item_code not in serialized_items: continue
|
||||
|
||||
serial_nos = get_serial_nos(d.serial_no)
|
||||
self.update_valuation_rate_for_serial_nos(d, serial_nos)
|
||||
@@ -372,7 +376,16 @@ class StockReconciliation(StockController):
|
||||
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
|
||||
|
||||
sl_entries = []
|
||||
self.get_sle_for_serialized_items(sl_entries)
|
||||
|
||||
serialized_items = []
|
||||
|
||||
for row in self.items:
|
||||
has_serial_no = frappe.get_cached_value("Item", row.item_code, "has_serial_no")
|
||||
if has_serial_no:
|
||||
serialized_items.append(row.item_code)
|
||||
|
||||
if serialized_items:
|
||||
self.get_sle_for_serialized_items(sl_entries, serialized_items)
|
||||
|
||||
if sl_entries:
|
||||
sl_entries.reverse()
|
||||
|
||||
@@ -207,9 +207,9 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
def test_stock_reco_for_serial_and_batch_item(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
item = frappe.db.exists("Item", {'item_name': 'Batched and Serialised Item'})
|
||||
item = frappe.db.exists("Item", {'item_name': 'Batched and Serialised Item 1'})
|
||||
if not item:
|
||||
item = create_item("Batched and Serialised Item")
|
||||
item = create_item("Batched and Serialised Item 1")
|
||||
item.has_batch_no = 1
|
||||
item.create_new_batch = 1
|
||||
item.has_serial_no = 1
|
||||
@@ -217,7 +217,7 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
item.serial_no_series = "S-.####"
|
||||
item.save()
|
||||
else:
|
||||
item = frappe.get_doc("Item", {'item_name': 'Batched and Serialised Item'})
|
||||
item = frappe.get_doc("Item", {'item_name': 'Batched and Serialised Item 1'})
|
||||
|
||||
warehouse = "_Test Warehouse for Stock Reco2 - _TC"
|
||||
|
||||
@@ -236,7 +236,7 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
self.assertEqual(frappe.db.exists("Batch", batch_no), None)
|
||||
|
||||
if frappe.db.exists("Serial No", serial_nos[0]):
|
||||
frappe.delete_doc("Serial No", serial_nos[0])
|
||||
frappe.delete_doc("Serial No", serial_nos[0])
|
||||
|
||||
def test_stock_reco_for_serial_and_batch_item_with_future_dependent_entry(self):
|
||||
"""
|
||||
@@ -255,9 +255,9 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
|
||||
set_perpetual_inventory()
|
||||
|
||||
item = frappe.db.exists("Item", {'item_name': 'Batched and Serialised Item'})
|
||||
item = frappe.db.exists("Item", {'item_name': 'Batched and Serialised Item 1'})
|
||||
if not item:
|
||||
item = create_item("Batched and Serialised Item")
|
||||
item = create_item("Batched and Serialised Item 1")
|
||||
item.has_batch_no = 1
|
||||
item.create_new_batch = 1
|
||||
item.has_serial_no = 1
|
||||
@@ -265,7 +265,7 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
item.serial_no_series = "S-.####"
|
||||
item.save()
|
||||
else:
|
||||
item = frappe.get_doc("Item", {'item_name': 'Batched and Serialised Item'})
|
||||
item = frappe.get_doc("Item", {'item_name': 'Batched and Serialised Item 1'})
|
||||
|
||||
warehouse = "_Test Warehouse for Stock Reco2 - _TC"
|
||||
|
||||
@@ -392,6 +392,35 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
doc.cancel()
|
||||
frappe.delete_doc(doc.doctype, doc.name)
|
||||
|
||||
def test_stock_reco_with_serial_and_batch(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
warehouse = "_Test Warehouse for Stock Reco1 - _TC"
|
||||
ste1=make_stock_entry(item_code="Stock-Reco-Serial-Item-1",
|
||||
target=warehouse, qty=2, basic_rate=100)
|
||||
|
||||
ste2=make_stock_entry(item_code="Stock-Reco-batch-Item-1",
|
||||
target=warehouse, qty=2, basic_rate=100)
|
||||
|
||||
sr = create_stock_reconciliation(item_code="Stock-Reco-Serial-Item-1",
|
||||
warehouse = warehouse, rate=200, do_not_submit=True)
|
||||
|
||||
sr.append("items", {
|
||||
"item_code": "Stock-Reco-batch-Item-1",
|
||||
"warehouse": warehouse,
|
||||
"batch_no": ste2.items[0].batch_no,
|
||||
"valuation_rate": 200
|
||||
})
|
||||
|
||||
sr.submit()
|
||||
sle = frappe.get_all("Stock Ledger Entry", filters={"item_code": "Stock-Reco-batch-Item-1",
|
||||
"warehouse": warehouse, "voucher_no": sr.name, "voucher_type": sr.doctype})
|
||||
|
||||
self.assertEquals(len(sle), 1)
|
||||
|
||||
for doc in [sr, ste2, ste1]:
|
||||
doc.cancel()
|
||||
|
||||
def insert_existing_sle(warehouse):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
|
||||
@@ -527,23 +527,40 @@ def get_default_deferred_account(args, item, fieldname=None):
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_default_cost_center(args, item, item_group, brand, company=None):
|
||||
def get_default_cost_center(args, item=None, item_group=None, brand=None, company=None):
|
||||
cost_center = None
|
||||
|
||||
if not company and args.get("company"):
|
||||
company = args.get("company")
|
||||
|
||||
if args.get('project'):
|
||||
cost_center = frappe.db.get_value("Project", args.get("project"), "cost_center", cache=True)
|
||||
|
||||
if not cost_center:
|
||||
if not cost_center and (item and item_group and brand):
|
||||
if args.get('customer'):
|
||||
cost_center = item.get('selling_cost_center') or item_group.get('selling_cost_center') or brand.get('selling_cost_center')
|
||||
else:
|
||||
cost_center = item.get('buying_cost_center') or item_group.get('buying_cost_center') or brand.get('buying_cost_center')
|
||||
|
||||
cost_center = cost_center or args.get("cost_center")
|
||||
elif not cost_center and args.get("item_code") and company:
|
||||
for method in ["get_item_defaults", "get_item_group_defaults", "get_brand_defaults"]:
|
||||
path = "erpnext.stock.get_item_details.{0}".format(method)
|
||||
data = frappe.get_attr(path)(args.get("item_code"), company)
|
||||
|
||||
if data and (data.selling_cost_center or data.buying_cost_center):
|
||||
return data.selling_cost_center or data.buying_cost_center
|
||||
|
||||
if not cost_center and args.get("cost_center"):
|
||||
cost_center = args.get("cost_center")
|
||||
|
||||
if (company and cost_center
|
||||
and frappe.get_cached_value("Cost Center", cost_center, "company") != company):
|
||||
return None
|
||||
|
||||
if not cost_center and company:
|
||||
cost_center = frappe.get_cached_value("Company",
|
||||
company, "cost_center")
|
||||
|
||||
return cost_center
|
||||
|
||||
def get_default_supplier(args, item, item_group, brand):
|
||||
|
||||
@@ -21,7 +21,7 @@ def execute(filters=None):
|
||||
|
||||
fifo_queue = sorted(filter(_func, item_dict["fifo_queue"]), key=_func)
|
||||
details = item_dict["details"]
|
||||
if not fifo_queue and (not item_dict.get("total_qty")): continue
|
||||
if not fifo_queue: continue
|
||||
|
||||
average_age = get_average_age(fifo_queue, to_date)
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ def get_stock_ledger_entries(filters, items):
|
||||
select
|
||||
sle.item_code, warehouse, sle.posting_date, sle.actual_qty, sle.valuation_rate,
|
||||
sle.company, sle.voucher_type, sle.qty_after_transaction, sle.stock_value_difference,
|
||||
sle.item_code as name, sle.voucher_no
|
||||
sle.item_code as name, sle.voucher_no, sle.stock_value
|
||||
from
|
||||
`tabStock Ledger Entry` sle force index (posting_sort_index)
|
||||
where sle.docstatus < 2 %s %s
|
||||
@@ -196,7 +196,7 @@ def get_item_warehouse_map(filters, sle):
|
||||
else:
|
||||
qty_diff = flt(d.actual_qty)
|
||||
|
||||
value_diff = flt(d.stock_value_difference)
|
||||
value_diff = flt(d.stock_value) - flt(qty_dict.bal_val)
|
||||
|
||||
if d.posting_date < from_date:
|
||||
qty_dict.opening_qty += qty_diff
|
||||
|
||||
@@ -284,7 +284,6 @@ def update_included_uom_in_report(columns, result, include_uom, conversion_facto
|
||||
return
|
||||
|
||||
convertible_cols = {}
|
||||
|
||||
is_dict_obj = False
|
||||
if isinstance(result[0], dict):
|
||||
is_dict_obj = True
|
||||
@@ -306,13 +305,13 @@ def update_included_uom_in_report(columns, result, include_uom, conversion_facto
|
||||
for row_idx, row in enumerate(result):
|
||||
data = row.items() if is_dict_obj else enumerate(row)
|
||||
for key, value in data:
|
||||
if not key in convertible_columns or not conversion_factors[row_idx]:
|
||||
if key not in convertible_columns or not conversion_factors[row_idx-1]:
|
||||
continue
|
||||
|
||||
if convertible_columns.get(key) == 'rate':
|
||||
new_value = flt(value) * conversion_factors[row_idx]
|
||||
new_value = flt(value) * conversion_factors[row_idx-1]
|
||||
else:
|
||||
new_value = flt(value) / conversion_factors[row_idx]
|
||||
new_value = flt(value) / conversion_factors[row_idx-1]
|
||||
|
||||
if not is_dict_obj:
|
||||
row.insert(key+1, new_value)
|
||||
|
||||
Reference in New Issue
Block a user