mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-15 04:45:09 +00:00
# [14.16.0](https://github.com/frappe/erpnext/compare/v14.15.1...v14.16.0) (2023-02-14) ### Bug Fixes * `amount` in `Material Request` ([f1dd923](f1dd923a50)) * `get_picked_items_details` ([7afbd92](7afbd9201d)) * `pymysql.err.ProgrammingError` ([aa3dd33](aa3dd33f56)) * Add missing 1 required positional argument: 'bill_date' ([ced9274](ced9274d1b)) * add payment hook to point of sale JS ([#33988](https://github.com/frappe/erpnext/issues/33988)) ([49fd712](49fd712966)) * allow PI cancel if linked asset is cancelled ([c98b2b5](c98b2b5918)) * Amount for debit and credit notes with 0 qty line items ([#33902](https://github.com/frappe/erpnext/issues/33902)) ([87a8c17](87a8c17314)) * Amount validation in Payment Request against Purchase Order ([#34042](https://github.com/frappe/erpnext/issues/34042)) ([c7c6123](c7c61239a3)) * BOM import failed as importer use same label field for Raw MaterialsItem table and Scrap Item table ([47d17f4](47d17f4136)) * Concurrency issues in Sales and Purchase returns ([#34019](https://github.com/frappe/erpnext/issues/34019)) ([087333a](087333abcb)) * consider `stock_qty` if `picked_qty` is zero ([df72e4a](df72e4a221)) * consider existing pick list ([466a791](466a791f68)) * currency formatting in item-wise sales history ([#33903](https://github.com/frappe/erpnext/issues/33903)) ([8e2d7bb](8e2d7bb44a)) * default due_date was wrong calculated on template "_Test Payment Term Template 1" (last day of next month) ([c8c9c50](c8c9c50993)) * **ecommerce:** throw invalid doctype error in shop by category ([#33901](https://github.com/frappe/erpnext/issues/33901)) ([1d0e71b](1d0e71bfe5)) * failed test, convert date time to string ([7228a49](7228a492ef)) * german chart of accounts "SKR03" ([#33909](https://github.com/frappe/erpnext/issues/33909)) ([02c4c55](02c4c55adc)) * Ignore mandatory fields while creating tax templates for new companies ([#34005](https://github.com/frappe/erpnext/issues/34005)) ([b0ed3c8](b0ed3c8aed)) * Ignore Payment Ledger Entry on dunning cancel (backport [#34025](https://github.com/frappe/erpnext/issues/34025)) ([#34028](https://github.com/frappe/erpnext/issues/34028)) ([699e93e](699e93e17f)) * incorrect actual qty in Bin ([01ff6a1](01ff6a1f19)) * IntegrityError while cancelling journals against cr note ([c71d035](c71d03555f)) * list view for Terms and Conditions ([#33925](https://github.com/frappe/erpnext/issues/33925)) ([bb8e232](bb8e232aea)) * negative stock error ([e0cd6c2](e0cd6c20a3)) * set per_billed based on hours when amounts are zero ([#33984](https://github.com/frappe/erpnext/issues/33984)) ([5270fbe](5270fbe01a)) * should never get cutomer price on purchase document ([#34002](https://github.com/frappe/erpnext/issues/34002)) ([6fe7600](6fe7600844)), closes [#33998](https://github.com/frappe/erpnext/issues/33998) * stock entry from item dashboard (stock levels) ([04a474d](04a474d0a1)) * **test:** `test_pick_list_for_items_with_multiple_UOM()` ([7124c0c](7124c0ca30)) * unwanted difference amount calculation on cr note and invoice with same currency ([#34020](https://github.com/frappe/erpnext/issues/34020)) ([cbafc51](cbafc51e75)) ### Features * Add filters in Loan Interest Report ([#33907](https://github.com/frappe/erpnext/issues/33907)) ([52bfb66](52bfb66729)) * add incoterm named place to RFQ ([68a1615](68a1615eae)) * mandatory and mandatory depends on in inventory dimension ([3aca84c](3aca84c43f)) * Setting to allow Sales Order creation against expired quotation ([#33952](https://github.com/frappe/erpnext/issues/33952)) ([4d0e27e](4d0e27ed2b)) ### Performance Improvements * reduce memory usage by paging through records ([3ce8dc7](3ce8dc70cb)) * reduce memory usage while migrating remarks ([c191a3f](c191a3f7c6))
150 lines
4.2 KiB
Python
150 lines
4.2 KiB
Python
import inspect
|
|
|
|
import frappe
|
|
|
|
__version__ = "14.16.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(user, "company")
|
|
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 not company 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 not company 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 not company 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 not company 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 not party_type 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 company or frappe.flags.company:
|
|
return frappe.get_cached_value("Company", company or frappe.flags.company, "country")
|
|
elif frappe.flags.country:
|
|
return frappe.flags.country
|
|
else:
|
|
return frappe.get_system_settings("country")
|
|
|
|
|
|
def allow_regional(fn):
|
|
"""Decorator to make a function regionally overridable
|
|
|
|
Example:
|
|
@erpnext.allow_regional
|
|
def myfunction():
|
|
pass"""
|
|
|
|
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
|