def validate_account_for_perpetual_inventory(gl_map): if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)): account_list = [gl_entries.account for gl_entries in gl_map] aii_accounts = [ d.name for d in frappe.get_all("Account", filters={ 'account_type': 'Stock', 'is_group': 0, 'company': gl_map[0].company }) ] for account in account_list: if account not in aii_accounts: continue account_bal, stock_bal, warehouse_list = get_stock_and_account_balance( account, gl_map[0].posting_date, gl_map[0].company) if gl_map[0].voucher_type == "Journal Entry": # In case of Journal Entry, there are no corresponding SL entries, # hence deducting currency amount account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit) if account_bal == stock_bal: frappe.throw( _("Account: {0} can only be updated via Stock Transactions" ).format(account), StockAccountInvalidTransaction)
def _test_reco_sle_gle(self, valuation_method): insert_existing_sle(warehouse='Stores - TCP1') company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') # [[qty, valuation_rate, posting_date, # posting_time, expected_stock_value, bin_qty, bin_valuation]] input_data = [ [50, 1000, "2012-12-26", "12:00"], [25, 900, "2012-12-26", "12:00"], ["", 1000, "2012-12-20", "12:05"], [20, "", "2012-12-26", "12:05"], [0, "", "2012-12-31", "12:10"] ] for d in input_data: set_valuation_method("_Test Item", valuation_method) last_sle = get_previous_sle({ "item_code": "_Test Item", "warehouse": "Stores - TCP1", "posting_date": d[2], "posting_time": d[3] }) # submit stock reconciliation stock_reco = create_stock_reconciliation(qty=d[0], rate=d[1], posting_date=d[2], posting_time=d[3], warehouse="Stores - TCP1", company=company, expense_account = "Stock Adjustment - TCP1") # check stock value sle = frappe.db.sql("""select * from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s""", stock_reco.name, as_dict=1) qty_after_transaction = flt(d[0]) if d[0] != "" else flt(last_sle.get("qty_after_transaction")) valuation_rate = flt(d[1]) if d[1] != "" else flt(last_sle.get("valuation_rate")) if qty_after_transaction == last_sle.get("qty_after_transaction") \ and valuation_rate == last_sle.get("valuation_rate"): self.assertFalse(sle) else: self.assertEqual(sle[0].qty_after_transaction, qty_after_transaction) self.assertEqual(sle[0].stock_value, qty_after_transaction * valuation_rate) # no gl entries self.assertTrue(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name})) acc_bal, stock_bal, wh_list = get_stock_and_account_balance("Stock In Hand - TCP1", stock_reco.posting_date, stock_reco.company) self.assertEqual(acc_bal, stock_bal) stock_reco.cancel() self.assertFalse(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name})) self.assertFalse(frappe.db.get_value("GL Entry", {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
def validate_stock_accounts(self): stock_accounts = get_stock_accounts(self.company, self.doctype, self.name) for account in stock_accounts: account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account, self.posting_date, self.company) if account_bal == stock_bal: frappe.throw(_("Account: {0} can only be updated via Stock Transactions") .format(account), StockAccountInvalidTransaction)
def validate_account_for_perpetual_inventory(gl_map): if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)): account_list = [gl_entries.account for gl_entries in gl_map] aii_accounts = [d.name for d in frappe.get_all("Account", filters={'account_type': 'Stock', 'is_group': 0, 'company': gl_map[0].company})] for account in account_list: if account not in aii_accounts: continue # Always use current date to get stock and account balance as there can future entries for # other items account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account, getdate(), gl_map[0].company) if gl_map[0].voucher_type=="Journal Entry": # In case of Journal Entry, there are no corresponding SL entries, # hence deducting currency amount account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit) if account_bal == stock_bal: frappe.throw(_("Account: {0} can only be updated via Stock Transactions") .format(account), StockAccountInvalidTransaction) elif abs(account_bal - stock_bal) > 0.1: precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency")) diff = flt(stock_bal - account_bal, precision) error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format( stock_bal, account_bal, frappe.bold(account)) error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff)) stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account") db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency') db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency') journal_entry_args = { 'accounts':[ {'account': account, db_or_cr_warehouse_account : abs(diff)}, {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }] } frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution), raise_exception=StockValueAndAccountBalanceOutOfSync, title=_('Values Out Of Sync'), primary_action={ 'label': _('Make Journal Entry'), 'client_action': 'erpnext.route_to_adjustment_jv', 'args': journal_entry_args })
def test_jv_against_stock_account(self): company = "_Test Company with perpetual inventory" stock_account = get_inventory_account(company) from erpnext.accounts.utils import get_stock_and_account_balance account_bal, stock_bal, warehouse_list = get_stock_and_account_balance( stock_account, nowdate(), company) diff = flt(account_bal) - flt(stock_bal) if not diff: diff = 100 jv = frappe.new_doc("Journal Entry") jv.company = company jv.posting_date = nowdate() jv.append( "accounts", { "account": stock_account, "cost_center": "Main - TCP1", "debit_in_account_currency": 0 if diff > 0 else abs(diff), "credit_in_account_currency": diff if diff > 0 else 0, }, ) jv.append( "accounts", { "account": "Stock Adjustment - TCP1", "cost_center": "Main - TCP1", "debit_in_account_currency": diff if diff > 0 else 0, "credit_in_account_currency": 0 if diff > 0 else abs(diff), }, ) jv.insert() if account_bal == stock_bal: self.assertRaises(StockAccountInvalidTransaction, jv.submit) frappe.db.rollback() else: jv.submit() jv.cancel()
def get_unsync_date(filters): date = filters.from_date if not date: date = frappe.db.sql( """ SELECT min(posting_date) from `tabStock Ledger Entry`""") date = date[0][0] if not date: return while getdate(date) < getdate(today()): account_bal, stock_bal, warehouse_list = get_stock_and_account_balance( posting_date=date, company=filters.company, account=filters.account) if abs(account_bal - stock_bal) > 0.1: return date date = add_days(date, 1)