Files
erpnext/erpnext/__init__.py
Frappe PR Bot f59093c6b7 chore(release): Bumped to Version 15.63.0
# [15.63.0](https://github.com/frappe/erpnext/compare/v15.62.0...v15.63.0) (2025-05-27)

### Bug Fixes

* absence of rounding causing discrepancy in the valuation rate calculation (backport [#47700](https://github.com/frappe/erpnext/issues/47700)) ([#47711](https://github.com/frappe/erpnext/issues/47711)) ([f41bcc6](f41bcc6fec))
* add no_copy for lost reasons ([db97dbd](db97dbd394))
* create Quality Inspection button not showing (backport [#47746](https://github.com/frappe/erpnext/issues/47746)) ([#47750](https://github.com/frappe/erpnext/issues/47750)) ([60dfe36](60dfe36195))
* display stock value in currency format in chart warehouse wise stock value ([ba009f4](ba009f4626))
* do not update same field twice ([63ba27e](63ba27e359))
* exchange rate not being fetched when creating supplier quotation from MR ([2c22615](2c22615b6b))
* filter of item for manufacture type material request (backport [#47712](https://github.com/frappe/erpnext/issues/47712)) ([#47717](https://github.com/frappe/erpnext/issues/47717)) ([2961e59](2961e595c2))
* handle multiselect filters for tree doctypes in Customer Ledger Summary Report ([f783bf6](f783bf60a4))
* Headline rendered twice on first save ([f94a14c](f94a14c06a))
* include rejected amount in PI/PR overbilling validation logic ([#47572](https://github.com/frappe/erpnext/issues/47572)) ([cd1c10a](cd1c10a43f))
* incorrect inventory dimension for material transfer (backport [#47592](https://github.com/frappe/erpnext/issues/47592)) ([#47644](https://github.com/frappe/erpnext/issues/47644)) ([9a78283](9a78283ecb))
* incorrect valuation rate due to positive qty (backport [#47686](https://github.com/frappe/erpnext/issues/47686)) ([#47688](https://github.com/frappe/erpnext/issues/47688)) ([62aa1cd](62aa1cdb33))
* linter ([c44493f](c44493fd7e))
* Linter (due to conflicts resolved on gh) ([37f4cf5](37f4cf5367))
* Linters ([91e167f](91e167fe72))
* made changes specifically for value adjustment entry ([74e29f1](74e29f1218))
* Merge conflicts ([3deb11e](3deb11e5b2))
* only include advances within the tcs period ([a2f5975](a2f5975133))
* party account based on party type's account type ([d3d22f6](d3d22f699e))
* patch to rename group_by filter in custom reports (backport [#47709](https://github.com/frappe/erpnext/issues/47709)) ([#47730](https://github.com/frappe/erpnext/issues/47730)) ([a137944](a137944955))
* patch to set status cancelled for already cancelled pos invoices (backport [#47725](https://github.com/frappe/erpnext/issues/47725)) ([#47759](https://github.com/frappe/erpnext/issues/47759)) ([4fd1af2](4fd1af2118))
* **portal:** User cannot create 0 qty SQ from RFQ ([f95a3f5](f95a3f5b8b))
* pos invoice status not updating on cancel (backport [#47556](https://github.com/frappe/erpnext/issues/47556)) ([#47657](https://github.com/frappe/erpnext/issues/47657)) ([db318a4](db318a4e9b))
* prettier ([0f22646](0f2264658f))
* prettier ([2c8db09](2c8db092a0))
* Relabel unit price settings for more clarity ([8891f46](8891f46a22))
* setting paid amount to 0 when is_paid is unchecked in purchase invoice ([895231a](895231a8a7))
* show general ledger in doc currency in Process Statement Of Accounts ([b3cbbf2](b3cbbf2ce3))
* skip drop ship items (backport [#47670](https://github.com/frappe/erpnext/issues/47670)) ([#47718](https://github.com/frappe/erpnext/issues/47718)) ([e058885](e05888502f))
* skip last purchase rate for free item (backport [#47693](https://github.com/frappe/erpnext/issues/47693)) ([#47696](https://github.com/frappe/erpnext/issues/47696)) ([f17b7b5](f17b7b5ee9))
* space ([fe78bb6](fe78bb60c4))
* space ([194e41a](194e41a2d9))
* translate_pos_buttons ([01b0d10](01b0d1057e))
* Treat rows as Unit Price rows only until the qty is 0 ([d963601](d9636018f5))
* typo in TREE_DOCTYPES list "Terrirtory" should be "Territory" ([3d2d1ba](3d2d1ba072))
* updated value after depreciation after value adjustment ([8ed6e98](8ed6e98565))
* use pypika object `LiteralValue` for adding match conditions ([fb2df77](fb2df77da2))

### Features

* add validation for Item Tax Template on rate change ([92d5e91](92d5e91e1f))
* Unit Price Contract ([33366fc](33366fce6c))
* Unit Price Items in Buying (RFQ, SQ, PO) ([f8fa775](f8fa775af3))
2025-05-27 14:56:33 +00:00

163 lines
4.4 KiB
Python

import functools
import inspect
import frappe
from frappe.utils.user import is_website_user
__version__ = "15.63.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