diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json
index 544f4fd6640..8ea57191024 100644
--- a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json
@@ -16,6 +16,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"section_break_8",
"rate",
"section_break_9",
@@ -92,6 +93,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
+ {
+ "allow_on_submit": 1,
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"fieldname": "section_break_8",
"fieldtype": "Section Break"
diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
index 6d1040a02ad..4ff2a13eae2 100644
--- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
+++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
@@ -137,8 +137,10 @@ def get_payment_entries_for_bank_clearance(
entries = []
condition = ""
+ pe_condition = ""
if not include_reconciled_entries:
condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')"
+ pe_condition = "and (pe.clearance_date IS NULL or pe.clearance_date='0000-00-00')"
journal_entries = frappe.db.sql(
f"""
@@ -163,19 +165,20 @@ def get_payment_entries_for_bank_clearance(
payment_entries = frappe.db.sql(
f"""
select
- "Payment Entry" as payment_document, name as payment_entry,
- reference_no as cheque_number, reference_date as cheque_date,
- if(paid_from=%(account)s, paid_amount + total_taxes_and_charges, 0) as credit,
- if(paid_from=%(account)s, 0, received_amount + total_taxes_and_charges) as debit,
- posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
- if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
- from `tabPayment Entry`
+ "Payment Entry" as payment_document, pe.name as payment_entry,
+ pe.reference_no as cheque_number, pe.reference_date as cheque_date,
+ if(pe.paid_from=%(account)s, pe.paid_amount + if(pe.payment_type = 'Pay' and c.default_currency = pe.paid_from_account_currency, pe.base_total_taxes_and_charges, pe.total_taxes_and_charges) , 0) as credit,
+ if(pe.paid_from=%(account)s, 0, pe.received_amount + pe.total_taxes_and_charges) as debit,
+ pe.posting_date, ifnull(pe.party,if(pe.paid_from=%(account)s,pe.paid_to,pe.paid_from)) as against_account, pe.clearance_date,
+ if(pe.paid_to=%(account)s, pe.paid_to_account_currency, pe.paid_from_account_currency) as account_currency
+ from `tabPayment Entry` as pe
+ join `tabCompany` c on c.name = pe.company
where
- (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
- and posting_date >= %(from)s and posting_date <= %(to)s
- {condition}
+ (pe.paid_from=%(account)s or pe.paid_to=%(account)s) and pe.docstatus=1
+ and pe.posting_date >= %(from)s and pe.posting_date <= %(to)s
+ {pe_condition}
order by
- posting_date ASC, name DESC
+ pe.posting_date ASC, pe.name DESC
""",
{
"account": account,
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 37ac27f3722..46690a1a29a 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -131,18 +131,20 @@ class GLEntry(Document):
if not self.is_cancelled and not (self.party_type and self.party):
account_type = frappe.get_cached_value("Account", self.account, "account_type")
- if account_type == "Receivable":
- frappe.throw(
- _("{0} {1}: Customer is required against Receivable account {2}").format(
- self.voucher_type, self.voucher_no, self.account
+ # skipping validation for payroll entry creation in case party is not required
+ if not frappe.flags.party_not_required_for_receivable_payable:
+ if account_type == "Receivable":
+ frappe.throw(
+ _("{0} {1}: Customer is required against Receivable account {2}").format(
+ self.voucher_type, self.voucher_no, self.account
+ )
)
- )
- elif account_type == "Payable":
- frappe.throw(
- _("{0} {1}: Supplier is required against Payable account {2}").format(
- self.voucher_type, self.voucher_no, self.account
+ elif account_type == "Payable":
+ frappe.throw(
+ _("{0} {1}: Supplier is required against Payable account {2}").format(
+ self.voucher_type, self.voucher_no, self.account
+ )
)
- )
# Zero value transaction is not allowed
if not (
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index a54bae9fb96..7f71454d11d 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -542,8 +542,11 @@ class JournalEntry(AccountsController):
def validate_party(self):
for d in self.get("accounts"):
account_type = frappe.get_cached_value("Account", d.account, "account_type")
+
+ # skipping validation for payroll entry creation
+ skip_validation = frappe.flags.party_not_required_for_receivable_payable
if account_type in ["Receivable", "Payable"]:
- if not (d.party_type and d.party):
+ if not (d.party_type and d.party) and not skip_validation:
frappe.throw(
_(
"Row {0}: Party Type and Party is required for Receivable / Payable account {1}"
diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.json b/erpnext/accounts/doctype/loyalty_program/loyalty_program.json
index f4eb500b1b6..6a0c7d4ab70 100644
--- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.json
+++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.json
@@ -24,6 +24,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"help_section",
"loyalty_program_help"
],
@@ -143,6 +144,12 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
}
],
"modified": "2019-05-26 09:11:46.120251",
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json
index daee8f8c1ab..5a43e1dbf3d 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json
@@ -13,6 +13,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"section_break_4",
"invoices"
],
@@ -62,6 +63,12 @@
"label": "Cost Center",
"options": "Cost Center"
},
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"collapsible": 1,
"fieldname": "accounting_dimensions_section",
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
index 219d6089a57..a0e9183f7ba 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
@@ -28,6 +28,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"sec_break1",
"invoice_name",
"invoices",
@@ -193,6 +194,12 @@
"label": "Cost Center",
"options": "Cost Center"
},
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"depends_on": "eval:doc.party",
"description": "Only 'Payment Entries' made against this advance account are supported.",
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index fe2b806a76b..1e1a71ea707 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -5,6 +5,7 @@
import frappe
from frappe import _, msgprint, qb
from frappe.model.document import Document
+from frappe.model.meta import get_field_precision
from frappe.query_builder import Criterion
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
@@ -392,6 +393,12 @@ class PaymentReconciliation(Document):
inv.outstanding_amount = flt(entry.get("outstanding_amount"))
def get_difference_amount(self, payment_entry, invoice, allocated_amount):
+ allocated_amount_precision = get_field_precision(
+ frappe.get_meta("Payment Reconciliation Allocation").get_field("allocated_amount")
+ )
+ difference_amount_precision = get_field_precision(
+ frappe.get_meta("Payment Reconciliation Allocation").get_field("difference_amount")
+ )
difference_amount = 0
if frappe.get_cached_value(
"Account", self.receivable_payable_account, "account_currency"
@@ -399,8 +406,14 @@ class PaymentReconciliation(Document):
if invoice.get("exchange_rate") and payment_entry.get("exchange_rate", 1) != invoice.get(
"exchange_rate", 1
):
- allocated_amount_in_ref_rate = payment_entry.get("exchange_rate", 1) * allocated_amount
- allocated_amount_in_inv_rate = invoice.get("exchange_rate", 1) * allocated_amount
+ allocated_amount_in_ref_rate = flt(
+ payment_entry.get("exchange_rate", 1) * flt(allocated_amount, allocated_amount_precision),
+ difference_amount_precision,
+ )
+ allocated_amount_in_inv_rate = flt(
+ invoice.get("exchange_rate", 1) * flt(allocated_amount, allocated_amount_precision),
+ difference_amount_precision,
+ )
difference_amount = allocated_amount_in_ref_rate - allocated_amount_in_inv_rate
return difference_amount
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
index 008d63ae76f..ea26d2b5460 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
@@ -22,6 +22,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"section_break_9",
"account_currency",
"tax_amount",
@@ -211,6 +212,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
+ {
+ "allow_on_submit": 1,
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"default": "0",
"depends_on": "eval:['Purchase Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
index 9e0a7983b74..8f7b1ece3c7 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
@@ -16,6 +16,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"section_break_8",
"rate",
"section_break_9",
@@ -188,6 +189,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
+ {
+ "allow_on_submit": 1,
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"default": "0",
"depends_on": "eval:['Sales Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.json b/erpnext/accounts/doctype/shipping_rule/shipping_rule.json
index 1b71db69eb5..8277c92d829 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.json
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.json
@@ -16,6 +16,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"shipping_amount_section",
"calculate_based_on",
"column_break_8",
@@ -136,6 +137,12 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
}
],
"icon": "fa fa-truck",
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 680ccf69ac6..0109b957c1e 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -164,6 +164,12 @@
{% } %}
+
+ {% if subtitle %}
+ {{ subtitle }}
+
+ {% endif %}
+
{% for(var i=0, l=data.length; i
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 6061be9f3a8..10a14ca4714 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -974,6 +974,7 @@ class ReceivablePayableReport:
if self.account_type == "Receivable":
self.add_customer_filters()
+ self.exclude_employee_transaction()
elif self.account_type == "Payable":
self.add_supplier_filters()
@@ -1053,6 +1054,9 @@ class ReceivablePayableReport:
)
)
+ def exclude_employee_transaction(self):
+ self.qb_selection_filter.append(self.ple.party_type != "Employee")
+
def add_supplier_filters(self):
supplier = qb.DocType("Supplier")
if self.filters.get("supplier_group"):
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 04625fc76fc..040ac6008c0 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -38,6 +38,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement
get_report_summary as get_pl_summary,
)
from erpnext.accounts.report.utils import convert, convert_to_presentation_currency
+from erpnext.accounts.utils import get_zero_cutoff
def execute(filters=None):
@@ -563,7 +564,7 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
row[company] = flt(d.get(company, 0.0), 3)
- if abs(row[company]) >= 0.005:
+ if abs(row[company]) >= get_zero_cutoff(filters.presentation_currency):
# ignore zero values
has_value = True
total += flt(row[company])
diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py
index ed30ad415d0..2d0015a461e 100644
--- a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py
+++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py
@@ -12,6 +12,7 @@ from erpnext.accounts.report.financial_statements import (
filter_out_zero_value_rows,
)
from erpnext.accounts.report.trial_balance.trial_balance import validate_filters
+from erpnext.accounts.utils import get_zero_cutoff
def execute(filters=None):
@@ -154,7 +155,7 @@ def prepare_data(accounts, filters, company_currency, dimension_list):
for dimension in dimension_list:
row[frappe.scrub(dimension)] = flt(d.get(frappe.scrub(dimension), 0.0), 3)
- if abs(row[frappe.scrub(dimension)]) >= 0.005:
+ if abs(row[frappe.scrub(dimension)]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True
total += flt(d.get(frappe.scrub(dimension), 0.0), 3)
diff --git a/erpnext/accounts/report/financial_statements.html b/erpnext/accounts/report/financial_statements.html
index 45d56a92037..f78775ec2ad 100644
--- a/erpnext/accounts/report/financial_statements.html
+++ b/erpnext/accounts/report/financial_statements.html
@@ -34,6 +34,12 @@
{% } %}
+
+ {% if subtitle %}
+ {{ subtitle }}
+
+ {% endif %}
+
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 04068dc08a1..bf46c9b07c6 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -18,7 +18,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_dimension_with_children,
)
from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency
-from erpnext.accounts.utils import get_fiscal_year
+from erpnext.accounts.utils import get_fiscal_year, get_zero_cutoff
def get_period_list(
@@ -304,7 +304,7 @@ def prepare_data(accounts, balance_must_be, period_list, company_currency, accum
row[period.key] = flt(d.get(period.key, 0.0), 3)
- if abs(row[period.key]) >= 0.005:
+ if abs(row[period.key]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True
total += flt(row[period.key])
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html
index c40c607fbed..681636b1249 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.html
+++ b/erpnext/accounts/report/general_ledger/general_ledger.html
@@ -21,6 +21,12 @@
{%= frappe.datetime.str_to_user(filters.to_date) %}
+
+ {% if subtitle %}
+ {{ subtitle }}
+
+ {% endif %}
+
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 94331ef1b92..7c6c809b939 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -645,7 +645,7 @@ def get_columns(filters):
"options": "GL Entry",
"hidden": 1,
},
- {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 100},
+ {"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 120},
{
"label": _("Account"),
"fieldname": "account",
diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.py b/erpnext/accounts/report/profitability_analysis/profitability_analysis.py
index dfb941d9123..5f3215fe7e2 100644
--- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.py
+++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.py
@@ -12,6 +12,7 @@ from erpnext.accounts.report.financial_statements import (
filter_out_zero_value_rows,
)
from erpnext.accounts.report.trial_balance.trial_balance import validate_filters
+from erpnext.accounts.utils import get_zero_cutoff
value_fields = ("income", "expense", "gross_profit_loss")
@@ -149,7 +150,7 @@ def prepare_data(accounts, filters, total_row, parent_children_map, based_on):
for key in value_fields:
row[key] = flt(d.get(key, 0.0), 3)
- if abs(row[key]) >= 0.005:
+ if abs(row[key]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 5575426dfff..9e1dd1a57c3 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -18,6 +18,7 @@ from erpnext.accounts.report.financial_statements import (
set_gl_entries_by_account,
)
from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency
+from erpnext.accounts.utils import get_zero_cutoff
value_fields = (
"opening_debit",
@@ -413,7 +414,7 @@ def prepare_data(accounts, filters, parent_children_map, company_currency):
for key in value_fields:
row[key] = flt(d.get(key, 0.0), 3)
- if abs(row[key]) >= 0.005:
+ if abs(row[key]) >= get_zero_cutoff(company_currency):
# ignore zero values
has_value = True
diff --git a/erpnext/accounts/test/test_utils.py b/erpnext/accounts/test/test_utils.py
index 5e108dee9b5..f89b47b2dfe 100644
--- a/erpnext/accounts/test/test_utils.py
+++ b/erpnext/accounts/test/test_utils.py
@@ -9,6 +9,7 @@ from erpnext.accounts.party import get_party_shipping_address
from erpnext.accounts.utils import (
get_future_stock_vouchers,
get_voucherwise_gl_entries,
+ get_zero_cutoff,
sort_stock_vouchers_by_posting_date,
)
from erpnext.stock.doctype.item.test_item import make_item
@@ -156,6 +157,11 @@ class TestUtils(unittest.TestCase):
self.assertSequenceEqual(doc_name[0:2], ("SUP", fiscal_year))
frappe.db.set_default("supp_master_name", "Supplier Name")
+ def test_get_zero_cutoff(self):
+ self.assertEqual(get_zero_cutoff(None), 0.005)
+ self.assertEqual(get_zero_cutoff("EUR"), 0.005)
+ self.assertEqual(get_zero_cutoff("BHD"), 0.0005)
+
ADDRESS_RECORDS = [
{
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 15117b2aa43..18cbc65731c 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -27,6 +27,7 @@ from frappe.utils import (
now,
nowdate,
)
+from frappe.utils.caching import site_cache
from pypika import Order
from pypika.functions import Coalesce
from pypika.terms import ExistsCriterion
@@ -1130,6 +1131,29 @@ def get_currency_precision():
return precision
+def get_fraction_units(currency: str) -> int:
+ """Returns the number of fraction units for a currency."""
+ fraction_units = frappe.db.get_value("Currency", currency, "fraction_units")
+
+ if fraction_units is None:
+ fraction_units = 100
+
+ return fraction_units
+
+
+@site_cache()
+def get_zero_cutoff(currency: str) -> float:
+ """Returns the zero cutoff for a currency.
+
+ For example, if the Fraction Units for a currency are set to 100, then the zero cutoff is 0.005.
+ We don't want to display values less than the zero cutoff.
+ This value was chosen for compatibility with the previous hard-coded value of 0.005.
+ """
+ fraction_units = get_fraction_units(currency)
+
+ return 0.5 / (fraction_units or 1)
+
+
def get_held_invoices(party_type, party):
"""
Returns a list of names Purchase Invoices for the given party that are on hold
@@ -2451,6 +2475,10 @@ def build_qb_match_conditions(doctype, user=None) -> list:
for filter in match_filters:
for link_option, allowed_values in filter.items():
fieldnames = link_fields_map.get(link_option, [])
+ cond = None
+
+ if link_option == doctype:
+ cond = _dt["name"].isin(allowed_values)
for fieldname in fieldnames:
field = _dt[fieldname]
@@ -2459,6 +2487,7 @@ def build_qb_match_conditions(doctype, user=None) -> list:
if not apply_strict_user_permissions:
cond = (Coalesce(field, "") == "") | cond
+ if cond:
criterion.append(cond)
return criterion
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
index a6796e55f82..c2de548b2de 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.json
@@ -44,6 +44,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"target_fixed_asset_account"
],
"fields": [
@@ -288,6 +289,12 @@
"label": "Cost Center",
"options": "Cost Center"
},
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
diff --git a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
index ebaaffbad15..98275acaef4 100644
--- a/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_asset_item/asset_capitalization_asset_item.json
@@ -18,6 +18,7 @@
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
+ "project",
"fixed_asset_account"
],
"fields": [
@@ -98,6 +99,13 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
+ {
+ "allow_on_submit": 1,
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
"fieldname": "finance_book",
"fieldtype": "Link",
diff --git a/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json b/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
index a6e67b956cf..d37c58bb5d6 100644
--- a/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
+++ b/erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
@@ -118,7 +118,8 @@
"fieldname": "rate",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "Rate"
+ "label": "Rate",
+ "options": "currency"
},
{
"columns": 1,
@@ -161,7 +162,8 @@
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
- "read_only": 1
+ "read_only": 1,
+ "options": "currency"
},
{
"fieldname": "column_break_yuca",
@@ -183,13 +185,15 @@
"fieldname": "base_amount",
"fieldtype": "Currency",
"hidden": 1,
- "label": "Base Amount"
+ "label": "Base Amount",
+ "options": "Company:company:default_currency"
},
{
"fieldname": "base_rate",
"fieldtype": "Currency",
"hidden": 1,
- "label": "Base Rate"
+ "label": "Base Rate",
+ "options": "Company:company:default_currency"
},
{
"default": "0",
diff --git a/erpnext/patches/v15_0/set_company_on_pos_inv_merge_log.py b/erpnext/patches/v15_0/set_company_on_pos_inv_merge_log.py
index 8f83898a877..21efdcfe936 100644
--- a/erpnext/patches/v15_0/set_company_on_pos_inv_merge_log.py
+++ b/erpnext/patches/v15_0/set_company_on_pos_inv_merge_log.py
@@ -6,7 +6,10 @@ def execute():
"POS Invoice Merge Log", {"docstatus": 1}, ["name", "pos_closing_entry"]
)
+ frappe.db.auto_commit_on_many_writes = 1
for log in pos_invoice_merge_logs:
if log.pos_closing_entry and frappe.db.exists("POS Closing Entry", log.pos_closing_entry):
company = frappe.db.get_value("POS Closing Entry", log.pos_closing_entry, "company")
frappe.db.set_value("POS Invoice Merge Log", log.name, "company", company)
+
+ frappe.db.auto_commit_on_many_writes = 0
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index e3680549cc0..ed7e4bf623b 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -931,7 +931,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
party_name = me.frm.doc.party_name
}
else{
- party_type = frappe.meta.has_field(me.frm.doc.doctype, "customer") ? "Customer" : "Supplier";
+ party_type = frappe.meta.has_field(me.frm.doc.doctype, "supplier") ? "Supplier" : "Customer";
party_name = me.frm.doc[party_type.toLowerCase()];
}
if (party_name) {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 0118e89cd3c..eb6134d4259 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -1762,6 +1762,11 @@ def create_pick_list(source_name, target_doc=None):
target.qty = qty_to_be_picked
target.stock_qty = qty_to_be_picked * flt(source.conversion_factor)
+ # update available qty
+ bin_details = get_bin_details(source.item_code, source.warehouse, source_parent.company)
+ target.actual_qty = bin_details.get("actual_qty")
+ target.company_total_stock = bin_details.get("company_total_stock")
+
def update_packed_item_qty(source, target, source_parent) -> None:
qty = flt(source.qty)
for item in source_parent.items:
diff --git a/erpnext/setup/doctype/employee/test_employee.py b/erpnext/setup/doctype/employee/test_employee.py
index 9b706836269..1e9a8278ec2 100644
--- a/erpnext/setup/doctype/employee/test_employee.py
+++ b/erpnext/setup/doctype/employee/test_employee.py
@@ -5,8 +5,10 @@ import unittest
import frappe
import frappe.utils
+from frappe.query_builder import Criterion
import erpnext
+from erpnext.accounts.utils import build_qb_match_conditions
from erpnext.setup.doctype.employee.employee import InactiveEmployeeStatusError
test_records = frappe.get_test_records("Employee")
@@ -34,6 +36,32 @@ class TestEmployee(unittest.TestCase):
employee_doc.save()
self.assertTrue("Employee" not in frappe.get_roles(user))
+ def test_employee_user_permission(self):
+ employee1 = make_employee("employee_1_test@company.com", create_user_permission=1)
+ employee2 = make_employee("employee_2_test@company.com", create_user_permission=1)
+ make_employee("employee_3_test@company.com", create_user_permission=1)
+
+ employee1_doc = frappe.get_doc("Employee", employee1)
+ employee2_doc = frappe.get_doc("Employee", employee2)
+
+ employee2_doc.reload()
+ employee2_doc.reports_to = employee1_doc.name
+ employee2_doc.save()
+
+ frappe.set_user(employee1_doc.user_id)
+
+ Employee = frappe.qb.DocType("Employee")
+ qb_employee_list = (
+ frappe.qb.from_(Employee)
+ .select(Employee.name)
+ .where(Criterion.all(build_qb_match_conditions("Employee")))
+ .orderby(Employee.Name)
+ ).run(pluck=Employee.name)
+ employee_list = frappe.db.get_list("Employee", pluck="name", order_by="name")
+
+ self.assertEqual(qb_employee_list, employee_list)
+ frappe.set_user("Administrator")
+
def tearDown(self):
frappe.db.rollback()
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index c7d9823d144..7b87d75cee9 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -218,6 +218,7 @@ def get_batch_qty(
batch_no=None,
warehouse=None,
item_code=None,
+ creation=None,
posting_date=None,
posting_time=None,
ignore_voucher_nos=None,
@@ -244,6 +245,7 @@ def get_batch_qty(
{
"item_code": item_code,
"warehouse": warehouse,
+ "creation": creation,
"posting_date": posting_date,
"posting_time": posting_time,
"batch_no": batch_no,
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 0ea35ddc1fb..e71c8eb6a00 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -724,7 +724,10 @@ class Item(Document):
item_defaults = frappe.db.get_values(
"Item Default",
- {"parent": self.item_group},
+ {
+ "parent": self.item_group,
+ "parenttype": "Item Group",
+ },
[
"company",
"default_warehouse",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index d021973a01f..9ea7f006df8 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -354,10 +354,12 @@ frappe.ui.form.on("Pick List Item", {
item_code: (frm, cdt, cdn) => {
let row = frappe.get_doc(cdt, cdn);
if (row.item_code) {
- get_item_details(row.item_code).then((data) => {
+ get_item_details(row.item_code, row.uom, row.warehouse, frm.doc.company).then((data) => {
frappe.model.set_value(cdt, cdn, "uom", data.stock_uom);
frappe.model.set_value(cdt, cdn, "stock_uom", data.stock_uom);
frappe.model.set_value(cdt, cdn, "conversion_factor", 1);
+ frappe.model.set_value(cdt, cdn, "actual_qty", data.actual_qty);
+ frappe.model.set_value(cdt, cdn, "company_total_stock", data.company_total_stock);
});
}
},
@@ -371,6 +373,15 @@ frappe.ui.form.on("Pick List Item", {
}
},
+ warehouse: (frm, cdt, cdn) => {
+ const row = frappe.get_doc(cdt, cdn);
+ if (!row.item_code || !row.warehouse) return;
+ get_item_details(row.item_code, row.uom, row.warehouse, frm.doc.company).then((data) => {
+ frappe.model.set_value(cdt, cdn, "actual_qty", data.actual_qty);
+ frappe.model.set_value(cdt, cdn, "company_total_stock", data.company_total_stock);
+ });
+ },
+
qty: (frm, cdt, cdn) => {
let row = frappe.get_doc(cdt, cdn);
frappe.model.set_value(cdt, cdn, "stock_qty", row.qty * row.conversion_factor);
@@ -412,11 +423,13 @@ frappe.ui.form.on("Pick List Item", {
},
});
-function get_item_details(item_code, uom = null) {
+function get_item_details(item_code, uom = null, warehouse = null, company = null) {
if (item_code) {
return frappe.xcall("erpnext.stock.doctype.pick_list.pick_list.get_item_details", {
item_code,
uom,
+ warehouse,
+ company,
});
}
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 9417751f682..f49a4c955cc 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -21,7 +21,7 @@ from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle impor
get_auto_batch_nos,
get_picked_serial_nos,
)
-from erpnext.stock.get_item_details import get_conversion_factor
+from erpnext.stock.get_item_details import get_company_total_stock, get_conversion_factor
from erpnext.stock.serial_batch_bundle import (
SerialBatchCreation,
get_batches_from_bundle,
@@ -74,6 +74,9 @@ class PickList(TransactionBase):
if self.has_reserved_stock():
self.set_onload("has_reserved_stock", True)
+ for item in self.get("locations"):
+ item.update(get_item_details(item.item_code, item.uom, item.warehouse, self.company))
+
def validate(self):
self.validate_expired_batches()
self.validate_for_qty()
@@ -1442,15 +1445,29 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
@frappe.whitelist()
-def get_item_details(item_code, uom=None):
+def get_item_details(item_code, uom=None, warehouse=None, company=None):
details = frappe.db.get_value("Item", item_code, ["stock_uom", "name"], as_dict=1)
details.uom = uom or details.stock_uom
if uom:
details.update(get_conversion_factor(item_code, uom))
+ if warehouse:
+ details.actual_qty = flt(get_actual_qty(item_code, warehouse))
+
+ if company:
+ details.company_total_stock = get_company_total_stock(item_code, company)
+
return details
+def get_actual_qty(item_code, warehouse):
+ return frappe.db.get_value(
+ "Bin",
+ {"item_code": item_code, "warehouse": warehouse},
+ "actual_qty",
+ )
+
+
def update_delivery_note_item(source, target, delivery_note):
cost_center = frappe.db.get_value("Project", delivery_note.project, "cost_center")
if not cost_center:
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index e7af1c6a005..a33123e3e16 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -22,6 +22,10 @@
"conversion_factor",
"stock_uom",
"delivered_qty",
+ "available_quantity_section",
+ "actual_qty",
+ "column_break_kyek",
+ "company_total_stock",
"serial_no_and_batch_section",
"pick_serial_and_batch",
"serial_and_batch_bundle",
@@ -124,7 +128,7 @@
"fieldname": "stock_qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Stock Qty",
+ "label": "Qty (in Stock UOM)",
"read_only": 1
},
{
@@ -248,11 +252,38 @@
"print_hide": 1,
"read_only": 1,
"report_hide": 1
+ },
+ {
+ "fieldname": "available_quantity_section",
+ "fieldtype": "Section Break",
+ "label": "Available Qty"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "actual_qty",
+ "fieldtype": "Float",
+ "label": "Qty (Warehouse)",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_kyek",
+ "fieldtype": "Column Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "company_total_stock",
+ "fieldtype": "Float",
+ "label": "Qty (Company)",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"istable": 1,
"links": [],
- "modified": "2025-05-31 19:57:43.531298",
+ "modified": "2025-09-23 00:02:57.817040",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.py b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
index af23a424949..bdba97f4056 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.py
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
@@ -15,7 +15,9 @@ class PickListItem(Document):
if TYPE_CHECKING:
from frappe.types import DF
+ actual_qty: DF.Float
batch_no: DF.Link | None
+ company_total_stock: DF.Float
conversion_factor: DF.Float
delivered_qty: DF.Float
description: DF.Text | None
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
index 35cdae457b8..aff309e5f80 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
@@ -2360,6 +2360,16 @@ def get_available_batches(kwargs):
kwargs.posting_date, kwargs.posting_time
)
+ if kwargs.get("creation"):
+ timestamp_condition = stock_ledger_entry.posting_datetime < get_combine_datetime(
+ kwargs.posting_date, kwargs.posting_time
+ )
+
+ timestamp_condition |= (
+ stock_ledger_entry.posting_datetime
+ == get_combine_datetime(kwargs.posting_date, kwargs.posting_time)
+ ) & (stock_ledger_entry.creation < kwargs.creation)
+
query = query.where(timestamp_condition)
for field in ["warehouse", "item_code"]:
@@ -2601,6 +2611,16 @@ def get_stock_ledgers_for_serial_nos(kwargs):
kwargs.posting_date, kwargs.posting_time
)
+ if kwargs.get("creation"):
+ timestamp_condition = stock_ledger_entry.posting_datetime < get_combine_datetime(
+ kwargs.posting_date, kwargs.posting_time
+ )
+
+ timestamp_condition |= (
+ stock_ledger_entry.posting_datetime
+ == get_combine_datetime(kwargs.posting_date, kwargs.posting_time)
+ ) & (stock_ledger_entry.creation < kwargs.creation)
+
query = query.where(timestamp_condition)
for field in ["warehouse", "item_code", "serial_no"]:
@@ -2659,6 +2679,16 @@ def get_stock_ledgers_batches(kwargs):
kwargs.posting_date, kwargs.posting_time
)
+ if kwargs.get("creation"):
+ timestamp_condition = stock_ledger_entry.posting_datetime < get_combine_datetime(
+ kwargs.posting_date, kwargs.posting_time
+ )
+
+ timestamp_condition |= (
+ stock_ledger_entry.posting_datetime
+ == get_combine_datetime(kwargs.posting_date, kwargs.posting_time)
+ ) & (stock_ledger_entry.creation < kwargs.creation)
+
query = query.where(timestamp_condition)
if kwargs.get("ignore_voucher_nos"):
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index ec54c9dc92e..bd0a0beceef 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -5,7 +5,7 @@
import frappe
from frappe import _, bold, json, msgprint
from frappe.query_builder.functions import CombineDatetime, Sum
-from frappe.utils import add_to_date, cint, cstr, flt, get_datetime
+from frappe.utils import add_to_date, cint, cstr, flt, get_datetime, now
import erpnext
from erpnext.accounts.utils import get_company_default
@@ -1034,7 +1034,7 @@ class StockReconciliation(StockController):
val_rate = 0.0
current_qty = 0.0
if row.current_serial_and_batch_bundle:
- current_qty = self.get_current_qty_for_serial_or_batch(row)
+ current_qty = self.get_current_qty_for_serial_or_batch(row, sle_creation)
elif row.serial_no:
item_dict = get_stock_balance_for(
row.item_code,
@@ -1143,17 +1143,17 @@ class StockReconciliation(StockController):
return allow_negative_stock
- def get_current_qty_for_serial_or_batch(self, row):
+ def get_current_qty_for_serial_or_batch(self, row, sle_creation):
doc = frappe.get_doc("Serial and Batch Bundle", row.current_serial_and_batch_bundle)
current_qty = 0.0
if doc.has_serial_no:
- current_qty = self.get_current_qty_for_serial_nos(doc)
+ current_qty = self.get_current_qty_for_serial_nos(doc, sle_creation)
elif doc.has_batch_no:
- current_qty = self.get_current_qty_for_batch_nos(doc)
+ current_qty = self.get_current_qty_for_batch_nos(doc, sle_creation)
return abs(current_qty)
- def get_current_qty_for_serial_nos(self, doc):
+ def get_current_qty_for_serial_nos(self, doc, sle_creation):
serial_nos_details = get_available_serial_nos(
frappe._dict(
{
@@ -1161,6 +1161,7 @@ class StockReconciliation(StockController):
"warehouse": doc.warehouse,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
+ "creation": sle_creation,
"voucher_no": self.name,
"ignore_warehouse": 1,
}
@@ -1190,7 +1191,7 @@ class StockReconciliation(StockController):
return current_qty
- def get_current_qty_for_batch_nos(self, doc):
+ def get_current_qty_for_batch_nos(self, doc, sle_creation):
current_qty = 0.0
precision = doc.entries[0].precision("qty")
for d in doc.entries:
@@ -1198,6 +1199,7 @@ class StockReconciliation(StockController):
get_batch_qty(
d.batch_no,
doc.warehouse,
+ creation=sle_creation,
posting_date=doc.posting_date,
posting_time=doc.posting_time,
ignore_voucher_nos=[doc.voucher_no],
@@ -1494,6 +1496,7 @@ def get_stock_balance_for(
"company": company,
"posting_date": posting_date,
"posting_time": posting_time,
+ "creation": row.get("creation") if row and row.get("creation") else now(),
}
)
)
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 22630d80f38..3ec23cf1481 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -312,7 +312,7 @@ def is_first_response(issue):
def calculate_first_response_time(issue, first_responded_on):
- issue_creation_date = issue.service_level_agreement_creation or issue.creation
+ issue_creation_date = get_datetime(issue.service_level_agreement_creation or issue.creation)
issue_creation_time = get_time_in_seconds(issue_creation_date)
first_responded_on_in_seconds = get_time_in_seconds(first_responded_on)
support_hours = frappe.get_cached_doc(
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index 26c017bddaa..6a39a434b6a 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -25,7 +25,7 @@ from frappe.utils.caching import redis_cache
from frappe.utils.nestedset import get_ancestors_of
from frappe.utils.safe_exec import get_safe_globals
-from erpnext.support.doctype.issue.issue import get_holidays
+from erpnext.support.doctype.issue.issue import calculate_first_response_time, get_holidays
class ServiceLevelAgreement(Document):
@@ -552,6 +552,8 @@ def handle_status_change(doc, apply_sla_for_resolution):
def set_first_response():
if doc.meta.has_field("first_responded_on") and not doc.get("first_responded_on"):
doc.first_responded_on = now_time
+ if doc.meta.has_field("first_response_time"):
+ doc.first_response_time = calculate_first_response_time(doc, doc.first_responded_on)
if get_datetime(doc.get("first_responded_on")) > get_datetime(doc.get("response_by")):
record_assigned_users_on_failure(doc)
diff --git a/erpnext/tests/test_activation.py b/erpnext/tests/test_activation.py
index b56e2332cf4..ec210c919de 100644
--- a/erpnext/tests/test_activation.py
+++ b/erpnext/tests/test_activation.py
@@ -5,5 +5,6 @@ from erpnext.utilities.activation import get_level
class TestActivation(FrappeTestCase):
def test_activation(self):
- levels = get_level()
+ site_info = {"activation": {"activation_level": 0, "sales_data": []}}
+ levels = get_level(site_info)
self.assertTrue(levels)
diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py
index 24bfdc63af6..f01aa1312f6 100644
--- a/erpnext/utilities/__init__.py
+++ b/erpnext/utilities/__init__.py
@@ -37,7 +37,7 @@ def get_site_info(site_info):
if company:
domain = frappe.get_cached_value("Company", cstr(company), "domain")
- return {"company": company, "domain": domain, "activation": get_level()}
+ return {"company": company, "domain": domain, "activation": get_level(site_info)}
@contextmanager
diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py
index e09d87dd769..509c9836d3c 100644
--- a/erpnext/utilities/activation.py
+++ b/erpnext/utilities/activation.py
@@ -9,9 +9,9 @@ from frappe.core.doctype.installed_applications.installed_applications import ge
import erpnext
-def get_level():
- activation_level = 0
- sales_data = []
+def get_level(site_info):
+ activation_level = site_info.get("activation", {}).get("activation_level", 0)
+ sales_data = site_info.get("activation", {}).get("sales_data", [])
min_count = 0
doctypes = {
"Asset": 5,