From e83069cb3235f9cdb966abb144e5fa9790356a90 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 14 Nov 2013 18:40:08 +0530 Subject: [PATCH] [fix] update future gl entries for stock --- .../doctype/sales_invoice/sales_invoice.py | 37 ++++++----- .../sales_invoice/test_sales_invoice.py | 64 +++++++++++++++++-- accounts/general_ledger.py | 5 +- controllers/accounts_controller.py | 10 +++ controllers/stock_controller.py | 15 ++--- .../purchase_receipt/purchase_receipt.py | 5 +- stock/doctype/stock_entry/stock_entry.py | 4 +- .../stock_reconciliation.py | 4 +- stock/doctype/warehouse/test_warehouse.py | 7 +- 9 files changed, 112 insertions(+), 39 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 6c02bbea66..eb46d1adc4 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -95,6 +95,7 @@ class DocType(SellingController): # this sequence because outstanding may get -ve self.make_gl_entries() + self.check_credit_limit(self.doc.debit_to) if not cint(self.doc.is_pos) == 1: self.update_against_document_in_jv() @@ -533,32 +534,39 @@ class DocType(SellingController): self.make_sl_entries(sl_entries) - def make_gl_entries(self): - from accounts.general_ledger import make_gl_entries, merge_similar_entries + def make_gl_entries(self, update_gl_entries_after=True): + gl_entries = self.get_gl_entries() + + if gl_entries: + from accounts.general_ledger import make_gl_entries + + update_outstanding = cint(self.doc.is_pos) and self.doc.write_off_account \ + and 'No' or 'Yes' + make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2), + update_outstanding=update_outstanding, merge_entries=False) + + if update_gl_entries_after and cint(self.doc.update_stock) \ + and cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")): + self.update_gl_entries_after() + + def get_gl_entries(self, warehouse_account=None): + from accounts.general_ledger import merge_similar_entries 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' + return gl_entries - if gl_entries: - make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2), - update_outstanding=update_outstanding, merge_entries=False) - - if cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")) \ - and cint(self.doc.update_stock): - self.update_gl_entries_after() - def make_customer_gl_entry(self, gl_entries): if self.doc.grand_total: gl_entries.append( @@ -602,7 +610,7 @@ class DocType(SellingController): # expense account gl entries if cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")) \ and cint(self.doc.update_stock): - gl_entries += self.get_gl_entries_for_stock() + gl_entries += super(DocType, self).get_gl_entries() 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: @@ -866,7 +874,6 @@ def send_notification(new_rv): def notify_errors(inv, owner): import webnotes - import website exception_msg = """ Dear User, diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index fbb344ec94..435ba12d42 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -3,7 +3,7 @@ import webnotes import unittest, json -from webnotes.utils import flt, cint +from webnotes.utils import flt from webnotes.model.bean import DocstatusTransitionError, TimestampMismatchError from accounts.utils import get_stock_and_account_difference from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory @@ -364,6 +364,7 @@ class TestSalesInvoice(unittest.TestCase): 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) + # print gl_entries stock_in_hand = webnotes.conn.get_value("Account", {"master_name": "_Test Warehouse - _TC"}) @@ -382,9 +383,6 @@ class TestSalesInvoice(unittest.TestCase): self.assertEquals(expected_gl_entries[i][1], gle.debit) self.assertEquals(expected_gl_entries[i][2], gle.credit) - - - # cancel si.cancel() gle = webnotes.conn.sql("""select * from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) @@ -395,6 +393,62 @@ class TestSalesInvoice(unittest.TestCase): set_perpetual_inventory(0) + def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self): + self.clear_stock_account_balance() + set_perpetual_inventory() + webnotes.delete_doc("Account", "_Test Warehouse No Account - _TC") + + # insert purchase receipt + from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \ + as pr_test_records + pr = webnotes.bean(copy=pr_test_records[0]) + pr.doc.naming_series = "_T-Purchase Receipt-" + pr.doclist[1].warehouse = "_Test Warehouse No Account - _TC" + pr.run_method("calculate_taxes_and_totals") + pr.insert() + pr.submit() + + si_doclist = webnotes.copy_doclist(test_records[1]) + si_doclist[0]["update_stock"] = 1 + si_doclist[0]["posting_time"] = "12:05" + si_doclist[1]["warehouse"] = "_Test Warehouse No Account - _TC" + + si = webnotes.bean(copy=si_doclist) + 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 No Account - _TC", -1.0]) + + # check gl entries + 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], + [si_doclist[1]["income_account"], 0.0, 500.0], + [si_doclist[2]["account_head"], 0.0, 80.0], + [si_doclist[3]["account_head"], 0.0, 50.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) + + si.cancel() + gle = webnotes.conn.sql("""select * from `tabGL Entry` + where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) + + self.assertFalse(gle) + set_perpetual_inventory(0) + def test_sales_invoice_gl_entry_with_aii_no_item_code(self): self.clear_stock_account_balance() set_perpetual_inventory() @@ -599,7 +653,7 @@ class TestSalesInvoice(unittest.TestCase): self._test_recurring_invoice(si7, True) def _test_recurring_invoice(self, base_si, first_and_last_day): - from webnotes.utils import add_months, get_last_day, getdate + from webnotes.utils import add_months, get_last_day from accounts.doctype.sales_invoice.sales_invoice import manage_recurring_invoices no_of_months = ({"Monthly": 1, "Quarterly": 3, "Yearly": 12})[base_si.doc.recurring_type] diff --git a/accounts/general_ledger.py b/accounts/general_ledger.py index b0c585a3a3..9afcf94b2c 100644 --- a/accounts/general_ledger.py +++ b/accounts/general_ledger.py @@ -3,9 +3,8 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import flt, cstr, now -from webnotes.model.doc import Document -from webnotes import msgprint, _ +from webnotes.utils import flt, cstr +from webnotes import _ from accounts.utils import validate_expense_against_budget diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 2b6a21f5ed..0c5ce2a9a3 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _, msgprint from webnotes.utils import flt, cint, today, cstr +from webnotes.model.code import get_obj from setup.utils import get_company_currency from accounts.utils import get_fiscal_year, validate_fiscal_year from utilities.transaction_base import TransactionBase, validate_conversion_rate @@ -422,3 +423,12 @@ class AccountsController(TransactionBase): self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") return self._abbr + + def check_credit_limit(self, account): + total_outstanding = webnotes.conn.sql(""" + select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) + from `tabGL Entry` where account = %s""", account) + + total_outstanding = flt(total_outstanding[0][0]) if total_outstanding else 0 + if total_outstanding: + get_obj('Account', account).check_credit_limit(total_outstanding) \ No newline at end of file diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py index 359dc9e86f..e07e752c7e 100644 --- a/controllers/stock_controller.py +++ b/controllers/stock_controller.py @@ -11,7 +11,7 @@ from controllers.accounts_controller import AccountsController from accounts.general_ledger import make_gl_entries, delete_gl_entries class StockController(AccountsController): - def make_gl_entries(self): + def make_gl_entries(self, update_gl_entries_after=True): if self.doc.docstatus == 2: delete_gl_entries(voucher_type=self.doc.doctype, voucher_no=self.doc.name) @@ -19,12 +19,13 @@ class StockController(AccountsController): warehouse_account = self.get_warehouse_account() if self.doc.docstatus==1: - gl_entries = self.get_gl_entries_for_stock(warehouse_account) + gl_entries = self.get_gl_entries(warehouse_account) make_gl_entries(gl_entries) - self.update_gl_entries_after(warehouse_account) + if update_gl_entries_after: + self.update_gl_entries_after(warehouse_account) - def get_gl_entries_for_stock(self, warehouse_account=None, default_expense_account=None, + def get_gl_entries(self, warehouse_account=None, default_expense_account=None, default_cost_center=None): from accounts.general_ledger import process_gl_map if not warehouse_account: @@ -99,12 +100,10 @@ class StockController(AccountsController): gle = self.get_voucherwise_gl_entries(future_stock_vouchers) if not warehouse_account: warehouse_account = self.get_warehouse_account() - for voucher_type, voucher_no in future_stock_vouchers: existing_gle = gle.get((voucher_type, voucher_no), []) voucher_obj = webnotes.get_obj(voucher_type, voucher_no) - expected_gle = voucher_obj.get_gl_entries_for_stock(warehouse_account) - + expected_gle = voucher_obj.get_gl_entries(warehouse_account) if expected_gle: matched = True if existing_gle: @@ -121,7 +120,7 @@ class StockController(AccountsController): if not matched: self.delete_gl_entries(voucher_type, voucher_no) - make_gl_entries(expected_gle) + voucher_obj.make_gl_entries(update_gl_entries_after=False) else: self.delete_gl_entries(voucher_type, voucher_no) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 6d4320fe18..1d91c4b727 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -294,11 +294,10 @@ class DocType(BuyingController): def get_rate(self,arg): return get_obj('Purchase Common').get_rate(arg,self) - def get_gl_entries_for_stock(self, warehouse_account=None): + def get_gl_entries(self, warehouse_account=None): against_stock_account = self.get_company_default("stock_received_but_not_billed") - gl_entries = super(DocType, self).get_gl_entries_for_stock(warehouse_account, - against_stock_account) + gl_entries = super(DocType, self).get_gl_entries(warehouse_account, against_stock_account) return gl_entries diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 12b0f514a3..c91239d22a 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -478,7 +478,7 @@ class DocType(StockController): self.doc.from_warehouse = "" item = webnotes.conn.sql("""select name, item_name, description, - uom, purchase_account, cost_center from `tabItem` + stock_uom, purchase_account, cost_center from `tabItem` where name=(select item from tabBOM where name=%s)""", self.doc.bom_no, as_dict=1) self.add_to_stock_entry_detail({ @@ -486,7 +486,7 @@ class DocType(StockController): "qty": self.doc.fg_completed_qty, "item_name": item[0].item_name, "description": item[0]["description"], - "stock_uom": item[0]["uom"], + "stock_uom": item[0]["stock_uom"], "from_warehouse": "", "expense_account": item[0].purchase_account, "cost_center": item[0].cost_center, diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index 9feb57e716..22d011765f 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -275,11 +275,11 @@ class DocType(StockController): "posting_time": self.doc.posting_time }) - def get_gl_entries_for_stock(self, warehouse_account=None): + def get_gl_entries(self, warehouse_account=None): if not self.doc.cost_center: msgprint(_("Please enter Cost Center"), raise_exception=1) - return super(DocType, self).get_gl_entries_for_stock(warehouse_account, + return super(DocType, self).get_gl_entries(warehouse_account, self.doc.expense_account, self.doc.cost_center) diff --git a/stock/doctype/warehouse/test_warehouse.py b/stock/doctype/warehouse/test_warehouse.py index 76b18180e2..43b260011c 100644 --- a/stock/doctype/warehouse/test_warehouse.py +++ b/stock/doctype/warehouse/test_warehouse.py @@ -23,5 +23,10 @@ test_records = [ "doctype": "Warehouse User", "parentfield": "warehouse_users", "user": "test2@example.com" - }] + }], + [{ + "doctype": "Warehouse", + "warehouse_name": "_Test Warehouse No Account", + "company": "_Test Company", + }], ]