From a0e7c1539b34556de94e4d5500d421f11460d855 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 21 Mar 2013 18:37:06 +0530 Subject: [PATCH] aii: book expense in delivery note instead of sales invoice --- .../doctype/sales_invoice/sales_invoice.py | 80 +++---------------- .../sales_invoice/test_sales_invoice.py | 64 --------------- .../sales_invoice_item/sales_invoice_item.txt | 5 +- controllers/selling_controller.py | 16 ++++ controllers/stock_controller.py | 16 +++- stock/doctype/delivery_note/delivery_note.js | 20 +++++ stock/doctype/delivery_note/delivery_note.py | 54 +++++-------- .../delivery_note/test_delivery_note.py | 9 ++- .../delivery_note_item/delivery_note_item.txt | 25 +++++- .../purchase_receipt/purchase_receipt.py | 6 +- stock/doctype/stock_entry/stock_entry.py | 12 ++- stock/doctype/stock_entry/test_stock_entry.py | 6 +- .../stock_reconciliation.py | 8 +- 13 files changed, 131 insertions(+), 190 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 22ac8458a8..9b5c80cfbb 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -27,8 +27,6 @@ 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} @@ -701,19 +699,9 @@ class DocType(SellingController): }) ) - def make_item_gl_entries(self, gl_entries): - # item gl 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_default_account("stock_in_hand_account") - else: - stock_account = self.get_default_account("stock_delivered_but_not_billed") - + def make_item_gl_entries(self, gl_entries): + # income account gl entries for item in self.doclist.get({"parentfield": "entries"}): - # income account gl entries if flt(item.amount): gl_entries.append( self.get_gl_dict({ @@ -725,28 +713,16 @@ class DocType(SellingController): }) ) - # expense account gl entries - if auto_inventory_accounting and flt(item.buying_amount): + # expense account gl entries + if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) \ + and cint(self.doc.is_pos) and cint(self.doc.update_stock): + + for item in self.doclist.get({"parentfield": "entries"}): self.check_expense_account(item) + + gl_entries += self.get_gl_entries_for_stock(item.expense_account, + -1*item.buying_amount, cost_center=item.cost_center) - 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 @@ -789,42 +765,6 @@ class DocType(SellingController): "cost_center": self.doc.write_off_cost_center }) ) - - 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 or \ - (item_sales_bom and item_sales_bom.get(item.item_code)): - 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, -1*item.qty, - self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom) - item.buying_amount = item_buying_amount > 0 and item_buying_amount or 0 - 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) - - 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/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index 92feae8153..7aa0c27d06 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -86,68 +86,6 @@ class TestSalesInvoice(unittest.TestCase): 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`") - - webnotes.defaults.set_global_default("auto_inventory_accounting", 1) - - self._insert_purchase_receipt() - dn = self._insert_delivery_note() - - si_against_dn = webnotes.copy_doclist(test_records[1]) - si_against_dn[1]["delivery_note"] = dn.doc.name - 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 - 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], - ["Stock Delivered But Not Billed - _TC", 0.0, 375.0], - [test_records[1][1]["expense_account"], 375.0, 0.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) - - 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) @@ -262,8 +200,6 @@ class TestSalesInvoice(unittest.TestCase): 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 \ as pr_test_records diff --git a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt index 6f6ad399c5..bc51198f3b 100644 --- a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt +++ b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:42:55", "docstatus": 0, - "modified": "2013-03-18 15:41:19", + "modified": "2013-03-21 18:35:47", "modified_by": "Administrator", "owner": "Administrator" }, @@ -207,11 +207,10 @@ "width": "120px" }, { - "depends_on": "eval:sys_defaults.auto_inventory_accounting", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", - "hidden": 0, + "hidden": 1, "in_filter": 1, "label": "Expense Account", "options": "Account", diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index cd81e18d60..fa8927c81a 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -39,3 +39,19 @@ class SellingController(StockController): 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) + + 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": self.fname}): + if item.item_code in self.stock_items or \ + (item_sales_bom and item_sales_bom.get(item.item_code)): + buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, + self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, + item_sales_bom) + item.buying_amount = buying_amount > 0 and buying_amount or 0 + webnotes.conn.set_value(self.tname, item.name, "buying_amount", + item.buying_amount) \ No newline at end of file diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py index eec7352f1a..c76865d371 100644 --- a/controllers/stock_controller.py +++ b/controllers/stock_controller.py @@ -16,11 +16,14 @@ from __future__ import unicode_literals import webnotes +from webnotes import msgprint, _ from controllers.accounts_controller import AccountsController class StockController(AccountsController): - def make_gl_entries(self, against_stock_account, amount, cost_center=None): - stock_in_hand_account = self.get_default_account("stock_in_hand_account") + def get_gl_entries_for_stock(self, against_stock_account, amount, + stock_in_hand_account=None, cost_center=None): + if not stock_in_hand_account: + stock_in_hand_account = self.get_default_account("stock_in_hand_account") if amount: gl_entries = [ @@ -41,9 +44,14 @@ class StockController(AccountsController): "remarks": self.doc.remarks or "Accounting Entry for Stock", }, self.doc.docstatus == 2), ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + return gl_entries + + + 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 get_stock_ledger_entries(self, item_list=None, warehouse_list=None): if not (item_list and warehouse_list): diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js index a8af1073fe..7e6031c6f9 100644 --- a/stock/doctype/delivery_note/delivery_note.js +++ b/stock/doctype/delivery_note/delivery_note.js @@ -308,4 +308,24 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) { if(cint(wn.boot.notification_settings.delivery_note)) { cur_frm.email_doc(wn.boot.notification_settings.delivery_note_message); } +} + +// expense account +cur_frm.fields_dict['delivery_note_details'].grid.get_field('expense_account').get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.company + } + } +} + +// cost center +cur_frm.fields_dict["delivery_note_details"].grid.get_field("cost_center").get_query = function(doc) { + return { + query: "accounts.utils.get_cost_center_list", + filters: { company_name: doc.company} + } } \ 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 cb7263be7c..6bc661ddd8 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -144,6 +144,8 @@ class DocType(SellingController): self.validate_mandatory() self.validate_reference_value() self.validate_for_items() + self.validate_warehouse() + sales_com_obj.validate_max_discount(self, 'delivery_note_details') sales_com_obj.get_allocated_sum(self) sales_com_obj.check_conversion_rate(self) @@ -203,6 +205,12 @@ class DocType(SellingController): else: chk_dupl_itm.append(f) + def validate_warehouse(self): + for d in self.get_item_list(): + if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes": + if not d['warehouse']: + msgprint("Please enter Warehouse for item %s as it is stock item" + % d['item_code'], raise_exception=1) def validate_items_with_prevdoc(self, d): """check if same item, warehouse present in prevdoc""" @@ -393,41 +401,17 @@ class DocType(SellingController): total = (amount/self.doc.net_total)*self.doc.grand_total get_obj('Sales Common').check_credit(self, total) - 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"}): - if item.item_code in self.stock_items or \ - (item_sales_bom and item_sales_bom.get(item.item_code)): - buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, - self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, - item_sales_bom) - item.buying_amount = buying_amount > 0 and buying_amount or 0 - webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", - item.buying_amount) - - self.validate_warehouse() - - def validate_warehouse(self): - for d in self.get_item_list(): - if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes": - if not d['warehouse']: - msgprint("Please enter Warehouse for item %s as it is stock item" - % d['item_code'], raise_exception=1) - def make_gl_entries(self): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - - against_stock_account = self.get_default_account("stock_delivered_but_not_billed") - total_buying_amount = self.get_total_buying_amount() - - super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount) - - def get_total_buying_amount(self): - total_buying_amount = sum([item.buying_amount for item in - self.doclist.get({"parentfield": "delivery_note_details"})]) - return total_buying_amount + + gl_entries = [] + for item in self.doclist.get({"parentfield": "delivery_note_details"}): + self.check_expense_account(item) + + gl_entries += self.get_gl_entries_for_stock(item.expense_account, -1*item.buying_amount, + cost_center=item.cost_center) + + if gl_entries: + from accounts.general_ledger import make_gl_entries + make_gl_entries(gl_entries) \ 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 d0b440cfee..d0ec631db0 100644 --- a/stock/doctype/delivery_note/test_delivery_note.py +++ b/stock/doctype/delivery_note/test_delivery_note.py @@ -56,15 +56,19 @@ class TestDeliveryNote(unittest.TestCase): self._insert_purchase_receipt() dn = webnotes.bean(copy=test_records[0]) + dn.doclist[1].expense_account = "Cost of Goods Sold - _TC" + dn.doclist[1].cost_center = "Auto Inventory Accounting - _TC" + stock_in_hand_account = webnotes.conn.get_value("Company", dn.doc.company, "stock_in_hand_account") from accounts.utils import get_balance_on prev_bal = get_balance_on(stock_in_hand_account, dn.doc.posting_date) - + dn.insert() dn.submit() + gl_entries = webnotes.conn.sql("""select account, debit, credit from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s order by account asc""", dn.doc.name, as_dict=1) @@ -72,9 +76,8 @@ class TestDeliveryNote(unittest.TestCase): expected_values = sorted([ [stock_in_hand_account, 0.0, 375.0], - ["Stock Delivered But Not Billed - _TC", 375.0, 0.0] + ["Cost of Goods Sold - _TC", 375.0, 0.0] ]) - for i, gle in enumerate(gl_entries): self.assertEquals(expected_values[i][0], gle.account) self.assertEquals(expected_values[i][1], gle.debit) diff --git a/stock/doctype/delivery_note_item/delivery_note_item.txt b/stock/doctype/delivery_note_item/delivery_note_item.txt index 47b0d33bcd..94c6541172 100644 --- a/stock/doctype/delivery_note_item/delivery_note_item.txt +++ b/stock/doctype/delivery_note_item/delivery_note_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:42:59", "docstatus": 0, - "modified": "2013-03-07 15:46:43", + "modified": "2013-03-21 18:36:22", "modified_by": "Administrator", "owner": "Administrator" }, @@ -236,6 +236,7 @@ "doctype": "DocField", "fieldname": "batch_no", "fieldtype": "Link", + "hidden": 0, "label": "Batch No", "oldfieldname": "batch_no", "oldfieldtype": "Link", @@ -243,6 +244,28 @@ "print_hide": 1, "read_only": 0 }, + { + "doctype": "DocField", + "fieldname": "expense_account", + "fieldtype": "Link", + "hidden": 1, + "label": "Expense Account", + "no_copy": 1, + "options": "Account", + "print_hide": 1, + "width": "120px" + }, + { + "doctype": "DocField", + "fieldname": "cost_center", + "fieldtype": "Link", + "hidden": 1, + "label": "Cost Center", + "no_copy": 1, + "options": "Cost Center", + "print_hide": 1, + "width": "120px" + }, { "doctype": "DocField", "fieldname": "item_group", diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index e7d030d719..7949a1c1c3 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -318,10 +318,14 @@ class DocType(BuyingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return + from accounts.general_ledger import make_gl_entries + against_stock_account = self.get_default_account("stock_received_but_not_billed") total_valuation_amount = self.get_total_valuation_amount() + gl_entries = self.get_gl_entries_for_stock(against_stock_account, total_valuation_amount) - super(DocType, self).make_gl_entries(against_stock_account, total_valuation_amount) + if gl_entries: + make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) def get_total_valuation_amount(self): total_valuation_amount = 0.0 diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 76d3a423b1..f54ce605a0 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -173,13 +173,17 @@ class DocType(StockController): if not self.doc.expense_adjustment_account: webnotes.msgprint(_("Please enter Expense/Adjustment Account"), raise_exception=1) - + + from accounts.general_ledger import make_gl_entries + cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) total_valuation_amount = self.get_total_valuation_amount() - super(DocType, self).make_gl_entries(self.doc.expense_adjustment_account, - total_valuation_amount, cost_center) - + gl_entries = self.get_gl_entries_for_stock(self.doc.expense_adjustment_account, + total_valuation_amount, cost_center=cost_center) + if gl_entries: + make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + def get_total_valuation_amount(self): total_valuation_amount = 0 for item in self.doclist.get({"parentfield": "mtn_details"}): diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 1bd068aa62..ded71db26b 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -26,7 +26,7 @@ class TestStockEntry(unittest.TestCase): self.assertTrue(mr_name) - def atest_material_receipt_gl_entry(self): + def test_material_receipt_gl_entry(self): webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.defaults.set_global_default("auto_inventory_accounting", 1) @@ -63,7 +63,7 @@ class TestStockEntry(unittest.TestCase): webnotes.defaults.set_global_default("auto_inventory_accounting", 0) - def atest_material_issue_gl_entry(self): + def test_material_issue_gl_entry(self): webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.defaults.set_global_default("auto_inventory_accounting", 1) @@ -151,7 +151,7 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(expected_sle[i][1], sle.warehouse) self.assertEquals(expected_sle[i][2], sle.actual_qty) - def acheck_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): + def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): # check gl entries gl_entries = webnotes.conn.sql("""select account, debit, credit diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index c2f5a940c5..ac0ab987f4 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -309,10 +309,14 @@ class DocType(StockController): if not self.doc.expense_account: msgprint(_("Please enter Expense Account"), raise_exception=1) + from accounts.general_ledger import make_gl_entries + cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) - super(DocType, self).make_gl_entries(self.doc.expense_account, - self.doc.stock_value_difference, cost_center) + gl_entries = self.get_gl_entries_for_stock(self.doc.expense_account, + self.doc.stock_value_difference, cost_center=cost_center) + if gl_entries: + make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) @webnotes.whitelist() def upload():