From d64a952b5db41c07ca575216446e4a4579467062 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 9 May 2014 11:50:24 +0530 Subject: [PATCH 1/5] Stock reco: item and warehouse validation and translation fixes --- .../stock_reconciliation.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 4bc34d6d59..fe65f22670 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -47,7 +47,7 @@ class StockReconciliation(StockController): self.reconciliation_json = json.dumps(data) def _get_msg(row_num, msg): - return _("Row # ") + ("%d: " % (row_num+head_row_no+2)) + _(msg) + return _("Row # {0}: ").format(row_num+head_row_no+2) + msg self.validation_messages = [] item_warehouse_combinations = [] @@ -60,27 +60,30 @@ class StockReconciliation(StockController): for row_num, row in enumerate(rows): # find duplicates if [row[0], row[1]] in item_warehouse_combinations: - self.validation_messages.append(_get_msg(row_num, "Duplicate entry")) + self.validation_messages.append(_get_msg(row_num, _("Duplicate entry"))) else: item_warehouse_combinations.append([row[0], row[1]]) self.validate_item(row[0], row_num+head_row_no+2) - # note: warehouse will be validated through link validation + + # validate warehouse + if not frappe.db.get_value("Warehouse", row[1]): + self.validation_messages.append(_get_msg(row_num, _("Warehouse not found in the system"))) # if both not specified if row[2] == "" and row[3] == "": self.validation_messages.append(_get_msg(row_num, - "Please specify either Quantity or Valuation Rate or both")) + _("Please specify either Quantity or Valuation Rate or both"))) # do not allow negative quantity if flt(row[2]) < 0: self.validation_messages.append(_get_msg(row_num, - "Negative Quantity is not allowed")) + _("Negative Quantity is not allowed"))) # do not allow negative valuation if flt(row[3]) < 0: self.validation_messages.append(_get_msg(row_num, - "Negative Valuation Rate is not allowed")) + _("Negative Valuation Rate is not allowed"))) # throw all validation messages if self.validation_messages: @@ -97,6 +100,8 @@ class StockReconciliation(StockController): try: item = frappe.get_doc("Item", item_code) + if not item: + raise frappe.ValidationError, (_("Item: {0} not found in the system").format(item_code)) # end of life and stock item validate_end_of_life(item_code, item.end_of_life, verbose=0) @@ -104,12 +109,13 @@ class StockReconciliation(StockController): # item should not be serialized if item.has_serial_no == "Yes": - raise frappe.ValidationError, _("Serialized Item {0} cannot be updated using Stock Reconciliation").format(item_code) + raise frappe.ValidationError, _("Serialized Item {0} cannot be updated \ + using Stock Reconciliation").format(item_code) # item managed batch-wise not allowed if item.has_batch_no == "Yes": - frappe.throw(_("Item: {0} managed batch-wise, can not be reconciled using \ - Stock Reconciliation, instead use Stock Entry").format(item_code)) + raise frappe.ValidationError, _("Item: {0} managed batch-wise, can not be reconciled using \ + Stock Reconciliation, instead use Stock Entry").format(item_code) # docstatus should be < 2 validate_cancelled_item(item_code, item.docstatus, verbose=0) From 7e373010d7d507eb80a85ba05b04325a5aa6c8ea Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sun, 11 May 2014 12:08:39 +0530 Subject: [PATCH 2/5] Test case fixes in time log batch --- .../doctype/time_log/test_time_log.py | 6 ++ .../doctype/time_log_batch/test_records.json | 14 ---- .../time_log_batch/test_time_log_batch.py | 75 ++++++++++++------- 3 files changed, 54 insertions(+), 41 deletions(-) delete mode 100644 erpnext/projects/doctype/time_log_batch/test_records.json diff --git a/erpnext/projects/doctype/time_log/test_time_log.py b/erpnext/projects/doctype/time_log/test_time_log.py index 7aadf5c286..4a312adb41 100644 --- a/erpnext/projects/doctype/time_log/test_time_log.py +++ b/erpnext/projects/doctype/time_log/test_time_log.py @@ -5,11 +5,17 @@ import frappe import unittest from erpnext.projects.doctype.time_log.time_log import OverlapError +from erpnext.projects.doctype.time_log_batch.test_time_log_batch import * class TestTimeLog(unittest.TestCase): def test_duplication(self): + frappe.db.sql("delete from `tabTime Log`") + frappe.get_doc(frappe.copy_doc(test_records[0])).insert() + ts = frappe.get_doc(frappe.copy_doc(test_records[0])) self.assertRaises(OverlapError, ts.insert) + frappe.db.sql("delete from `tabTime Log`") + test_records = frappe.get_test_records('Time Log') test_ignore = ["Time Log Batch", "Sales Invoice"] diff --git a/erpnext/projects/doctype/time_log_batch/test_records.json b/erpnext/projects/doctype/time_log_batch/test_records.json deleted file mode 100644 index d386000e34..0000000000 --- a/erpnext/projects/doctype/time_log_batch/test_records.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "doctype": "Time Log Batch", - "rate": "500", - "time_log_batch_details": [ - { - "doctype": "Time Log Batch Detail", - "parentfield": "time_log_batch_details", - "parenttype": "Time Log Batch", - "time_log": "_T-Time Log-00001" - } - ] - } -] \ No newline at end of file diff --git a/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py b/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py index dceaee78ff..de57f28e2c 100644 --- a/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py +++ b/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py @@ -4,36 +4,57 @@ import frappe, unittest class TimeLogBatchTest(unittest.TestCase): - def setUp(self): - for name in frappe.db.sql_list("select name from `tabTime Log Batch` where docstatus=1"): - frappe.get_doc("Time Log Batch", name).cancel() - frappe.delete_doc("Time Log Batch", name) - - for name in frappe.db.sql_list("select name from `tabTime Log` where docstatus=1"): - frappe.get_doc("Time Log", name).cancel() - frappe.delete_doc("Time Log", name) - def test_time_log_status(self): - from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records - time_log = frappe.copy_doc(time_log_records[0]) - time_log.update({ - "from_time": "2013-01-02 10:00:00.000000", - "to_time": "2013-01-02 11:00:00.000000", - "docstatus": 0 - }) - time_log.insert() - time_log.submit() + delete_time_log_and_batch() + time_log = create_time_log() - self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted") - tlb = frappe.copy_doc(test_records[0]) - tlb.get("time_log_batch_details")[0].time_log = time_log.name - tlb.insert() - tlb.submit() + self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Submitted") - self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Batched for Billing") + tlb = create_time_log_batch(time_log) + + self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Batched for Billing") tlb.cancel() - self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted") + self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Submitted") + + delete_time_log_and_batch() + +def delete_time_log_and_batch(): + for name in frappe.db.sql_list("select name from `tabTime Log Batch` where docstatus=1"): + frappe.get_doc("Time Log Batch", name).cancel() + frappe.delete_doc("Time Log Batch", name) + + for name in frappe.db.sql_list("select name from `tabTime Log` where docstatus=1"): + frappe.get_doc("Time Log", name).cancel() + frappe.delete_doc("Time Log", name) + +def create_time_log(): + from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records + time_log = frappe.copy_doc(time_log_records[0]) + time_log.update({ + "from_time": "2013-01-02 10:00:00.000000", + "to_time": "2013-01-02 11:00:00.000000", + "docstatus": 0 + }) + time_log.insert() + time_log.submit() + return time_log.name + +def create_time_log_batch(time_log): + tlb = frappe.get_doc({ + "doctype": "Time Log Batch", + "rate": "500", + "time_log_batch_details": [ + { + "doctype": "Time Log Batch Detail", + "parentfield": "time_log_batch_details", + "parenttype": "Time Log Batch", + "time_log": time_log + } + ] + }) + + tlb.insert() + tlb.submit() + return tlb -test_records = frappe.get_test_records('Time Log Batch') -test_dependencies = ["Time Log"] test_ignore = ["Sales Invoice"] From 5365108ef9500bdd6ddfb4745420b41bdadffd5d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sun, 11 May 2014 12:10:17 +0530 Subject: [PATCH 3/5] Test case fixes for pos setting --- .../doctype/pos_setting/test_pos_setting.py | 6 -- .../doctype/pos_setting/test_records.json | 16 ------ .../sales_invoice/test_sales_invoice.py | 57 ++++++++++++------- 3 files changed, 37 insertions(+), 42 deletions(-) delete mode 100644 erpnext/accounts/doctype/pos_setting/test_pos_setting.py delete mode 100644 erpnext/accounts/doctype/pos_setting/test_records.json diff --git a/erpnext/accounts/doctype/pos_setting/test_pos_setting.py b/erpnext/accounts/doctype/pos_setting/test_pos_setting.py deleted file mode 100644 index d563be96d7..0000000000 --- a/erpnext/accounts/doctype/pos_setting/test_pos_setting.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - - -import frappe -test_records = frappe.get_test_records('Pos Setting') \ No newline at end of file diff --git a/erpnext/accounts/doctype/pos_setting/test_records.json b/erpnext/accounts/doctype/pos_setting/test_records.json deleted file mode 100644 index 0d382a716a..0000000000 --- a/erpnext/accounts/doctype/pos_setting/test_records.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "cash_bank_account": "_Test Account Bank Account - _TC", - "company": "_Test Company", - "cost_center": "_Test Cost Center - _TC", - "currency": "INR", - "doctype": "POS Setting", - "expense_account": "_Test Account Cost for Goods Sold - _TC", - "income_account": "Sales - _TC", - "name": "_Test POS Setting", - "naming_series": "_T-POS Setting-", - "selling_price_list": "_Test Price List", - "territory": "_Test Territory", - "warehouse": "_Test Warehouse - _TC" - } -] diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 2a0bc248a0..85e57822e2 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -6,6 +6,8 @@ import unittest, json, copy from frappe.utils import flt from erpnext.accounts.utils import get_stock_and_account_difference from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory +from erpnext.projects.doctype.time_log_batch.test_time_log_batch import * + class TestSalesInvoice(unittest.TestCase): def make(self): @@ -365,27 +367,30 @@ class TestSalesInvoice(unittest.TestCase): 561.8) def test_time_log_batch(self): - tlb = frappe.get_doc("Time Log Batch", "_T-Time Log Batch-00001") + delete_time_log_and_batch() + time_log = create_time_log() + tlb = create_time_log_batch(time_log) + + tlb = frappe.get_doc("Time Log Batch", tlb.name) tlb.submit() si = frappe.get_doc(frappe.copy_doc(test_records[0])) - si.get("entries")[0].time_log_batch = "_T-Time Log Batch-00001" + si.get("entries")[0].time_log_batch = tlb.name si.insert() si.submit() - self.assertEquals(frappe.db.get_value("Time Log Batch", "_T-Time Log Batch-00001", - "status"), "Billed") + self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Billed") - self.assertEquals(frappe.db.get_value("Time Log", "_T-Time Log-00001", "status"), - "Billed") + self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Billed") si.cancel() - self.assertEquals(frappe.db.get_value("Time Log Batch", "_T-Time Log Batch-00001", - "status"), "Submitted") + self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Submitted") - self.assertEquals(frappe.db.get_value("Time Log", "_T-Time Log-00001", "status"), - "Batched for Billing") + self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Batched for Billing") + + frappe.delete_doc("Sales Invoice", si.name) + delete_time_log_and_batch() def test_sales_invoice_gl_entry_without_aii(self): self.clear_stock_account_balance() @@ -423,9 +428,9 @@ class TestSalesInvoice(unittest.TestCase): def test_pos_gl_entry_with_aii(self): self.clear_stock_account_balance() set_perpetual_inventory() + self.make_pos_setting() self._insert_purchase_receipt() - self._insert_pos_settings() pos = copy.deepcopy(test_records[1]) pos["is_pos"] = 1 @@ -479,6 +484,26 @@ class TestSalesInvoice(unittest.TestCase): set_perpetual_inventory(0) + frappe.db.sql("delete from `tabPOS Setting`") + + def make_pos_setting(self): + pos_setting = frappe.get_doc({ + "cash_bank_account": "_Test Account Bank Account - _TC", + "company": "_Test Company", + "cost_center": "_Test Cost Center - _TC", + "currency": "INR", + "doctype": "POS Setting", + "expense_account": "_Test Account Cost for Goods Sold - _TC", + "income_account": "Sales - _TC", + "name": "_Test POS Setting", + "naming_series": "_T-POS Setting-", + "selling_price_list": "_Test Price List", + "territory": "_Test Territory", + "warehouse": "_Test Warehouse - _TC" + }) + + pos_setting.insert() + def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self): self.clear_stock_account_balance() set_perpetual_inventory() @@ -604,14 +629,6 @@ class TestSalesInvoice(unittest.TestCase): dn.submit() return dn - def _insert_pos_settings(self): - from erpnext.accounts.doctype.pos_setting.test_pos_setting \ - import test_records as pos_setting_test_records - frappe.db.sql("""delete from `tabPOS Setting`""") - - ps = frappe.copy_doc(pos_setting_test_records[0]) - ps.insert() - def test_sales_invoice_with_advance(self): from erpnext.accounts.doctype.journal_voucher.test_journal_voucher \ import test_records as jv_test_records @@ -843,5 +860,5 @@ class TestSalesInvoice(unittest.TestCase): self.assertRaises(SerialNoStatusError, si.submit) -test_dependencies = ["Journal Voucher", "POS Setting", "Contact", "Address"] +test_dependencies = ["Journal Voucher", "Contact", "Address"] test_records = frappe.get_test_records('Sales Invoice') From 6d5c24840218e8b30491ce86192c427b4d6afaad Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sun, 11 May 2014 12:10:57 +0530 Subject: [PATCH 4/5] Test case fixes for serial no --- erpnext/stock/doctype/stock_entry/test_stock_entry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 4739d21a7f..fc60fce4e3 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -256,7 +256,7 @@ class TestStockEntry(unittest.TestCase): # insert a pos invoice with update stock si = frappe.copy_doc(sales_invoice_test_records[1]) - si.is_pos = si.update_stock = 1 + si.update_stock = 1 si.get("entries")[0].warehouse = "_Test Warehouse - _TC" si.get("entries")[0].item_code = item_code si.get("entries")[0].qty = 5.0 @@ -663,6 +663,7 @@ class TestStockEntry(unittest.TestCase): def test_serial_no_not_exists(self): self._clear_stock_account_balance() + frappe.db.sql("delete from `tabSerial No` where name in ('ABCD', 'EFGH')") se = frappe.copy_doc(test_records[0]) se.purpose = "Material Issue" se.get("mtn_details")[0].item_code = "_Test Serialized Item" @@ -823,8 +824,6 @@ def make_serialized_item(): se.submit() return se -test_records = frappe.get_test_records('Stock Entry') - def make_stock_entry(item, source, target, qty, incoming_rate=None): s = frappe.new_doc("Stock Entry") if source and target: @@ -845,3 +844,5 @@ def make_stock_entry(item, source, target, qty, incoming_rate=None): s.insert() s.submit() return s + +test_records = frappe.get_test_records('Stock Entry') From 75e50ee082510408ddee90af2c9411f21035a242 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sun, 11 May 2014 12:11:15 +0530 Subject: [PATCH 5/5] Fixes for subcontracting --- erpnext/controllers/buying_controller.py | 2 +- .../stock/doctype/purchase_receipt/test_purchase_receipt.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 43276e5977..ad56d8fe94 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -256,7 +256,7 @@ class BuyingController(StockController): rm_supplied_idx += 1 - raw_materials_cost += required_qty * flt(item.rate) + raw_materials_cost += required_qty * flt(bom_item.rate) if self.doctype == "Purchase Receipt": item.rm_supp_cost = raw_materials_cost diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 0aa3accd4a..77de44d021 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -94,8 +94,9 @@ class TestPurchaseReceipt(unittest.TestCase): pr.run_method("calculate_taxes_and_totals") pr.insert() - self.assertEquals(pr.get("purchase_receipt_details")[0].rm_supp_cost, 70000.0) self.assertEquals(len(pr.get("pr_raw_material_details")), 2) + self.assertEquals(pr.get("purchase_receipt_details")[0].rm_supp_cost, 70000.0) + def test_serial_no_supplier(self): pr = frappe.copy_doc(test_records[0])