mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 21:59:13 +00:00
Warehouse Account Linking (#9292)
* [enhance] Added account in the warehouse * documentation * patch to move account head from account to warehouse * fixed test cases * Fixes in warehouse-account linking * minor fix in test case
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 1,
|
"allow_copy": 1,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
@@ -402,35 +403,6 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "warehouse",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Warehouse",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Warehouse",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@@ -545,18 +517,18 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"icon": "fa fa-money",
|
"icon": "fa fa-money",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-02-17 16:22:49.249075",
|
"modified": "2017-04-21 17:22:41.150984",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Account",
|
"name": "Account",
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class Account(Document):
|
|||||||
self.validate_group_or_ledger()
|
self.validate_group_or_ledger()
|
||||||
self.set_root_and_report_type()
|
self.set_root_and_report_type()
|
||||||
self.validate_mandatory()
|
self.validate_mandatory()
|
||||||
self.validate_warehouse_account()
|
|
||||||
self.validate_frozen_accounts_modifier()
|
self.validate_frozen_accounts_modifier()
|
||||||
self.validate_balance_must_be_debit_or_credit()
|
self.validate_balance_must_be_debit_or_credit()
|
||||||
self.validate_account_currency()
|
self.validate_account_currency()
|
||||||
@@ -162,46 +161,6 @@ class Account(Document):
|
|||||||
if not self.report_type:
|
if not self.report_type:
|
||||||
throw(_("Report Type is mandatory"))
|
throw(_("Report Type is mandatory"))
|
||||||
|
|
||||||
def validate_warehouse_account(self):
|
|
||||||
'''If perpetual inventory is set, and warehouse is linked,
|
|
||||||
the account balance and stock balance as of now must always match.
|
|
||||||
'''
|
|
||||||
from erpnext.accounts.utils import get_balance_on
|
|
||||||
from erpnext.stock.utils import get_stock_value_on
|
|
||||||
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
|
||||||
return
|
|
||||||
|
|
||||||
if self.account_type == "Stock":
|
|
||||||
if self.is_group == 0 and not self.warehouse:
|
|
||||||
frappe.throw(_("Warehouse is mandatory for non group Accounts of type Stock"))
|
|
||||||
|
|
||||||
if self.warehouse:
|
|
||||||
# company must be same
|
|
||||||
if frappe.get_value('Warehouse', self.warehouse, 'company') != self.company:
|
|
||||||
frappe.throw(_("Warehouse company must be same as Account company"))
|
|
||||||
|
|
||||||
# balance must be same
|
|
||||||
stock_balance = get_stock_value_on(self.warehouse)
|
|
||||||
if self.is_new():
|
|
||||||
account_balance = 0.0
|
|
||||||
else:
|
|
||||||
account_balance = get_balance_on(self.name)
|
|
||||||
|
|
||||||
if account_balance != stock_balance:
|
|
||||||
frappe.throw(_('Account balance ({0}) for {1} and stock value ({2}) for warehouse {3} must be same')
|
|
||||||
.format(fmt_money(account_balance, currency=self.account_currency), self.name,
|
|
||||||
fmt_money(stock_balance, currency=self.account_currency), self.warehouse))
|
|
||||||
|
|
||||||
elif self.warehouse:
|
|
||||||
self.warehouse = None
|
|
||||||
|
|
||||||
def validate_warehouse(self, warehouse):
|
|
||||||
lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
|
|
||||||
|
|
||||||
if lft and rgt:
|
|
||||||
if frappe.db.sql_list("""select sle.name from `tabStock Ledger Entry` sle where exists (select wh.name from
|
|
||||||
tabWarehouse wh where lft >= %s and rgt <= %s and sle.warehouse = wh.name)""", (lft, rgt)):
|
|
||||||
throw(_("Stock entries exist against Warehouse {0}, hence you cannot re-assign or modify it").format(warehouse))
|
|
||||||
|
|
||||||
def update_nsm_model(self):
|
def update_nsm_model(self):
|
||||||
"""update lft, rgt indices for nested set model"""
|
"""update lft, rgt indices for nested set model"""
|
||||||
|
|||||||
@@ -37,16 +37,6 @@ frappe.treeview_settings["Account"] = {
|
|||||||
},
|
},
|
||||||
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'),
|
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'),
|
||||||
depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"'},
|
depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"'},
|
||||||
{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse",
|
|
||||||
depends_on: 'eval:(!doc.is_group&&doc.account_type=="Stock")',
|
|
||||||
get_query: function() {
|
|
||||||
return {
|
|
||||||
filters:{
|
|
||||||
"company": frappe.treeview_settings.filters["company"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
|
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
|
||||||
description: __("Optional. Sets company's default currency, if not specified.")}
|
description: __("Optional. Sets company's default currency, if not specified.")}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ def get_charts_for_country(country):
|
|||||||
|
|
||||||
def get_account_tree_from_existing_company(existing_company):
|
def get_account_tree_from_existing_company(existing_company):
|
||||||
all_accounts = frappe.get_all('Account',
|
all_accounts = frappe.get_all('Account',
|
||||||
filters={'company': existing_company, "warehouse": ""},
|
filters={'company': existing_company},
|
||||||
fields = ["name", "account_name", "parent_account", "account_type",
|
fields = ["name", "account_name", "parent_account", "account_type",
|
||||||
"is_group", "root_type", "tax_rate"],
|
"is_group", "root_type", "tax_rate"],
|
||||||
order_by="lft, rgt")
|
order_by="lft, rgt")
|
||||||
|
|||||||
@@ -88,7 +88,6 @@
|
|||||||
"Items Delivered to Customs on temprary Base": {}
|
"Items Delivered to Customs on temprary Base": {}
|
||||||
},
|
},
|
||||||
"Stock in Hand": {
|
"Stock in Hand": {
|
||||||
"is_group": 1,
|
|
||||||
"account_type": "Stock"
|
"account_type": "Stock"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,8 +65,9 @@
|
|||||||
"account_type": "Fixed Asset"
|
"account_type": "Fixed Asset"
|
||||||
},
|
},
|
||||||
"Stock": {
|
"Stock": {
|
||||||
"account_type": "Stock",
|
"Stock in Hand": {
|
||||||
"is_group": 1
|
"account_type": "Stock"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"root_type": "Asset"
|
"root_type": "Asset"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,8 +26,9 @@
|
|||||||
"Earnest Money": {}
|
"Earnest Money": {}
|
||||||
},
|
},
|
||||||
"Stock Assets": {
|
"Stock Assets": {
|
||||||
"account_type": "Stock",
|
"Stock in Hand": {
|
||||||
"is_group": 1
|
"account_type": "Stock"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Tax Assets": {
|
"Tax Assets": {
|
||||||
"is_group": 1
|
"is_group": 1
|
||||||
|
|||||||
@@ -40,8 +40,9 @@
|
|||||||
"Rental Deposits": {}
|
"Rental Deposits": {}
|
||||||
},
|
},
|
||||||
"Stock Assets": {
|
"Stock Assets": {
|
||||||
"is_group": 1,
|
"Stock in Hand": {
|
||||||
"account_type": "Stock"
|
"account_type": "Stock"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Tax Assets": {
|
"Tax Assets": {
|
||||||
"GST-Input": {}
|
"GST-Input": {}
|
||||||
|
|||||||
@@ -40,8 +40,9 @@
|
|||||||
"Rental Deposits": {}
|
"Rental Deposits": {}
|
||||||
},
|
},
|
||||||
"Stock Assets": {
|
"Stock Assets": {
|
||||||
"account_type": "Stock",
|
"Stock in Hand": {
|
||||||
"is_group": 1
|
"account_type": "Stock"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Tax Assets": {
|
"Tax Assets": {
|
||||||
"GST-Input": {}
|
"GST-Input": {}
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ def get():
|
|||||||
_("Earnest Money"): {}
|
_("Earnest Money"): {}
|
||||||
},
|
},
|
||||||
_("Stock Assets"): {
|
_("Stock Assets"): {
|
||||||
|
_("Stock In Hand"): {
|
||||||
|
"account_type": "Stock"
|
||||||
|
},
|
||||||
"account_type": "Stock",
|
"account_type": "Stock",
|
||||||
"is_group": 1
|
|
||||||
},
|
},
|
||||||
_("Tax Assets"): {
|
_("Tax Assets"): {
|
||||||
"is_group": 1
|
"is_group": 1
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
from erpnext.stock import get_warehouse_account, get_company_default_inventory_account
|
||||||
|
|
||||||
|
|
||||||
def _make_test_records(verbose):
|
def _make_test_records(verbose):
|
||||||
from frappe.test_runner import make_test_objects
|
from frappe.test_runner import make_test_objects
|
||||||
@@ -63,3 +65,24 @@ def _make_test_records(verbose):
|
|||||||
} for account_name, parent_account, is_group, account_type, currency in accounts])
|
} for account_name, parent_account, is_group, account_type, currency in accounts])
|
||||||
|
|
||||||
return test_objects
|
return test_objects
|
||||||
|
|
||||||
|
def get_inventory_account(company, warehouse=None):
|
||||||
|
account = None
|
||||||
|
if warehouse:
|
||||||
|
account = get_warehouse_account(warehouse, company)
|
||||||
|
else:
|
||||||
|
account = get_company_default_inventory_account(company)
|
||||||
|
|
||||||
|
return account
|
||||||
|
|
||||||
|
def create_account(**kwargs):
|
||||||
|
account = frappe.get_doc(dict(
|
||||||
|
doctype = "Account",
|
||||||
|
account_name = kwargs.get('account_name'),
|
||||||
|
account_type = kwargs.get('account_type'),
|
||||||
|
parent_account = kwargs.get('parent_account'),
|
||||||
|
company = kwargs.get('company')
|
||||||
|
))
|
||||||
|
|
||||||
|
account.save()
|
||||||
|
return account.name
|
||||||
|
|||||||
@@ -20,15 +20,9 @@ class AccountsSettings(Document):
|
|||||||
company.flags.ignore_permissions = True
|
company.flags.ignore_permissions = True
|
||||||
company.save()
|
company.save()
|
||||||
|
|
||||||
# Create account head for warehouses
|
# validate warehouse linked to company
|
||||||
warehouse_list = frappe.db.sql("""select name, company from tabWarehouse
|
warehouse_with_no_company = frappe.db.sql_list("""select name from tabWarehouse
|
||||||
where disabled=0""", as_dict=1)
|
where disabled=0 and company is null or company = ''""")
|
||||||
warehouse_with_no_company = [d.name for d in warehouse_list if not d.company]
|
|
||||||
if warehouse_with_no_company:
|
if warehouse_with_no_company:
|
||||||
frappe.throw(_("Company is missing in warehouses {0}")
|
frappe.throw(_("Company is missing in warehouses {0}")
|
||||||
.format(comma_and(warehouse_with_no_company)))
|
.format(comma_and(warehouse_with_no_company)))
|
||||||
|
|
||||||
for wh in warehouse_list:
|
|
||||||
wh_doc = frappe.get_doc("Warehouse", wh.name)
|
|
||||||
wh_doc.flags.ignore_permissions = True
|
|
||||||
wh_doc.save()
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import unittest, frappe
|
import unittest, frappe
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.exceptions import InvalidAccountCurrency
|
from erpnext.exceptions import InvalidAccountCurrency
|
||||||
|
|
||||||
|
|
||||||
@@ -83,7 +84,8 @@ class TestJournalEntry(unittest.TestCase):
|
|||||||
|
|
||||||
jv = frappe.copy_doc(test_records[0])
|
jv = frappe.copy_doc(test_records[0])
|
||||||
jv.get("accounts")[0].update({
|
jv.get("accounts")[0].update({
|
||||||
"account": "_Test Warehouse - _TC",
|
"account": get_inventory_account('_Test Company'),
|
||||||
|
"company": "_Test Company",
|
||||||
"party_type": None,
|
"party_type": None,
|
||||||
"party": None
|
"party": None
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ class ModeofPayment(Document):
|
|||||||
for entry in self.accounts:
|
for entry in self.accounts:
|
||||||
"""Error when Company of Ledger account doesn't match with Company Selected"""
|
"""Error when Company of Ledger account doesn't match with Company Selected"""
|
||||||
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company:
|
if frappe.db.get_value("Account", entry.default_account, "company") != entry.company:
|
||||||
frappe.throw(_("Account does not match with Company"))
|
frappe.throw(_("Account {0} does not match with Company {1} in Mode of Account: {2}")
|
||||||
|
.format(entry.default_account, entry.company, self.name))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from erpnext.controllers.buying_controller import BuyingController
|
|||||||
from erpnext.accounts.party import get_party_account, get_due_date
|
from erpnext.accounts.party import get_party_account, get_due_date
|
||||||
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
|
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
|
||||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
|
||||||
from erpnext.controllers.stock_controller import get_warehouse_account
|
from erpnext.stock import get_warehouse_account_map
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
||||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||||
from erpnext.buying.utils import check_for_closed_status
|
from erpnext.buying.utils import check_for_closed_status
|
||||||
@@ -172,7 +172,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if self.update_stock:
|
if self.update_stock:
|
||||||
self.validate_item_code()
|
self.validate_item_code()
|
||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account_map()
|
||||||
|
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
# in case of auto inventory accounting,
|
# in case of auto inventory accounting,
|
||||||
@@ -185,7 +185,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")):
|
not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")):
|
||||||
|
|
||||||
if self.update_stock:
|
if self.update_stock:
|
||||||
item.expense_account = warehouse_account[item.warehouse]["name"]
|
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||||
else:
|
else:
|
||||||
item.expense_account = stock_not_billed_account
|
item.expense_account = stock_not_billed_account
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
# item gl entries
|
# item gl entries
|
||||||
stock_items = self.get_stock_items()
|
stock_items = self.get_stock_items()
|
||||||
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account_map()
|
||||||
|
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if flt(item.base_net_amount):
|
if flt(item.base_net_amount):
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
|||||||
test_records as pr_test_records
|
test_records as pr_test_records
|
||||||
from erpnext.exceptions import InvalidCurrency
|
from erpnext.exceptions import InvalidCurrency
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
|
||||||
test_dependencies = ["Item", "Cost Center"]
|
test_dependencies = ["Item", "Cost Center"]
|
||||||
test_ignore = ["Serial No"]
|
test_ignore = ["Serial No"]
|
||||||
@@ -357,10 +358,11 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
order by account asc""", pi.name, as_dict=1)
|
order by account asc""", pi.name, as_dict=1)
|
||||||
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
|
||||||
|
|
||||||
expected_gl_entries = dict((d[0], d) for d in [
|
expected_gl_entries = dict((d[0], d) for d in [
|
||||||
[pi.credit_to, 0.0, 250.0],
|
[pi.credit_to, 0.0, 250.0],
|
||||||
[pi.items[0].warehouse, 250.0, 0.0]
|
[stock_in_hand_account, 250.0, 0.0]
|
||||||
])
|
])
|
||||||
|
|
||||||
for i, gle in enumerate(gl_entries):
|
for i, gle in enumerate(gl_entries):
|
||||||
@@ -378,11 +380,12 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
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)
|
group by account, voucher_no order by account asc;""", pi.name, as_dict=1)
|
||||||
|
|
||||||
|
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
|
||||||
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.0, 250.0],
|
[pi.credit_to, 250.0, 250.0],
|
||||||
[pi.items[0].warehouse, 250.0, 0.0],
|
[stock_in_hand_account, 250.0, 0.0],
|
||||||
["Cash - _TC", 0.0, 250.0]
|
["Cash - _TC", 0.0, 250.0]
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
|||||||
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
|
||||||
class TestSalesInvoice(unittest.TestCase):
|
class TestSalesInvoice(unittest.TestCase):
|
||||||
def make(self):
|
def make(self):
|
||||||
@@ -582,7 +583,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
order by account asc, debit asc""", si.name, as_dict=1)
|
order by account asc, debit asc""", si.name, as_dict=1)
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
stock_in_hand = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"})
|
stock_in_hand = get_inventory_account('_Test Company')
|
||||||
|
|
||||||
expected_gl_entries = sorted([
|
expected_gl_entries = sorted([
|
||||||
[si.debit_to, 630.0, 0.0],
|
[si.debit_to, 630.0, 0.0],
|
||||||
@@ -837,11 +838,11 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
["incoming_rate", "stock_value_difference"])
|
["incoming_rate", "stock_value_difference"])
|
||||||
|
|
||||||
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
||||||
|
stock_in_hand_account = get_inventory_account('_Test Company', si1.items[0].warehouse)
|
||||||
|
|
||||||
# Check gl entry
|
# Check gl entry
|
||||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||||
"voucher_no": si1.name, "account": "_Test Warehouse - _TC"}, "debit")
|
"voucher_no": si1.name, "account": stock_in_hand_account}, "debit")
|
||||||
|
|
||||||
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def validate_account_for_auto_accounting_for_stock(gl_map):
|
|||||||
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \
|
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \
|
||||||
and gl_map[0].voucher_type=="Journal Entry":
|
and gl_map[0].voucher_type=="Journal Entry":
|
||||||
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||||
where account_type = 'Stock' and (warehouse != '' and warehouse is not null) and is_group=0""")]
|
where account_type = 'Stock' and is_group=0""")]
|
||||||
|
|
||||||
for entry in gl_map:
|
for entry in gl_map:
|
||||||
if entry.account in aii_accounts:
|
if entry.account in aii_accounts:
|
||||||
|
|||||||
@@ -216,7 +216,8 @@ def get_count_on(account, fieldname, date):
|
|||||||
else:
|
else:
|
||||||
dr_or_cr = "debit" if fieldname == "invoiced_amount" else "credit"
|
dr_or_cr = "debit" if fieldname == "invoiced_amount" else "credit"
|
||||||
cr_or_dr = "credit" if fieldname == "invoiced_amount" else "debit"
|
cr_or_dr = "credit" if fieldname == "invoiced_amount" else "debit"
|
||||||
select_fields = "ifnull(sum(credit-debit),0)" if fieldname == "invoiced_amount" else "ifnull(sum(debit-credit),0)"
|
select_fields = "ifnull(sum(credit-debit),0)" \
|
||||||
|
if fieldname == "invoiced_amount" else "ifnull(sum(debit-credit),0)"
|
||||||
|
|
||||||
if ((not gle.against_voucher) or (gle.against_voucher_type in ["Sales Order", "Purchase Order"]) or
|
if ((not gle.against_voucher) or (gle.against_voucher_type in ["Sales Order", "Purchase Order"]) or
|
||||||
(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0)):
|
(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0)):
|
||||||
@@ -224,8 +225,10 @@ def get_count_on(account, fieldname, date):
|
|||||||
SELECT {0}
|
SELECT {0}
|
||||||
FROM `tabGL Entry` gle
|
FROM `tabGL Entry` gle
|
||||||
WHERE docstatus < 2 and posting_date <= %(date)s and against_voucher = %(voucher_no)s
|
WHERE docstatus < 2 and posting_date <= %(date)s and against_voucher = %(voucher_no)s
|
||||||
and party = %(party)s and name != %(name)s""".format(select_fields),
|
and party = %(party)s and name != %(name)s"""
|
||||||
{"date": date, "voucher_no": gle.voucher_no, "party": gle.party, "name": gle.name})[0][0]
|
.format(select_fields),
|
||||||
|
{"date": date, "voucher_no": gle.voucher_no,
|
||||||
|
"party": gle.party, "name": gle.name})[0][0]
|
||||||
|
|
||||||
outstanding_amount = flt(gle.get(dr_or_cr)) - flt(gle.get(cr_or_dr)) - payment_amount
|
outstanding_amount = flt(gle.get(dr_or_cr)) - flt(gle.get(cr_or_dr)) - payment_amount
|
||||||
currency_precision = get_currency_precision() or 2
|
currency_precision = get_currency_precision() or 2
|
||||||
@@ -519,17 +522,16 @@ def fix_total_debit_credit():
|
|||||||
|
|
||||||
def get_stock_and_account_difference(account_list=None, posting_date=None):
|
def get_stock_and_account_difference(account_list=None, posting_date=None):
|
||||||
from erpnext.stock.utils import get_stock_value_on
|
from erpnext.stock.utils import get_stock_value_on
|
||||||
|
from erpnext.stock import get_warehouse_account_map
|
||||||
|
|
||||||
if not posting_date: posting_date = nowdate()
|
if not posting_date: posting_date = nowdate()
|
||||||
|
|
||||||
difference = {}
|
difference = {}
|
||||||
|
warehouse_account = get_warehouse_account_map()
|
||||||
|
|
||||||
account_warehouse = dict(frappe.db.sql("""select name, warehouse from tabAccount
|
for warehouse, account_data in warehouse_account.items():
|
||||||
where account_type = 'Stock' and (warehouse is not null and warehouse != '') and is_group=0
|
if account_data.get('account') in account_list:
|
||||||
and name in (%s)""" % ', '.join(['%s']*len(account_list)), account_list))
|
account_balance = get_balance_on(account_data.get('account'), posting_date, in_account_currency=False)
|
||||||
|
|
||||||
for account, warehouse in account_warehouse.items():
|
|
||||||
account_balance = get_balance_on(account, posting_date, in_account_currency=False)
|
|
||||||
stock_value = get_stock_value_on(warehouse, posting_date)
|
stock_value = get_stock_value_on(warehouse, 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))
|
||||||
|
|||||||
@@ -274,7 +274,9 @@ class AccountsController(TransactionBase):
|
|||||||
if not account_currency:
|
if not account_currency:
|
||||||
account_currency = get_account_currency(gl_dict.account)
|
account_currency = get_account_currency(gl_dict.account)
|
||||||
|
|
||||||
if self.doctype not in ["Journal Entry", "Period Closing Voucher", "Payment Entry"]:
|
if gl_dict.account and self.doctype not in ["Journal Entry",
|
||||||
|
"Period Closing Voucher", "Payment Entry"]:
|
||||||
|
|
||||||
self.validate_account_currency(gl_dict.account, account_currency)
|
self.validate_account_currency(gl_dict.account, account_currency)
|
||||||
set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"), self.company_currency)
|
set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"), self.company_currency)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from erpnext.accounts.utils import get_fiscal_year
|
|||||||
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
|
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
|
from erpnext.stock import get_warehouse_account_map
|
||||||
|
|
||||||
class StockController(AccountsController):
|
class StockController(AccountsController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@@ -21,7 +22,7 @@ class StockController(AccountsController):
|
|||||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||||
|
|
||||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account_map()
|
||||||
|
|
||||||
if self.docstatus==1:
|
if self.docstatus==1:
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
@@ -37,7 +38,7 @@ class StockController(AccountsController):
|
|||||||
default_cost_center=None):
|
default_cost_center=None):
|
||||||
|
|
||||||
if not warehouse_account:
|
if not warehouse_account:
|
||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account_map()
|
||||||
|
|
||||||
sle_map = self.get_stock_ledger_details()
|
sle_map = self.get_stock_ledger_details()
|
||||||
voucher_details = self.get_voucher_details(default_expense_account, default_cost_center, sle_map)
|
voucher_details = self.get_voucher_details(default_expense_account, default_cost_center, sle_map)
|
||||||
@@ -66,7 +67,7 @@ class StockController(AccountsController):
|
|||||||
sle = self.update_stock_ledger_entries(sle)
|
sle = self.update_stock_ledger_entries(sle)
|
||||||
|
|
||||||
gl_list.append(self.get_gl_dict({
|
gl_list.append(self.get_gl_dict({
|
||||||
"account": warehouse_account[sle.warehouse]["name"],
|
"account": warehouse_account[sle.warehouse]["account"],
|
||||||
"against": item_row.expense_account,
|
"against": item_row.expense_account,
|
||||||
"cost_center": item_row.cost_center,
|
"cost_center": item_row.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||||
@@ -76,7 +77,7 @@ class StockController(AccountsController):
|
|||||||
# to target warehouse / expense account
|
# to target warehouse / expense account
|
||||||
gl_list.append(self.get_gl_dict({
|
gl_list.append(self.get_gl_dict({
|
||||||
"account": item_row.expense_account,
|
"account": item_row.expense_account,
|
||||||
"against": warehouse_account[sle.warehouse]["name"],
|
"against": warehouse_account[sle.warehouse]["account"],
|
||||||
"cost_center": item_row.cost_center,
|
"cost_center": item_row.cost_center,
|
||||||
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
"remarks": self.get("remarks") or "Accounting Entry for Stock",
|
||||||
"credit": flt(sle.stock_value_difference, 2),
|
"credit": flt(sle.stock_value_difference, 2),
|
||||||
@@ -88,10 +89,7 @@ class StockController(AccountsController):
|
|||||||
if warehouse_with_no_account:
|
if warehouse_with_no_account:
|
||||||
for wh in warehouse_with_no_account:
|
for wh in warehouse_with_no_account:
|
||||||
if frappe.db.get_value("Warehouse", wh, "company"):
|
if frappe.db.get_value("Warehouse", wh, "company"):
|
||||||
frappe.throw(_("Warehouse {0} is not linked to any account, please create/link the corresponding (Asset) account for the warehouse.").format(wh))
|
frappe.throw(_("Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}.").format(wh, self.company))
|
||||||
|
|
||||||
msgprint(_("No accounting entries for the following warehouses") + ": \n" +
|
|
||||||
"\n".join(warehouse_with_no_account))
|
|
||||||
|
|
||||||
return process_gl_map(gl_list)
|
return process_gl_map(gl_list)
|
||||||
|
|
||||||
@@ -341,7 +339,7 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for
|
|||||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||||
|
|
||||||
if not warehouse_account:
|
if not warehouse_account:
|
||||||
warehouse_account = get_warehouse_account()
|
warehouse_account = get_warehouse_account_map()
|
||||||
|
|
||||||
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
|
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
|
||||||
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
|
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
|
||||||
@@ -406,21 +404,3 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
|
|||||||
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
|
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
|
||||||
|
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
def get_warehouse_account():
|
|
||||||
if not frappe.flags.warehouse_account_map or frappe.flags.in_test:
|
|
||||||
warehouse_account = frappe._dict()
|
|
||||||
|
|
||||||
for d in frappe.db.sql("""select
|
|
||||||
warehouse, name, account_currency
|
|
||||||
from
|
|
||||||
tabAccount
|
|
||||||
where
|
|
||||||
account_type = 'Stock'
|
|
||||||
and (warehouse is not null and warehouse != '')
|
|
||||||
and is_group=0 """, as_dict=1):
|
|
||||||
warehouse_account.setdefault(d.warehouse, d)
|
|
||||||
|
|
||||||
frappe.flags.warehouse_account_map = warehouse_account
|
|
||||||
|
|
||||||
return frappe.flags.warehouse_account_map
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
erpnext/docs/assets/img/accounts/inventory_account.png
Normal file
BIN
erpnext/docs/assets/img/accounts/inventory_account.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -640,8 +640,8 @@ attach them to the start of each source file to most effectively state
|
|||||||
the exclusion of warranty; and each file should have at least the
|
the exclusion of warranty; and each file should have at least the
|
||||||
"copyright" line and a pointer to where the full notice is found.</p>
|
"copyright" line and a pointer to where the full notice is found.</p>
|
||||||
|
|
||||||
<pre><code> <one line to give the program's name and a brief idea of what it does.>
|
<pre><code> <one line="" to="" give="" the="" program's="" name="" and="" a="" brief="" idea="" of="" what="" it="" does.="">
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of="" author="">
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -6,20 +6,27 @@ On receipt of items in a particular warehouse, the balance in the Warehouse Acco
|
|||||||
|
|
||||||
##Activation
|
##Activation
|
||||||
|
|
||||||
1. Setup the following default accounts for each Company. These accounts are created automatically in the new ERPNext accounts.
|
* Activate Perpetual Inventory
|
||||||
|
|
||||||
|
> Explore > Accounts > Accounts Settings > "Make Accounting Entry For Every Stock Movement"
|
||||||
|
|
||||||
|
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-1.png">
|
||||||
|
|
||||||
|
* Setup the following default accounts for each Company. These accounts are created automatically in the new ERPNext accounts.
|
||||||
|
|
||||||
|
* Default Inventory Account
|
||||||
* Stock Received But Not Billed
|
* Stock Received But Not Billed
|
||||||
* Stock Adjustment Account
|
* Stock Adjustment Account
|
||||||
* Expenses Included In Valuation
|
* Expenses Included In Valuation
|
||||||
* Cost Center
|
* Cost Center
|
||||||
|
|
||||||
2. Ensure each Warehouse is an Account in the Chart of Accounts master. As per the default configuration, Accounts for Warehouse are created under `Assets > Current Asset > Stock Assets > (Warehouse)`
|
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/company_default_inventory_account.png">
|
||||||
|
|
||||||
3. Activate Perpetual Inventory
|
* If user wants to set an individual account for each warehouse, create account head for each account under `Assets > Current Asset > Stock Assets > (Warehouse)` and set it on the respective warehouse under field 'Account'.
|
||||||
|
|
||||||
> Explore > Accounts > Accounts Settings > "Make Accounting Entry For Every Stock Movement"
|
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/inventory_account.png">
|
||||||
|
|
||||||
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-1.png">
|
* For stock transactions, general ledger entries made against the account head set on the warehouse, if user had not set the account for the warhouse then system gets the account head from the parent warehouse. If account had not set for parent warehouse then system gets the account(Default Inventory Account) from the company master.
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ erpnext.patches.v4_0.apply_user_permissions
|
|||||||
erpnext.patches.v4_0.move_warehouse_user_to_restrictions
|
erpnext.patches.v4_0.move_warehouse_user_to_restrictions
|
||||||
erpnext.patches.v4_0.global_defaults_to_system_settings
|
erpnext.patches.v4_0.global_defaults_to_system_settings
|
||||||
erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule
|
erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule
|
||||||
execute:frappe.reload_doc('stock', 'doctype', 'warehouse')
|
execute:frappe.reload_doc('stock', 'doctype', 'warehouse') # 2017-04-24
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2016-08-31
|
execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2016-08-31
|
||||||
execute:frappe.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-29
|
execute:frappe.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-29
|
||||||
execute:frappe.reload_doc('selling', 'doctype', 'quotation') # 2014-01-29
|
execute:frappe.reload_doc('selling', 'doctype', 'quotation') # 2014-01-29
|
||||||
@@ -401,3 +401,4 @@ erpnext.patches.v8_0.delete_schools_depricated_doctypes
|
|||||||
erpnext.patches.v8_0.update_customer_pos_id
|
erpnext.patches.v8_0.update_customer_pos_id
|
||||||
erpnext.patches.v8_0.rename_items_in_status_field_of_material_request
|
erpnext.patches.v8_0.rename_items_in_status_field_of_material_request
|
||||||
erpnext.patches.v8_0.delete_bin_indexes
|
erpnext.patches.v8_0.delete_bin_indexes
|
||||||
|
erpnext.patches.v8_0.move_account_head_from_account_to_warehouse_for_inventory
|
||||||
|
|||||||
@@ -90,8 +90,7 @@ def create_default_warehouse_group(company=None, stock_account_group=None, ignor
|
|||||||
"warehouse_name": _("All Warehouses"),
|
"warehouse_name": _("All Warehouses"),
|
||||||
"is_group": 1,
|
"is_group": 1,
|
||||||
"company": company.name if company else "",
|
"company": company.name if company else "",
|
||||||
"parent_warehouse": "",
|
"parent_warehouse": ""
|
||||||
"create_account_under": stock_account_group
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if ignore_mandatory:
|
if ignore_mandatory:
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cint
|
from frappe.utils import cint
|
||||||
from erpnext.controllers.stock_controller import get_warehouse_account, update_gl_entries_after
|
from erpnext.stock import get_warehouse_account_map
|
||||||
|
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||||
@@ -13,7 +14,7 @@ def execute():
|
|||||||
frappe.reload_doc('accounts', 'doctype', 'sales_invoice')
|
frappe.reload_doc('accounts', 'doctype', 'sales_invoice')
|
||||||
|
|
||||||
frappe.reload_doctype("Purchase Invoice")
|
frappe.reload_doctype("Purchase Invoice")
|
||||||
wh_account = get_warehouse_account()
|
wh_account = get_warehouse_account_map()
|
||||||
|
|
||||||
for pi in frappe.get_all("Purchase Invoice", filters={"docstatus": 1, "update_stock": 1}):
|
for pi in frappe.get_all("Purchase Invoice", filters={"docstatus": 1, "update_stock": 1}):
|
||||||
pi_doc = frappe.get_doc("Purchase Invoice", pi.name)
|
pi_doc = frappe.get_doc("Purchase Invoice", pi.name)
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doctype("Warehouse")
|
||||||
|
frappe.db.sql("""
|
||||||
|
update
|
||||||
|
`tabWarehouse`
|
||||||
|
set
|
||||||
|
account = (select name from `tabAccount`
|
||||||
|
where account_type = 'Stock' and
|
||||||
|
warehouse = `tabWarehouse`.name and is_group = 0)""")
|
||||||
@@ -15,7 +15,7 @@ frappe.ui.form.on("Company", {
|
|||||||
|
|
||||||
frm.toggle_display('address_html', !frm.doc.__islocal);
|
frm.toggle_display('address_html', !frm.doc.__islocal);
|
||||||
if(!frm.doc.__islocal) {
|
if(!frm.doc.__islocal) {
|
||||||
frappe.geo.render_address_and_contact(frm);
|
frappe.contacts.render_address_and_contact(frm);
|
||||||
|
|
||||||
frm.toggle_enable("default_currency", (frm.doc.__onload &&
|
frm.toggle_enable("default_currency", (frm.doc.__onload &&
|
||||||
!frm.doc.__onload.transactions_exist));
|
!frm.doc.__onload.transactions_exist));
|
||||||
@@ -148,6 +148,7 @@ erpnext.company.setup_queries = function(frm) {
|
|||||||
{"root_type": "Asset", "account_type": "Accumulated Depreciation"}],
|
{"root_type": "Asset", "account_type": "Accumulated Depreciation"}],
|
||||||
["depreciation_expense_account", {"root_type": "Expense", "account_type": "Depreciation"}],
|
["depreciation_expense_account", {"root_type": "Expense", "account_type": "Depreciation"}],
|
||||||
["disposal_account", {"report_type": "Profit and Loss"}],
|
["disposal_account", {"report_type": "Profit and Loss"}],
|
||||||
|
["default_inventory_account", {"account_type": "Stock"}],
|
||||||
["cost_center", {}],
|
["cost_center", {}],
|
||||||
["round_off_cost_center", {}],
|
["round_off_cost_center", {}],
|
||||||
["depreciation_cost_center", {}]
|
["depreciation_cost_center", {}]
|
||||||
|
|||||||
@@ -1128,20 +1128,21 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "stock_received_but_not_billed",
|
"fieldname": "default_inventory_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Stock Received But Not Billed",
|
"label": "Default Inventory Account",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 1,
|
"no_copy": 0,
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@@ -1213,6 +1214,35 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "stock_received_but_not_billed",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Stock Received But Not Billed",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "Account",
|
||||||
|
"permlevel": 0,
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@@ -1747,7 +1777,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-05-09 11:06:33.629948",
|
"modified": "2017-06-14 11:06:33.629948",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Company",
|
"name": "Company",
|
||||||
|
|||||||
@@ -50,9 +50,11 @@ class Company(Document):
|
|||||||
frappe.throw(_("Abbreviation already used for another company"))
|
frappe.throw(_("Abbreviation already used for another company"))
|
||||||
|
|
||||||
def validate_default_accounts(self):
|
def validate_default_accounts(self):
|
||||||
for field in ["default_bank_account", "default_cash_account", "default_receivable_account", "default_payable_account",
|
for field in ["default_bank_account", "default_cash_account",
|
||||||
"default_expense_account", "default_income_account", "stock_received_but_not_billed",
|
"default_receivable_account", "default_payable_account",
|
||||||
"stock_adjustment_account", "expenses_included_in_valuation", "default_payroll_payable_account"]:
|
"default_expense_account", "default_income_account",
|
||||||
|
"stock_received_but_not_billed", "stock_adjustment_account",
|
||||||
|
"expenses_included_in_valuation", "default_payroll_payable_account"]:
|
||||||
if self.get(field):
|
if self.get(field):
|
||||||
for_company = frappe.db.get_value("Account", self.get(field), "company")
|
for_company = frappe.db.get_value("Account", self.get(field), "company")
|
||||||
if for_company != self.name:
|
if for_company != self.name:
|
||||||
@@ -111,8 +113,7 @@ class Company(Document):
|
|||||||
"is_group": wh_detail["is_group"],
|
"is_group": wh_detail["is_group"],
|
||||||
"company": self.name,
|
"company": self.name,
|
||||||
"parent_warehouse": "{0} - {1}".format(_("All Warehouses"), self.abbr) \
|
"parent_warehouse": "{0} - {1}".format(_("All Warehouses"), self.abbr) \
|
||||||
if not wh_detail["is_group"] else "",
|
if not wh_detail["is_group"] else ""
|
||||||
"create_account_under": stock_group
|
|
||||||
})
|
})
|
||||||
warehouse.flags.ignore_permissions = True
|
warehouse.flags.ignore_permissions = True
|
||||||
warehouse.insert()
|
warehouse.insert()
|
||||||
@@ -147,6 +148,7 @@ class Company(Document):
|
|||||||
|
|
||||||
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")):
|
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")):
|
||||||
self._set_default_account("stock_received_but_not_billed", "Stock Received But Not Billed")
|
self._set_default_account("stock_received_but_not_billed", "Stock Received But Not Billed")
|
||||||
|
self._set_default_account("default_inventory_account", "Stock")
|
||||||
self._set_default_account("stock_adjustment_account", "Stock Adjustment")
|
self._set_default_account("stock_adjustment_account", "Stock Adjustment")
|
||||||
self._set_default_account("expenses_included_in_valuation", "Expenses Included In Valuation")
|
self._set_default_account("expenses_included_in_valuation", "Expenses Included In Valuation")
|
||||||
self._set_default_account("default_expense_account", "Cost of Goods Sold")
|
self._set_default_account("default_expense_account", "Cost of Goods Sold")
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class TestCompany(unittest.TestCase):
|
|||||||
"company": template,
|
"company": template,
|
||||||
"account_type": account_type
|
"account_type": account_type
|
||||||
}
|
}
|
||||||
if account_type in ["Bank", "Cash", "Stock"]:
|
if account_type in ["Bank", "Cash"]:
|
||||||
filters["is_group"] = 1
|
filters["is_group"] = 1
|
||||||
|
|
||||||
self.assertTrue(frappe.get_all("Account", filters))
|
self.assertTrue(frappe.get_all("Account", filters))
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
install_docs = [
|
install_docs = [
|
||||||
{"doctype":"Role", "role_name":"Stock Manager", "name":"Stock Manager"},
|
{"doctype":"Role", "role_name":"Stock Manager", "name":"Stock Manager"},
|
||||||
{"doctype":"Role", "role_name":"Item Manager", "name":"Item Manager"},
|
{"doctype":"Role", "role_name":"Item Manager", "name":"Item Manager"},
|
||||||
@@ -8,3 +10,39 @@ install_docs = [
|
|||||||
{"doctype":"Item Group", "item_group_name":"Default",
|
{"doctype":"Item Group", "item_group_name":"Default",
|
||||||
"parent_item_group":"All Item Groups", "is_group": 0},
|
"parent_item_group":"All Item Groups", "is_group": 0},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_warehouse_account_map():
|
||||||
|
if not frappe.flags.warehouse_account_map or frappe.flags.in_test:
|
||||||
|
warehouse_account = frappe._dict()
|
||||||
|
|
||||||
|
for d in frappe.get_all('Warehouse', filters = {"is_group": 0},
|
||||||
|
fields = ["name", "account", "parent_warehouse", "company"]):
|
||||||
|
if not d.account:
|
||||||
|
d.account = get_warehouse_account(d.name, d.company)
|
||||||
|
|
||||||
|
if d.account:
|
||||||
|
d.account_currency = frappe.db.get_value('Account', d.account, 'account_currency')
|
||||||
|
warehouse_account.setdefault(d.name, d)
|
||||||
|
|
||||||
|
frappe.flags.warehouse_account_map = warehouse_account
|
||||||
|
return frappe.flags.warehouse_account_map
|
||||||
|
|
||||||
|
def get_warehouse_account(warehouse, company):
|
||||||
|
lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
|
||||||
|
account = frappe.db.sql("""
|
||||||
|
select
|
||||||
|
account from `tabWarehouse`
|
||||||
|
where
|
||||||
|
lft <= %s and rgt >= %s and company = %s
|
||||||
|
and account is not null and ifnull(account, '') !=''
|
||||||
|
order by lft desc limit 1""", (lft, rgt, company), as_list=1)
|
||||||
|
|
||||||
|
account = account[0][0] if account else None
|
||||||
|
|
||||||
|
if not account:
|
||||||
|
account = get_company_default_inventory_account(company)
|
||||||
|
|
||||||
|
return account
|
||||||
|
|
||||||
|
def get_company_default_inventory_account(company):
|
||||||
|
return frappe.db.get_value('Company', company, 'default_inventory_account')
|
||||||
@@ -19,8 +19,19 @@ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoWa
|
|||||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
|
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
|
||||||
import create_stock_reconciliation, set_valuation_method
|
import create_stock_reconciliation, set_valuation_method
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||||
|
|
||||||
class TestDeliveryNote(unittest.TestCase):
|
class TestDeliveryNote(unittest.TestCase):
|
||||||
|
def tearDown(self):
|
||||||
|
target_warehouse = "_Test Warehouse 1 - _TC"
|
||||||
|
company = "_Test Company"
|
||||||
|
if not frappe.db.exists("Account", target_warehouse):
|
||||||
|
parent_account = frappe.db.get_value('Account',
|
||||||
|
{'company': company, 'is_group':1, 'account_type': 'Stock'},'name')
|
||||||
|
account = create_account(account_name="_Test Warehouse 1", \
|
||||||
|
account_type="Stock", parent_account= parent_account, company=company)
|
||||||
|
frappe.db.set_value('Warehouse', target_warehouse, 'account', account)
|
||||||
|
|
||||||
def test_over_billing_against_dn(self):
|
def test_over_billing_against_dn(self):
|
||||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
|
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
|
||||||
|
|
||||||
@@ -63,7 +74,7 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
|
|
||||||
make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
|
make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"})
|
stock_in_hand_account = get_inventory_account('_Test Company')
|
||||||
prev_bal = get_balance_on(stock_in_hand_account)
|
prev_bal = get_balance_on(stock_in_hand_account)
|
||||||
|
|
||||||
dn = create_delivery_note()
|
dn = create_delivery_note()
|
||||||
@@ -113,7 +124,7 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
make_stock_entry(item_code="_Test Item Home Desktop 100",
|
make_stock_entry(item_code="_Test Item Home Desktop 100",
|
||||||
target="_Test Warehouse - _TC", qty=10, basic_rate=100)
|
target="_Test Warehouse - _TC", qty=10, basic_rate=100)
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"})
|
stock_in_hand_account = get_inventory_account('_Test Company')
|
||||||
prev_bal = get_balance_on(stock_in_hand_account)
|
prev_bal = get_balance_on(stock_in_hand_account)
|
||||||
|
|
||||||
dn = create_delivery_note(item_code="_Test Product Bundle Item")
|
dn = create_delivery_note(item_code="_Test Product Bundle Item")
|
||||||
@@ -212,9 +223,10 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
["incoming_rate", "stock_value_difference"])
|
["incoming_rate", "stock_value_difference"])
|
||||||
|
|
||||||
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
||||||
|
stock_in_hand_account = get_inventory_account('_Test Company', dn1.items[0].warehouse)
|
||||||
|
|
||||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
|
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
|
||||||
"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
|
"voucher_no": dn1.name, "account": stock_in_hand_account}, "debit")
|
||||||
|
|
||||||
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
||||||
|
|
||||||
@@ -250,10 +262,11 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
["incoming_rate", "stock_value_difference"])
|
["incoming_rate", "stock_value_difference"])
|
||||||
|
|
||||||
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
||||||
|
stock_in_hand_account = get_inventory_account('_Test Company', dn1.items[0].warehouse)
|
||||||
|
|
||||||
# Check gl entry for warehouse
|
# Check gl entry for warehouse
|
||||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
|
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
|
||||||
"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
|
"voucher_no": dn1.name, "account": stock_in_hand_account}, "debit")
|
||||||
|
|
||||||
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
||||||
|
|
||||||
@@ -282,10 +295,11 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
["incoming_rate", "stock_value_difference"])
|
["incoming_rate", "stock_value_difference"])
|
||||||
|
|
||||||
self.assertEquals(incoming_rate, 100)
|
self.assertEquals(incoming_rate, 100)
|
||||||
|
stock_in_hand_account = get_inventory_account('_Test Company', dn1.items[0].warehouse)
|
||||||
|
|
||||||
# Check gl entry for warehouse
|
# Check gl entry for warehouse
|
||||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
|
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
|
||||||
"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
|
"voucher_no": dn1.name, "account": stock_in_hand_account}, "debit")
|
||||||
|
|
||||||
self.assertEquals(gle_warehouse_amount, 1400)
|
self.assertEquals(gle_warehouse_amount, 1400)
|
||||||
|
|
||||||
@@ -339,7 +353,6 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
target=warehouse, qty=100, rate=100)
|
target=warehouse, qty=100, rate=100)
|
||||||
|
|
||||||
opening_qty_test_warehouse_1 = get_qty_after_transaction(warehouse="_Test Warehouse 1 - _TC")
|
opening_qty_test_warehouse_1 = get_qty_after_transaction(warehouse="_Test Warehouse 1 - _TC")
|
||||||
|
|
||||||
dn = create_delivery_note(item_code="_Test Product Bundle Item",
|
dn = create_delivery_note(item_code="_Test Product Bundle Item",
|
||||||
qty=5, rate=500, target_warehouse="_Test Warehouse 1 - _TC", do_not_submit=True)
|
qty=5, rate=500, target_warehouse="_Test Warehouse 1 - _TC", do_not_submit=True)
|
||||||
|
|
||||||
@@ -390,7 +403,7 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
and warehouse='_Test Warehouse - _TC'""", dn.name)[0][0])
|
and warehouse='_Test Warehouse - _TC'""", dn.name)[0][0])
|
||||||
|
|
||||||
expected_values = {
|
expected_values = {
|
||||||
"_Test Warehouse - _TC": [0.0, stock_value_difference],
|
"Stock In Hand - _TC": [0.0, stock_value_difference],
|
||||||
"_Test Warehouse 1 - _TC": [stock_value_difference, 0.0]
|
"_Test Warehouse 1 - _TC": [stock_value_difference, 0.0]
|
||||||
}
|
}
|
||||||
for i, gle in enumerate(gl_entries):
|
for i, gle in enumerate(gl_entries):
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from frappe.utils import flt
|
|||||||
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, make_purchase_receipt
|
import set_perpetual_inventory, get_gl_entries, test_records as pr_test_records, make_purchase_receipt
|
||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
|
||||||
class TestLandedCostVoucher(unittest.TestCase):
|
class TestLandedCostVoucher(unittest.TestCase):
|
||||||
def test_landed_cost_voucher(self):
|
def test_landed_cost_voucher(self):
|
||||||
@@ -46,10 +47,17 @@ class TestLandedCostVoucher(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
stock_in_hand_account = pr.get("items")[0].warehouse
|
stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
|
||||||
fixed_asset_account = pr.get("items")[1].warehouse
|
fixed_asset_account = get_inventory_account(pr.company, pr.get("items")[1].warehouse)
|
||||||
|
|
||||||
|
if stock_in_hand_account == fixed_asset_account:
|
||||||
|
expected_values = {
|
||||||
|
stock_in_hand_account: [800.0, 0.0],
|
||||||
|
"Stock Received But Not Billed - _TC": [0.0, 500.0],
|
||||||
|
"Expenses Included In Valuation - _TC": [0.0, 300.0]
|
||||||
|
}
|
||||||
|
|
||||||
|
else:
|
||||||
expected_values = {
|
expected_values = {
|
||||||
stock_in_hand_account: [400.0, 0.0],
|
stock_in_hand_account: [400.0, 0.0],
|
||||||
fixed_asset_account: [400.0, 0.0],
|
fixed_asset_account: [400.0, 0.0],
|
||||||
@@ -99,9 +107,10 @@ class TestLandedCostVoucher(unittest.TestCase):
|
|||||||
gl_entries = get_gl_entries("Purchase Invoice", pi.name)
|
gl_entries = get_gl_entries("Purchase Invoice", pi.name)
|
||||||
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
|
||||||
|
|
||||||
expected_values = {
|
expected_values = {
|
||||||
pi.get("items")[0].warehouse: [300.0, 0.0],
|
stock_in_hand_account: [300.0, 0.0],
|
||||||
"Creditors - _TC": [0.0, 250.0],
|
"Creditors - _TC": [0.0, 250.0],
|
||||||
"Expenses Included In Valuation - _TC": [0.0, 50.0]
|
"Expenses Included In Valuation - _TC": [0.0, 50.0]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
if not stock_value_diff:
|
if not stock_value_diff:
|
||||||
continue
|
continue
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": warehouse_account[d.warehouse]["name"],
|
"account": warehouse_account[d.warehouse]["account"],
|
||||||
"against": stock_rbnb,
|
"against": stock_rbnb,
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
@@ -200,7 +200,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
stock_rbnb_currency = get_account_currency(stock_rbnb)
|
stock_rbnb_currency = get_account_currency(stock_rbnb)
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": stock_rbnb,
|
"account": stock_rbnb,
|
||||||
"against": warehouse_account[d.warehouse]["name"],
|
"against": warehouse_account[d.warehouse]["account"],
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": flt(d.base_net_amount, d.precision("base_net_amount")),
|
"credit": flt(d.base_net_amount, d.precision("base_net_amount")),
|
||||||
@@ -214,7 +214,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
if flt(d.landed_cost_voucher_amount):
|
if flt(d.landed_cost_voucher_amount):
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": expenses_included_in_valuation,
|
"account": expenses_included_in_valuation,
|
||||||
"against": warehouse_account[d.warehouse]["name"],
|
"against": warehouse_account[d.warehouse]["account"],
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": flt(d.landed_cost_voucher_amount),
|
"credit": flt(d.landed_cost_voucher_amount),
|
||||||
@@ -225,7 +225,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
|
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": warehouse_account[self.supplier_warehouse]["name"],
|
"account": warehouse_account[self.supplier_warehouse]["name"],
|
||||||
"against": warehouse_account[d.warehouse]["name"],
|
"against": warehouse_account[d.warehouse]["account"],
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": flt(d.rm_supp_cost)
|
"credit": flt(d.rm_supp_cost)
|
||||||
@@ -246,7 +246,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": loss_account,
|
"account": loss_account,
|
||||||
"against": warehouse_account[d.warehouse]["name"],
|
"against": warehouse_account[d.warehouse]["account"],
|
||||||
"cost_center": d.cost_center,
|
"cost_center": d.cost_center,
|
||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"debit": divisional_loss,
|
"debit": divisional_loss,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import frappe.defaults
|
|||||||
from frappe.utils import cint, flt, cstr, today
|
from frappe.utils import cint, flt, cstr, today
|
||||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
|
||||||
from erpnext import set_perpetual_inventory
|
from erpnext import set_perpetual_inventory
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
|
||||||
class TestPurchaseReceipt(unittest.TestCase):
|
class TestPurchaseReceipt(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -59,11 +60,16 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account",
|
stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
|
||||||
{"warehouse": pr.get("items")[0].warehouse})
|
fixed_asset_account = get_inventory_account(pr.company, pr.get("items")[1].warehouse)
|
||||||
fixed_asset_account = frappe.db.get_value("Account",
|
|
||||||
{"warehouse": pr.get("items")[1].warehouse})
|
|
||||||
|
|
||||||
|
if stock_in_hand_account == fixed_asset_account:
|
||||||
|
expected_values = {
|
||||||
|
stock_in_hand_account: [750.0, 0.0],
|
||||||
|
"Stock Received But Not Billed - _TC": [0.0, 500.0],
|
||||||
|
"Expenses Included In Valuation - _TC": [0.0, 250.0]
|
||||||
|
}
|
||||||
|
else:
|
||||||
expected_values = {
|
expected_values = {
|
||||||
stock_in_hand_account: [375.0, 0.0],
|
stock_in_hand_account: [375.0, 0.0],
|
||||||
fixed_asset_account: [375.0, 0.0],
|
fixed_asset_account: [375.0, 0.0],
|
||||||
@@ -141,9 +147,10 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
gl_entries = get_gl_entries("Purchase Receipt", return_pr.name)
|
gl_entries = get_gl_entries("Purchase Receipt", return_pr.name)
|
||||||
|
|
||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
stock_in_hand_account = get_inventory_account(return_pr.company)
|
||||||
|
|
||||||
expected_values = {
|
expected_values = {
|
||||||
"_Test Warehouse - _TC": [0.0, 100.0],
|
stock_in_hand_account: [0.0, 100.0],
|
||||||
"Stock Received But Not Billed - _TC": [100.0, 0.0],
|
"Stock Received But Not Billed - _TC": [100.0, 0.0],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from erpnext.stock.stock_ledger import get_previous_sle
|
|||||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
||||||
from frappe.tests.test_permissions import set_user_permission_doctypes
|
from frappe.tests.test_permissions import set_user_permission_doctypes
|
||||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
|
|
||||||
def get_sle(**args):
|
def get_sle(**args):
|
||||||
condition, values = "", []
|
condition, values = "", []
|
||||||
@@ -127,9 +128,7 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
|
mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
|
||||||
qty=50, basic_rate=100, expense_account="Stock Adjustment - _TC")
|
qty=50, basic_rate=100, expense_account="Stock Adjustment - _TC")
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Stock",
|
stock_in_hand_account = get_inventory_account(mr.company, mr.get("items")[0].t_warehouse)
|
||||||
"warehouse": mr.get("items")[0].t_warehouse})
|
|
||||||
|
|
||||||
self.check_stock_ledger_entries("Stock Entry", mr.name,
|
self.check_stock_ledger_entries("Stock Entry", mr.name,
|
||||||
[["_Test Item", "_Test Warehouse - _TC", 50.0]])
|
[["_Test Item", "_Test Warehouse - _TC", 50.0]])
|
||||||
|
|
||||||
@@ -160,9 +159,7 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
self.check_stock_ledger_entries("Stock Entry", mi.name,
|
self.check_stock_ledger_entries("Stock Entry", mi.name,
|
||||||
[["_Test Item", "_Test Warehouse - _TC", -40.0]])
|
[["_Test Item", "_Test Warehouse - _TC", -40.0]])
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Stock",
|
stock_in_hand_account = get_inventory_account(mi.company, "_Test Warehouse - _TC")
|
||||||
"warehouse": "_Test Warehouse - _TC"})
|
|
||||||
|
|
||||||
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
|
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
|
||||||
"voucher_no": mi.name}, "stock_value_difference"))
|
"voucher_no": mi.name}, "stock_value_difference"))
|
||||||
|
|
||||||
@@ -192,12 +189,16 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
self.check_stock_ledger_entries("Stock Entry", mtn.name,
|
self.check_stock_ledger_entries("Stock Entry", mtn.name,
|
||||||
[["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]])
|
[["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]])
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Stock",
|
stock_in_hand_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
|
||||||
"warehouse": mtn.get("items")[0].s_warehouse})
|
|
||||||
|
|
||||||
fixed_asset_account = frappe.db.get_value("Account", {"account_type": "Stock",
|
fixed_asset_account = get_inventory_account(mtn.company, mtn.get("items")[0].t_warehouse)
|
||||||
"warehouse": mtn.get("items")[0].t_warehouse})
|
|
||||||
|
|
||||||
|
if stock_in_hand_account == fixed_asset_account:
|
||||||
|
# no gl entry as both source and target warehouse has linked to same account.
|
||||||
|
self.assertFalse(frappe.db.sql("""select * from `tabGL Entry`
|
||||||
|
where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name))
|
||||||
|
|
||||||
|
else:
|
||||||
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
|
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
|
||||||
"voucher_no": mtn.name, "warehouse": "_Test Warehouse - _TC"}, "stock_value_difference"))
|
"voucher_no": mtn.name, "warehouse": "_Test Warehouse - _TC"}, "stock_value_difference"))
|
||||||
|
|
||||||
@@ -260,9 +261,7 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
repack.insert()
|
repack.insert()
|
||||||
repack.submit()
|
repack.submit()
|
||||||
|
|
||||||
stock_in_hand_account = frappe.db.get_value("Account", {"account_type": "Stock",
|
stock_in_hand_account = get_inventory_account(repack.company, repack.get("items")[1].t_warehouse)
|
||||||
"warehouse": repack.get("items")[1].t_warehouse})
|
|
||||||
|
|
||||||
rm_stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
|
rm_stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
|
||||||
"voucher_no": repack.name, "item_code": "_Test Item"}, "stock_value_difference"))
|
"voucher_no": repack.name, "item_code": "_Test Item"}, "stock_value_difference"))
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
|||||||
from frappe.utils import cint
|
from frappe.utils import cint
|
||||||
from erpnext import set_perpetual_inventory
|
from erpnext import set_perpetual_inventory
|
||||||
from frappe.test_runner import make_test_records
|
from frappe.test_runner import make_test_records
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
@@ -33,21 +34,16 @@ class TestWarehouse(unittest.TestCase):
|
|||||||
def test_warehouse_renaming(self):
|
def test_warehouse_renaming(self):
|
||||||
set_perpetual_inventory(1)
|
set_perpetual_inventory(1)
|
||||||
create_warehouse("Test Warehouse for Renaming 1")
|
create_warehouse("Test Warehouse for Renaming 1")
|
||||||
|
account = get_inventory_account("_Test Company", "Test Warehouse for Renaming 1 - _TC")
|
||||||
self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 1 - _TC"))
|
self.assertTrue(frappe.db.get_value("Warehouse", filters={"account": account}))
|
||||||
self.assertTrue(frappe.db.get_value("Account",
|
|
||||||
filters={"warehouse": "Test Warehouse for Renaming 1 - _TC"}))
|
|
||||||
|
|
||||||
# Rename with abbr
|
# Rename with abbr
|
||||||
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"):
|
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"):
|
||||||
frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC")
|
frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC")
|
||||||
rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
|
rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
|
||||||
|
|
||||||
self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 2 - _TC"))
|
self.assertTrue(frappe.db.get_value("Warehouse",
|
||||||
self.assertTrue(frappe.db.get_value("Account",
|
filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
|
||||||
filters={"warehouse": "Test Warehouse for Renaming 2 - _TC"}))
|
|
||||||
self.assertFalse(frappe.db.get_value("Account",
|
|
||||||
filters={"warehouse": "Test Warehouse for Renaming 1 - _TC"}))
|
|
||||||
|
|
||||||
# Rename without abbr
|
# Rename without abbr
|
||||||
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"):
|
if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"):
|
||||||
@@ -55,19 +51,14 @@ class TestWarehouse(unittest.TestCase):
|
|||||||
|
|
||||||
rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
|
rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
|
||||||
|
|
||||||
self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 3 - _TC"))
|
self.assertTrue(frappe.db.get_value("Warehouse",
|
||||||
self.assertTrue(frappe.db.get_value("Account",
|
filters={"account": "Test Warehouse for Renaming 1 - _TC"}))
|
||||||
filters={"warehouse": "Test Warehouse for Renaming 3 - _TC"}))
|
|
||||||
|
|
||||||
# Another rename with multiple dashes
|
# Another rename with multiple dashes
|
||||||
if frappe.db.exists("Warehouse", "Test - Warehouse - Company - _TC"):
|
if frappe.db.exists("Warehouse", "Test - Warehouse - Company - _TC"):
|
||||||
frappe.delete_doc("Warehouse", "Test - Warehouse - Company - _TC")
|
frappe.delete_doc("Warehouse", "Test - Warehouse - Company - _TC")
|
||||||
rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company")
|
rename_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC", "Test - Warehouse - Company")
|
||||||
|
|
||||||
self.assertTrue(frappe.db.exists("Account", "Test - Warehouse - Company - _TC"))
|
|
||||||
self.assertTrue(frappe.db.get_value("Account", filters={"warehouse": "Test - Warehouse - Company - _TC"}))
|
|
||||||
self.assertFalse(frappe.db.get_value("Account", filters={"warehouse": "Test Warehouse for Renaming 3 - _TC"}))
|
|
||||||
|
|
||||||
def test_warehouse_merging(self):
|
def test_warehouse_merging(self):
|
||||||
set_perpetual_inventory(1)
|
set_perpetual_inventory(1)
|
||||||
|
|
||||||
@@ -96,10 +87,8 @@ class TestWarehouse(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(bin_qty, existing_bin_qty)
|
self.assertEqual(bin_qty, existing_bin_qty)
|
||||||
|
|
||||||
self.assertFalse(frappe.db.exists("Account", "Test Warehouse for Merging 1 - _TC"))
|
self.assertTrue(frappe.db.get_value("Warehouse",
|
||||||
self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Merging 2 - _TC"))
|
filters={"account": "Test Warehouse for Merging 2 - _TC"}))
|
||||||
self.assertTrue(frappe.db.get_value("Account",
|
|
||||||
filters={"warehouse": "Test Warehouse for Merging 2 - _TC"}))
|
|
||||||
|
|
||||||
def create_warehouse(warehouse_name):
|
def create_warehouse(warehouse_name):
|
||||||
if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
|
if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
|
||||||
@@ -107,8 +96,13 @@ def create_warehouse(warehouse_name):
|
|||||||
w.warehouse_name = warehouse_name
|
w.warehouse_name = warehouse_name
|
||||||
w.parent_warehouse = "_Test Warehouse Group - _TC"
|
w.parent_warehouse = "_Test Warehouse Group - _TC"
|
||||||
w.company = "_Test Company"
|
w.company = "_Test Company"
|
||||||
|
make_account_for_warehouse(warehouse_name, w)
|
||||||
|
w.account = warehouse_name + " - _TC"
|
||||||
w.save()
|
w.save()
|
||||||
|
|
||||||
if not frappe.get_value('Account', dict(warehouse=warehouse_name + ' - _TC')):
|
def make_account_for_warehouse(warehouse_name, warehouse_obj):
|
||||||
print 'Warehouse {0} not linked'.format(warehouse_name)
|
if not frappe.db.exists("Account", warehouse_name + " - _TC"):
|
||||||
|
parent_account = frappe.db.get_value('Account',
|
||||||
|
{'company': warehouse_obj.company, 'is_group':1, 'account_type': 'Stock'},'name')
|
||||||
|
account = create_account(account_name=warehouse_name, \
|
||||||
|
account_type="Stock", parent_account= parent_account, company=warehouse_obj.company)
|
||||||
@@ -28,7 +28,7 @@ frappe.ui.form.on("Warehouse", {
|
|||||||
function() { convert_to_group_or_ledger(frm); }, 'fa fa-retweet', 'btn-default')
|
function() { convert_to_group_or_ledger(frm); }, 'fa fa-retweet', 'btn-default')
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.toggle_enable(['is_group', 'company'], false);
|
frm.toggle_enable(['is_group', 'company'], false);
|
||||||
|
|
||||||
frm.fields_dict['parent_warehouse'].get_query = function(doc) {
|
frm.fields_dict['parent_warehouse'].get_query = function(doc) {
|
||||||
return {
|
return {
|
||||||
@@ -37,17 +37,18 @@ frappe.ui.form.on("Warehouse", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
cur_frm.set_query("create_account_under", function() {
|
frm.fields_dict['account'].get_query = function(doc) {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
"company": cur_frm.doc.company,
|
"is_group": 0,
|
||||||
'is_group': 1
|
"account_type": "Stock",
|
||||||
|
"company": frm.doc.company
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function convert_to_group_or_ledger(frm){
|
function convert_to_group_or_ledger(frm){
|
||||||
frappe.call({
|
frappe.call({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
@@ -193,9 +194,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"depends_on": "eval:sys_defaults.auto_accounting_for_stock",
|
"fieldname": "account",
|
||||||
"description": "Account for the warehouse (Perpetual Inventory) will be created under this Account.",
|
|
||||||
"fieldname": "create_account_under",
|
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@@ -204,11 +203,12 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Parent Account",
|
"label": "Account",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
@@ -666,18 +666,18 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"icon": "fa fa-building",
|
"icon": "fa fa-building",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-02-20 13:27:03.696714",
|
"modified": "2017-04-21 16:49:19.018576",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Warehouse",
|
"name": "Warehouse",
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.utils import cint, validate_email_add
|
from frappe.utils import cint, validate_email_add
|
||||||
from frappe import throw, msgprint, _
|
from frappe import throw, _
|
||||||
from frappe.utils.nestedset import NestedSet
|
from frappe.utils.nestedset import NestedSet
|
||||||
|
from erpnext.stock import get_warehouse_account
|
||||||
|
|
||||||
class Warehouse(NestedSet):
|
class Warehouse(NestedSet):
|
||||||
nsm_parent_field = 'parent_warehouse'
|
nsm_parent_field = 'parent_warehouse'
|
||||||
@@ -20,8 +21,7 @@ class Warehouse(NestedSet):
|
|||||||
|
|
||||||
def onload(self):
|
def onload(self):
|
||||||
'''load account name for General Ledger Report'''
|
'''load account name for General Ledger Report'''
|
||||||
account = frappe.db.get_value("Account", {
|
account = self.account or get_warehouse_account(self.name, self.company)
|
||||||
"account_type": "Stock", "company": self.company, "warehouse": self.name, "is_group": 0})
|
|
||||||
|
|
||||||
if account:
|
if account:
|
||||||
self.set_onload('account', account)
|
self.set_onload('account', account)
|
||||||
@@ -30,77 +30,9 @@ class Warehouse(NestedSet):
|
|||||||
if self.email_id:
|
if self.email_id:
|
||||||
validate_email_add(self.email_id, True)
|
validate_email_add(self.email_id, True)
|
||||||
|
|
||||||
self.update_parent_account()
|
|
||||||
|
|
||||||
def update_parent_account(self):
|
|
||||||
if not getattr(self, "__islocal", None) \
|
|
||||||
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
|
|
||||||
and (self.create_account_under != frappe.db.get_value("Warehouse", self.name, "create_account_under")):
|
|
||||||
|
|
||||||
self.validate_parent_account()
|
|
||||||
|
|
||||||
warehouse_account = frappe.db.get_value("Account",
|
|
||||||
{"account_type": "Stock", "company": self.company, "warehouse": self.name, "is_group": 0},
|
|
||||||
["name", "parent_account"])
|
|
||||||
|
|
||||||
if warehouse_account and warehouse_account[1] != self.create_account_under:
|
|
||||||
acc_doc = frappe.get_doc("Account", warehouse_account[0])
|
|
||||||
acc_doc.parent_account = self.create_account_under
|
|
||||||
acc_doc.save()
|
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
self.create_account_head()
|
|
||||||
self.update_nsm_model()
|
self.update_nsm_model()
|
||||||
|
|
||||||
def create_account_head(self):
|
|
||||||
'''Create new account head if there is no account linked to this Warehouse'''
|
|
||||||
from erpnext.accounts.doctype.account.account import BalanceMismatchError
|
|
||||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
|
||||||
if not self.get_account():
|
|
||||||
if self.get("__islocal") or not frappe.db.get_value(
|
|
||||||
"Stock Ledger Entry", {"warehouse": self.name}):
|
|
||||||
|
|
||||||
self.validate_parent_account()
|
|
||||||
ac_doc = frappe.get_doc({
|
|
||||||
"doctype": "Account",
|
|
||||||
'account_name': self.warehouse_name,
|
|
||||||
'parent_account': self.parent_warehouse if self.parent_warehouse \
|
|
||||||
else self.create_account_under,
|
|
||||||
'is_group': self.is_group,
|
|
||||||
'company':self.company,
|
|
||||||
"account_type": "Stock",
|
|
||||||
"warehouse": self.name,
|
|
||||||
"freeze_account": "No"
|
|
||||||
})
|
|
||||||
ac_doc.flags.ignore_permissions = True
|
|
||||||
ac_doc.flags.ignore_mandatory = True
|
|
||||||
try:
|
|
||||||
ac_doc.insert()
|
|
||||||
msgprint(_("Account head {0} created").format(ac_doc.name), indicator='green', alert=True)
|
|
||||||
|
|
||||||
except frappe.DuplicateEntryError:
|
|
||||||
msgprint(_("Please create an Account for this Warehouse and link it. This cannot be done automatically as an account with name {0} already exists").format(frappe.bold(self.name)),
|
|
||||||
indicator='orange')
|
|
||||||
|
|
||||||
except BalanceMismatchError:
|
|
||||||
msgprint(_("Cannot automatically create Account as there is already stock balance in the Account. You must create a matching account before you can make an entry on this warehouse"))
|
|
||||||
|
|
||||||
def validate_parent_account(self):
|
|
||||||
if not self.company:
|
|
||||||
frappe.throw(_("Warehouse {0}: Company is mandatory").format(self.name))
|
|
||||||
|
|
||||||
if not self.create_account_under:
|
|
||||||
parent_account = frappe.db.sql("""select name from tabAccount
|
|
||||||
where account_type='Stock' and company=%s and is_group=1
|
|
||||||
and (warehouse is null or warehouse = '')""", self.company)
|
|
||||||
|
|
||||||
if parent_account:
|
|
||||||
frappe.db.set_value("Warehouse", self.name, "create_account_under", parent_account[0][0])
|
|
||||||
self.create_account_under = parent_account[0][0]
|
|
||||||
elif frappe.db.get_value("Account", self.create_account_under, "company") != self.company:
|
|
||||||
frappe.throw(_("Warehouse {0}: Parent account {1} does not bolong to the company {2}")
|
|
||||||
.format(self.name, self.create_account_under, self.company))
|
|
||||||
|
|
||||||
def update_nsm_model(self):
|
def update_nsm_model(self):
|
||||||
frappe.utils.nestedset.update_nsm(self)
|
frappe.utils.nestedset.update_nsm(self)
|
||||||
|
|
||||||
@@ -115,10 +47,6 @@ class Warehouse(NestedSet):
|
|||||||
else:
|
else:
|
||||||
frappe.db.sql("delete from `tabBin` where name = %s", d['name'])
|
frappe.db.sql("delete from `tabBin` where name = %s", d['name'])
|
||||||
|
|
||||||
warehouse_account = self.get_account()
|
|
||||||
if warehouse_account:
|
|
||||||
frappe.delete_doc("Account", warehouse_account)
|
|
||||||
|
|
||||||
if self.check_if_sle_exists():
|
if self.check_if_sle_exists():
|
||||||
throw(_("Warehouse can not be deleted as stock ledger entry exists for this warehouse."))
|
throw(_("Warehouse can not be deleted as stock ledger entry exists for this warehouse."))
|
||||||
|
|
||||||
@@ -146,36 +74,8 @@ class Warehouse(NestedSet):
|
|||||||
if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"):
|
if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"):
|
||||||
frappe.throw(_("Both Warehouse must belong to same Company"))
|
frappe.throw(_("Both Warehouse must belong to same Company"))
|
||||||
|
|
||||||
self.rename_account_for(old_name, new_warehouse, merge)
|
|
||||||
|
|
||||||
return new_warehouse
|
return new_warehouse
|
||||||
|
|
||||||
def rename_account_for(self, old_name, new_name, merge):
|
|
||||||
old_account_name = frappe.get_value('Account', dict(warehouse=old_name))
|
|
||||||
|
|
||||||
if old_account_name:
|
|
||||||
if not merge:
|
|
||||||
# old account name is same as old name, so rename the account too
|
|
||||||
if old_account_name == erpnext.encode_company_abbr(old_name, self.company):
|
|
||||||
frappe.rename_doc("Account", old_account_name, new_name)
|
|
||||||
else:
|
|
||||||
# merge
|
|
||||||
target_account = frappe.get_value('Account', dict(warehouse=new_name))
|
|
||||||
if target_account:
|
|
||||||
# target warehouse has account, merge into target account
|
|
||||||
frappe.rename_doc("Account", old_account_name,
|
|
||||||
target_account, merge=True)
|
|
||||||
else:
|
|
||||||
# target warehouse does not have account, use this account
|
|
||||||
frappe.rename_doc("Account", old_account_name,
|
|
||||||
new_name, merge=False)
|
|
||||||
|
|
||||||
# rename link
|
|
||||||
frappe.db.set_value('Account', new_name, 'warehouse', new_name)
|
|
||||||
|
|
||||||
def get_account(self):
|
|
||||||
return frappe.get_value('Account', dict(warehouse=self.name))
|
|
||||||
|
|
||||||
def after_rename(self, old_name, new_name, merge=False):
|
def after_rename(self, old_name, new_name, merge=False):
|
||||||
new_warehouse_name = self.get_new_warehouse_name_without_abbr(new_name)
|
new_warehouse_name = self.get_new_warehouse_name_without_abbr(new_name)
|
||||||
self.db_set("warehouse_name", new_warehouse_name)
|
self.db_set("warehouse_name", new_warehouse_name)
|
||||||
@@ -222,12 +122,6 @@ class Warehouse(NestedSet):
|
|||||||
elif self.check_if_sle_exists():
|
elif self.check_if_sle_exists():
|
||||||
throw(_("Warehouses with existing transaction can not be converted to ledger."))
|
throw(_("Warehouses with existing transaction can not be converted to ledger."))
|
||||||
else:
|
else:
|
||||||
account_name = self.get_account()
|
|
||||||
if account_name:
|
|
||||||
doc = frappe.get_doc("Account", account_name)
|
|
||||||
doc.warehouse = self.name
|
|
||||||
doc.convert_group_to_ledger()
|
|
||||||
|
|
||||||
self.is_group = 0
|
self.is_group = 0
|
||||||
self.save()
|
self.save()
|
||||||
return 1
|
return 1
|
||||||
@@ -236,12 +130,6 @@ class Warehouse(NestedSet):
|
|||||||
if self.check_if_sle_exists():
|
if self.check_if_sle_exists():
|
||||||
throw(_("Warehouses with existing transaction can not be converted to group."))
|
throw(_("Warehouses with existing transaction can not be converted to group."))
|
||||||
else:
|
else:
|
||||||
account_name = self.get_account()
|
|
||||||
if account_name:
|
|
||||||
doc = frappe.get_doc("Account", account_name)
|
|
||||||
doc.flags.exclude_account_type_check = True
|
|
||||||
doc.convert_ledger_to_group()
|
|
||||||
|
|
||||||
self.is_group = 1
|
self.is_group = 1
|
||||||
self.save()
|
self.save()
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
Reference in New Issue
Block a user