Merge pull request #9355 from rohitwaghchaure/company_wise_manufacturing_settings

[Enhance] Company wise perpetual inventory settings
This commit is contained in:
Makarand Bauskar 2017-06-22 12:35:41 +05:30 committed by GitHub
commit e995371b08
41 changed files with 2260 additions and 2043 deletions

View File

@ -36,12 +36,13 @@ def get_company_currency(company):
frappe.flags.company_currency[company] = frappe.db.get_value('Company', company, 'default_currency') frappe.flags.company_currency[company] = frappe.db.get_value('Company', company, 'default_currency')
return frappe.flags.company_currency[company] return frappe.flags.company_currency[company]
def set_perpetual_inventory(enable=1, company=None):
if not company:
company = "_Test Company" if frappe.flags.in_test else get_default_company()
def set_perpetual_inventory(enable=1): company = frappe.get_doc("Company", company)
accounts_settings = frappe.get_doc("Accounts Settings") company.enable_perpetual_inventory = enable
accounts_settings.auto_accounting_for_stock = enable company.save()
accounts_settings.save()
def encode_company_abbr(name, company): def encode_company_abbr(name, company):
'''Returns name encoded with company abbreviation''' '''Returns name encoded with company abbreviation'''
@ -53,4 +54,15 @@ def encode_company_abbr(name, company):
return " - ".join(parts) return " - ".join(parts)
def is_perpetual_inventory_enabled(company):
if not company:
company = "_Test Company" if frappe.flags.in_test else get_default_company()
if not hasattr(frappe.local, 'enable_perpetual_inventory'):
frappe.local.enable_perpetual_inventory = {}
if not company in frappe.local.enable_perpetual_inventory:
frappe.local.enable_perpetual_inventory[company] = frappe.db.get_value("Company",
company, "enable_perpetual_inventory") or 0
return frappe.local.enable_perpetual_inventory[company]

View File

@ -14,6 +14,7 @@
"engine": "InnoDB", "engine": "InnoDB",
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -22,7 +23,7 @@
"description": "If enabled, the system will post accounting entries for inventory automatically.", "description": "If enabled, the system will post accounting entries for inventory automatically.",
"fieldname": "auto_accounting_for_stock", "fieldname": "auto_accounting_for_stock",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 1,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
@ -44,6 +45,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -73,6 +75,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -103,6 +106,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -131,6 +135,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -161,6 +166,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -190,6 +196,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -219,6 +226,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -249,6 +257,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -290,7 +299,7 @@
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-04-18 13:35:59.166250", "modified": "2017-06-16 17:39:50.614522",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@ -11,18 +11,4 @@ from frappe.model.document import Document
class AccountsSettings(Document): class AccountsSettings(Document):
def on_update(self): def on_update(self):
frappe.db.set_default("auto_accounting_for_stock", self.auto_accounting_for_stock) pass
if cint(self.auto_accounting_for_stock):
# set default perpetual account in company
for company in frappe.db.sql("select name from tabCompany"):
company = frappe.get_doc("Company", company[0])
company.flags.ignore_permissions = True
company.save()
# validate warehouse linked to company
warehouse_with_no_company = frappe.db.sql_list("""select name from tabWarehouse
where disabled=0 and company is null or company = ''""")
if warehouse_with_no_company:
frappe.throw(_("Company is missing in warehouses {0}")
.format(comma_and(warehouse_with_no_company)))

View File

@ -26,6 +26,23 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) {
}); });
}); });
frappe.ui.form.on('POS Profile', {
refresh: function(frm) {
if(frm.doc.company) {
frm.trigger("toggle_display_account_head");
}
},
company: function(frm) {
frm.trigger("toggle_display_account_head");
},
toggle_display_account_head: function(frm) {
frm.toggle_display('expense_account',
erpnext.is_perpetual_inventory_enabled(frm.doc.company));
}
})
// Income Account // Income Account
// -------------------------------- // --------------------------------
cur_frm.fields_dict['income_account'].get_query = function(doc,cdt,cdn) { cur_frm.fields_dict['income_account'].get_query = function(doc,cdt,cdn) {

View File

@ -1132,7 +1132,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "depends_on": "",
"fieldname": "expense_account", "fieldname": "expense_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -1201,7 +1201,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-06-15 20:07:55.682137", "modified": "2017-06-16 17:04:33.165676",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Profile", "name": "POS Profile",

View File

@ -164,7 +164,7 @@ class PurchaseInvoice(BuyingController):
frappe.msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True) frappe.msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
def set_expense_account(self, for_validate=False): def set_expense_account(self, for_validate=False):
auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
if auto_accounting_for_stock: if auto_accounting_for_stock:
stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
@ -335,9 +335,7 @@ class PurchaseInvoice(BuyingController):
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name) delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
def get_gl_entries(self, warehouse_account=None): def get_gl_entries(self, warehouse_account=None):
self.auto_accounting_for_stock = \ self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed") self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed")
self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
self.negative_expense_to_be_booked = 0.0 self.negative_expense_to_be_booked = 0.0

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import unittest
import frappe import frappe, erpnext
import frappe.model import frappe.model
from frappe.utils import cint, flt, today, nowdate from frappe.utils import cint, flt, today, nowdate
import frappe.defaults import frappe.defaults
@ -25,11 +25,10 @@ class TestPurchaseInvoice(unittest.TestCase):
def tearDown(self): def tearDown(self):
unlink_payment_on_cancel_of_invoice(0) unlink_payment_on_cancel_of_invoice(0)
def test_gl_entries_without_auto_accounting_for_stock(self): def test_gl_entries_without_perpetual_inventory(self):
set_perpetual_inventory(0)
self.assertTrue(not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")))
wrapper = frappe.copy_doc(test_records[0]) wrapper = frappe.copy_doc(test_records[0])
set_perpetual_inventory(0, wrapper.company)
self.assertTrue(not cint(erpnext.is_perpetual_inventory_enabled(wrapper.company)))
wrapper.insert() wrapper.insert()
wrapper.submit() wrapper.submit()
wrapper.load_from_db() wrapper.load_from_db()
@ -51,17 +50,16 @@ class TestPurchaseInvoice(unittest.TestCase):
for d in gl_entries: for d in gl_entries:
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account)) self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
def test_gl_entries_with_auto_accounting_for_stock(self): def test_gl_entries_with_perpetual_inventory(self):
set_perpetual_inventory(1)
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1)
pi = frappe.copy_doc(test_records[1]) pi = frappe.copy_doc(test_records[1])
set_perpetual_inventory(1, pi.company)
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pi.company)), 1)
pi.insert() pi.insert()
pi.submit() pi.submit()
self.check_gle_for_pi(pi.name) self.check_gle_for_pi(pi.name)
set_perpetual_inventory(0) set_perpetual_inventory(0, pi.company)
def test_payment_entry_unlink_against_purchase_invoice(self): def test_payment_entry_unlink_against_purchase_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
@ -84,11 +82,10 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertRaises(frappe.LinkExistsError, pi_doc.cancel) self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
def test_gl_entries_with_auto_accounting_for_stock_against_pr(self): def test_gl_entries_with_perpetual_inventory_against_pr(self):
set_perpetual_inventory(1)
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1)
pr = frappe.copy_doc(pr_test_records[0]) pr = frappe.copy_doc(pr_test_records[0])
set_perpetual_inventory(1, pr.company)
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
pr.submit() pr.submit()
pi = frappe.copy_doc(test_records[1]) pi = frappe.copy_doc(test_records[1])
@ -99,7 +96,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.check_gle_for_pi(pi.name) self.check_gle_for_pi(pi.name)
set_perpetual_inventory(0) set_perpetual_inventory(0, pr.company)
def check_gle_for_pi(self, pi): def check_gle_for_pi(self, pi):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
@ -133,10 +130,9 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertRaises(frappe.CannotChangeConstantError, pi.save) self.assertRaises(frappe.CannotChangeConstantError, pi.save)
def test_gl_entries_with_aia_for_non_stock_items(self): def test_gl_entries_with_aia_for_non_stock_items(self):
set_perpetual_inventory()
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1)
pi = frappe.copy_doc(test_records[1]) pi = frappe.copy_doc(test_records[1])
set_perpetual_inventory(1, pi.company)
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pi.company)), 1)
pi.get("items")[0].item_code = "_Test Non Stock Item" pi.get("items")[0].item_code = "_Test Non Stock Item"
pi.get("items")[0].expense_account = "_Test Account Cost for Goods Sold - _TC" pi.get("items")[0].expense_account = "_Test Account Cost for Goods Sold - _TC"
pi.get("taxes").pop(0) pi.get("taxes").pop(0)
@ -159,7 +155,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEquals(expected_values[i][0], gle.account) self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit) self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit) self.assertEquals(expected_values[i][2], gle.credit)
set_perpetual_inventory(0) set_perpetual_inventory(0, pi.company)
def test_purchase_invoice_calculation(self): def test_purchase_invoice_calculation(self):
pi = frappe.copy_doc(test_records[0]) pi = frappe.copy_doc(test_records[0])

View File

@ -400,19 +400,6 @@ cur_frm.set_query("income_account", "items", function(doc) {
} }
}); });
// expense account
if (frappe.sys_defaults.auto_accounting_for_stock) {
cur_frm.fields_dict['items'].grid.get_field('expense_account').get_query = function(doc) {
return {
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
"is_group": 0
}
}
}
}
// Cost Center in Details Table // Cost Center in Details Table
// ----------------------------- // -----------------------------
@ -502,6 +489,21 @@ frappe.ui.form.on('Sales Invoice', {
filters: {'project': doc.project} filters: {'project': doc.project}
} }
} }
// expense account
frm.fields_dict['items'].grid.get_field('expense_account').get_query = function(doc) {
if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
return {
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
"is_group": 0
}
}
}
}
}, },
project: function(frm){ project: function(frm){

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
import frappe.defaults import frappe.defaults
from frappe.utils import cint, flt from frappe.utils import cint, flt
from frappe import _, msgprint, throw from frappe import _, msgprint, throw
@ -559,6 +559,8 @@ class SalesInvoice(SellingController):
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note)) throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
if not self.grand_total: if not self.grand_total:
return return
@ -580,11 +582,11 @@ class SalesInvoice(SellingController):
self.doctype, self.return_against if cint(self.is_return) else self.name) self.doctype, self.return_against if cint(self.is_return) else self.name)
if repost_future_gle and cint(self.update_stock) \ if repost_future_gle and cint(self.update_stock) \
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): and cint(auto_accounting_for_stock):
items, warehouses = self.get_items_and_warehouses() items, warehouses = self.get_items_and_warehouses()
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items) update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
elif self.docstatus == 2 and cint(self.update_stock) \ elif self.docstatus == 2 and cint(self.update_stock) \
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): and cint(auto_accounting_for_stock):
from erpnext.accounts.general_ledger import delete_gl_entries from erpnext.accounts.general_ledger import delete_gl_entries
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name) delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
@ -672,8 +674,8 @@ class SalesInvoice(SellingController):
) )
# expense account gl entries # expense account gl entries
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \ if cint(self.update_stock) and \
and cint(self.update_stock): erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries() gl_entries += super(SalesInvoice, self).get_gl_entries()
def make_pos_gl_entries(self, gl_entries): def make_pos_gl_entries(self, gl_entries):

View File

@ -488,8 +488,8 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8) self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
def test_sales_invoice_gl_entry_without_perpetual_inventory(self): def test_sales_invoice_gl_entry_without_perpetual_inventory(self):
set_perpetual_inventory(0)
si = frappe.copy_doc(test_records[1]) si = frappe.copy_doc(test_records[1])
set_perpetual_inventory(0, si.company)
si.insert() si.insert()
si.submit() si.submit()
@ -617,6 +617,7 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(expected_gl_entries[i][2], gle.credit) self.assertEquals(expected_gl_entries[i][2], gle.credit)
si.cancel() si.cancel()
frappe.delete_doc('Sales Invoice', si.name)
gle = frappe.db.sql("""select * from `tabGL Entry` gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name) where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe.utils import flt, cstr, cint from frappe.utils import flt, cstr, cint
from frappe import _ from frappe import _
from frappe.model.meta import get_field_precision from frappe.model.meta import get_field_precision
@ -80,7 +80,7 @@ def check_if_in_list(gle, gl_map):
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False): def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
if not from_repost: if not from_repost:
validate_account_for_auto_accounting_for_stock(gl_map) validate_account_for_perpetual_inventory(gl_map)
round_off_debit_credit(gl_map) round_off_debit_credit(gl_map)
@ -100,8 +100,8 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost) gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
gle.submit() gle.submit()
def validate_account_for_auto_accounting_for_stock(gl_map): def validate_account_for_perpetual_inventory(gl_map):
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \ if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)) \
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 is_group=0""")] where account_type = 'Stock' and is_group=0""")]

View File

@ -227,7 +227,7 @@ class GrossProfitGenerator(object):
if not average_buying_rate: if not average_buying_rate:
average_buying_rate = get_valuation_rate(item_code, row.warehouse, average_buying_rate = get_valuation_rate(item_code, row.warehouse,
row.parenttype, row.parent, allow_zero_rate=True, row.parenttype, row.parent, allow_zero_rate=True,
currency=self.filters.currency) currency=self.filters.currency, company=self.filters.company)
self.average_buying_rate[item_code] = flt(average_buying_rate) self.average_buying_rate[item_code] = flt(average_buying_rate)

View File

@ -227,7 +227,7 @@ class BuyingController(StockController):
}) })
if not rm.rate: if not rm.rate:
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse, rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
self.doctype, self.name, currency=self.company_currency) self.doctype, self.name, currency=self.company_currency, company = self.company)
else: else:
rm.rate = bom_item.rate rm.rate = bom_item.rate

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe.utils import cint, flt, cstr from frappe.utils import cint, flt, cstr
from frappe import msgprint, _ from frappe import msgprint, _
import frappe.defaults import frappe.defaults
@ -21,7 +21,7 @@ class StockController(AccountsController):
if self.docstatus == 2: if self.docstatus == 2:
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(erpnext.is_perpetual_inventory_enabled(self.company)):
warehouse_account = get_warehouse_account_map() warehouse_account = get_warehouse_account_map()
if self.docstatus==1: if self.docstatus==1:
@ -95,7 +95,7 @@ class StockController(AccountsController):
def update_stock_ledger_entries(self, sle): def update_stock_ledger_entries(self, sle):
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse, sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
self.doctype, self.name, currency=self.company_currency) self.doctype, self.name, currency=self.company_currency, company=self.company)
sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate) sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate)
sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate) sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -8,7 +8,7 @@ On receipt of items in a particular warehouse, the balance in the Warehouse Acco
* Activate Perpetual Inventory * Activate Perpetual Inventory
> Explore > Accounts > Accounts Settings > "Make Accounting Entry For Every Stock Movement" > Setup > Company > Stock Settings > "Enable Perpetual Inventory"
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-1.png"> <img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-1.png">

View File

@ -1,5 +1,5 @@
execute:import unidecode # new requirement execute:import unidecode # new requirement
erpnext.patches.v8_0.move_perpetual_inventory_setting
erpnext.patches.v4_0.validate_v3_patch erpnext.patches.v4_0.validate_v3_patch
erpnext.patches.v4_0.fix_employee_user_id erpnext.patches.v4_0.fix_employee_user_id
erpnext.patches.v4_0.remove_employee_role_if_no_employee erpnext.patches.v4_0.remove_employee_role_if_no_employee

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe import _ from frappe import _
from frappe.utils import cint from frappe.utils import cint
from frappe.utils.nestedset import rebuild_tree from frappe.utils.nestedset import rebuild_tree
@ -51,7 +51,8 @@ def check_is_warehouse_associated_with_company():
def make_warehouse_nestedset(company=None): def make_warehouse_nestedset(company=None):
validate_parent_account_for_warehouse(company) validate_parent_account_for_warehouse(company)
stock_account_group = get_stock_account_group(company.name) stock_account_group = get_stock_account_group(company.name)
if not stock_account_group and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): enable_perpetual_inventory = cint(erpnext.is_perpetual_inventory_enabled(company)) or 0
if not stock_account_group and enable_perpetual_inventory:
return return
if company: if company:
@ -65,14 +66,14 @@ def make_warehouse_nestedset(company=None):
create_default_warehouse_group(company, stock_account_group, ignore_mandatory) create_default_warehouse_group(company, stock_account_group, ignore_mandatory)
set_parent_to_warehouse(warehouse_group, company) set_parent_to_warehouse(warehouse_group, company)
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): if enable_perpetual_inventory:
set_parent_to_warehouse_account(company) set_parent_to_warehouse_account(company)
def validate_parent_account_for_warehouse(company=None): def validate_parent_account_for_warehouse(company=None):
if not company: if not company:
return return
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): if cint(erpnext.is_perpetual_inventory_enabled(company)):
parent_account = frappe.db.sql("""select name from tabAccount parent_account = frappe.db.sql("""select name from tabAccount
where account_type='Stock' and company=%s and is_group=1 where account_type='Stock' and company=%s and is_group=1
and (warehouse is null or warehouse = '')""", company.name) and (warehouse is null or warehouse = '')""", company.name)

View File

@ -2,18 +2,16 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
def execute(): def execute():
if not frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock"):
return
frappe.reload_doctype("Account") frappe.reload_doctype("Account")
warehouses = frappe.db.sql_list("""select name from tabAccount warehouses = frappe.db.sql_list("""select name, company from tabAccount
where account_type = 'Stock' and is_group = 0 where account_type = 'Stock' and is_group = 0
and (warehouse is null or warehouse = '')""") and (warehouse is null or warehouse = '')""", as_dict)
if warehouses: warehouses = [d.name for d in warehouses if erpnext.is_perpetual_inventory_enabled(d.company)]
if len(warehouses) > 0:
warehouses = set_warehouse_for_stock_account(warehouses) warehouses = set_warehouse_for_stock_account(warehouses)
if not warehouses: if not warehouses:
return return

View File

@ -8,17 +8,16 @@ from erpnext.stock import get_warehouse_account_map
from erpnext.controllers.stock_controller import update_gl_entries_after 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")): company_list = frappe.db.sql_list("""Select name from tabCompany where enable_perpetual_inventory = 1""")
return
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_map() 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", fields=["name", "company"], filters={"docstatus": 1, "update_stock": 1}):
pi_doc = frappe.get_doc("Purchase Invoice", pi.name) if pi.company in company_list:
items, warehouses = pi_doc.get_items_and_warehouses() pi_doc = frappe.get_doc("Purchase Invoice", pi.name)
update_gl_entries_after(pi_doc.posting_date, pi_doc.posting_time, warehouses, items, wh_account) items, warehouses = pi_doc.get_items_and_warehouses()
update_gl_entries_after(pi_doc.posting_date, pi_doc.posting_time, warehouses, items, wh_account)
frappe.db.commit() frappe.db.commit()

View File

@ -6,13 +6,11 @@ import frappe
from frappe.utils import cint from frappe.utils import cint
def execute(): def execute():
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
return
frappe.reload_doctype("Purchase Invoice") frappe.reload_doctype("Purchase Invoice")
for pi in frappe.db.sql("""select name from `tabPurchase Invoice` for pi in frappe.db.sql("""select name from `tabPurchase Invoice`
where update_stock=1 and docstatus=1 order by posting_date asc""", as_dict=1): where company in(select name from tabCompany where enable_perpetual_inventory = 1) and
update_stock=1 and docstatus=1 order by posting_date asc""", as_dict=1):
frappe.db.sql("""delete from `tabGL Entry` frappe.db.sql("""delete from `tabGL Entry`
where voucher_type = 'Purchase Invoice' and voucher_no = %s""", pi.name) where voucher_type = 'Purchase Invoice' and voucher_no = %s""", pi.name)

View File

@ -0,0 +1,13 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doctype('Company')
enabled = frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock") or 0
for data in frappe.get_all('Company', fields = ["name"]):
doc = frappe.get_doc('Company', data.name)
doc.enable_perpetual_inventory = enabled
doc.save(ignore_permissions=True)

View File

@ -31,6 +31,12 @@ $.extend(erpnext, {
} }
}, },
is_perpetual_inventory_enabled: function(company) {
if(company) {
return frappe.get_doc(":Company", company).enable_perpetual_inventory
}
},
setup_serial_no: function() { setup_serial_no: function() {
var grid_row = cur_frm.open_grid_row(); var grid_row = cur_frm.open_grid_row();
if(!grid_row || !grid_row.grid_form.fields_dict.serial_no || if(!grid_row || !grid_row.grid_form.fields_dict.serial_no ||

View File

@ -156,7 +156,7 @@ erpnext.company.setup_queries = function(frm) {
erpnext.company.set_custom_query(frm, v); erpnext.company.set_custom_query(frm, v);
}); });
if (frappe.sys_defaults.auto_accounting_for_stock) { if (frm.doc.enable_perpetual_inventory) {
$.each([ $.each([
["stock_adjustment_account", ["stock_adjustment_account",
{"root_type": "Expense", "account_type": "Stock Adjustment"}], {"root_type": "Expense", "account_type": "Stock Adjustment"}],

View File

@ -1122,6 +1122,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "enable_perpetual_inventory",
"fieldtype": "Check",
"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": "Enable Perpetual Inventory",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -1243,6 +1274,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1777,7 +1809,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-06-14 11:06:33.629948", "modified": "2017-06-15 19:46:10.875108",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Company", "name": "Company",

View File

@ -33,6 +33,7 @@ class Company(Document):
self.validate_default_accounts() self.validate_default_accounts()
self.validate_currency() self.validate_currency()
self.validate_coa_input() self.validate_coa_input()
self.validate_perpetual_inventory()
def validate_abbr(self): def validate_abbr(self):
if not self.abbr: if not self.abbr:
@ -88,6 +89,10 @@ class Company(Document):
if self.default_currency: if self.default_currency:
frappe.db.set_value("Currency", self.default_currency, "enabled", 1) frappe.db.set_value("Currency", self.default_currency, "enabled", 1)
if hasattr(frappe.local, 'enable_perpetual_inventory') and \
self.name in frappe.local.enable_perpetual_inventory:
frappe.local.enable_perpetual_inventory[self.name] = self.enable_perpetual_inventory
frappe.clear_cache() frappe.clear_cache()
def install_country_fixtures(self): def install_country_fixtures(self):
@ -139,6 +144,12 @@ class Company(Document):
if not self.chart_of_accounts: if not self.chart_of_accounts:
self.chart_of_accounts = "Standard" self.chart_of_accounts = "Standard"
def validate_perpetual_inventory(self):
if not self.get("__islocal"):
if cint(self.enable_perpetual_inventory) == 1 and not self.default_inventory_account:
frappe.msgprint(_("Set default inventory account for perpetual inventory"),
alert=True, indicator='orange')
def set_default_accounts(self): def set_default_accounts(self):
self._set_default_account("default_cash_account", "Cash") self._set_default_account("default_cash_account", "Cash")
self._set_default_account("default_bank_account", "Bank") self._set_default_account("default_bank_account", "Bank")
@ -146,7 +157,7 @@ class Company(Document):
self._set_default_account("accumulated_depreciation_account", "Accumulated Depreciation") self._set_default_account("accumulated_depreciation_account", "Accumulated Depreciation")
self._set_default_account("depreciation_expense_account", "Depreciation") self._set_default_account("depreciation_expense_account", "Depreciation")
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")): if self.enable_perpetual_inventory:
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("default_inventory_account", "Stock")
self._set_default_account("stock_adjustment_account", "Stock Adjustment") self._set_default_account("stock_adjustment_account", "Stock Adjustment")

View File

@ -85,6 +85,7 @@ def create_fiscal_year_and_company(args):
frappe.get_doc({ frappe.get_doc({
"doctype":"Company", "doctype":"Company",
'company_name':args.get('company_name').strip(), 'company_name':args.get('company_name').strip(),
'enable_perpetual_inventory': 1,
'abbr':args.get('company_abbr'), 'abbr':args.get('company_abbr'),
'default_currency':args.get('currency'), 'default_currency':args.get('currency'),
'country': args.get('country'), 'country': args.get('country'),
@ -159,10 +160,6 @@ def set_defaults(args):
frappe.db.set_value("System Settings", None, "email_footer_address", args.get("company")) frappe.db.set_value("System Settings", None, "email_footer_address", args.get("company"))
accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.auto_accounting_for_stock = 1
accounts_settings.save()
stock_settings = frappe.get_doc("Stock Settings") stock_settings = frappe.get_doc("Stock Settings")
stock_settings.item_naming_by = "Item Code" stock_settings.item_naming_by = "Item Code"
stock_settings.valuation_method = "FIFO" stock_settings.valuation_method = "FIFO"

View File

@ -27,8 +27,8 @@ def boot_session(bootinfo):
bootinfo.setup_complete = frappe.db.sql("""select name from bootinfo.setup_complete = frappe.db.sql("""select name from
tabCompany limit 1""") and 'Yes' or 'No' tabCompany limit 1""") and 'Yes' or 'No'
bootinfo.docs += frappe.db.sql("""select name, default_currency, cost_center, bootinfo.docs += frappe.db.sql("""select name, default_currency, cost_center, default_terms,
default_terms, default_letter_head, default_bank_account from `tabCompany`""", default_letter_head, default_bank_account, enable_perpetual_inventory from `tabCompany`""",
as_dict=1, update={"doctype":":Company"}) as_dict=1, update={"doctype":":Company"})
def load_country_and_currency(bootinfo): def load_country_and_currency(bootinfo):

View File

@ -38,8 +38,9 @@ frappe.ui.form.on("Delivery Note", {
} }
}); });
if (frappe.sys_defaults.auto_accounting_for_stock) {
frm.set_query('expense_account', 'items', function(doc, cdt, cdn) { frm.set_query('expense_account', 'items', function(doc, cdt, cdn) {
if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
return { return {
filters: { filters: {
"report_type": "Profit and Loss", "report_type": "Profit and Loss",
@ -47,17 +48,20 @@ frappe.ui.form.on("Delivery Note", {
"is_group": 0 "is_group": 0
} }
} }
}); }
});
frm.set_query('cost_center', 'items', function(doc, cdt, cdn) { frm.set_query('cost_center', 'items', function(doc, cdt, cdn) {
if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
return { return {
filters: { filters: {
'company': doc.company, 'company': doc.company,
"is_group": 0 "is_group": 0
} }
} }
}); }
} });
$.extend(frm.cscript, new erpnext.stock.DeliveryNoteController({frm: frm})); $.extend(frm.cscript, new erpnext.stock.DeliveryNoteController({frm: frm}));
}, },
@ -137,7 +141,7 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
if (doc.docstatus==1) { if (doc.docstatus==1) {
this.show_stock_ledger(); this.show_stock_ledger();
if (cint(frappe.defaults.get_default("auto_accounting_for_stock"))) { if (erpnext.is_perpetual_inventory_enabled(doc.company)) {
this.show_general_ledger(); this.show_general_ledger();
} }
if (this.frm.has_perm("submit") && doc.status !== "Closed") { if (this.frm.has_perm("submit") && doc.status !== "Closed") {
@ -164,10 +168,6 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
__("Status")) __("Status"))
} }
erpnext.stock.delivery_note.set_print_hide(doc, dt, dn); erpnext.stock.delivery_note.set_print_hide(doc, dt, dn);
// unhide expense_account and cost_center is auto_accounting_for_stock enabled
var aii_enabled = cint(frappe.sys_defaults.auto_accounting_for_stock)
this.frm.fields_dict["items"].grid.set_column_disp(["expense_account", "cost_center"], aii_enabled);
}, },
make_sales_invoice: function() { make_sales_invoice: function() {
@ -225,6 +225,24 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
}); });
frappe.ui.form.on('Delivery Note', {
setup: function(frm) {
if(frm.doc.company) {
frm.trigger("unhide_account_head");
}
},
company: function(frm) {
frm.trigger("unhide_account_head");
},
unhide_account_head: function(frm) {
// unhide expense_account and cost_center if perpetual inventory is enabled in the company
var aii_enabled = erpnext.is_perpetual_inventory_enabled(frm.doc.company)
frm.fields_dict["items"].grid.set_column_disp(["expense_account", "cost_center"], aii_enabled);
}
})
erpnext.stock.delivery_note.set_print_hide = function(doc, cdt, cdn){ erpnext.stock.delivery_note.set_print_hide = function(doc, cdt, cdn){
var dn_fields = frappe.meta.docfield_map['Delivery Note']; var dn_fields = frappe.meta.docfield_map['Delivery Note'];

View File

@ -47,9 +47,8 @@ class TestDeliveryNote(unittest.TestCase):
self.assertRaises(frappe.ValidationError, frappe.get_doc(si).insert) self.assertRaises(frappe.ValidationError, frappe.get_doc(si).insert)
def test_delivery_note_no_gl_entry(self): def test_delivery_note_no_gl_entry(self):
set_perpetual_inventory(0) company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 0) set_perpetual_inventory(0, company)
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_queue = json.loads(get_previous_sle({ stock_queue = json.loads(get_previous_sle({
@ -68,8 +67,9 @@ class TestDeliveryNote(unittest.TestCase):
self.assertFalse(get_gl_entries("Delivery Note", dn.name)) self.assertFalse(get_gl_entries("Delivery Note", dn.name))
def test_delivery_note_gl_entry(self): def test_delivery_note_gl_entry(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) set_perpetual_inventory(1, company)
set_valuation_method("_Test Item", "FIFO") set_valuation_method("_Test Item", "FIFO")
make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100) make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
@ -115,10 +115,11 @@ class TestDeliveryNote(unittest.TestCase):
dn.cancel() dn.cancel()
self.assertFalse(get_gl_entries("Delivery Note", dn.name)) self.assertFalse(get_gl_entries("Delivery Note", dn.name))
set_perpetual_inventory(0) set_perpetual_inventory(0, company)
def test_delivery_note_gl_entry_packing_item(self): def test_delivery_note_gl_entry_packing_item(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, basic_rate=100) make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, basic_rate=100)
make_stock_entry(item_code="_Test Item Home Desktop 100", make_stock_entry(item_code="_Test Item Home Desktop 100",
@ -156,7 +157,7 @@ class TestDeliveryNote(unittest.TestCase):
dn.cancel() dn.cancel()
self.assertFalse(get_gl_entries("Delivery Note", dn.name)) self.assertFalse(get_gl_entries("Delivery Note", dn.name))
set_perpetual_inventory(0) set_perpetual_inventory(0, company)
def test_serialized(self): def test_serialized(self):
se = make_serialized_item() se = make_serialized_item()
@ -196,7 +197,8 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEquals(cstr(serial_no.get(field)), value) self.assertEquals(cstr(serial_no.get(field)), value)
def test_sales_return_for_non_bundled_items(self): def test_sales_return_for_non_bundled_items(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
@ -230,10 +232,11 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEquals(gle_warehouse_amount, stock_value_difference) self.assertEquals(gle_warehouse_amount, stock_value_difference)
set_perpetual_inventory(0) set_perpetual_inventory(0, company)
def test_return_single_item_from_bundled_items(self): def test_return_single_item_from_bundled_items(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100) create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
@ -270,10 +273,11 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEquals(gle_warehouse_amount, stock_value_difference) self.assertEquals(gle_warehouse_amount, stock_value_difference)
set_perpetual_inventory(0) set_perpetual_inventory(0, company)
def test_return_entire_bundled_items(self): def test_return_entire_bundled_items(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
create_stock_reconciliation(item_code="_Test Item", create_stock_reconciliation(item_code="_Test Item",
target="_Test Warehouse - _TC", qty=50, rate=100) target="_Test Warehouse - _TC", qty=50, rate=100)
@ -312,7 +316,7 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEquals(gle_warehouse_amount, 1400) self.assertEquals(gle_warehouse_amount, 1400)
set_perpetual_inventory(0) set_perpetual_inventory(0, company)
def test_return_for_serialized_items(self): def test_return_for_serialized_items(self):
se = make_serialized_item() se = make_serialized_item()
@ -350,7 +354,8 @@ class TestDeliveryNote(unittest.TestCase):
}) })
def test_delivery_of_bundled_items_to_target_warehouse(self): def test_delivery_of_bundled_items_to_target_warehouse(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
set_valuation_method("_Test Item", "FIFO") set_valuation_method("_Test Item", "FIFO")
set_valuation_method("_Test Item Home Desktop 100", "FIFO") set_valuation_method("_Test Item Home Desktop 100", "FIFO")
@ -418,7 +423,7 @@ class TestDeliveryNote(unittest.TestCase):
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
set_perpetual_inventory(0) set_perpetual_inventory(0, company)
def test_closed_delivery_note(self): def test_closed_delivery_note(self):
from erpnext.stock.doctype.delivery_note.delivery_note import update_delivery_note_status from erpnext.stock.doctype.delivery_note.delivery_note import update_delivery_note_status

View File

@ -5,13 +5,13 @@
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, unittest import frappe, unittest, erpnext
from frappe.utils import flt from frappe.utils import flt
from erpnext.stock.doctype.material_request.material_request import raise_production_orders from erpnext.stock.doctype.material_request.material_request import raise_production_orders
class TestMaterialRequest(unittest.TestCase): class TestMaterialRequest(unittest.TestCase):
def setUp(self): def setUp(self):
frappe.defaults.set_global_default("auto_accounting_for_stock", 0) erpnext.set_perpetual_inventory(0)
def test_make_purchase_order(self): def test_make_purchase_order(self):
from erpnext.stock.doctype.material_request.material_request import make_purchase_order from erpnext.stock.doctype.material_request.material_request import make_purchase_order

View File

@ -33,6 +33,21 @@ frappe.ui.form.on("Purchase Receipt", {
} }
}); });
},
refresh: function(frm) {
if(frm.doc.company) {
frm.trigger("toggle_display_account_head");
}
},
company: function(frm) {
frm.trigger("toggle_display_account_head");
},
toggle_display_account_head: function(frm) {
var enabled = erpnext.is_perpetual_inventory_enabled(frm.doc.company)
frm.fields_dict["items"].grid.set_column_disp(["cost_center"], enabled);
} }
}); });
@ -47,7 +62,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
this._super(); this._super();
if(this.frm.doc.docstatus===1) { if(this.frm.doc.docstatus===1) {
this.show_stock_ledger(); this.show_stock_ledger();
if (cint(frappe.defaults.get_default("auto_accounting_for_stock"))) { if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
this.show_general_ledger(); this.show_general_ledger();
} }
} }

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import unittest
import frappe import frappe, erpnext
import frappe.defaults 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
@ -30,7 +30,8 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertRaises(frappe.ValidationError, frappe.get_doc(pi).submit) self.assertRaises(frappe.ValidationError, frappe.get_doc(pi).submit)
def test_purchase_receipt_no_gl_entry(self): def test_purchase_receipt_no_gl_entry(self):
set_perpetual_inventory(0) company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(0, company)
existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item", existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "stock_value") "warehouse": "_Test Warehouse - _TC"}, "stock_value")
@ -50,9 +51,9 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertFalse(get_gl_entries("Purchase Receipt", pr.name)) self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
def test_purchase_receipt_gl_entry(self): def test_purchase_receipt_gl_entry(self):
set_perpetual_inventory()
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1)
pr = frappe.copy_doc(test_records[0]) pr = frappe.copy_doc(test_records[0])
set_perpetual_inventory(1, pr.company)
self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
pr.insert() pr.insert()
pr.submit() pr.submit()
@ -84,7 +85,7 @@ class TestPurchaseReceipt(unittest.TestCase):
pr.cancel() pr.cancel()
self.assertFalse(get_gl_entries("Purchase Receipt", pr.name)) self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
set_perpetual_inventory(0) set_perpetual_inventory(0, pr.company)
def test_subcontracting(self): def test_subcontracting(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry

View File

@ -13,6 +13,7 @@
"editable_grid": 1, "editable_grid": 1,
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -42,6 +43,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -70,6 +72,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -103,6 +106,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -131,6 +135,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -161,6 +166,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -190,6 +196,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -222,6 +229,7 @@
"width": "300px" "width": "300px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -249,6 +257,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -278,6 +287,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -308,6 +318,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -336,6 +347,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -368,6 +380,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -400,6 +413,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -432,6 +446,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -459,6 +474,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -492,6 +508,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -525,6 +542,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -557,6 +575,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -585,6 +604,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -614,6 +634,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -643,6 +664,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -670,6 +692,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -699,6 +722,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -726,6 +750,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -759,6 +784,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -790,6 +816,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -817,6 +844,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -850,6 +878,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -883,6 +912,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -912,6 +942,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -940,6 +971,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -970,6 +1002,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1000,6 +1033,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1028,6 +1062,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1058,6 +1093,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1088,6 +1124,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1116,6 +1153,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -1149,6 +1187,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1182,6 +1221,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1214,6 +1254,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1242,6 +1283,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1275,6 +1317,7 @@
"width": "150px" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1305,6 +1348,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1337,6 +1381,7 @@
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1365,6 +1410,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1395,6 +1441,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1426,6 +1473,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1455,6 +1503,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1483,6 +1532,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1511,6 +1561,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1540,12 +1591,13 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": ":Company", "default": ":Company",
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "depends_on": "",
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -1571,6 +1623,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1603,6 +1656,7 @@
"width": "150px" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1630,6 +1684,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1659,6 +1714,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1689,6 +1745,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1718,6 +1775,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1746,6 +1804,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1777,6 +1836,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1809,6 +1869,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1842,6 +1903,7 @@
"width": "150px" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1875,6 +1937,7 @@
"width": "150px" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1908,6 +1971,7 @@
"width": "80px" "width": "80px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1939,6 +2003,7 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1979,7 +2044,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-04-19 11:54:00.260886", "modified": "2017-06-16 17:23:01.404744",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt Item", "name": "Purchase Receipt Item",

View File

@ -67,6 +67,10 @@ frappe.ui.form.on('Stock Entry', {
}); });
}); });
} }
if(frm.doc.company) {
frm.trigger("toggle_display_account_head");
}
}, },
purpose: function(frm) { purpose: function(frm) {
frm.fields_dict.items.grid.refresh(); frm.fields_dict.items.grid.refresh();
@ -78,6 +82,7 @@ frappe.ui.form.on('Stock Entry', {
if(company_doc.default_letter_head) { if(company_doc.default_letter_head) {
frm.set_value("letter_head", company_doc.default_letter_head); frm.set_value("letter_head", company_doc.default_letter_head);
} }
frm.trigger("toggle_display_account_head");
} }
}, },
set_serial_no: function(frm, cdt, cdn) { set_serial_no: function(frm, cdt, cdn) {
@ -98,6 +103,10 @@ frappe.ui.form.on('Stock Entry', {
} }
}); });
}, },
toggle_display_account_head: function(frm) {
var enabled = erpnext.is_perpetual_inventory_enabled(frm.doc.company);
frm.fields_dict["items"].grid.set_column_disp(["cost_center", "expense_account"], enabled);
}
}) })
frappe.ui.form.on('Stock Entry Detail', { frappe.ui.form.on('Stock Entry Detail', {
@ -213,17 +222,19 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}; };
}); });
if(cint(frappe.defaults.get_default("auto_accounting_for_stock"))) { if(me.frm.doc.company && erpnext.is_perpetual_inventory_enabled(me.frm.doc.company)) {
this.frm.add_fetch("company", "stock_adjustment_account", "expense_account"); this.frm.add_fetch("company", "stock_adjustment_account", "expense_account");
this.frm.fields_dict.items.grid.get_field('expense_account').get_query = }
function() {
return { this.frm.fields_dict.items.grid.get_field('expense_account').get_query = function() {
filters: { if (erpnext.is_perpetual_inventory_enabled(me.frm.doc.company)) {
"company": me.frm.doc.company, return {
"is_group": 0 filters: {
} "company": me.frm.doc.company,
"is_group": 0
} }
} }
}
} }
this.frm.set_indicator_formatter('item_code', this.frm.set_indicator_formatter('item_code',
@ -254,7 +265,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
this.toggle_related_fields(this.frm.doc); this.toggle_related_fields(this.frm.doc);
this.toggle_enable_bom(); this.toggle_enable_bom();
this.show_stock_ledger(); this.show_stock_ledger();
if (cint(frappe.defaults.get_default("auto_accounting_for_stock"))) { if (this.frm.doc.docstatus===1 && erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
this.show_general_ledger(); this.show_general_ledger();
} }
erpnext.hide_company(); erpnext.hide_company();
@ -272,7 +283,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
set_default_account: function(callback) { set_default_account: function(callback) {
var me = this; var me = this;
if(cint(frappe.defaults.get_default("auto_accounting_for_stock")) && this.frm.doc.company) { if(this.frm.doc.company && erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
return this.frm.call({ return this.frm.call({
method: "erpnext.accounts.utils.get_company_default", method: "erpnext.accounts.utils.get_company_default",
args: { args: {

View File

@ -123,7 +123,8 @@ class TestStockEntry(unittest.TestCase):
self.assertTrue(item_code in items) self.assertTrue(item_code in items)
def test_material_receipt_gl_entry(self): def test_material_receipt_gl_entry(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
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")
@ -148,7 +149,8 @@ class TestStockEntry(unittest.TestCase):
where voucher_type='Stock Entry' and voucher_no=%s""", mr.name)) where voucher_type='Stock Entry' and voucher_no=%s""", mr.name))
def test_material_issue_gl_entry(self): def test_material_issue_gl_entry(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", 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")
@ -179,7 +181,8 @@ class TestStockEntry(unittest.TestCase):
where voucher_type='Stock Entry' and voucher_no=%s""", mi.name)) where voucher_type='Stock Entry' and voucher_no=%s""", mi.name))
def test_material_transfer_gl_entry(self): def test_material_transfer_gl_entry(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
create_stock_reconciliation(qty=100, rate=100) create_stock_reconciliation(qty=100, rate=100)
@ -217,7 +220,8 @@ class TestStockEntry(unittest.TestCase):
where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name)) where voucher_type='Stock Entry' and voucher_no=%s""", mtn.name))
def test_repack_no_change_in_valuation(self): def test_repack_no_change_in_valuation(self):
set_perpetual_inventory(0) company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(0, company)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
@ -238,10 +242,11 @@ class TestStockEntry(unittest.TestCase):
order by account desc""", repack.name, as_dict=1) order by account desc""", repack.name, as_dict=1)
self.assertFalse(gl_entries) self.assertFalse(gl_entries)
set_perpetual_inventory(0) set_perpetual_inventory(0, repack.company)
def test_repack_with_additional_costs(self): def test_repack_with_additional_costs(self):
set_perpetual_inventory() company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
set_perpetual_inventory(1, company)
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100) make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
repack = frappe.copy_doc(test_records[3]) repack = frappe.copy_doc(test_records[3])
@ -278,7 +283,7 @@ class TestStockEntry(unittest.TestCase):
["Expenses Included In Valuation - _TC", 0.0, 1200.0] ["Expenses Included In Valuation - _TC", 0.0, 1200.0]
]) ])
) )
set_perpetual_inventory(0) set_perpetual_inventory(0, repack.company)
def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle): def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle):
expected_sle.sort(key=lambda x: x[0]) expected_sle.sort(key=lambda x: x[0])
@ -452,7 +457,8 @@ class TestStockEntry(unittest.TestCase):
self.assertFalse(frappe.db.get_value("Serial No", serial_no, "warehouse")) self.assertFalse(frappe.db.get_value("Serial No", serial_no, "warehouse"))
def test_warehouse_company_validation(self): def test_warehouse_company_validation(self):
set_perpetual_inventory(0) company = frappe.db.get_value('Warehouse', '_Test Warehouse 2 - _TC1', 'company')
set_perpetual_inventory(0, company)
frappe.get_doc("User", "test2@example.com")\ frappe.get_doc("User", "test2@example.com")\
.add_roles("Sales User", "Sales Manager", "Stock User", "Stock Manager") .add_roles("Sales User", "Sales Manager", "Stock User", "Stock Manager")
frappe.set_user("test2@example.com") frappe.set_user("test2@example.com")
@ -465,8 +471,6 @@ class TestStockEntry(unittest.TestCase):
# permission tests # permission tests
def test_warehouse_user(self): def test_warehouse_user(self):
set_perpetual_inventory(0)
for role in ("Stock User", "Sales User"): for role in ("Stock User", "Sales User"):
set_user_permission_doctypes(doctype="Stock Entry", role=role, set_user_permission_doctypes(doctype="Stock Entry", role=role,
apply_user_permissions=1, user_permission_doctypes=["Warehouse"]) apply_user_permissions=1, user_permission_doctypes=["Warehouse"])
@ -483,6 +487,7 @@ class TestStockEntry(unittest.TestCase):
frappe.set_user("test@example.com") frappe.set_user("test@example.com")
st1 = frappe.copy_doc(test_records[0]) st1 = frappe.copy_doc(test_records[0])
st1.company = "_Test Company 1" st1.company = "_Test Company 1"
set_perpetual_inventory(0, st1.company)
st1.get("items")[0].t_warehouse="_Test Warehouse 2 - _TC1" st1.get("items")[0].t_warehouse="_Test Warehouse 2 - _TC1"
self.assertRaises(frappe.PermissionError, st1.insert) self.assertRaises(frappe.PermissionError, st1.insert)
@ -490,6 +495,8 @@ class TestStockEntry(unittest.TestCase):
st1 = frappe.copy_doc(test_records[0]) st1 = frappe.copy_doc(test_records[0])
st1.company = "_Test Company 1" st1.company = "_Test Company 1"
st1.get("items")[0].t_warehouse="_Test Warehouse 2 - _TC1" st1.get("items")[0].t_warehouse="_Test Warehouse 2 - _TC1"
st1.get("items")[0].expense_account = "Stock Adjustment - _TC1"
st1.get("items")[0].cost_center = "Main - _TC1"
st1.insert() st1.insert()
st1.submit() st1.submit()

View File

@ -960,7 +960,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:cint(frappe.sys_defaults.auto_accounting_for_stock)", "depends_on": "",
"fieldname": "expense_account", "fieldname": "expense_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -1020,7 +1020,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": ":Company", "default": ":Company",
"depends_on": "eval:cint(frappe.sys_defaults.auto_accounting_for_stock)", "depends_on": "",
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -1266,8 +1266,8 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-06-08 10:38:10.914780", "modified": "2017-06-16 17:32:56.989049",
"modified_by": "prateeksha@erpnext.com", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Entry Detail", "name": "Stock Entry Detail",
"owner": "Administrator", "owner": "Administrator",

View File

@ -31,6 +31,10 @@ frappe.ui.form.on("Stock Reconciliation", {
frm.events.get_items(frm); frm.events.get_items(frm);
}); });
} }
if(frm.doc.company) {
frm.trigger("toggle_display_account_head");
}
}, },
get_items: function(frm) { get_items: function(frm) {
@ -103,6 +107,13 @@ frappe.ui.form.on("Stock Reconciliation", {
frappe.model.set_value(cdt, cdn, "quantity_difference", flt(d.qty) - flt(d.current_qty)); frappe.model.set_value(cdt, cdn, "quantity_difference", flt(d.qty) - flt(d.current_qty));
frappe.model.set_value(cdt, cdn, "amount_difference", flt(d.amount) - flt(d.current_amount)); frappe.model.set_value(cdt, cdn, "amount_difference", flt(d.amount) - flt(d.current_amount));
} }
},
company: function(frm) {
frm.trigger("toggle_display_account_head");
},
toggle_display_account_head: function(frm) {
frm.toggle_display(['expense_account', 'cost_center'],
erpnext.is_perpetual_inventory_enabled(frm.doc.company));
} }
}); });
@ -133,7 +144,7 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
set_default_expense_account: function() { set_default_expense_account: function() {
var me = this; var me = this;
if(this.frm.doc.company) { if(this.frm.doc.company) {
if (frappe.sys_defaults.auto_accounting_for_stock && !this.frm.doc.expense_account) { if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company) && !this.frm.doc.expense_account) {
return this.frm.call({ return this.frm.call({
method: "erpnext.accounts.utils.get_company_default", method: "erpnext.accounts.utils.get_company_default",
args: { args: {
@ -155,11 +166,12 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
this.setup_posting_date_time_check(); this.setup_posting_date_time_check();
if (frappe.sys_defaults.auto_accounting_for_stock) { if (me.frm.doc.company && erpnext.is_perpetual_inventory_enabled(me.frm.doc.company)) {
this.frm.add_fetch("company", "stock_adjustment_account", "expense_account"); this.frm.add_fetch("company", "stock_adjustment_account", "expense_account");
this.frm.add_fetch("company", "cost_center", "cost_center"); this.frm.add_fetch("company", "cost_center", "cost_center");
}
this.frm.fields_dict["expense_account"].get_query = function() { this.frm.fields_dict["expense_account"].get_query = function() {
if(erpnext.is_perpetual_inventory_enabled(me.frm.doc.company)) {
return { return {
"filters": { "filters": {
'company': me.frm.doc.company, 'company': me.frm.doc.company,
@ -167,7 +179,9 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
} }
} }
} }
this.frm.fields_dict["cost_center"].get_query = function() { }
this.frm.fields_dict["cost_center"].get_query = function() {
if(erpnext.is_perpetual_inventory_enabled(me.frm.doc.company)) {
return { return {
"filters": { "filters": {
'company': me.frm.doc.company, 'company': me.frm.doc.company,
@ -181,7 +195,7 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
refresh: function() { refresh: function() {
if(this.frm.doc.docstatus==1) { if(this.frm.doc.docstatus==1) {
this.show_stock_ledger(); this.show_stock_ledger();
if (cint(frappe.defaults.get_default("auto_accounting_for_stock"))) { if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
this.show_general_ledger(); this.show_general_ledger();
} }
} }

View File

@ -320,7 +320,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "depends_on": "",
"fieldname": "expense_account", "fieldname": "expense_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -351,7 +351,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "depends_on": "",
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -477,7 +477,7 @@
"istable": 0, "istable": 0,
"max_attachments": 1, "max_attachments": 1,
"menu_index": 0, "menu_index": 0,
"modified": "2017-06-13 14:28:56.013804", "modified": "2017-06-16 17:35:54.811500",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Reconciliation", "name": "Stock Reconciliation",

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
import frappe.defaults import frappe.defaults
from frappe import msgprint, _ from frappe import msgprint, _
from frappe.utils import cstr, flt, cint from frappe.utils import cstr, flt, cint
@ -231,7 +231,7 @@ class StockReconciliation(StockController):
self.expense_account, self.cost_center) self.expense_account, self.cost_center)
def validate_expense_account(self): def validate_expense_account(self):
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): if not cint(erpnext.is_perpetual_inventory_enabled(self.company)):
return return
if not self.expense_account: if not self.expense_account:

View File

@ -423,8 +423,11 @@ def get_stock_ledger_entries(previous_sle, operator=None, order="desc", limit=No
}, previous_sle, as_dict=1, debug=debug) }, previous_sle, as_dict=1, debug=debug)
def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
allow_zero_rate=False, currency=None): allow_zero_rate=False, currency=None, company=None):
# Get valuation rate from last sle for the same item and warehouse # Get valuation rate from last sle for the same item and warehouse
if not company:
company = erpnext.get_default_company()
last_valuation_rate = frappe.db.sql("""select valuation_rate last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry` from `tabStock Ledger Entry`
where item_code = %s and warehouse = %s where item_code = %s and warehouse = %s
@ -451,7 +454,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
dict(item_code=item_code, buying=1, currency=currency), 'price_list_rate') dict(item_code=item_code, buying=1, currency=currency), 'price_list_rate')
if not allow_zero_rate and not valuation_rate \ if not allow_zero_rate and not valuation_rate \
and cint(frappe.db.get_value("Accounts Settings", None, "auto_accounting_for_stock")): and cint(erpnext.is_perpetual_inventory_enabled(company)):
frappe.local.message_log = [] frappe.local.message_log = []
frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a sample item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting/cancelling this entry").format(item_code, voucher_type, voucher_no)) frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a sample item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting/cancelling this entry").format(item_code, voucher_type, voucher_no))