From 8c7234f2704fdaf45562b15329183cb6efee4ae2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 11 Mar 2013 16:32:33 +0530 Subject: [PATCH 1/3] aii: gl_entries for sales invoice --- .../doctype/sales_invoice/sales_invoice.py | 163 +++++++++----- .../sales_invoice/test_sales_invoice.py | 201 +++++++++++++++++- .../sales_invoice_item/sales_invoice_item.txt | 56 ++++- accounts/report/gross_profit/gross_profit.py | 2 +- controllers/accounts_controller.py | 4 +- controllers/selling_controller.py | 25 ++- home/page/latest_updates/latest_updates.js | 10 +- .../march_2013/p03_update_buying_amount.py | 10 + .../doctype/sales_person/test_sales_person.py | 14 ++ stock/doctype/delivery_note/delivery_note.py | 66 ++---- .../delivery_note/test_delivery_note.py | 2 + .../delivery_note_item/delivery_note_item.txt | 36 +++- stock/doctype/item/test_item.py | 19 ++ stock/stock_ledger.py | 2 - stock/utils.py | 13 +- 15 files changed, 484 insertions(+), 139 deletions(-) create mode 100644 patches/march_2013/p03_update_buying_amount.py diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index b31d54919c..597e2ff1aa 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -25,6 +25,8 @@ from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import _, msgprint +from stock.utils import get_buying_amount, get_sales_bom + session = webnotes.session month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12} @@ -95,7 +97,8 @@ class DocType(SellingController): if not self.doc.recurring_id: get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self) - + + self.set_buying_amount() self.check_prev_docstatus() get_obj("Sales Common").update_prevdoc_detail(1,self) @@ -126,7 +129,7 @@ class DocType(SellingController): self.check_next_docstatus() sales_com_obj.update_prevdoc_detail(0, self) - self.make_gl_entries(is_cancel=1) + self.make_gl_entries() def on_update_after_submit(self): self.validate_recurring_invoice() @@ -619,8 +622,7 @@ class DocType(SellingController): 'is_cancelled' : (update_stock==1) and 'No' or 'Yes', 'batch_no' : cstr(d['batch_no']), 'serial_no' : d['serial_no'] - }) - + }) def update_stock_ledger(self, update_stock): self.values = [] @@ -648,14 +650,29 @@ class DocType(SellingController): return ret - def make_gl_entries(self, is_cancel=0): - from accounts.general_ledger import make_gl_entries - gl_entries = [] - auto_inventory_accounting = webnotes.conn.get_value("Global Defaults", None, - "automatic_inventory_accounting") - abbr = self.get_company_abbr() + def make_gl_entries(self): + from accounts.general_ledger import make_gl_entries, merge_similar_entries - # parent's gl entry + gl_entries = [] + + self.make_customer_gl_entry(gl_entries) + + self.make_tax_gl_entries(gl_entries) + + self.make_item_gl_entries(gl_entries) + + # merge gl entries before adding pos entries + gl_entries = merge_similar_entries(gl_entries) + + self.make_pos_gl_entries(gl_entries) + + update_outstanding = cint(self.doc.is_pos) and self.doc.write_off_account and 'No' or 'Yes' + + if gl_entries: + make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2), + update_outstanding=update_outstanding, merge_entries=False) + + def make_customer_gl_entry(self, gl_entries): if self.doc.grand_total: gl_entries.append( self.get_gl_dict({ @@ -665,10 +682,10 @@ class DocType(SellingController): "remarks": self.doc.remarks, "against_voucher": self.doc.name, "against_voucher_type": self.doc.doctype, - }, is_cancel) + }) ) - - # tax table gl entries + + def make_tax_gl_entries(self, gl_entries): for tax in self.doclist.get({"parentfield": "other_charges"}): if flt(tax.tax_amount): gl_entries.append( @@ -678,11 +695,21 @@ class DocType(SellingController): "credit": flt(tax.tax_amount), "remarks": self.doc.remarks, "cost_center": tax.cost_center_other_charges - }, is_cancel) + }) ) - + + def make_item_gl_entries(self, gl_entries): # item gl entries - for item in getlist(self.doclist, 'entries'): + auto_inventory_accounting = \ + cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) + + if auto_inventory_accounting: + if cint(self.doc.is_pos) and cint(self.doc.update_stock): + stock_account = self.get_stock_in_hand_account() + else: + stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) + + for item in self.doclist.get({"parentfield": "entries"}): # income account gl entries if flt(item.amount): gl_entries.append( @@ -692,35 +719,31 @@ class DocType(SellingController): "credit": item.amount, "remarks": self.doc.remarks, "cost_center": item.cost_center - }, is_cancel) + }) ) - # if auto inventory accounting enabled and stock item, - # then do stock related gl entries - if auto_inventory_accounting and item.delivery_note and \ - webnotes.conn.get_value("Item", item.item_code, "is_stock_item")=="Yes": - # to-do - purchase_rate = webnotes.conn.get_value("Delivery Note Item", - item.dn_detail, "purchase_rate") - valuation_amount = purchase_rate * item.qty - # expense account gl entries - if flt(valuation_amount): - gl_entries.append( - self.get_gl_dict({ - "account": item.expense_account, - "against": "Stock Delivered But Not Billed - %s" % (abbr,), - "debit": valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock" - }, is_cancel) - ) - gl_entries.append( - self.get_gl_dict({ - "account": "Stock Delivered But Not Billed - %s" % (abbr,), - "against": item.expense_account, - "credit": valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock" - }, is_cancel) - ) - if self.doc.is_pos and self.doc.cash_bank_account and self.doc.paid_amount: + + # expense account gl entries + if auto_inventory_accounting and flt(item.buying_amount): + gl_entries.append( + self.get_gl_dict({ + "account": item.expense_account, + "against": stock_account, + "debit": item.buying_amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock", + "cost_center": item.cost_center + }) + ) + gl_entries.append( + self.get_gl_dict({ + "account": stock_account, + "against": item.expense_account, + "credit": item.buying_amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock" + }) + ) + + def make_pos_gl_entries(self, gl_entries): + if cint(self.doc.is_pos) and self.doc.cash_bank_account and self.doc.paid_amount: # POS, make payment entries gl_entries.append( self.get_gl_dict({ @@ -730,7 +753,7 @@ class DocType(SellingController): "remarks": self.doc.remarks, "against_voucher": self.doc.name, "against_voucher_type": self.doc.doctype, - }, is_cancel) + }) ) gl_entries.append( self.get_gl_dict({ @@ -738,7 +761,7 @@ class DocType(SellingController): "against": self.doc.debit_to, "debit": self.doc.paid_amount, "remarks": self.doc.remarks, - }, is_cancel) + }) ) # write off entries, applicable if only pos if self.doc.write_off_account and self.doc.write_off_amount: @@ -750,7 +773,7 @@ class DocType(SellingController): "remarks": self.doc.remarks, "against_voucher": self.doc.name, "against_voucher_type": self.doc.doctype, - }, is_cancel) + }) ) gl_entries.append( self.get_gl_dict({ @@ -759,23 +782,45 @@ class DocType(SellingController): "debit": self.doc.write_off_amount, "remarks": self.doc.remarks, "cost_center": self.doc.write_off_cost_center - }, is_cancel) + }) ) + + def set_buying_amount(self): + if cint(self.doc.is_pos) and cint(self.doc.update_stock): + stock_ledger_entries = self.get_stock_ledger_entries() + item_sales_bom = get_sales_bom() + else: + stock_ledger_entries = item_sales_bom = None + + for item in self.doclist.get({"parentfield": "entries"}): + if item.item_code in self.stock_items: + item.buying_amount = self.get_item_buying_amount(item, stock_ledger_entries, + item_sales_bom) + webnotes.conn.set_value("Sales Invoice Item", item.name, + "buying_amount", item.buying_amount) + + def get_item_buying_amount(self, item, stock_ledger_entries, item_sales_bom): + item_buying_amount = 0 + if stock_ledger_entries: + # is pos and update stock + item_buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, + self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom) + elif item.delivery_note and item.dn_detail: + # against delivery note + dn_item = webnotes.conn.get_value("Delivery Note Item", item.dn_detail, + ["buying_amount", "qty"], as_dict=1) + item_buying_rate = flt(dn_item.buying_amount) / flt(dn_item.qty) + item_buying_amount = item_buying_rate * flt(item.qty) - - update_outstanding = self.doc.is_pos and self.doc.write_off_account and 'No' or 'Yes' - merge_entries=cint(self.doc.is_pos)!=1 and 1 or 0 - if gl_entries: - make_gl_entries(gl_entries, cancel=is_cancel, - update_outstanding=update_outstanding, merge_entries=merge_entries) - + return item_buying_amount + def update_c_form(self): """Update amended id in C-form""" if self.doc.c_form_no and self.doc.amended_from: webnotes.conn.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s, - invoice_date = %s, territory = %s, net_total = %s, - grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no)) - + invoice_date = %s, territory = %s, net_total = %s, + grand_total = %s where invoice_no = %s and parent = %s""", + (self.doc.name, self.doc.amended_from, self.doc.c_form_no)) def check_next_docstatus(self): submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name)) diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index 1f165f0c33..84eddea218 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -53,16 +53,17 @@ class TestSalesInvoice(unittest.TestCase): "Batched for Billing") def test_sales_invoice_gl_entry_without_aii(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + si = webnotes.bean(webnotes.copy_doclist(test_records[1])) si.insert() si.submit() - webnotes.defaults.set_global_default("auto_inventory_accounting", 0) - gl_entries = webnotes.conn.sql("""select account, debit, credit from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s order by account asc""", si.doc.name, as_dict=1) self.assertTrue(gl_entries) + expected_values = sorted([ [si.doc.debit_to, 630.0, 0.0], [test_records[1][1]["income_account"], 0.0, 500.0], @@ -74,8 +75,20 @@ class TestSalesInvoice(unittest.TestCase): self.assertEquals(expected_values[i][0], gle.account) self.assertEquals(expected_values[i][1], gle.debit) self.assertEquals(expected_values[i][2], gle.credit) + + # cancel + si.cancel() + + gle_count = webnotes.conn.sql("""select count(name) from `tabGL Entry` + where voucher_type='Sales Invoice' and voucher_no=%s + and ifnull(is_cancelled, 'No') = 'Yes' + order by account asc""", si.doc.name) + + self.assertEquals(gle_count[0][0], 8) + + def test_sales_invoice_gl_entry_with_aii_delivery_note(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") - def test_sales_invoice_gl_entry_with_aii(self): webnotes.defaults.set_global_default("auto_inventory_accounting", 1) self._insert_purchase_receipt() @@ -83,8 +96,10 @@ class TestSalesInvoice(unittest.TestCase): si_against_dn = webnotes.copy_doclist(test_records[1]) si_against_dn[1]["delivery_note"] = dn.doc.name - si = webnotes.bean(si_against_dn) + si_against_dn[1]["dn_detail"] = dn.doclist[1].name + si = webnotes.bean(si_against_dn) si.insert() + si.submit() gl_entries = webnotes.conn.sql("""select account, debit, credit @@ -100,15 +115,154 @@ class TestSalesInvoice(unittest.TestCase): ["Stock Delivered But Not Billed - _TC", 0.0, 375.0], [test_records[1][1]["expense_account"], 375.0, 0.0] ]) - print expected_values - print gl_entries for i, gle in enumerate(gl_entries): self.assertEquals(expected_values[i][0], gle.account) self.assertEquals(expected_values[i][1], gle.debit) self.assertEquals(expected_values[i][2], gle.credit) + si.cancel() + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + and ifnull(is_cancelled, 'No') = 'No' + order by account asc, name asc""", si.doc.name, as_dict=1) + + expected_values = sorted([ + [si.doc.debit_to, 630.0, 0.0], + [si.doc.debit_to, 0.0, 630.0], + [test_records[1][1]["income_account"], 0.0, 500.0], + [test_records[1][1]["income_account"], 500.0, 0.0], + [test_records[1][2]["account_head"], 0.0, 80.0], + [test_records[1][2]["account_head"], 80.0, 0.0], + [test_records[1][3]["account_head"], 0.0, 50.0], + [test_records[1][3]["account_head"], 50.0, 0.0], + ["Stock Delivered But Not Billed - _TC", 0.0, 375.0], + ["Stock Delivered But Not Billed - _TC", 375.0, 0.0], + [test_records[1][1]["expense_account"], 375.0, 0.0], + [test_records[1][1]["expense_account"], 0.0, 375.0] + + ]) + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_values[i][0], gle.account) + self.assertEquals(expected_values[i][1], gle.debit) + self.assertEquals(expected_values[i][2], gle.credit) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_pos_gl_entry_with_aii(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + self._insert_purchase_receipt() + self._insert_pos_settings() + + pos = webnotes.copy_doclist(test_records[1]) + pos[0]["is_pos"] = 1 + pos[0]["update_stock"] = 1 + pos[0]["posting_time"] = "12:05" + pos[0]["cash_bank_account"] = "_Test Account Bank Account - _TC" + pos[0]["paid_amount"] = 600.0 + + si = webnotes.bean(pos) + si.insert() + si.submit() + + # check stock ledger entries + sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where voucher_type = 'Sales Invoice' and voucher_no = %s""", si.doc.name, as_dict=1)[0] + self.assertTrue(sle) + self.assertEquals([sle.item_code, sle.warehouse, sle.actual_qty], + ["_Test Item", "_Test Warehouse", -5.0]) + + # check gl entries + stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company", + "stock_in_hand_account") + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + order by account asc, debit asc""", si.doc.name, as_dict=1) + self.assertTrue(gl_entries) + + expected_gl_entries = sorted([ + [si.doc.debit_to, 630.0, 0.0], + [test_records[1][1]["income_account"], 0.0, 500.0], + [test_records[1][2]["account_head"], 0.0, 80.0], + [test_records[1][3]["account_head"], 0.0, 50.0], + [stock_in_hand_account, 0.0, 375.0], + [test_records[1][1]["expense_account"], 375.0, 0.0], + [si.doc.debit_to, 0.0, 600.0], + ["_Test Account Bank Account - _TC", 600.0, 0.0] + ]) + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_gl_entries[i][0], gle.account) + self.assertEquals(expected_gl_entries[i][1], gle.debit) + self.assertEquals(expected_gl_entries[i][2], gle.credit) + + # cancel + si.cancel() + gl_count = webnotes.conn.sql("""select count(name) + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + and ifnull(is_cancelled, 'No') = 'Yes' + order by account asc, name asc""", si.doc.name) + + self.assertEquals(gl_count[0][0], 16) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_sales_invoice_gl_entry_with_aii_no_item_code(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + si_copy = webnotes.copy_doclist(test_records[1]) + si_copy[1]["item_code"] = None + si = webnotes.bean(si_copy) + si.insert() + si.submit() + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + order by account asc""", si.doc.name, as_dict=1) + self.assertTrue(gl_entries) + + expected_values = sorted([ + [si.doc.debit_to, 630.0, 0.0], + [test_records[1][1]["income_account"], 0.0, 500.0], + [test_records[1][2]["account_head"], 0.0, 80.0], + [test_records[1][3]["account_head"], 0.0, 50.0], + ]) + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_values[i][0], gle.account) + self.assertEquals(expected_values[i][1], gle.debit) + self.assertEquals(expected_values[i][2], gle.credit) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_sales_invoice_gl_entry_with_aii_non_stock_item(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + si_copy = webnotes.copy_doclist(test_records[1]) + si_copy[1]["item_code"] = "_Test Non Stock Item" + si = webnotes.bean(si_copy) + si.insert() + si.submit() + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + order by account asc""", si.doc.name, as_dict=1) + self.assertTrue(gl_entries) + + expected_values = sorted([ + [si.doc.debit_to, 630.0, 0.0], + [test_records[1][1]["income_account"], 0.0, 500.0], + [test_records[1][2]["account_head"], 0.0, 80.0], + [test_records[1][3]["account_head"], 0.0, 50.0], + ]) + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_values[i][0], gle.account) + self.assertEquals(expected_values[i][1], gle.debit) + self.assertEquals(expected_values[i][2], gle.credit) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def _insert_purchase_receipt(self): from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \ @@ -126,6 +280,23 @@ class TestSalesInvoice(unittest.TestCase): dn.submit() return dn + def _insert_pos_settings(self): + ps = webnotes.bean([ + { + "cash_bank_account": "_Test Account Bank Account - _TC", + "company": "_Test Company", + "conversion_rate": 1.0, + "cost_center": "_Test Cost Center - _TC", + "currency": "INR", + "doctype": "POS Setting", + "income_account": "_Test Account Bank Account - _TC", + "price_list_name": "_Test Price List", + "territory": "_Test Territory", + "warehouse": "_Test Warehouse" + } + ]) + ps.insert() + test_dependencies = ["Journal Voucher"] test_records = [ @@ -178,7 +349,19 @@ test_records = [ "doctype": "Sales Taxes and Charges", "parentfield": "other_charges", "tax_amount": 31.8, - } + }, + { + "parentfield": "sales_team", + "doctype": "Sales Team", + "sales_person": "_Test Sales Person 1", + "allocated_percentage": 65.5, + }, + { + "parentfield": "sales_team", + "doctype": "Sales Team", + "sales_person": "_Test Sales Person 2", + "allocated_percentage": 34.5, + }, ], [ { @@ -207,13 +390,13 @@ test_records = [ "description": "_Test Item", "doctype": "Sales Invoice Item", "parentfield": "entries", - "qty": 1.0, + "qty": 5.0, "basic_rate": 500.0, "amount": 500.0, "export_rate": 500.0, "export_amount": 500.0, "income_account": "Sales - _TC", - "expense_account": "_Test Account Cost for Goods Sold", + "expense_account": "_Test Account Cost for Goods Sold - _TC", "cost_center": "_Test Cost Center - _TC", }, { diff --git a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt index c8b18a4880..ca078b53f4 100644 --- a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt +++ b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-03-05 09:11:04", + "creation": "2013-03-07 11:42:55", "docstatus": 0, - "modified": "2013-03-07 07:03:30", + "modified": "2013-03-11 14:58:50", "modified_by": "Administrator", "owner": "Administrator" }, @@ -30,7 +30,8 @@ "fieldname": "barcode", "fieldtype": "Data", "label": "Barcode", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -42,6 +43,7 @@ "oldfieldtype": "Link", "options": "Item", "print_hide": 0, + "read_only": 0, "reqd": 0, "search_index": 1 }, @@ -63,6 +65,7 @@ "oldfieldname": "item_name", "oldfieldtype": "Data", "print_hide": 1, + "read_only": 0, "reqd": 1, "search_index": 0 }, @@ -74,6 +77,7 @@ "oldfieldname": "description", "oldfieldtype": "Text", "print_width": "200px", + "read_only": 0, "reqd": 1, "width": "200px" }, @@ -84,6 +88,7 @@ "label": "Qty", "oldfieldname": "qty", "oldfieldtype": "Currency", + "read_only": 0, "reqd": 0 }, { @@ -102,6 +107,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, + "read_only": 0, "reqd": 0 }, { @@ -111,7 +117,8 @@ "label": "Discount (%)", "oldfieldname": "adj_rate", "oldfieldtype": "Float", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -121,6 +128,7 @@ "oldfieldname": "export_rate", "oldfieldtype": "Currency", "options": "currency", + "read_only": 0, "reqd": 1 }, { @@ -155,6 +163,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, + "read_only": 0, "reqd": 1, "search_index": 0 }, @@ -179,7 +188,8 @@ "oldfieldname": "warehouse", "oldfieldtype": "Link", "options": "Warehouse", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -192,9 +202,20 @@ "options": "Account", "print_hide": 1, "print_width": "120px", + "read_only": 0, "reqd": 1, "width": "120px" }, + { + "doctype": "DocField", + "fieldname": "expense_account", + "fieldtype": "Link", + "hidden": 1, + "in_filter": 1, + "label": "Expense Account", + "options": "Account", + "print_hide": 1 + }, { "doctype": "DocField", "fieldname": "cost_center", @@ -206,6 +227,7 @@ "options": "Cost Center", "print_hide": 1, "print_width": "120px", + "read_only": 0, "reqd": 0, "width": "120px" }, @@ -217,7 +239,8 @@ "label": "Serial No", "oldfieldname": "serial_no", "oldfieldtype": "Small Text", - "print_hide": 0 + "print_hide": 0, + "read_only": 0 }, { "doctype": "DocField", @@ -225,7 +248,8 @@ "fieldtype": "Link", "label": "Batch No", "options": "Batch", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -249,7 +273,8 @@ "label": "Brand Name", "oldfieldname": "brand", "oldfieldtype": "Data", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -328,7 +353,8 @@ "fieldname": "time_log_batch", "fieldtype": "Link", "label": "Time Log Batch", - "options": "Time Log Batch" + "options": "Time Log Batch", + "read_only": 0 }, { "doctype": "DocField", @@ -353,6 +379,17 @@ "print_hide": 1, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "buying_amount", + "fieldtype": "Currency", + "hidden": 1, + "label": "Buying Amount", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, { "allow_on_submit": 1, "doctype": "DocField", @@ -361,6 +398,7 @@ "label": "Page Break", "no_copy": 1, "print_hide": 1, + "read_only": 0, "report_hide": 1 } ] \ No newline at end of file diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py index fa926dacde..f1ae00e13f 100644 --- a/accounts/report/gross_profit/gross_profit.py +++ b/accounts/report/gross_profit/gross_profit.py @@ -25,7 +25,7 @@ def execute(filters=None): for row in delivery_note_items: selling_amount = flt(row.amount) buying_amount = get_buying_amount(row.item_code, row.warehouse, - row.qty, row.name, row.item_row, stock_ledger_entries, item_sales_bom) + row.qty, "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom) if selling_amount: gross_profit = selling_amount - buying_amount gross_profit_percent = (gross_profit / selling_amount) * 100.0 diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index aa52b5e412..73d7608240 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -21,7 +21,7 @@ from webnotes.utils import flt from utilities.transaction_base import TransactionBase class AccountsController(TransactionBase): - def get_gl_dict(self, args, cancel): + def get_gl_dict(self, args, cancel=None): """this method populates the common properties of a gl entry record""" gl_dict = { 'company': self.doc.company, @@ -30,7 +30,7 @@ class AccountsController(TransactionBase): 'voucher_no': self.doc.name, 'aging_date': self.doc.fields.get("aging_date") or self.doc.posting_date, 'remarks': self.doc.remarks, - 'is_cancelled': cancel and "Yes" or "No", + 'is_cancelled': self.doc.docstatus == 2 and "Yes" or "No", 'fiscal_year': self.doc.fiscal_year, 'debit': 0, 'credit': 0, diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 94a56e3300..40606c3198 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -37,4 +37,27 @@ class SellingController(AccountsController): self.doc.grand_total or self.doc.rounded_total, company_currency) if self.meta.get_field("in_words_export"): self.doc.in_words_export = money_in_words(disable_rounded_total and - self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) \ No newline at end of file + self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) + + def get_stock_ledger_entries(self): + item_list, warehouse_list = self.get_distinct_item_warehouse() + if item_list and warehouse_list: + return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, + voucher_detail_no, posting_date, posting_time, stock_value, + warehouse, actual_qty as qty from `tabStock Ledger Entry` + where ifnull(`is_cancelled`, "No") = "No" and company = %s + and item_code in (%s) and warehouse in (%s) + order by item_code desc, warehouse desc, posting_date desc, + posting_time desc, name desc""" % + ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), + tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) + + def get_distinct_item_warehouse(self): + item_list = [] + warehouse_list = [] + for item in self.doclist.get({"parentfield": self.fname}) \ + + self.doclist.get({"parentfield": "packing_details"}): + item_list.append(item.item_code) + warehouse_list.append(item.warehouse) + + return list(set(item_list)), list(set(warehouse_list)) \ No newline at end of file diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index b387aad67a..b66fe4c9a1 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,6 +1,14 @@ erpnext.updates = [ + ["5th March", ["Refactored Upload Attendace Tool"]], + ["4th March", ["Lead organization added in Quotation classic/spartan/modern print format"]], ["1st March", [ - "Time Log, Time Log Batch: Created feature to batch Time Logs so that they can be tracked for billing." + "Time Log, Time Log Batch: Created feature to batch Time Logs so that they can be tracked for billing.", + "Sub-contracting code refactored for PO", + ]], + ["28th February", [ + "Datatype validation in Voucher Import Tool", + "Fixes for conversion factor in old invoices", + "Fixed asynchronus issue in purchase cycle" ]], ["27th February", [ "Time Log: Created Time Log System, with Calendar View." diff --git a/patches/march_2013/p03_update_buying_amount.py b/patches/march_2013/p03_update_buying_amount.py new file mode 100644 index 0000000000..e45a3dbd1c --- /dev/null +++ b/patches/march_2013/p03_update_buying_amount.py @@ -0,0 +1,10 @@ +import webnotes + +def execute(): + dn_list = webnotes.conn.sql("""select name from `tabDelivery Note` where docstatus < 2""") + for dn in dn_list: + webnotes.bean("Delivery Note", dn[0]).set_buying_amount() + + si_list = webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus < 2""") + for si in si_list: + webnotes.bean("Sales Invoice", si[0]).set_buying_amount() \ No newline at end of file diff --git a/setup/doctype/sales_person/test_sales_person.py b/setup/doctype/sales_person/test_sales_person.py index 5af450916b..2dea3e5dee 100644 --- a/setup/doctype/sales_person/test_sales_person.py +++ b/setup/doctype/sales_person/test_sales_person.py @@ -4,5 +4,19 @@ test_records = [ "sales_person_name": "_Test Sales Person", "parent_sales_person": "All Sales Persons", "is_group": "No" + }], + [{ + "doctype": "Sales Person", + "sales_person_name": "_Test Sales Person 1", + "parent_sales_person": "All Sales Persons", + "is_group": "No" + }], + [{ + "doctype": "Sales Person", + "sales_person_name": "_Test Sales Person 2", + "parent_sales_person": "All Sales Persons", + "is_group": "No" }] + + ] \ No newline at end of file diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index c0b99166ee..3d799c4dad 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -225,7 +225,12 @@ class DocType(SellingController): bin = sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0 - + + def on_update(self): + self.doclist = get_obj('Sales Common').make_packing_list(self,'delivery_note_details') + sl = get_obj('Stock Ledger') + sl.scrub_serial_nos(self) + sl.scrub_serial_nos(self, 'packing_details') def on_submit(self): self.validate_packed_qty() @@ -252,6 +257,7 @@ class DocType(SellingController): self.credit_limit() + self.set_buying_amount() self.make_gl_entries() # set DN status @@ -387,13 +393,19 @@ class DocType(SellingController): if amount != 0: total = (amount/self.doc.net_total)*self.doc.grand_total get_obj('Sales Common').check_credit(self, total) - - - def on_update(self): - self.doclist = get_obj('Sales Common').make_packing_list(self,'delivery_note_details') - sl = get_obj('Stock Ledger') - sl.scrub_serial_nos(self) - sl.scrub_serial_nos(self, 'packing_details') + + def set_buying_amount(self): + from stock.utils import get_buying_amount, get_sales_bom + stock_ledger_entries = self.get_stock_ledger_entries() + item_sales_bom = get_sales_bom() + + if stock_ledger_entries: + for item in self.doclist.get({"parentfield": "delivery_note_details"}): + item.buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, + self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, + item_sales_bom) + webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", + item.buying_amount) def make_gl_entries(self): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): @@ -426,38 +438,6 @@ class DocType(SellingController): make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) def get_total_buying_amount(self): - from stock.utils import get_buying_amount, get_sales_bom - stock_ledger_entries = self.get_stock_ledger_entries() - item_sales_bom = get_sales_bom() - total_buying_amount = 0 - - if stock_ledger_entries: - for item in self.doclist.get({"parentfield": "delivery_note_details"}): - buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, - self.doc.name, item.name, stock_ledger_entries, item_sales_bom) - total_buying_amount += buying_amount - - return total_buying_amount - - def get_stock_ledger_entries(self): - item_list, warehouse_list = self.get_distinct_item_warehouse() - if item_list and warehouse_list: - return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, - voucher_detail_no, posting_date, posting_time, stock_value, - warehouse, actual_qty as qty from `tabStock Ledger Entry` - where ifnull(`is_cancelled`, "No") = "No" and company = %s - and item_code in (%s) and warehouse in (%s) - order by item_code desc, warehouse desc, posting_date desc, - posting_time desc, name desc""" % - ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), - tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) - - def get_distinct_item_warehouse(self): - item_list = [] - warehouse_list = [] - for item in self.doclist.get({"parentfield": "delivery_note_details"}) \ - + self.doclist.get({"parentfield": "packing_details"}): - item_list.append(item.item_code) - warehouse_list.append(item.warehouse) - - return list(set(item_list)), list(set(warehouse_list)) \ No newline at end of file + total_buying_amount = sum([item.buying_amount for item in + self.doclist.get({"parentfield": "delivery_note_details"})]) + return total_buying_amount \ No newline at end of file diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py index acdf8b9e07..d0b440cfee 100644 --- a/stock/doctype/delivery_note/test_delivery_note.py +++ b/stock/doctype/delivery_note/test_delivery_note.py @@ -48,6 +48,8 @@ class TestDeliveryNote(unittest.TestCase): def test_delivery_note_gl_entry(self): webnotes.conn.sql("""delete from `tabBin`""") + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) self.assertEqual(cint(webnotes.defaults.get_global_default("auto_inventory_accounting")), 1) diff --git a/stock/doctype/delivery_note_item/delivery_note_item.txt b/stock/doctype/delivery_note_item/delivery_note_item.txt index 985a072756..47b0d33bcd 100644 --- a/stock/doctype/delivery_note_item/delivery_note_item.txt +++ b/stock/doctype/delivery_note_item/delivery_note_item.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 01:28:00", + "creation": "2013-03-07 11:42:59", "docstatus": 0, - "modified": "2013-03-07 07:03:20", + "modified": "2013-03-07 15:46:43", "modified_by": "Administrator", "owner": "Administrator" }, @@ -30,7 +30,8 @@ "fieldname": "barcode", "fieldtype": "Data", "label": "Barcode", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -42,6 +43,7 @@ "oldfieldtype": "Link", "options": "Item", "print_width": "150px", + "read_only": 0, "reqd": 1, "search_index": 1, "width": "150px" @@ -64,6 +66,7 @@ "oldfieldtype": "Data", "print_hide": 1, "print_width": "150px", + "read_only": 0, "reqd": 1, "width": "150px" }, @@ -75,6 +78,7 @@ "oldfieldname": "description", "oldfieldtype": "Small Text", "print_width": "300px", + "read_only": 0, "reqd": 1, "width": "300px" }, @@ -87,6 +91,7 @@ "oldfieldname": "qty", "oldfieldtype": "Currency", "print_width": "100px", + "read_only": 0, "reqd": 1, "width": "100px" }, @@ -115,6 +120,7 @@ "options": "currency", "print_hide": 1, "print_width": "100px", + "read_only": 0, "reqd": 0, "width": "100px" }, @@ -128,6 +134,7 @@ "oldfieldtype": "Float", "print_hide": 1, "print_width": "100px", + "read_only": 0, "width": "100px" }, { @@ -140,6 +147,7 @@ "options": "currency", "print_hide": 0, "print_width": "150px", + "read_only": 0, "reqd": 0, "width": "150px" }, @@ -181,6 +189,7 @@ "options": "Company:company:default_currency", "print_hide": 1, "print_width": "150px", + "read_only": 0, "reqd": 0, "width": "150px" }, @@ -208,6 +217,7 @@ "options": "Warehouse", "print_hide": 1, "print_width": "100px", + "read_only": 0, "width": "100px" }, { @@ -219,7 +229,8 @@ "no_copy": 1, "oldfieldname": "serial_no", "oldfieldtype": "Text", - "print_hide": 0 + "print_hide": 0, + "read_only": 0 }, { "doctype": "DocField", @@ -229,7 +240,8 @@ "oldfieldname": "batch_no", "oldfieldtype": "Link", "options": "Batch", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -375,6 +387,17 @@ "print_hide": 1, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "buying_amount", + "fieldtype": "Currency", + "hidden": 1, + "label": "Buying Amount", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, { "allow_on_submit": 1, "doctype": "DocField", @@ -383,6 +406,7 @@ "label": "Page Break", "oldfieldname": "page_break", "oldfieldtype": "Check", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 } ] \ No newline at end of file diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index 035774b50b..f31f245e81 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -127,4 +127,23 @@ test_records = [ "is_sub_contracted_item": "Yes", "stock_uom": "_Test UOM" }], + [{ + "doctype": "Item", + "item_code": "_Test Non Stock Item", + "item_name": "_Test Non Stock Item", + "description": "_Test Non Stock Item", + "item_group": "_Test Item Group Desktops", + "is_stock_item": "No", + "is_asset_item": "No", + "has_batch_no": "No", + "has_serial_no": "No", + "is_purchase_item": "Yes", + "is_sales_item": "Yes", + "is_service_item": "No", + "is_sample_item": "No", + "inspection_required": "No", + "is_pro_applicable": "No", + "is_sub_contracted_item": "No", + "stock_uom": "_Test UOM" + }], ] \ No newline at end of file diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py index 60b5fd4aea..883ced7f71 100644 --- a/stock/stock_ledger.py +++ b/stock/stock_ledger.py @@ -36,7 +36,6 @@ def update_entries_after(args, verbose=1): } """ previous_sle = get_sle_before_datetime(args) - qty_after_transaction = flt(previous_sle.get("qty_after_transaction")) valuation_rate = flt(previous_sle.get("valuation_rate")) stock_queue = json.loads(previous_sle.get("stock_queue") or "[]") @@ -214,7 +213,6 @@ def get_moving_average_values(qty_after_transaction, sle, valuation_rate): def get_fifo_values(qty_after_transaction, sle, stock_queue): incoming_rate = flt(sle.incoming_rate) actual_qty = flt(sle.actual_qty) - if not stock_queue: stock_queue.append([0, 0]) diff --git a/stock/utils.py b/stock/utils.py index 9055ceea25..bc6054f70b 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -164,23 +164,24 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters): wlist.append([w]) return wlist -def get_buying_amount(item_code, warehouse, qty, voucher_no, voucher_detail_no, +def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries, item_sales_bom): if item_sales_bom.get(item_code): # sales bom item buying_amount = 0.0 for bom_item in item_sales_bom[item_code]: - buying_amount += _get_buying_amount(voucher_no, "[** No Item Row **]", + buying_amount += _get_buying_amount(voucher_type, voucher_no, "[** No Item Row **]", item_code, warehouse, bom_item.qty * qty, stock_ledger_entries) return buying_amount else: # doesn't have sales bom - return _get_buying_amount(voucher_no, voucher_detail_no, item_code, warehouse, qty, - stock_ledger_entries) + return _get_buying_amount(voucher_type, voucher_no, voucher_detail_no, + item_code, warehouse, qty, stock_ledger_entries) -def _get_buying_amount(voucher_no, item_row, item_code, warehouse, qty, stock_ledger_entries): +def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse, qty, + stock_ledger_entries): for i, sle in enumerate(stock_ledger_entries): - if sle.voucher_type == "Delivery Note" and sle.voucher_no == voucher_no: + if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no: if (sle.voucher_detail_no == item_row) or \ (sle.item_code == item_code and sle.warehouse == warehouse and \ abs(flt(sle.qty)) == qty): From bffbc18b2d354cc57195ea353c5faf1c8c491910 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 12 Mar 2013 10:41:21 +0530 Subject: [PATCH 2/3] fixes in cleanup data --- .../doctype/sales_invoice/sales_invoice.py | 7 + utilities/cleanup_data.py | 136 +++++++++--------- 2 files changed, 74 insertions(+), 69 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 597e2ff1aa..906de23677 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -724,6 +724,8 @@ class DocType(SellingController): # expense account gl entries if auto_inventory_accounting and flt(item.buying_amount): + self.check_expense_account(item) + gl_entries.append( self.get_gl_dict({ "account": item.expense_account, @@ -813,6 +815,11 @@ class DocType(SellingController): item_buying_amount = item_buying_rate * flt(item.qty) return item_buying_amount + + def check_expense_account(self, item): + if not item.expense_account: + msgprint(_("""Expense account is mandatory for item: """) + item.item_code, + raise_exception=1) def update_c_form(self): """Update amended id in C-form""" diff --git a/utilities/cleanup_data.py b/utilities/cleanup_data.py index a9cc5c340e..ed04a94bfa 100644 --- a/utilities/cleanup_data.py +++ b/utilities/cleanup_data.py @@ -20,16 +20,14 @@ import webnotes def delete_transactions(): print "Deleting transactions..." - trans = ['Timesheet','Task','Support Ticket','Stock Reconciliation', 'Stock Ledger Entry', \ - 'Stock Entry','Sales Order','Salary Slip','Sales Invoice','Quotation', 'Quality Inspection', \ - 'Purchase Receipt','Purchase Order','Production Order', 'POS Setting','Period Closing Voucher', \ - 'Purchase Invoice','Maintenance Visit','Maintenance Schedule','Leave Application', \ - 'Leave Allocation', 'Lead', 'Journal Voucher', 'Installation Note','Material Request', \ - 'GL Entry','Expense Claim','Opportunity','Delivery Note','Customer Issue','Bin', \ - 'Authorization Rule','Attendance', 'C-Form', 'Form 16A', 'Lease Agreement', \ - 'Lease Installment', 'TDS Payment', 'TDS Return Acknowledgement', 'Appraisal', \ - 'Installation Note', 'Communication' - ] + trans = ['Timesheet', 'Task', 'Support Ticket', 'Stock Reconciliation', 'Stock Ledger Entry', + 'Stock Entry', 'Sales Order', 'Salary Slip','Sales Invoice', 'Quotation', + 'Quality Inspection', 'Purchase Receipt', 'Purchase Order', 'Production Order', + 'POS Setting', 'Period Closing Voucher', 'Purchase Invoice', 'Maintenance Visit', + 'Maintenance Schedule', 'Leave Application', 'Leave Allocation', 'Lead', 'Journal Voucher', + 'Installation Note', 'Material Request', 'GL Entry', 'Expense Claim', 'Opportunity', + 'Delivery Note', 'Customer Issue', 'Bin', 'Authorization Rule', 'Attendance', 'C-Form', + 'Appraisal', 'Installation Note', 'Communication'] for d in trans: for t in webnotes.conn.sql("select options from tabDocField where parent='%s' and fieldtype='Table'" % d): webnotes.conn.sql("delete from `tab%s`" % (t)) @@ -41,55 +39,55 @@ def delete_transactions(): def delete_masters(): print "Deleting masters...." masters = { - 'Workstation':['Default Workstation'], - 'Warehouse Type':['Default Warehouse Type', 'Fixed Asset', 'Rejected', 'Reserved', + 'Workstation': ['Default Workstation'], + 'Warehouse Type': ['Default Warehouse Type', 'Fixed Asset', 'Rejected', 'Reserved', 'Sample', 'Stores', 'WIP Warehouse'], - 'Warehouse':['Default Warehouse'], - 'UOM':['Kg', 'Mtr', 'Box', 'Ltr', 'Nos', 'Ft', 'Pair', 'Set'], - 'Territory':['All Territories', 'Default Territory'], - 'Terms and Conditions':'', - 'Tag':'', - 'Supplier Type':['Default Supplier Type'], - 'Supplier':'', - 'Serial No':'', - 'Sales Person':['All Sales Persons'], - 'Sales Partner':'', - 'Sales BOM':'', - 'Salary Structure':'', - 'Purchase Taxes and Charges Master':'', - 'Project':'', - 'Print Heading':'', - 'Price List':['Default Price List'], - 'Sales Taxes and Charges Master':'', - 'Letter Head':'', - 'Leave Type':['Leave Without Pay', 'Privilege Leave', 'Casual Leave', 'PL', 'CL', 'LWP', + 'Warehouse': ['Default Warehouse'], + 'UOM': ['Kg', 'Mtr', 'Box', 'Ltr', 'Nos', 'Ft', 'Pair', 'Set'], + 'Territory': ['All Territories', 'Default Territory'], + 'Terms and Conditions': '', + 'Tag': '', + 'Supplier Type': ['Default Supplier Type'], + 'Supplier': '', + 'Serial No': '', + 'Sales Person': ['All Sales Persons'], + 'Sales Partner': '', + 'Sales BOM': '', + 'Salary Structure': '', + 'Purchase Taxes and Charges Master': '', + 'Project': '', + 'Print Heading': '', + 'Price List': ['Default Price List'], + 'Sales Taxes and Charges Master': '', + 'Letter Head': '', + 'Leave Type': ['Leave Without Pay', 'Privilege Leave', 'Casual Leave', 'PL', 'CL', 'LWP', 'Compensatory Off', 'Sick Leave'], - 'Appraisal Template':'', - 'Item Group':['All Item Groups', 'Default'], - 'Item':'', - 'Holiday List':'', - 'Grade':'', - 'Feed':'', - 'Expense Claim Type':['Travel', 'Medical', 'Calls', 'Food', 'Others'], - 'Event':'', - 'Employment Type':'', - 'Employee':'', - 'Earning Type':['Basic', 'Conveyance', 'House Rent Allowance', 'Dearness Allowance', + 'Appraisal Template': '', + 'Item Group': ['All Item Groups', 'Default'], + 'Item': '', + 'Holiday List': '', + 'Grade': '', + 'Feed': '', + 'Expense Claim Type': ['Travel', 'Medical', 'Calls', 'Food', 'Others'], + 'Event': '', + 'Employment Type': '', + 'Employee': '', + 'Earning Type': ['Basic', 'Conveyance', 'House Rent Allowance', 'Dearness Allowance', 'Medical Allowance', 'Telephone'], - 'Designation':'', - 'Department':'', - 'Deduction Type':['Income Tax', 'Professional Tax', 'Provident Fund', 'Leave Deduction'], - 'Customer Group':['All Customer Groups', 'Default Customer Group'], - 'Customer':'', - 'Cost Center':'', - 'Contact':'', - 'Campaign':'', - 'Budget Distribution':'', - 'Brand':'', - 'Branch':'', - 'Batch':'', - 'Appraisal':'', - 'Account':'', + 'Designation': '', + 'Department': '', + 'Deduction Type': ['Income Tax', 'Professional Tax', 'Provident Fund', 'Leave Deduction'], + 'Customer Group': ['All Customer Groups', 'Default Customer Group'], + 'Customer': '', + 'Cost Center': '', + 'Contact': '', + 'Campaign': '', + 'Budget Distribution': '', + 'Brand': '', + 'Branch': '', + 'Batch': '', + 'Appraisal': '', + 'Account': '', 'BOM': '' } for d in masters.keys(): @@ -115,40 +113,40 @@ def reset_all_series(): def reset_transaction_series(): webnotes.conn.sql("""update tabSeries set current = 0 where name in ('JV', 'INV', 'BILL', 'SO', 'DN', 'PO', 'LEAD', 'ENQUIRY', 'ENQ', 'CI', - 'IN', 'PS', 'IDT', 'QAI', 'QTN', 'STE', 'SQTN', 'SUP', 'TDSP', 'SR', + 'IN', 'PS', 'IDT', 'QAI', 'QTN', 'STE', 'SQTN', 'SUP', 'SR', 'POS', 'LAP', 'LAL', 'EXP')""") print "Series updated" def delete_main_masters(): - main_masters = ['Fiscal Year','Company', 'DefaultValue'] + main_masters = ['Fiscal Year', 'Company', 'DefaultValue'] for d in main_masters: for t in webnotes.conn.sql("select options from tabDocField where parent='%s' and fieldtype='Table'" % d): webnotes.conn.sql("delete from `tab%s`" % (t)) webnotes.conn.sql("delete from `tab%s`" % (d)) print "Deleted " + d - - def reset_global_defaults(): flds = { - 'default_company': '', - 'default_currency': '', - 'current_fiscal_year': '', + 'default_company': None, + 'default_currency': None, + 'current_fiscal_year': None, 'date_format': 'dd-mm-yyyy', - 'sms_sender_name': '', + 'sms_sender_name': None, 'default_item_group': 'Default', 'default_stock_uom': 'Nos', 'default_valuation_method': 'FIFO', 'default_warehouse_type': 'Default Warehouse Type', - 'tolerance': '', - 'acc_frozen_upto': '', - 'bde_auth_role': '', - 'credit_controller': '', + 'tolerance': None, + 'acc_frozen_upto': None, + 'bde_auth_role': None, + 'credit_controller': None, 'default_customer_group': 'Default Customer Group', 'default_territory': 'Default', 'default_price_list': 'Standard', - 'default_supplier_type': 'Default Supplier Type' + 'default_supplier_type': 'Default Supplier Type', + 'hide_currency_symbol': None, + 'default_price_list_currency': None, } from webnotes.model.code import get_obj From f7df8b28d268cbceb7dcb9b44f9aae8b07b7871c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 12 Mar 2013 10:58:11 +0530 Subject: [PATCH 3/3] -m --- patches/february_2013/p07_clear_web_cache.py | 2 +- patches/patch_list.py | 1 + stock/doctype/stock_entry/test_stock_entry.py | 71 +++++++++++++++++++ stock/doctype/warehouse/warehouse.txt | 49 +++++++------ 4 files changed, 99 insertions(+), 24 deletions(-) diff --git a/patches/february_2013/p07_clear_web_cache.py b/patches/february_2013/p07_clear_web_cache.py index 5aca2d6ee6..26329249d0 100644 --- a/patches/february_2013/p07_clear_web_cache.py +++ b/patches/february_2013/p07_clear_web_cache.py @@ -1,6 +1,6 @@ import webnotes def execute(): + webnotes.reload_doc("website", "doctype", "blog_post") from website.utils import clear_cache clear_cache() - \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index bff51a9ae0..7409c0e986 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -18,6 +18,7 @@ from __future__ import unicode_literals patch_list = [ "execute:webnotes.reload_doc('core', 'doctype', 'docfield')", "execute:webnotes.reload_doc('core', 'doctype', 'report')", + "execute:webnotes.reload_doc('core', 'doctype', 'doctype')", "patches.mar_2012.so_rv_mapper_fix", "patches.mar_2012.clean_property_setter", "patches.april_2012.naming_series_patch", diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 39ec58ac3a..21d15f7e23 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -21,6 +21,77 @@ class TestStockEntry(unittest.TestCase): where item_code='_Test Item'""") self.assertTrue(mr_name) + + def test_material_receipt_gl_entry(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + mr = webnotes.bean(copy=test_records[0]) + mr.insert() + mr.submit() + + stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company", + "stock_in_hand_account") + + self.check_stock_ledger_entries("Stock Entry", mr.doc.name, + [["_Test Item", "_Test Warehouse", 50.0]]) + + self.check_gl_entries("Stock Entry", mr.doc.name, + sorted([ + [stock_in_hand_account, 5000.0, 0.0], + ["Stock Adjustment - _TC", 0.0, 5000.0] + ]) + ) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_material_issue_gl_entry(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + mr = webnotes.bean(copy=test_records[0]) + mr.insert() + mr.submit() + + stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company", + "stock_in_hand_account") + + self.check_stock_ledger_entries("Stock Entry", mr.doc.name, + [["_Test Item", "_Test Warehouse", 50.0]]) + + self.check_gl_entries("Stock Entry", mr.doc.name, + sorted([ + [stock_in_hand_account, 5000.0, 0.0], + ["Stock Adjustment - _TC", 0.0, 5000.0] + ]) + ) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle): + # check stock ledger entries + sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where voucher_type = %s and voucher_no = %s order by item_code, warehouse""", + (voucher_type, voucher_no), as_dict=1) + self.assertTrue(sle) + + for i, sle in enumerate(sle): + self.assertEquals(expected_sle[i][0], sle.item_code) + self.assertEquals(expected_sle[i][1], sle.warehouse) + self.assertEquals(expected_sle[i][2], sle.actual_qty) + + def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): + # check gl entries + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type=%s and voucher_no=%s + order by account asc, debit asc""", (voucher_type, voucher_no), as_dict=1) + self.assertTrue(gl_entries) + + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_gl_entries[i][0], gle.account) + self.assertEquals(expected_gl_entries[i][1], gle.debit) + self.assertEquals(expected_gl_entries[i][2], gle.credit) test_records = [ [ diff --git a/stock/doctype/warehouse/warehouse.txt b/stock/doctype/warehouse/warehouse.txt index d0dd73c086..d08b3ccff3 100644 --- a/stock/doctype/warehouse/warehouse.txt +++ b/stock/doctype/warehouse/warehouse.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-10 16:34:30", + "creation": "2013-03-07 18:50:32", "docstatus": 0, - "modified": "2013-02-04 11:35:53", + "modified": "2013-03-11 17:58:45", "modified_by": "Administrator", "owner": "Administrator" }, @@ -21,7 +21,8 @@ "name": "__common__", "parent": "Warehouse", "parentfield": "fields", - "parenttype": "DocType" + "parenttype": "DocType", + "read_only": 0 }, { "doctype": "DocPerm", @@ -190,7 +191,7 @@ "permlevel": 0 }, { - "description": "This feature is for merging duplicate warehouses. It will replace all the links of this warehouse by \"Merge With\" warehouse. After merging you can delete this warehouse, as stock level for this warehouse will be zero.", + "description": "This feature is for merging duplicate warehouses. It will replace all the links of this warehouse by \"Merge Into\" warehouse. After merging you can delete this warehouse, as stock level for this warehouse will be zero.", "doctype": "DocField", "fieldname": "merge_warehouses_section", "fieldtype": "Section Break", @@ -201,7 +202,7 @@ "doctype": "DocField", "fieldname": "merge_with", "fieldtype": "Link", - "label": "Merge With", + "label": "Merge Into", "options": "Warehouse", "permlevel": 2 }, @@ -221,24 +222,6 @@ "role": "Material Master Manager", "write": 1 }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "permlevel": 0, - "role": "Material User", - "write": 0 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "permlevel": 2, - "role": "Material User", - "write": 0 - }, { "cancel": 1, "create": 1, @@ -248,6 +231,26 @@ "write": 1 }, { + "amend": 0, + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 0, + "role": "Material Manager", + "write": 0 + }, + { + "amend": 0, + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 0, + "role": "Material User", + "write": 0 + }, + { + "amend": 0, + "cancel": 0, "create": 0, "doctype": "DocPerm", "permlevel": 2,