mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 20:29:09 +00:00
# [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))
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.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
|