From 7fee1b83439d223aa680bdcd479cbe92dbf8d037 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 12 Apr 2016 11:01:04 +0530 Subject: [PATCH] [fixes] set expence account to item on sales invoice --- .../purchase_invoice/purchase_invoice.py | 78 +++++++++++-------- .../purchase_invoice/test_purchase_invoice.py | 14 ++-- erpnext/accounts/general_ledger.py | 1 - .../test_landed_cost_voucher.py | 26 +++++-- 4 files changed, 75 insertions(+), 44 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 8c4db50458..81d386717e 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -58,6 +58,7 @@ class PurchaseInvoice(BuyingController): self.check_for_closed_status() self.validate_with_previous_doc() self.validate_uom_is_integer("uom", "qty") + self.set_expense_account() self.set_against_expense_account() self.validate_write_off_account() self.update_valuation_rate("items") @@ -150,52 +151,56 @@ class PurchaseInvoice(BuyingController): ["Purchase Order", "purchase_order", "po_detail"], ["Purchase Receipt", "purchase_receipt", "pr_detail"] ]) - - def set_against_expense_account(self): + + def set_expense_account(self): auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) if auto_accounting_for_stock: stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") - - against_accounts = [] - stock_items = self.get_stock_items() + stock_items = self.get_stock_items() + + if self.update_stock: + warehouse_account = get_warehouse_account() + for item in self.get("items"): # in case of auto inventory accounting, # expense account is always "Stock Received But Not Billed" for a stock item # except epening entry, drop-ship entry and fixed asset items - if auto_accounting_for_stock and item.item_code in stock_items and self.is_opening == 'No' \ - and (not item.po_detail - or not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier") - or not frappe.db.get_value("Item", item.item_code, "is_fixed_asset")): + if auto_accounting_for_stock and self.is_opening == 'No' \ + and item.item_code in stock_items and ((not item.po_detail + or not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")) + or not frappe.db.get_value("Item", item.item_code, "is_fixed_asset")): - item.expense_account = stock_not_billed_account + if self.update_stock: + item.expense_account = warehouse_account[item.warehouse]["name"] + else: + item.expense_account = stock_not_billed_account + item.cost_center = None - - if stock_not_billed_account not in against_accounts: - against_accounts.append(stock_not_billed_account) - elif not item.expense_account: throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) - elif item.expense_account not in against_accounts: - # if no auto_accounting_for_stock or not a stock item + def set_against_expense_account(self): + against_accounts = [] + for item in self.get("items"): + if item.expense_account not in against_accounts: against_accounts.append(item.expense_account) self.against_expense_account = ",".join(against_accounts) def po_required(self): if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes': - for d in self.get('items'): - if not d.purchase_order: - throw(_("Purchse Order number required for Item {0}").format(d.item_code)) + for d in self.get('items'): + if not d.purchase_order: + throw(_("Purchse Order number required for Item {0}").format(d.item_code)) def pr_required(self): stock_items = self.get_stock_items() if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes': - for d in self.get('items'): - if not d.purchase_receipt and d.item_code in stock_items: - throw(_("Purchase Receipt number required for Item {0}").format(d.item_code)) + for d in self.get('items'): + if not d.purchase_receipt and d.item_code in stock_items: + throw(_("Purchase Receipt number required for Item {0}").format(d.item_code)) def validate_write_off_account(self): if self.write_off_amount and not self.write_off_account: @@ -334,7 +339,7 @@ class PurchaseInvoice(BuyingController): if self.docstatus==1 and not asset.supplier: frappe.db.set_value("Asset", asset.name, "supplier", self.supplier) - def make_gl_entries(self): + def make_gl_entries(self, repost_future_gle=False): self.auto_accounting_for_stock = \ cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) @@ -360,6 +365,23 @@ class PurchaseInvoice(BuyingController): make_gl_entries(gl_entries, cancel=(self.docstatus == 2), update_outstanding=update_outstanding, merge_entries=False) + + if update_outstanding == "No": + from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt + update_outstanding_amt(self.credit_to, "Supplier", self.supplier, + self.doctype, self.return_against if cint(self.is_return) else self.name) + + if repost_future_gle and cint(self.update_stock) \ + and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): + from erpnext.controllers.stock_controller import update_gl_entries_after + items, warehouses = self.get_items_and_warehouses() + update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items) + + elif self.docstatus == 2 and cint(self.update_stock) \ + and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): + from erpnext.accounts.general_ledger import delete_gl_entries + delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name) + def make_supplier_gl_entry(self, gl_entries): # parent's gl entry @@ -384,20 +406,14 @@ class PurchaseInvoice(BuyingController): def make_item_gl_entries(self, gl_entries): # item gl entries stock_items = self.get_stock_items() - warehouse_account = get_warehouse_account() - + for item in self.get("items"): if flt(item.base_net_amount): account_currency = get_account_currency(item.expense_account) - if self.auto_accounting_for_stock and self.update_stock: - expense_account = warehouse_account[item.warehouse]["name"] - else: - expense_account = item.expense_account - gl_entries.append( self.get_gl_dict({ - "account": expense_account, + "account": item.expense_account, "against": self.supplier, "debit": item.base_net_amount, "debit_in_account_currency": item.base_net_amount \ diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index f58fd44902..c0691744a6 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -344,19 +344,19 @@ class TestPurchaseInvoice(unittest.TestCase): pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(), posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - _TC", is_paid=1) - gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, - debit_in_account_currency, credit_in_account_currency - from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s - order by account asc""", pi.name, as_dict=1) + gl_entries = frappe.db.sql("""select account, account_currency, sum(debit) as debit, + sum(credit) as credit, debit_in_account_currency, credit_in_account_currency + from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s + group by account, voucher_no order by account asc;""", pi.name, as_dict=1) self.assertTrue(gl_entries) expected_gl_entries = dict((d[0], d) for d in [ - [pi.credit_to, 250, 250.0], + [pi.credit_to, 250.0, 250.0], [pi.items[0].warehouse, 250.0, 0.0], ["Cash - _TC", 0.0, 250.0] ]) - + for i, gle in enumerate(gl_entries): self.assertEquals(expected_gl_entries[gle.account][0], gle.account) self.assertEquals(expected_gl_entries[gle.account][1], gle.debit) @@ -365,7 +365,7 @@ class TestPurchaseInvoice(unittest.TestCase): def test_update_stock_and_purchase_return(self): actual_qty_0 = get_qty_after_transaction() - pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(), + pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(), posting_time=frappe.utils.nowtime()) actual_qty_1 = get_qty_after_transaction() diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index cf9f4fc819..a8a090f9e8 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -25,7 +25,6 @@ def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, upd def process_gl_map(gl_map, merge_entries=True): if merge_entries: gl_map = merge_similar_entries(gl_map) - print gl_map for entry in gl_map: # toggle debit, credit if negative entry if flt(entry.debit) < 0: diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index 8323460902..81708ce83d 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -7,13 +7,16 @@ import unittest import frappe from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ import set_perpetual_inventory, get_gl_entries, test_records as pr_test_records - +from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice class TestLandedCostVoucher(unittest.TestCase): def test_landed_cost_voucher(self): set_perpetual_inventory(1) pr = frappe.copy_doc(pr_test_records[0]) pr.submit() + + pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(), + posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - _TC", is_paid=1) last_sle = frappe.db.get_value("Stock Ledger Entry", { "voucher_type": pr.doctype, @@ -24,10 +27,13 @@ class TestLandedCostVoucher(unittest.TestCase): fieldname=["qty_after_transaction", "stock_value"], as_dict=1) - self.submit_landed_cost_voucher(pr) + self.submit_landed_cost_voucher(pr, pi) pr_lc_value = frappe.db.get_value("Purchase Receipt Item", {"parent": pr.name}, "landed_cost_voucher_amount") self.assertEquals(pr_lc_value, 25.0) + + pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name}, "landed_cost_voucher_amount") + self.assertEquals(pi_lc_value, 25.0) last_sle_after_landed_cost = frappe.db.get_value("Stock Ledger Entry", { "voucher_type": pr.doctype, @@ -79,12 +85,12 @@ class TestLandedCostVoucher(unittest.TestCase): serial_no = frappe.db.get_value("Serial No", "SN001", ["warehouse", "purchase_rate"], as_dict=1) - self.assertEquals(serial_no.purchase_rate - serial_no_rate, 5.0) + self.assertEquals(serial_no.purchase_rate - serial_no_rate, 7.5) self.assertEquals(serial_no.warehouse, "_Test Warehouse - _TC") set_perpetual_inventory(0) - def submit_landed_cost_voucher(self, pr): + def submit_landed_cost_voucher(self, pr, pi=None): lcv = frappe.new_doc("Landed Cost Voucher") lcv.company = "_Test Company" lcv.set("purchase_receipts", [{ @@ -94,10 +100,20 @@ class TestLandedCostVoucher(unittest.TestCase): "posting_date": pr.posting_date, "grand_total": pr.base_grand_total }]) + + if pi: + lcv.append("purchase_receipts", { + "receipt_document_type": "Purchase Invoice", + "receipt_document": pi.name, + "supplier": pi.supplier, + "posting_date": pi.posting_date, + "grand_total": pi.base_grand_total + }) + lcv.set("taxes", [{ "description": "Insurance Charges", "account": "_Test Account Insurance Charges - _TC", - "amount": 50.0 + "amount": 75.0 }]) lcv.insert()