[fixes] set expence account to item on sales invoice

This commit is contained in:
Saurabh
2016-04-12 11:01:04 +05:30
committed by Nabin Hait
parent 224737b9ed
commit 7fee1b8343
4 changed files with 75 additions and 44 deletions

View File

@@ -58,6 +58,7 @@ class PurchaseInvoice(BuyingController):
self.check_for_closed_status() self.check_for_closed_status()
self.validate_with_previous_doc() self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
self.set_expense_account()
self.set_against_expense_account() self.set_against_expense_account()
self.validate_write_off_account() self.validate_write_off_account()
self.update_valuation_rate("items") self.update_valuation_rate("items")
@@ -150,52 +151,56 @@ class PurchaseInvoice(BuyingController):
["Purchase Order", "purchase_order", "po_detail"], ["Purchase Order", "purchase_order", "po_detail"],
["Purchase Receipt", "purchase_receipt", "pr_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")) auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
if auto_accounting_for_stock: if auto_accounting_for_stock:
stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
stock_items = self.get_stock_items()
against_accounts = []
stock_items = self.get_stock_items() if self.update_stock:
warehouse_account = get_warehouse_account()
for item in self.get("items"): for item in self.get("items"):
# in case of auto inventory accounting, # in case of auto inventory accounting,
# expense account is always "Stock Received But Not Billed" for a stock item # expense account is always "Stock Received But Not Billed" for a stock item
# except epening entry, drop-ship entry and fixed asset items # 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' \ if auto_accounting_for_stock and self.is_opening == 'No' \
and (not item.po_detail 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("Purchase Order Item", item.po_detail, "delivered_by_supplier"))
or not frappe.db.get_value("Item", item.item_code, "is_fixed_asset")): 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 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: elif not item.expense_account:
throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
elif item.expense_account not in against_accounts: def set_against_expense_account(self):
# if no auto_accounting_for_stock or not a stock item against_accounts = []
for item in self.get("items"):
if item.expense_account not in against_accounts:
against_accounts.append(item.expense_account) against_accounts.append(item.expense_account)
self.against_expense_account = ",".join(against_accounts) self.against_expense_account = ",".join(against_accounts)
def po_required(self): def po_required(self):
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes': if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
for d in self.get('items'): for d in self.get('items'):
if not d.purchase_order: if not d.purchase_order:
throw(_("Purchse Order number required for Item {0}").format(d.item_code)) throw(_("Purchse Order number required for Item {0}").format(d.item_code))
def pr_required(self): def pr_required(self):
stock_items = self.get_stock_items() stock_items = self.get_stock_items()
if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes': if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes':
for d in self.get('items'): for d in self.get('items'):
if not d.purchase_receipt and d.item_code in stock_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)) throw(_("Purchase Receipt number required for Item {0}").format(d.item_code))
def validate_write_off_account(self): def validate_write_off_account(self):
if self.write_off_amount and not self.write_off_account: 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: if self.docstatus==1 and not asset.supplier:
frappe.db.set_value("Asset", asset.name, "supplier", self.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 = \ self.auto_accounting_for_stock = \
cint(frappe.defaults.get_global_default("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), make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False) 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): def make_supplier_gl_entry(self, gl_entries):
# parent's gl entry # parent's gl entry
@@ -384,20 +406,14 @@ class PurchaseInvoice(BuyingController):
def make_item_gl_entries(self, gl_entries): def make_item_gl_entries(self, gl_entries):
# item gl entries # item gl entries
stock_items = self.get_stock_items() stock_items = self.get_stock_items()
warehouse_account = get_warehouse_account()
for item in self.get("items"): for item in self.get("items"):
if flt(item.base_net_amount): if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account) 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( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": expense_account, "account": item.expense_account,
"against": self.supplier, "against": self.supplier,
"debit": item.base_net_amount, "debit": item.base_net_amount,
"debit_in_account_currency": item.base_net_amount \ "debit_in_account_currency": item.base_net_amount \

View File

@@ -344,19 +344,19 @@ class TestPurchaseInvoice(unittest.TestCase):
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(), cash_bank_account="Cash - _TC", is_paid=1) posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - _TC", is_paid=1)
gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, gl_entries = frappe.db.sql("""select account, account_currency, sum(debit) as debit,
debit_in_account_currency, credit_in_account_currency sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""", pi.name, as_dict=1) group by account, voucher_no order by account asc;""", pi.name, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_gl_entries = dict((d[0], d) for d in [ 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], [pi.items[0].warehouse, 250.0, 0.0],
["Cash - _TC", 0.0, 250.0] ["Cash - _TC", 0.0, 250.0]
]) ])
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEquals(expected_gl_entries[gle.account][0], gle.account) self.assertEquals(expected_gl_entries[gle.account][0], gle.account)
self.assertEquals(expected_gl_entries[gle.account][1], gle.debit) 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): def test_update_stock_and_purchase_return(self):
actual_qty_0 = get_qty_after_transaction() 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()) posting_time=frappe.utils.nowtime())
actual_qty_1 = get_qty_after_transaction() actual_qty_1 = get_qty_after_transaction()

View File

@@ -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): def process_gl_map(gl_map, merge_entries=True):
if merge_entries: if merge_entries:
gl_map = merge_similar_entries(gl_map) gl_map = merge_similar_entries(gl_map)
print gl_map
for entry in gl_map: for entry in gl_map:
# toggle debit, credit if negative entry # toggle debit, credit if negative entry
if flt(entry.debit) < 0: if flt(entry.debit) < 0:

View File

@@ -7,13 +7,16 @@ import unittest
import frappe import frappe
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
import set_perpetual_inventory, get_gl_entries, test_records as pr_test_records 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): class TestLandedCostVoucher(unittest.TestCase):
def test_landed_cost_voucher(self): def test_landed_cost_voucher(self):
set_perpetual_inventory(1) set_perpetual_inventory(1)
pr = frappe.copy_doc(pr_test_records[0]) pr = frappe.copy_doc(pr_test_records[0])
pr.submit() 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", { last_sle = frappe.db.get_value("Stock Ledger Entry", {
"voucher_type": pr.doctype, "voucher_type": pr.doctype,
@@ -24,10 +27,13 @@ class TestLandedCostVoucher(unittest.TestCase):
fieldname=["qty_after_transaction", "stock_value"], fieldname=["qty_after_transaction", "stock_value"],
as_dict=1) 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") pr_lc_value = frappe.db.get_value("Purchase Receipt Item", {"parent": pr.name}, "landed_cost_voucher_amount")
self.assertEquals(pr_lc_value, 25.0) 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", { last_sle_after_landed_cost = frappe.db.get_value("Stock Ledger Entry", {
"voucher_type": pr.doctype, "voucher_type": pr.doctype,
@@ -79,12 +85,12 @@ class TestLandedCostVoucher(unittest.TestCase):
serial_no = frappe.db.get_value("Serial No", "SN001", serial_no = frappe.db.get_value("Serial No", "SN001",
["warehouse", "purchase_rate"], as_dict=1) ["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") self.assertEquals(serial_no.warehouse, "_Test Warehouse - _TC")
set_perpetual_inventory(0) 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 = frappe.new_doc("Landed Cost Voucher")
lcv.company = "_Test Company" lcv.company = "_Test Company"
lcv.set("purchase_receipts", [{ lcv.set("purchase_receipts", [{
@@ -94,10 +100,20 @@ class TestLandedCostVoucher(unittest.TestCase):
"posting_date": pr.posting_date, "posting_date": pr.posting_date,
"grand_total": pr.base_grand_total "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", [{ lcv.set("taxes", [{
"description": "Insurance Charges", "description": "Insurance Charges",
"account": "_Test Account Insurance Charges - _TC", "account": "_Test Account Insurance Charges - _TC",
"amount": 50.0 "amount": 75.0
}]) }])
lcv.insert() lcv.insert()