From e29248bcb341ea38c897592d005698e864a323ed Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 4 Apr 2016 11:55:52 +0530 Subject: [PATCH] [fixes] test-case to validate quantity after update stock and purchase return and code-cleaning --- .../purchase_invoice/purchase_invoice.js | 8 +-- .../purchase_invoice/purchase_invoice.py | 42 ++------------- .../purchase_invoice/test_purchase_invoice.py | 18 +++++++ erpnext/controllers/accounts_controller.py | 2 +- erpnext/controllers/buying_controller.py | 51 ++++++++++++++++++- .../purchase_receipt/purchase_receipt.py | 47 ----------------- 6 files changed, 77 insertions(+), 91 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 123f4ea6613..03d01801057 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -16,7 +16,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ } } - cur_frm.cscript.hide_fields(this.frm.doc); + hide_fields(this.frm.doc); }, refresh: function(doc) { @@ -108,7 +108,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ }, is_paid: function() { - cur_frm.cscript.hide_fields(this.frm.doc); + hide_fields(this.frm.doc); if(cint(this.frm.doc.is_paid)) { if(!this.frm.doc.company) { cur_frm.set_value("is_paid", 0) @@ -164,7 +164,7 @@ cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice); // Hide Fields // ------------ -cur_frm.cscript.hide_fields = function(doc) { +function hide_fields(doc) { parent_fields = ['due_date', 'is_opening', 'advances_section', 'from_date', 'to_date']; if(cint(doc.is_paid) == 1) { @@ -186,7 +186,7 @@ cur_frm.cscript.hide_fields = function(doc) { } cur_frm.cscript.update_stock = function(doc, dt, dn) { - cur_frm.cscript.hide_fields(doc, dt, dn); + hide_fields(doc, dt, dn); } cur_frm.fields_dict.cash_bank_account.get_query = function(doc) { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 728088bd060..14f157ecd62 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cstr, cint, formatdate, flt, getdate +from frappe.utils import cint, formatdate, flt, getdate from frappe import msgprint, _, throw from erpnext.setup.utils import get_company_currency import frappe.defaults @@ -53,6 +53,9 @@ class PurchaseInvoice(BuyingController): # validate stock items if (self.update_stock == 1): + pc_obj = frappe.get_doc('Purchase Common') + pc_obj.validate_for_items(self) + self.validate_purchase_return() self.validate_rejected_warehouse() self.validate_accepted_rejected_qty() @@ -318,43 +321,6 @@ class PurchaseInvoice(BuyingController): } ]) - def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False): - sl_entries = [] - stock_items = self.get_stock_items() - - for d in self.get('items'): - if d.item_code in stock_items and d.warehouse: - pr_qty = flt(d.qty) * flt(d.conversion_factor) - - if pr_qty: - val_rate_db_precision = 6 if cint(self.precision("valuation_rate", d)) <= 6 else 9 - rate = flt(d.valuation_rate, val_rate_db_precision) - sle = self.get_sl_entries(d, { - "actual_qty": flt(pr_qty), - "serial_no": cstr(d.serial_no).strip() - }) - if self.is_return: - sle.update({ - "outgoing_rate": rate - }) - else: - sle.update({ - "incoming_rate": rate - }) - sl_entries.append(sle) - - if flt(d.rejected_qty) > 0: - sl_entries.append(self.get_sl_entries(d, { - "warehouse": d.rejected_warehouse, - "actual_qty": flt(d.rejected_qty) * flt(d.conversion_factor), - "serial_no": cstr(d.rejected_serial_no).strip(), - "incoming_rate": 0.0 - })) - - # self.bk_flush_supp_wh(sl_entries) - self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock, - via_landed_cost_voucher=via_landed_cost_voucher) - def on_submit(self): self.check_prev_docstatus() self.validate_asset() diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 54053735d30..f58fd449025 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -11,6 +11,7 @@ import frappe.defaults from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \ test_records as pr_test_records from erpnext.exceptions import InvalidCurrency +from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction test_dependencies = ["Item", "Cost Center"] test_ignore = ["Serial No"] @@ -317,6 +318,7 @@ class TestPurchaseInvoice(unittest.TestCase): def test_purchase_invoice_update_stock_gl_entry_with_perpetual_inventory(self): set_perpetual_inventory() + pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(), posting_time=frappe.utils.nowtime()) @@ -359,6 +361,22 @@ class TestPurchaseInvoice(unittest.TestCase): self.assertEquals(expected_gl_entries[gle.account][0], gle.account) self.assertEquals(expected_gl_entries[gle.account][1], gle.debit) self.assertEquals(expected_gl_entries[gle.account][2], gle.credit) + + def test_update_stock_and_purchase_return(self): + actual_qty_0 = get_qty_after_transaction() + + pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(), + posting_time=frappe.utils.nowtime()) + + actual_qty_1 = get_qty_after_transaction() + self.assertEquals(actual_qty_0 + 5, actual_qty_1) + + # return entry + pi1 = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2, rate=50, update_stock=1) + + actual_qty_2 = get_qty_after_transaction() + + self.assertEquals(actual_qty_1 - 2, actual_qty_2) def make_purchase_invoice(**args): pi = frappe.new_doc("Purchase Invoice") diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index cc64a26aa87..cf93e5ba4ae 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -68,7 +68,7 @@ class AccountsController(TransactionBase): else: # show message that the amount is not paid frappe.db.set(self,'paid_amount',0) - frappe.msgprint(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified")) + frappe.throw(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified")) else: frappe.db.set(self,'paid_amount',0) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 6a1b205057a..abd176488f4 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _, msgprint -from frappe.utils import flt +from frappe.utils import flt,cint, cstr from erpnext.setup.utils import get_company_currency from erpnext.accounts.party import get_party_details @@ -261,3 +261,52 @@ class BuyingController(StockController): if not d.conversion_factor: frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx)) d.stock_qty = flt(d.qty) * flt(d.conversion_factor) + + def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False): + sl_entries = [] + stock_items = self.get_stock_items() + + for d in self.get('items'): + if d.item_code in stock_items and d.warehouse: + pr_qty = flt(d.qty) * flt(d.conversion_factor) + + if pr_qty: + val_rate_db_precision = 6 if cint(self.precision("valuation_rate", d)) <= 6 else 9 + rate = flt(d.valuation_rate, val_rate_db_precision) + sle = self.get_sl_entries(d, { + "actual_qty": flt(pr_qty), + "serial_no": cstr(d.serial_no).strip() + }) + if self.is_return: + sle.update({ + "outgoing_rate": rate + }) + else: + sle.update({ + "incoming_rate": rate + }) + sl_entries.append(sle) + + if flt(d.rejected_qty) > 0: + sl_entries.append(self.get_sl_entries(d, { + "warehouse": d.rejected_warehouse, + "actual_qty": flt(d.rejected_qty) * flt(d.conversion_factor), + "serial_no": cstr(d.rejected_serial_no).strip(), + "incoming_rate": 0.0 + })) + + self.make_sl_entries_for_supplier_warehouse(sl_entries) + self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock, + via_landed_cost_voucher=via_landed_cost_voucher) + + def make_sl_entries_for_supplier_warehouse(self, sl_entries): + if hasattr(self, 'supplied_items'): + for d in self.get('supplied_items'): + # negative quantity is passed, as raw material qty has to be decreased + # when PR is submitted and it has to be increased when PR is cancelled + sl_entries.append(self.get_sl_entries(d, { + "item_code": d.rm_item_code, + "warehouse": self.supplier_warehouse, + "actual_qty": -1*flt(d.consumed_qty), + })) + diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 8ee6de9d0e1..d16dd3988b8 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -130,43 +130,6 @@ 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, via_landed_cost_voucher=False): - sl_entries = [] - stock_items = self.get_stock_items() - - for d in self.get('items'): - if d.item_code in stock_items and d.warehouse: - pr_qty = flt(d.qty) * flt(d.conversion_factor) - - if pr_qty: - val_rate_db_precision = 6 if cint(self.precision("valuation_rate", d)) <= 6 else 9 - rate = flt(d.valuation_rate, val_rate_db_precision) - sle = self.get_sl_entries(d, { - "actual_qty": flt(pr_qty), - "serial_no": cstr(d.serial_no).strip() - }) - if self.is_return: - sle.update({ - "outgoing_rate": rate - }) - else: - sle.update({ - "incoming_rate": rate - }) - sl_entries.append(sle) - - if flt(d.rejected_qty) > 0: - sl_entries.append(self.get_sl_entries(d, { - "warehouse": d.rejected_warehouse, - "actual_qty": flt(d.rejected_qty) * flt(d.conversion_factor), - "serial_no": cstr(d.rejected_serial_no).strip(), - "incoming_rate": 0.0 - })) - - self.bk_flush_supp_wh(sl_entries) - 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 = {} for d in self.get("items"): @@ -195,16 +158,6 @@ class PurchaseReceipt(BuyingController): ["qty", "warehouse"]) return po_qty, po_warehouse - def bk_flush_supp_wh(self, sl_entries): - for d in self.get('supplied_items'): - # negative quantity is passed as raw material qty has to be decreased - # when PR is submitted and it has to be increased when PR is cancelled - sl_entries.append(self.get_sl_entries(d, { - "item_code": d.rm_item_code, - "warehouse": self.supplier_warehouse, - "actual_qty": -1*flt(d.consumed_qty), - })) - def validate_inspection(self): for d in self.get('items'): #Enter inspection date for all items that require inspection if frappe.db.get_value("Item", d.item_code, "inspection_required") and not d.qa_no: