mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-19 09:28:46 +00:00
# [15.116.0](https://github.com/frappe/erpnext/compare/v15.115.0...v15.116.0) (2026-07-13) ### Bug Fixes * **`frappe_crm_api`:** handle failure for `after_app_install` and `after_app_uninstall` ([983ec56](983ec5660c)) * **accounts:** clear clearance date when amending reconciled voucher (backport [#55947](https://github.com/frappe/erpnext/issues/55947)) ([5f14f2c](5f14f2ccd6)), closes [#55972](https://github.com/frappe/erpnext/issues/55972) * **accounts:** retain invoice table on opening invoice creation error (backport [#56353](https://github.com/frappe/erpnext/issues/56353)) ([#57057](https://github.com/frappe/erpnext/issues/57057)) ([cfc546c](cfc546cf3f)) * added permission checks on various whitelisted functions (backport [#56745](https://github.com/frappe/erpnext/issues/56745)) ([#56945](https://github.com/frappe/erpnext/issues/56945)) ([55e0d10](55e0d106c9)) * address review comments ([3c47adb](3c47adb021)) * block serialized to non-serialized item change when SABB exists (backport [#56773](https://github.com/frappe/erpnext/issues/56773)) ([#56774](https://github.com/frappe/erpnext/issues/56774)) ([44a7013](44a7013ab4)) * **company:** ignore user permissions for link fields having link to `Account` and `Cost Center` (backport [#56748](https://github.com/frappe/erpnext/issues/56748)) ([#56794](https://github.com/frappe/erpnext/issues/56794)) ([5666fd1](5666fd1334)) * **crm_settings:** skip allowed users check when frappe crm is installed locally ([95b3bd4](95b3bd4e1d)) * disallow editing on reversal journals ([ac2e69f](ac2e69fbfd)) * display outstanding amount using company default currency (backport [#56785](https://github.com/frappe/erpnext/issues/56785)) ([#57008](https://github.com/frappe/erpnext/issues/57008)) ([8688f1f](8688f1f51a)) * don't attempt to create SABB for non-serialized / non-batch items (backport [#56627](https://github.com/frappe/erpnext/issues/56627)) ([#56802](https://github.com/frappe/erpnext/issues/56802)) ([b0446b6](b0446b6a09)) * don't treat batch slot at FIFO queue head as qty slot ([a9330e8](a9330e8900)) * fetch asset category expense account on purchase receipt ([b7e0331](b7e0331d56)) * fetch payment entry reference amounts from invoice (backport [#56928](https://github.com/frappe/erpnext/issues/56928)) ([#57041](https://github.com/frappe/erpnext/issues/57041)) ([0f6b2b6](0f6b2b68fa)) * FIFO queue checks and incorrect entries filter in stock ledger reports ([19fc8b8](19fc8b8e6f)), closes [#43619](https://github.com/frappe/erpnext/issues/43619) * for purchases do voucher based reposting (backport [#56601](https://github.com/frappe/erpnext/issues/56601)) ([#56607](https://github.com/frappe/erpnext/issues/56607)) ([6b022a5](6b022a5a7e)) * **inactive_customers:** add allowlist for doctype filter and migrate to qb ([29dd6e6](29dd6e6681)) * incorrect import path for FrappeTestCase ([cecfcf8](cecfcf82e0)) * **journal entry:** validate opening entry against pcv on save ([2ed7c84](2ed7c84d0a)) * make represents company field in purchase invoice ignore user permissions ([b7f2769](b7f276989d)) * make trend report based-on and group-by column labels translatable ([d2d5fae](d2d5fae033)) * **manufacturing:** update work order status on partial pick-list transfer (backport [#56800](https://github.com/frappe/erpnext/issues/56800)) ([afa7288](afa72884bb)), closes [56836/#57001](https://github.com/frappe/erpnext/issues/57001) * map stock_qty in apply_price_list_on_item (backport [#56869](https://github.com/frappe/erpnext/issues/56869)) ([#57051](https://github.com/frappe/erpnext/issues/57051)) ([3e2a734](3e2a734414)) * partial delivery note against pick list ([#56985](https://github.com/frappe/erpnext/issues/56985)) ([53af4d5](53af4d53ef)) * **patch:** moved create_company_custom_fields from `pre_model_sync` to `post_model_sync` ([#56962](https://github.com/frappe/erpnext/issues/56962)) ([d0f2940](d0f29405d0)) * precision issue causing reconciliation error ([#54043](https://github.com/frappe/erpnext/issues/54043)) ([d62831d](d62831d885)) * prevent repeatable read related concurrency errors ([1ee8904](1ee8904a94)) * race condition and repeatable read in process pcv ([ae43f47](ae43f47c39)) * remove company default on cost center in stock entry detail ([b170913](b170913880)) * remove incorrect Payable account_type from Customer Deposits in Philippines CoA (backport [#57018](https://github.com/frappe/erpnext/issues/57018)) ([#57060](https://github.com/frappe/erpnext/issues/57060)) ([bd62699](bd6269918f)) * rename variant item_code/item_name when attribute abbreviation changes ([99bdef6](99bdef6baf)) * replay immutable SLE qty for serial/batch bundle valuation (backport [#56814](https://github.com/frappe/erpnext/issues/56814)) ([#56834](https://github.com/frappe/erpnext/issues/56834)) ([1cf94f5](1cf94f5501)) * resolve conflicts ([da623eb](da623eb124)) * **selling:** update sales order per billed on credit note submission ([63e85c6](63e85c6551)) * set customer group in inactive customers report test setup ([ede2a68](ede2a68afd)) * show only template items in Variant Of filter ([fde7cd5](fde7cd5345)) * **stock:** backfill transferred qty for existing pick lists ([cd61243](cd612434a4)) * **stock:** correct stock ageing value for moving average and lifo items (backport [#56693](https://github.com/frappe/erpnext/issues/56693)) ([#57016](https://github.com/frappe/erpnext/issues/57016)) ([9d654b7](9d654b7890)) * **stock:** pick list serial batch posting date ([#56957](https://github.com/frappe/erpnext/issues/56957)) ([#57014](https://github.com/frappe/erpnext/issues/57014)) ([4091188](4091188908)), closes [#56951](https://github.com/frappe/erpnext/issues/56951) * **stock:** set stock received but not billed account for purchase ([#55149](https://github.com/frappe/erpnext/issues/55149)) ([38b7042](38b7042481)) * update BOM operations when routing is changed ([de0c75b](de0c75bcba)) * update events order by date asc (backport [#56963](https://github.com/frappe/erpnext/issues/56963)) ([#57055](https://github.com/frappe/erpnext/issues/57055)) ([1cb4307](1cb4307578)) * update modified timestamp in item.json ([902a3c5](902a3c5c55)) * use change_settings decorator matching version-15-hotfix test utils ([5cedc50](5cedc50c55)) * use correct import ([db4136b](db4136b258)) * use live source warehouse valuation for internal transfer purchse receipts ([#56812](https://github.com/frappe/erpnext/issues/56812)) ([ece1c98](ece1c9872f)) * validate planned end date is not before planned start date in work order ([de6a157](de6a157773)) * validate reverse GL entries on current date under immutable ledger (backport [#56709](https://github.com/frappe/erpnext/issues/56709)) ([#56751](https://github.com/frappe/erpnext/issues/56751)) ([71a2d6e](71a2d6e43d)) * validate template and its variant in the same Pricing Rule ([3df52c7](3df52c7fc6)) ### Features * **crm_settings:** auto-update crm sync settings on frappe crm install and uninstall ([0a5daee](0a5daeed57)) * **opening invoice creation tool:** add project to opening invoice child row (backport [#54662](https://github.com/frappe/erpnext/issues/54662)) ([#56400](https://github.com/frappe/erpnext/issues/56400)) ([808109a](808109abc0)) * **sla:** filter service level agreement link by document type (backport [#56954](https://github.com/frappe/erpnext/issues/56954)) ([#56955](https://github.com/frappe/erpnext/issues/56955)) ([5166950](51669501ab)) * **stock:** support partial transfer from pick list ([02168b7](02168b7b3d)) ### Performance Improvements * avoid per-row Warehouse doc fetches in auto reorder job ([c10b86d](c10b86d538)) * batch bin lookups in delivery note stock update ([989a6b5](989a6b507d))
163 lines
4.4 KiB
Python
163 lines
4.4 KiB
Python
import functools
|
|
import inspect
|
|
|
|
import frappe
|
|
from frappe.utils.user import is_website_user
|
|
|
|
__version__ = "15.116.0"
|
|
|
|
|
|
def get_default_company(user=None):
|
|
"""Get default company for user"""
|
|
from frappe.defaults import get_user_default_as_list
|
|
|
|
if not user:
|
|
user = frappe.session.user
|
|
|
|
companies = get_user_default_as_list("company", user)
|
|
if companies:
|
|
default_company = companies[0]
|
|
else:
|
|
default_company = frappe.db.get_single_value("Global Defaults", "default_company")
|
|
|
|
return default_company
|
|
|
|
|
|
def get_default_currency():
|
|
"""Returns the currency of the default company"""
|
|
company = get_default_company()
|
|
if company:
|
|
return frappe.get_cached_value("Company", company, "default_currency")
|
|
|
|
|
|
def get_default_cost_center(company):
|
|
"""Returns the default cost center of the company"""
|
|
if not company:
|
|
return None
|
|
|
|
if not frappe.flags.company_cost_center:
|
|
frappe.flags.company_cost_center = {}
|
|
if company not in frappe.flags.company_cost_center:
|
|
frappe.flags.company_cost_center[company] = frappe.get_cached_value("Company", company, "cost_center")
|
|
return frappe.flags.company_cost_center[company]
|
|
|
|
|
|
def get_company_currency(company):
|
|
"""Returns the default company currency"""
|
|
if not frappe.flags.company_currency:
|
|
frappe.flags.company_currency = {}
|
|
if company not in frappe.flags.company_currency:
|
|
frappe.flags.company_currency[company] = frappe.db.get_value(
|
|
"Company", company, "default_currency", cache=True
|
|
)
|
|
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()
|
|
|
|
company = frappe.get_doc("Company", company)
|
|
company.enable_perpetual_inventory = enable
|
|
company.save()
|
|
|
|
|
|
def encode_company_abbr(name, company=None, abbr=None):
|
|
"""Returns name encoded with company abbreviation"""
|
|
company_abbr = abbr or frappe.get_cached_value("Company", company, "abbr")
|
|
parts = name.rsplit(" - ", 1)
|
|
|
|
if parts[-1].lower() != company_abbr.lower():
|
|
parts.append(company_abbr)
|
|
|
|
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 company not in frappe.local.enable_perpetual_inventory:
|
|
frappe.local.enable_perpetual_inventory[company] = (
|
|
frappe.get_cached_value("Company", company, "enable_perpetual_inventory") or 0
|
|
)
|
|
|
|
return frappe.local.enable_perpetual_inventory[company]
|
|
|
|
|
|
def get_default_finance_book(company=None):
|
|
if not company:
|
|
company = get_default_company()
|
|
|
|
if not hasattr(frappe.local, "default_finance_book"):
|
|
frappe.local.default_finance_book = {}
|
|
|
|
if company not in frappe.local.default_finance_book:
|
|
frappe.local.default_finance_book[company] = frappe.get_cached_value(
|
|
"Company", company, "default_finance_book"
|
|
)
|
|
|
|
return frappe.local.default_finance_book[company]
|
|
|
|
|
|
def get_party_account_type(party_type):
|
|
if not hasattr(frappe.local, "party_account_types"):
|
|
frappe.local.party_account_types = {}
|
|
|
|
if party_type not in frappe.local.party_account_types:
|
|
frappe.local.party_account_types[party_type] = (
|
|
frappe.db.get_value("Party Type", party_type, "account_type") or ""
|
|
)
|
|
|
|
return frappe.local.party_account_types[party_type]
|
|
|
|
|
|
def get_region(company=None):
|
|
"""Return the default country based on flag, company or global settings
|
|
|
|
You can also set global company flag in `frappe.flags.company`
|
|
"""
|
|
|
|
if not company:
|
|
company = frappe.local.flags.company
|
|
|
|
if company:
|
|
return frappe.get_cached_value("Company", company, "country")
|
|
|
|
return frappe.flags.country or frappe.get_system_settings("country")
|
|
|
|
|
|
def allow_regional(fn):
|
|
"""Decorator to make a function regionally overridable
|
|
|
|
Example:
|
|
@erpnext.allow_regional
|
|
def myfunction():
|
|
pass"""
|
|
|
|
@functools.wraps(fn)
|
|
def caller(*args, **kwargs):
|
|
overrides = frappe.get_hooks("regional_overrides", {}).get(get_region())
|
|
function_path = f"{inspect.getmodule(fn).__name__}.{fn.__name__}"
|
|
|
|
if not overrides or function_path not in overrides:
|
|
return fn(*args, **kwargs)
|
|
|
|
# Priority given to last installed app
|
|
return frappe.get_attr(overrides[function_path][-1])(*args, **kwargs)
|
|
|
|
return caller
|
|
|
|
|
|
def check_app_permission():
|
|
if frappe.session.user == "Administrator":
|
|
return True
|
|
|
|
if is_website_user():
|
|
return False
|
|
|
|
return True
|