[fix] [minor] Repost future gl entries and testcases
This commit is contained in:
parent
92b0e777e8
commit
2e296fa46f
@ -557,8 +557,10 @@ class DocType(SellingController):
|
|||||||
if gl_entries:
|
if gl_entries:
|
||||||
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2),
|
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2),
|
||||||
update_outstanding=update_outstanding, merge_entries=False)
|
update_outstanding=update_outstanding, merge_entries=False)
|
||||||
|
|
||||||
self.update_gl_entries_after()
|
if cint(webnotes.defaults.get_global_default("perpetual_accounting")) \
|
||||||
|
and cint(self.doc.update_stock):
|
||||||
|
self.update_gl_entries_after()
|
||||||
|
|
||||||
def make_customer_gl_entry(self, gl_entries):
|
def make_customer_gl_entry(self, gl_entries):
|
||||||
if self.doc.grand_total:
|
if self.doc.grand_total:
|
||||||
|
@ -9,11 +9,12 @@ from accounts.utils import validate_expense_against_budget
|
|||||||
|
|
||||||
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
|
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
|
||||||
update_outstanding='Yes'):
|
update_outstanding='Yes'):
|
||||||
if not cancel:
|
if gl_map:
|
||||||
gl_map = process_gl_map(gl_map, merge_entries)
|
if not cancel:
|
||||||
save_entries(gl_map, adv_adj, update_outstanding)
|
gl_map = process_gl_map(gl_map, merge_entries)
|
||||||
else:
|
save_entries(gl_map, adv_adj, update_outstanding)
|
||||||
delete_gl_entries(gl_map, adv_adj, update_outstanding)
|
else:
|
||||||
|
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
||||||
|
|
||||||
def process_gl_map(gl_map, merge_entries=True):
|
def process_gl_map(gl_map, merge_entries=True):
|
||||||
if merge_entries:
|
if merge_entries:
|
||||||
@ -21,12 +22,13 @@ def process_gl_map(gl_map, merge_entries=True):
|
|||||||
|
|
||||||
for entry in gl_map:
|
for entry in gl_map:
|
||||||
# round off upto 2 decimal
|
# round off upto 2 decimal
|
||||||
entry["debit"] = flt(entry["debit"], 2)
|
entry.debit = flt(entry.debit, 2)
|
||||||
entry["credit"] = flt(entry["credit"], 2)
|
entry.credit = flt(entry.credit, 2)
|
||||||
|
|
||||||
# toggle debit, credit if negative entry
|
# toggle debit, credit if negative entry
|
||||||
if flt(entry["debit"]) < 0 or flt(entry["credit"]) < 0:
|
if flt(entry.debit) < 0 or flt(entry.credit) < 0:
|
||||||
entry["debit"], entry["credit"] = abs(flt(entry["credit"])), abs(flt(entry["debit"]))
|
entry.debit, entry.credit = abs(flt(entry.credit)), abs(flt(entry.debit))
|
||||||
|
|
||||||
return gl_map
|
return gl_map
|
||||||
|
|
||||||
def merge_similar_entries(gl_map):
|
def merge_similar_entries(gl_map):
|
||||||
@ -36,18 +38,18 @@ def merge_similar_entries(gl_map):
|
|||||||
# to that entry
|
# to that entry
|
||||||
same_head = check_if_in_list(entry, merged_gl_map)
|
same_head = check_if_in_list(entry, merged_gl_map)
|
||||||
if same_head:
|
if same_head:
|
||||||
same_head['debit'] = flt(same_head['debit']) + flt(entry['debit'])
|
same_head.debit = flt(same_head.debit) + flt(entry.debit)
|
||||||
same_head['credit'] = flt(same_head['credit']) + flt(entry['credit'])
|
same_head.credit = flt(same_head.credit) + flt(entry.credit)
|
||||||
else:
|
else:
|
||||||
merged_gl_map.append(entry)
|
merged_gl_map.append(entry)
|
||||||
|
|
||||||
# filter zero debit and credit entries
|
# filter zero debit and credit entries
|
||||||
merged_gl_map = filter(lambda x: flt(x["debit"])!=0 or flt(x["credit"])!=0, merged_gl_map)
|
merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
|
||||||
return merged_gl_map
|
return merged_gl_map
|
||||||
|
|
||||||
def check_if_in_list(gle, gl_mqp):
|
def check_if_in_list(gle, gl_mqp):
|
||||||
for e in gl_mqp:
|
for e in gl_mqp:
|
||||||
if e['account'] == gle['account'] and \
|
if e.account == gle.account and \
|
||||||
cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
||||||
and cstr(e.get('against_voucher_type')) == \
|
and cstr(e.get('against_voucher_type')) == \
|
||||||
cstr(gle.get('against_voucher_type')) \
|
cstr(gle.get('against_voucher_type')) \
|
||||||
@ -62,8 +64,8 @@ def save_entries(gl_map, adv_adj, update_outstanding):
|
|||||||
validate_expense_against_budget(entry)
|
validate_expense_against_budget(entry)
|
||||||
|
|
||||||
# update total debit / credit
|
# update total debit / credit
|
||||||
total_debit += flt(entry["debit"])
|
total_debit += flt(entry.debit)
|
||||||
total_credit += flt(entry["credit"])
|
total_credit += flt(entry.credit)
|
||||||
|
|
||||||
validate_total_debit_credit(total_debit, total_credit)
|
validate_total_debit_credit(total_debit, total_credit)
|
||||||
|
|
||||||
@ -80,14 +82,20 @@ def validate_total_debit_credit(total_debit, total_credit):
|
|||||||
webnotes.throw(webnotes._("Debit and Credit not equal for this voucher: Diff (Debit) is ") +
|
webnotes.throw(webnotes._("Debit and Credit not equal for this voucher: Diff (Debit) is ") +
|
||||||
cstr(total_debit - total_credit))
|
cstr(total_debit - total_credit))
|
||||||
|
|
||||||
def delete_gl_entries(gl_entries=None, adv_adj=False, update_outstanding="Yes"):
|
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
||||||
|
adv_adj=False, update_outstanding="Yes"):
|
||||||
|
|
||||||
from accounts.doctype.gl_entry.gl_entry import check_negative_balance, \
|
from accounts.doctype.gl_entry.gl_entry import check_negative_balance, \
|
||||||
check_freezing_date, update_outstanding_amt, validate_freezed_account
|
check_freezing_date, update_outstanding_amt, validate_freezed_account
|
||||||
|
|
||||||
|
if not gl_entries:
|
||||||
|
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
|
||||||
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
|
||||||
if gl_entries:
|
if gl_entries:
|
||||||
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
|
||||||
|
|
||||||
webnotes.conn.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
|
webnotes.conn.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
|
||||||
(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"]))
|
(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
|
||||||
|
|
||||||
for entry in gl_entries:
|
for entry in gl_entries:
|
||||||
validate_freezed_account(entry["account"], adv_adj)
|
validate_freezed_account(entry["account"], adv_adj)
|
||||||
|
@ -360,7 +360,6 @@ def get_stock_and_account_difference(account_list=None, posting_date=None):
|
|||||||
for account, warehouse_list in account_warehouse_map.items():
|
for account, warehouse_list in account_warehouse_map.items():
|
||||||
account_balance = get_balance_on(account, posting_date)
|
account_balance = get_balance_on(account, posting_date)
|
||||||
stock_value = get_stock_balance_on(warehouse_list, posting_date)
|
stock_value = get_stock_balance_on(warehouse_list, posting_date)
|
||||||
|
|
||||||
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
|
if abs(flt(stock_value) - flt(account_balance)) > 0.005:
|
||||||
difference.setdefault(account, flt(stock_value) - flt(account_balance))
|
difference.setdefault(account, flt(stock_value) - flt(account_balance))
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
def get_gl_dict(self, args):
|
def get_gl_dict(self, args):
|
||||||
"""this method populates the common properties of a gl entry record"""
|
"""this method populates the common properties of a gl entry record"""
|
||||||
gl_dict = {
|
gl_dict = webnotes._dict({
|
||||||
'company': self.doc.company,
|
'company': self.doc.company,
|
||||||
'posting_date': self.doc.posting_date,
|
'posting_date': self.doc.posting_date,
|
||||||
'voucher_type': self.doc.doctype,
|
'voucher_type': self.doc.doctype,
|
||||||
@ -343,7 +343,7 @@ class AccountsController(TransactionBase):
|
|||||||
'debit': 0,
|
'debit': 0,
|
||||||
'credit': 0,
|
'credit': 0,
|
||||||
'is_opening': self.doc.fields.get("is_opening") or "No",
|
'is_opening': self.doc.fields.get("is_opening") or "No",
|
||||||
}
|
})
|
||||||
gl_dict.update(args)
|
gl_dict.update(args)
|
||||||
return gl_dict
|
return gl_dict
|
||||||
|
|
||||||
|
@ -8,130 +8,130 @@ from webnotes import msgprint, _
|
|||||||
import webnotes.defaults
|
import webnotes.defaults
|
||||||
|
|
||||||
from controllers.accounts_controller import AccountsController
|
from controllers.accounts_controller import AccountsController
|
||||||
|
from accounts.general_ledger import make_gl_entries, delete_gl_entries
|
||||||
|
|
||||||
class StockController(AccountsController):
|
class StockController(AccountsController):
|
||||||
def make_gl_entries(self):
|
def make_gl_entries(self):
|
||||||
if not cint(webnotes.defaults.get_global_default("perpetual_accounting")):
|
if not cint(webnotes.defaults.get_global_default("perpetual_accounting")):
|
||||||
return
|
return
|
||||||
|
|
||||||
from accounts.general_ledger import make_gl_entries, delete_gl_entries
|
if self.doc.docstatus==1:
|
||||||
gl_entries = self.get_gl_entries_for_stock()
|
gl_entries = self.get_gl_entries_for_stock()
|
||||||
|
|
||||||
if gl_entries and self.doc.docstatus==1:
|
|
||||||
make_gl_entries(gl_entries)
|
make_gl_entries(gl_entries)
|
||||||
elif self.doc.docstatus==2:
|
else:
|
||||||
webnotes.conn.sql("""delete from `tabGL Entry` where voucher_type=%s
|
delete_gl_entries(voucher_type=self.doc.doctype, voucher_no=self.doc.name)
|
||||||
and voucher_no=%s""", (self.doc.doctype, self.doc.name))
|
|
||||||
|
|
||||||
self.update_gl_entries_after()
|
self.update_gl_entries_after()
|
||||||
|
|
||||||
|
def get_gl_entries_for_stock(self, default_expense_account=None, default_cost_center=None):
|
||||||
def get_gl_entries_for_stock(self, item_acc_map=None, expense_account=None, cost_center=None):
|
|
||||||
from accounts.general_ledger import process_gl_map
|
from accounts.general_ledger import process_gl_map
|
||||||
|
warehouse_account = self.get_warehouse_account()
|
||||||
|
stock_ledger = self.get_stock_ledger_details()
|
||||||
|
voucher_details = self.get_voucher_details(stock_ledger, default_expense_account,
|
||||||
|
default_cost_center)
|
||||||
|
|
||||||
|
gl_list = []
|
||||||
|
for detail in voucher_details:
|
||||||
|
sle_list = stock_ledger.get(detail.name)
|
||||||
|
if sle_list:
|
||||||
|
for sle in sle_list:
|
||||||
|
if warehouse_account.get(sle.warehouse):
|
||||||
|
|
||||||
|
# from warehouse account
|
||||||
|
gl_list.append(self.get_gl_dict({
|
||||||
|
"account": warehouse_account[sle.warehouse],
|
||||||
|
"against": detail.expense_account,
|
||||||
|
"cost_center": detail.cost_center,
|
||||||
|
"remarks": self.doc.remarks or "Accounting Entry for Stock",
|
||||||
|
"debit": sle.stock_value_difference
|
||||||
|
}))
|
||||||
|
|
||||||
if not (expense_account or cost_center or item_acc_map):
|
# to target warehouse / expense account
|
||||||
item_acc_map = {}
|
gl_list.append(self.get_gl_dict({
|
||||||
for item in self.doclist.get({"parentfield": self.fname}):
|
"account": detail.expense_account,
|
||||||
self.check_expense_account(item)
|
"against": warehouse_account[sle.warehouse],
|
||||||
item_acc_map.setdefault(item.name, [item.expense_account, item.cost_center])
|
"cost_center": detail.cost_center,
|
||||||
|
|
||||||
gl_entries = []
|
|
||||||
stock_value_diff = self.get_stock_value_diff_from_sle(item_acc_map, expense_account,
|
|
||||||
cost_center)
|
|
||||||
for stock_in_hand_account, against_stock_account_dict in stock_value_diff.items():
|
|
||||||
for against_stock_account, cost_center_dict in against_stock_account_dict.items():
|
|
||||||
for cost_center, value_diff in cost_center_dict.items():
|
|
||||||
gl_entries += [
|
|
||||||
# stock in hand account
|
|
||||||
self.get_gl_dict({
|
|
||||||
"account": stock_in_hand_account,
|
|
||||||
"against": against_stock_account,
|
|
||||||
"debit": value_diff,
|
|
||||||
"remarks": self.doc.remarks or "Accounting Entry for Stock",
|
"remarks": self.doc.remarks or "Accounting Entry for Stock",
|
||||||
}),
|
"credit": sle.stock_value_difference
|
||||||
|
}))
|
||||||
# account against stock in hand
|
|
||||||
self.get_gl_dict({
|
|
||||||
"account": against_stock_account,
|
|
||||||
"against": stock_in_hand_account,
|
|
||||||
"credit": value_diff,
|
|
||||||
"cost_center": cost_center != "No Cost Center" and cost_center or None,
|
|
||||||
"remarks": self.doc.remarks or "Accounting Entry for Stock",
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
gl_entries = process_gl_map(gl_entries)
|
|
||||||
return gl_entries
|
|
||||||
|
|
||||||
|
return process_gl_map(gl_list)
|
||||||
|
|
||||||
def get_stock_value_diff_from_sle(self, item_acc_map, expense_account, cost_center):
|
def get_voucher_details(self, stock_ledger, default_expense_account, default_cost_center):
|
||||||
wh_acc_map = self.get_warehouse_account_map()
|
if not default_expense_account:
|
||||||
stock_value_diff = {}
|
details = self.doclist.get({"parentfield": self.fname})
|
||||||
|
for d in details:
|
||||||
|
self.check_expense_account(d)
|
||||||
|
else:
|
||||||
|
details = [webnotes._dict({
|
||||||
|
"name":d,
|
||||||
|
"expense_account": default_expense_account,
|
||||||
|
"cost_center": default_cost_center
|
||||||
|
}) for d in stock_ledger.keys()]
|
||||||
|
|
||||||
|
return details
|
||||||
|
|
||||||
|
def get_stock_ledger_details(self):
|
||||||
|
stock_ledger = {}
|
||||||
for sle in webnotes.conn.sql("""select warehouse, stock_value_difference, voucher_detail_no
|
for sle in webnotes.conn.sql("""select warehouse, stock_value_difference, voucher_detail_no
|
||||||
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
|
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
|
||||||
(self.doc.doctype, self.doc.name), as_dict=True):
|
(self.doc.doctype, self.doc.name), as_dict=True):
|
||||||
account = wh_acc_map[sle.warehouse]
|
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
|
||||||
against_account = expense_account or item_acc_map[sle.voucher_detail_no][0]
|
return stock_ledger
|
||||||
cost_center = cost_center or item_acc_map[sle.voucher_detail_no][1] or \
|
|
||||||
"No Cost Center"
|
|
||||||
|
|
||||||
stock_value_diff.setdefault(account, {}).setdefault(against_account, {})\
|
|
||||||
.setdefault(cost_center, 0)
|
|
||||||
stock_value_diff[account][against_account][cost_center] += \
|
|
||||||
flt(sle.stock_value_difference)
|
|
||||||
|
|
||||||
return stock_value_diff
|
|
||||||
|
|
||||||
def get_warehouse_account_map(self):
|
def get_warehouse_account(self):
|
||||||
wh_acc_map = {}
|
warehouse_account = dict(webnotes.conn.sql("""select name, account from `tabWarehouse`
|
||||||
warehouse_with_no_account = []
|
where ifnull(account, '') != ''"""))
|
||||||
for d in webnotes.conn.sql("""select name, account from `tabWarehouse`""", as_dict=True):
|
|
||||||
if not d.account: warehouse_with_no_account.append(d.name)
|
|
||||||
wh_acc_map.setdefault(d.name, d.account)
|
|
||||||
|
|
||||||
if warehouse_with_no_account:
|
|
||||||
webnotes.throw(_("Please mention Perpetual Account in warehouse master for \
|
|
||||||
following warehouses") + ": " + '\n'.join(warehouse_with_no_account))
|
|
||||||
|
|
||||||
return wh_acc_map
|
return warehouse_account
|
||||||
|
|
||||||
def update_gl_entries_after(self):
|
def update_gl_entries_after(self):
|
||||||
|
from accounts.utils import get_stock_and_account_difference
|
||||||
future_stock_vouchers = self.get_future_stock_vouchers()
|
future_stock_vouchers = self.get_future_stock_vouchers()
|
||||||
gle = self.get_voucherwise_gl_entries(future_stock_vouchers)
|
gle = self.get_voucherwise_gl_entries(future_stock_vouchers)
|
||||||
for voucher_type, voucher_no in future_stock_vouchers:
|
for voucher_type, voucher_no in future_stock_vouchers:
|
||||||
existing_gle = gle.get((voucher_type, voucher_no), {})
|
existing_gle = gle.get((voucher_type, voucher_no), [])
|
||||||
voucher_bean = webnotes.bean(voucher_type, voucher_no)
|
voucher_obj = webnotes.get_obj(voucher_type, voucher_no)
|
||||||
expected_gle = voucher_bean.run_method("get_gl_entries_for_stock")
|
expected_gle = voucher_obj.get_gl_entries_for_stock()
|
||||||
|
|
||||||
if expected_gle:
|
if expected_gle:
|
||||||
|
matched = True
|
||||||
if existing_gle:
|
if existing_gle:
|
||||||
matched = True
|
|
||||||
for entry in expected_gle:
|
for entry in expected_gle:
|
||||||
entry_amount = existing_gle.get(entry.account, {}).get(entry.cost_center \
|
for e in existing_gle:
|
||||||
or "No Cost Center", [0, 0])
|
if entry.account==e.account \
|
||||||
|
and entry.against_account==e.against_account\
|
||||||
if [entry.debit, entry.credit] != entry_amount:
|
and entry.cost_center==e.cost_center:
|
||||||
matched = False
|
if entry.debit != e.debit or entry.credit != e.credit:
|
||||||
break
|
matched = False
|
||||||
|
break
|
||||||
if not matched:
|
|
||||||
# make updated entry
|
|
||||||
webnotes.conn.sql("""delete from `tabGL Entry`
|
|
||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
|
||||||
|
|
||||||
voucher_bean.run_method("make_gl_entries")
|
|
||||||
else:
|
else:
|
||||||
# make adjustment entry on that date
|
matched = False
|
||||||
self.make_adjustment_entry(expected_gle, voucher_bean)
|
|
||||||
|
if not matched:
|
||||||
|
self.delete_gl_entries(voucher_type, voucher_no)
|
||||||
|
make_gl_entries(expected_gle)
|
||||||
|
else:
|
||||||
|
self.delete_gl_entries(voucher_type, voucher_no)
|
||||||
|
|
||||||
|
# else:
|
||||||
|
# # make adjustment entry on that date
|
||||||
|
# self.make_adjustment_entry(expected_gle, voucher_obj)
|
||||||
|
|
||||||
|
|
||||||
def get_future_stock_vouchers(self):
|
def get_future_stock_vouchers(self):
|
||||||
future_stock_vouchers = []
|
future_stock_vouchers = []
|
||||||
for d in webnotes.conn.sql("""select distinct voucher_type, voucher_no
|
item_codes = webnotes.conn.sql_list("""select distinct item_code
|
||||||
from `tabStock Ledger Entry`
|
from `tabStock Ledger Entry`
|
||||||
where timestamp(posting_date, posting_time) >= timestamp(%s, %s)
|
where voucher_type=%s and voucher_no=%s""", (self.doc.doctype, self.doc.name))
|
||||||
order by timestamp(posting_date, posting_time) asc, name asc""",
|
|
||||||
|
for d in webnotes.conn.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||||
|
from `tabStock Ledger Entry` sle
|
||||||
|
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s)
|
||||||
|
order by timestamp(sle.posting_date, sle.posting_time) asc, name asc""",
|
||||||
(self.doc.posting_date, self.doc.posting_time), as_dict=True):
|
(self.doc.posting_date, self.doc.posting_time), as_dict=True):
|
||||||
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
|
future_stock_vouchers.append([d.voucher_type, d.voucher_no])
|
||||||
|
|
||||||
return future_stock_vouchers
|
return future_stock_vouchers
|
||||||
|
|
||||||
def get_voucherwise_gl_entries(self, future_stock_vouchers):
|
def get_voucherwise_gl_entries(self, future_stock_vouchers):
|
||||||
@ -141,13 +141,15 @@ class StockController(AccountsController):
|
|||||||
where posting_date >= %s and voucher_no in (%s)""" %
|
where posting_date >= %s and voucher_no in (%s)""" %
|
||||||
('%s', ', '.join(['%s']*len(future_stock_vouchers))),
|
('%s', ', '.join(['%s']*len(future_stock_vouchers))),
|
||||||
tuple([self.doc.posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
|
tuple([self.doc.posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
|
||||||
gl_entries.setdefault((d.voucher_type, d.voucher_no), {})\
|
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
|
||||||
.setdefault(d.account, {})\
|
|
||||||
.setdefault(d.cost_center, [d.debit, d.credit])
|
|
||||||
|
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
|
def delete_gl_entries(self, voucher_type, voucher_no):
|
||||||
|
webnotes.conn.sql("""delete from `tabGL Entry`
|
||||||
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
|
|
||||||
def make_adjustment_entry(self, expected_gle, voucher_bean):
|
def make_adjustment_entry(self, expected_gle, voucher_obj):
|
||||||
from accounts.utils import get_stock_and_account_difference
|
from accounts.utils import get_stock_and_account_difference
|
||||||
account_list = [d.account for d in expected_gle]
|
account_list = [d.account for d in expected_gle]
|
||||||
acc_diff = get_stock_and_account_difference(account_list, expected_gle[0].posting_date)
|
acc_diff = get_stock_and_account_difference(account_list, expected_gle[0].posting_date)
|
||||||
@ -160,7 +162,7 @@ class StockController(AccountsController):
|
|||||||
if diff:
|
if diff:
|
||||||
gl_entries.append([
|
gl_entries.append([
|
||||||
# stock in hand account
|
# stock in hand account
|
||||||
voucher_bean.get_gl_dict({
|
voucher_obj.get_gl_dict({
|
||||||
"account": account,
|
"account": account,
|
||||||
"against": stock_adjustment_account,
|
"against": stock_adjustment_account,
|
||||||
"debit": diff,
|
"debit": diff,
|
||||||
@ -168,7 +170,7 @@ class StockController(AccountsController):
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
# account against stock in hand
|
# account against stock in hand
|
||||||
voucher_bean.get_gl_dict({
|
voucher_obj.get_gl_dict({
|
||||||
"account": stock_adjustment_account,
|
"account": stock_adjustment_account,
|
||||||
"against": account,
|
"against": account,
|
||||||
"credit": diff,
|
"credit": diff,
|
||||||
|
@ -123,7 +123,6 @@ class DocType(SellingController):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def validate_proj_cust(self):
|
def validate_proj_cust(self):
|
||||||
"""check for does customer belong to same project as entered.."""
|
"""check for does customer belong to same project as entered.."""
|
||||||
if self.doc.project_name and self.doc.customer:
|
if self.doc.project_name and self.doc.customer:
|
||||||
|
@ -7,13 +7,13 @@ import unittest
|
|||||||
import webnotes
|
import webnotes
|
||||||
import webnotes.defaults
|
import webnotes.defaults
|
||||||
from webnotes.utils import cint
|
from webnotes.utils import cint
|
||||||
from accounts.utils import get_stock_and_account_difference
|
from stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries, test_records as pr_test_records
|
||||||
|
|
||||||
class TestDeliveryNote(unittest.TestCase):
|
class TestDeliveryNote(unittest.TestCase):
|
||||||
def _insert_purchase_receipt(self):
|
def _insert_purchase_receipt(self, item_code=None):
|
||||||
from stock.doctype.purchase_receipt.test_purchase_receipt import test_records as pr_test_records
|
|
||||||
pr = webnotes.bean(copy=pr_test_records[0])
|
pr = webnotes.bean(copy=pr_test_records[0])
|
||||||
pr.run_method("calculate_taxes_and_totals")
|
if item_code:
|
||||||
|
pr.doclist[1].item_code = item_code
|
||||||
pr.insert()
|
pr.insert()
|
||||||
pr.submit()
|
pr.submit()
|
||||||
|
|
||||||
@ -61,13 +61,14 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s
|
from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s
|
||||||
order by account desc""", dn.doc.name, as_dict=1)
|
order by account desc""", dn.doc.name, as_dict=1)
|
||||||
|
|
||||||
self.assertTrue(not gl_entries)
|
self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
|
||||||
|
|
||||||
def test_delivery_note_gl_entry(self):
|
def test_delivery_note_gl_entry(self):
|
||||||
self.clear_stock_account_balance()
|
self.clear_stock_account_balance()
|
||||||
|
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
||||||
self.assertEqual(cint(webnotes.defaults.get_global_default("perpetual_accounting")), 1)
|
self.assertEqual(cint(webnotes.defaults.get_global_default("perpetual_accounting")), 1)
|
||||||
|
webnotes.conn.set_value("Item", "_Test Item", "valuation_method", "FIFO")
|
||||||
|
|
||||||
self._insert_purchase_receipt()
|
self._insert_purchase_receipt()
|
||||||
|
|
||||||
@ -84,25 +85,78 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
dn.insert()
|
dn.insert()
|
||||||
dn.submit()
|
dn.submit()
|
||||||
|
|
||||||
|
gl_entries = get_gl_entries("Delivery Note", dn.doc.name)
|
||||||
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)
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
expected_values = {
|
||||||
expected_values = sorted([
|
stock_in_hand_account: [0.0, 375.0],
|
||||||
[stock_in_hand_account, 0.0, 375.0],
|
"Cost of Goods Sold - _TC": [375.0, 0.0]
|
||||||
["Cost of Goods Sold - _TC", 375.0, 0.0]
|
}
|
||||||
])
|
|
||||||
for i, gle in enumerate(gl_entries):
|
for i, gle in enumerate(gl_entries):
|
||||||
self.assertEquals(expected_values[i][0], gle.account)
|
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
|
||||||
self.assertEquals(expected_values[i][1], gle.debit)
|
|
||||||
self.assertEquals(expected_values[i][2], gle.credit)
|
|
||||||
|
|
||||||
# check stock in hand balance
|
# check stock in hand balance
|
||||||
bal = get_balance_on(stock_in_hand_account, dn.doc.posting_date)
|
bal = get_balance_on(stock_in_hand_account, dn.doc.posting_date)
|
||||||
self.assertEquals(bal, prev_bal - 375.0)
|
self.assertEquals(bal, prev_bal - 375.0)
|
||||||
self.assertFalse(get_stock_and_account_difference([dn.doclist[1].warehouse]))
|
|
||||||
|
# back dated purchase receipt
|
||||||
|
pr = webnotes.bean(copy=pr_test_records[0])
|
||||||
|
pr.doc.posting_date = "2013-01-01"
|
||||||
|
pr.doclist[1].import_rate = 100
|
||||||
|
pr.doclist[1].amount = 100
|
||||||
|
|
||||||
|
pr.insert()
|
||||||
|
pr.submit()
|
||||||
|
|
||||||
|
gl_entries = get_gl_entries("Delivery Note", dn.doc.name)
|
||||||
|
self.assertTrue(gl_entries)
|
||||||
|
expected_values = {
|
||||||
|
stock_in_hand_account: [0.0, 666.65],
|
||||||
|
"Cost of Goods Sold - _TC": [666.65, 0.0]
|
||||||
|
}
|
||||||
|
for i, gle in enumerate(gl_entries):
|
||||||
|
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
|
||||||
|
|
||||||
|
dn.cancel()
|
||||||
|
self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
|
||||||
|
|
||||||
|
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
||||||
|
|
||||||
|
def test_delivery_note_gl_entry_packing_item(self):
|
||||||
|
self.clear_stock_account_balance()
|
||||||
|
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
||||||
|
|
||||||
|
self._insert_purchase_receipt()
|
||||||
|
self._insert_purchase_receipt("_Test Item Home Desktop 100")
|
||||||
|
|
||||||
|
dn = webnotes.bean(copy=test_records[0])
|
||||||
|
dn.doclist[1].item_code = "_Test Sales BOM Item"
|
||||||
|
dn.doclist[1].qty = 1
|
||||||
|
|
||||||
|
stock_in_hand_account = webnotes.conn.get_value("Warehouse", dn.doclist[1].warehouse,
|
||||||
|
"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 = get_gl_entries("Delivery Note", dn.doc.name)
|
||||||
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
|
expected_values = {
|
||||||
|
stock_in_hand_account: [0.0, 525],
|
||||||
|
"Cost of Goods Sold - _TC": [525.0, 0.0]
|
||||||
|
}
|
||||||
|
for i, gle in enumerate(gl_entries):
|
||||||
|
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
|
||||||
|
|
||||||
|
# check stock in hand balance
|
||||||
|
bal = get_balance_on(stock_in_hand_account, dn.doc.posting_date)
|
||||||
|
self.assertEquals(bal, prev_bal - 525.0)
|
||||||
|
|
||||||
|
dn.cancel()
|
||||||
|
self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
|
||||||
|
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
||||||
|
|
||||||
@ -163,6 +217,8 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
|
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
|
||||||
webnotes.conn.sql("delete from `tabGL Entry`")
|
webnotes.conn.sql("delete from `tabGL Entry`")
|
||||||
|
|
||||||
|
test_dependencies = ["Sales BOM"]
|
||||||
|
|
||||||
test_records = [
|
test_records = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -196,8 +252,10 @@ test_records = [
|
|||||||
"export_rate": 100.0,
|
"export_rate": 100.0,
|
||||||
"amount": 500.0,
|
"amount": 500.0,
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
"stock_uom": "_Test UOM"
|
"stock_uom": "_Test UOM",
|
||||||
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
|
"cost_center": "Main - _TC"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -302,11 +302,8 @@ class DocType(BuyingController):
|
|||||||
|
|
||||||
def get_gl_entries_for_stock(self):
|
def get_gl_entries_for_stock(self):
|
||||||
against_stock_account = self.get_company_default("stock_received_but_not_billed")
|
against_stock_account = self.get_company_default("stock_received_but_not_billed")
|
||||||
item_acc_map = {}
|
|
||||||
for item in self.doclist.get({"parentfield": "purchase_receipt_details"}):
|
gl_entries = super(DocType, self).get_gl_entries_for_stock(against_stock_account, None)
|
||||||
item_acc_map.setdefault(item.name, [against_stock_account, None])
|
|
||||||
|
|
||||||
gl_entries = super(DocType, self).get_gl_entries_for_stock(item_acc_map)
|
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,11 +50,7 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
"warehouse": "_Test Warehouse - _TC"}, "stock_value")
|
"warehouse": "_Test Warehouse - _TC"}, "stock_value")
|
||||||
self.assertEqual(bin_stock_value, 375)
|
self.assertEqual(bin_stock_value, 375)
|
||||||
|
|
||||||
gl_entries = webnotes.conn.sql("""select account, debit, credit
|
self.assertFalse(get_gl_entries("Purchase Receipt", pr.doc.name))
|
||||||
from `tabGL Entry` where voucher_type='Purchase Receipt' and voucher_no=%s
|
|
||||||
order by account desc""", pr.doc.name, as_dict=1)
|
|
||||||
|
|
||||||
self.assertTrue(not gl_entries)
|
|
||||||
|
|
||||||
def test_purchase_receipt_gl_entry(self):
|
def test_purchase_receipt_gl_entry(self):
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
||||||
@ -66,14 +62,12 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
pr.insert()
|
pr.insert()
|
||||||
pr.submit()
|
pr.submit()
|
||||||
|
|
||||||
gl_entries = webnotes.conn.sql("""select account, debit, credit
|
gl_entries = get_gl_entries("Purchase Receipt", pr.doc.name)
|
||||||
from `tabGL Entry` where voucher_type='Purchase Receipt' and voucher_no=%s
|
|
||||||
order by account desc""", pr.doc.name, as_dict=1)
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
stock_in_hand_account = webnotes.conn.get_value("Warehouse", pr.doclist[1].warehouse,
|
stock_in_hand_account = webnotes.conn.get_value("Warehouse", pr.doclist[1].warehouse,
|
||||||
"account")
|
"account")
|
||||||
|
|
||||||
fixed_asset_account = webnotes.conn.get_value("Warehouse", pr.doclist[2].warehouse,
|
fixed_asset_account = webnotes.conn.get_value("Warehouse", pr.doclist[2].warehouse,
|
||||||
"account")
|
"account")
|
||||||
|
|
||||||
@ -87,9 +81,9 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
self.assertEquals(expected_values[gle.account][0], gle.debit)
|
self.assertEquals(expected_values[gle.account][0], gle.debit)
|
||||||
self.assertEquals(expected_values[gle.account][1], gle.credit)
|
self.assertEquals(expected_values[gle.account][1], gle.credit)
|
||||||
|
|
||||||
self.assertFalse(get_stock_and_account_difference([pr.doclist[1].warehouse,
|
pr.cancel()
|
||||||
pr.doclist[2].warehouse]))
|
self.assertFalse(get_gl_entries("Purchase Receipt", pr.doc.name))
|
||||||
|
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
||||||
|
|
||||||
def _clear_stock_account_balance(self):
|
def _clear_stock_account_balance(self):
|
||||||
@ -126,6 +120,11 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(webnotes.conn.get_value("Serial No", pr.doclist[1].serial_no,
|
self.assertEqual(webnotes.conn.get_value("Serial No", pr.doclist[1].serial_no,
|
||||||
"status"), "Not Available")
|
"status"), "Not Available")
|
||||||
|
|
||||||
|
def get_gl_entries(voucher_type, voucher_no):
|
||||||
|
return webnotes.conn.sql("""select account, debit, credit
|
||||||
|
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
|
||||||
|
order by account desc""", (voucher_type, voucher_no), as_dict=1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ class DocType(StockController):
|
|||||||
sl_entries.append(self.get_sl_entries(d, {
|
sl_entries.append(self.get_sl_entries(d, {
|
||||||
"warehouse": cstr(d.s_warehouse),
|
"warehouse": cstr(d.s_warehouse),
|
||||||
"actual_qty": -flt(d.transfer_qty),
|
"actual_qty": -flt(d.transfer_qty),
|
||||||
"incoming_rate": flt(d.incoming_rate)
|
"incoming_rate": 0
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if cstr(d.t_warehouse):
|
if cstr(d.t_warehouse):
|
||||||
|
@ -298,8 +298,8 @@ class DocType(StockController):
|
|||||||
if not self.doc.cost_center:
|
if not self.doc.cost_center:
|
||||||
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
msgprint(_("Please enter Cost Center"), raise_exception=1)
|
||||||
|
|
||||||
super(DocType, self).get_gl_entries_for_stock(expense_account=self.doc.expense_account,
|
return super(DocType, self).get_gl_entries_for_stock(self.doc.expense_account,
|
||||||
cost_center=self.doc.cost_center)
|
self.doc.cost_center)
|
||||||
|
|
||||||
|
|
||||||
def validate_expense_account(self):
|
def validate_expense_account(self):
|
||||||
|
@ -12,7 +12,7 @@ from accounts.utils import get_fiscal_year, get_stock_and_account_difference, ge
|
|||||||
|
|
||||||
|
|
||||||
class TestStockReconciliation(unittest.TestCase):
|
class TestStockReconciliation(unittest.TestCase):
|
||||||
def atest_reco_for_fifo(self):
|
def test_reco_for_fifo(self):
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
||||||
# [[qty, valuation_rate, posting_date,
|
# [[qty, valuation_rate, posting_date,
|
||||||
# posting_time, expected_stock_value, bin_qty, bin_valuation]]
|
# posting_time, expected_stock_value, bin_qty, bin_valuation]]
|
||||||
@ -90,7 +90,6 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
self.assertEqual(res and flt(res[0][0], 4) or 0, d[4])
|
self.assertEqual(res and flt(res[0][0], 4) or 0, d[4])
|
||||||
|
|
||||||
# bin qty and stock value
|
# bin qty and stock value
|
||||||
print "bin"
|
|
||||||
bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin`
|
bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin`
|
||||||
where item_code = '_Test Item' and warehouse = '_Test Warehouse - _TC'""")
|
where item_code = '_Test Item' and warehouse = '_Test Warehouse - _TC'""")
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
stock_reco.doc.name)
|
stock_reco.doc.name)
|
||||||
self.assertFalse(gl_entries)
|
self.assertFalse(gl_entries)
|
||||||
|
|
||||||
def atest_reco_fifo_gl_entries(self):
|
def test_reco_fifo_gl_entries(self):
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
||||||
|
|
||||||
# [[qty, valuation_rate, posting_date, posting_time, stock_in_hand_debit]]
|
# [[qty, valuation_rate, posting_date, posting_time, stock_in_hand_debit]]
|
||||||
@ -120,23 +119,23 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
[50, 1000, "2013-01-01", "12:00"],
|
[50, 1000, "2013-01-01", "12:00"],
|
||||||
[5, 1000, "2013-01-01", "12:00"],
|
[5, 1000, "2013-01-01", "12:00"],
|
||||||
[1, 1000, "2012-12-01", "00:00"],
|
[1, 1000, "2012-12-01", "00:00"],
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for d in input_data:
|
for d in input_data:
|
||||||
# print d[0], d[1], d[2], d[3]
|
|
||||||
self.cleanup_data()
|
self.cleanup_data()
|
||||||
self.insert_existing_sle("FIFO")
|
self.insert_existing_sle("FIFO")
|
||||||
|
self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"]))
|
||||||
stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3])
|
stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3])
|
||||||
|
|
||||||
self.assertFalse(get_stock_and_account_difference(["_Test Warehouse - _TC"]))
|
|
||||||
# cancel
|
|
||||||
stock_reco.cancel()
|
|
||||||
self.assertFalse(get_stock_and_account_difference(["_Test Warehouse - _TC"]))
|
|
||||||
|
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
|
||||||
|
|
||||||
def atest_reco_moving_average_gl_entries(self):
|
self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"]))
|
||||||
|
|
||||||
|
stock_reco.cancel()
|
||||||
|
self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"]))
|
||||||
|
|
||||||
|
webnotes.defaults.set_global_default("perpetual_accounting", 0)
|
||||||
|
|
||||||
|
def test_reco_moving_average_gl_entries(self):
|
||||||
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
webnotes.defaults.set_global_default("perpetual_accounting", 1)
|
||||||
|
|
||||||
# [[qty, valuation_rate, posting_date,
|
# [[qty, valuation_rate, posting_date,
|
||||||
@ -259,6 +258,7 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
pr3.insert()
|
pr3.insert()
|
||||||
pr3.submit()
|
pr3.submit()
|
||||||
|
|
||||||
|
|
||||||
pr4 = webnotes.bean(copy=stock_entry)
|
pr4 = webnotes.bean(copy=stock_entry)
|
||||||
pr4.doc.posting_date = "2013-01-05"
|
pr4.doc.posting_date = "2013-01-05"
|
||||||
pr4.doc.fiscal_year = "_Test Fiscal Year 2013"
|
pr4.doc.fiscal_year = "_Test Fiscal Year 2013"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user