feat: respect set_query filters in Account selection dialog
Extract link filters from the source control's set_query/df.filters and pass them to the backend. This ensures that field-specific constraints (e.g. root_type=Expense, company filters) are respected when selecting accounts through the custom dialog. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3a3b850733
commit
3dc04ed092
|
|
@ -634,7 +634,7 @@ def add_items_to_document(doctype, docname, items):
|
|||
# ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_filters=None):
|
||||
def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_filters=None, link_filters=None):
|
||||
"""
|
||||
Получить список счетов для формы подбора
|
||||
|
||||
|
|
@ -643,6 +643,7 @@ def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_fil
|
|||
start (int): Смещение для пагинации
|
||||
page_length (int): Количество записей на странице
|
||||
custom_filters (list): Произвольные фильтры [{field, operator, value}]
|
||||
link_filters (dict): Фильтры из set_query контрола-источника
|
||||
|
||||
Returns:
|
||||
dict: {items: [...], total_count: int}
|
||||
|
|
@ -651,6 +652,7 @@ def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_fil
|
|||
|
||||
filters = frappe.parse_json(filters) if isinstance(filters, str) else (filters or {})
|
||||
custom_filters = frappe.parse_json(custom_filters) if isinstance(custom_filters, str) else (custom_filters or [])
|
||||
link_filters = frappe.parse_json(link_filters) if isinstance(link_filters, str) else (link_filters or {})
|
||||
start = cint(start)
|
||||
page_length = cint(page_length)
|
||||
|
||||
|
|
@ -673,6 +675,10 @@ def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_fil
|
|||
.where(Account.is_group == 0)
|
||||
)
|
||||
|
||||
# Фильтры из set_query контрола (root_type, account_type, company и т.д.)
|
||||
if link_filters:
|
||||
query = _apply_link_filters(query, Account, link_filters)
|
||||
|
||||
# Поиск по номеру и названию
|
||||
search_term = cstr(filters.get('search_term', '')).strip()
|
||||
if search_term:
|
||||
|
|
@ -702,6 +708,8 @@ def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_fil
|
|||
.where(Account.disabled == 0)
|
||||
.where(Account.is_group == 0)
|
||||
)
|
||||
if link_filters:
|
||||
count_query = _apply_link_filters(count_query, Account, link_filters)
|
||||
if search_term:
|
||||
term = f"%{search_term}%"
|
||||
count_query = count_query.where(
|
||||
|
|
@ -744,6 +752,52 @@ def get_accounts_for_selection(filters=None, start=0, page_length=50, custom_fil
|
|||
}
|
||||
|
||||
|
||||
def _apply_link_filters(query, Account, link_filters):
|
||||
"""
|
||||
Применить фильтры из set_query контрола-источника.
|
||||
|
||||
Формат Frappe link_filters:
|
||||
{field: value} — равенство
|
||||
{field: ['in', [v1, v2]]} — оператор
|
||||
{field: ['like', '%text%']} — like
|
||||
"""
|
||||
account_meta = frappe.get_meta('Account')
|
||||
valid_fields = {f.fieldname for f in account_meta.fields}
|
||||
valid_fields.update({'name', 'owner', 'creation', 'modified'})
|
||||
|
||||
for field, value in link_filters.items():
|
||||
if field not in valid_fields:
|
||||
continue
|
||||
col = Account[field]
|
||||
|
||||
if isinstance(value, (list, tuple)) and len(value) == 2:
|
||||
op, val = value[0].lower(), value[1]
|
||||
if op == 'in' and isinstance(val, (list, tuple)):
|
||||
query = query.where(col.isin(val))
|
||||
elif op == 'not in' and isinstance(val, (list, tuple)):
|
||||
query = query.where(col.notin(val))
|
||||
elif op == 'like':
|
||||
query = query.where(col.like(val))
|
||||
elif op == 'not like':
|
||||
query = query.where(~col.like(val))
|
||||
elif op == '!=':
|
||||
query = query.where(col != val)
|
||||
elif op == '>':
|
||||
query = query.where(col > val)
|
||||
elif op == '<':
|
||||
query = query.where(col < val)
|
||||
elif op == '>=':
|
||||
query = query.where(col >= val)
|
||||
elif op == '<=':
|
||||
query = query.where(col <= val)
|
||||
else:
|
||||
query = query.where(col == val)
|
||||
else:
|
||||
query = query.where(col == value)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def _apply_account_custom_filters(query, Account, custom_filters):
|
||||
"""
|
||||
Применить произвольные фильтры по полям DocType Account
|
||||
|
|
|
|||
|
|
@ -15,10 +15,23 @@ class AccountSelectionDialog {
|
|||
this.custom_filters = [];
|
||||
this._account_fields = [];
|
||||
this.accounts_data = [];
|
||||
this.link_filters = this._extract_link_filters();
|
||||
|
||||
this.make_dialog();
|
||||
}
|
||||
|
||||
// Извлечь фильтры из set_query / df.filters контрола-источника
|
||||
_extract_link_filters() {
|
||||
const target = this.link_selector_opts.target;
|
||||
if (!target) return {};
|
||||
|
||||
const args = {};
|
||||
if (target.set_custom_query) {
|
||||
try { target.set_custom_query(args); } catch (e) { /* ignore */ }
|
||||
}
|
||||
return args.filters || {};
|
||||
}
|
||||
|
||||
make_dialog() {
|
||||
this.dialog = new frappe.ui.Dialog({
|
||||
title: __('Select Account'),
|
||||
|
|
@ -276,6 +289,7 @@ class AccountSelectionDialog {
|
|||
custom_filters: this.custom_filters.map(f => ({
|
||||
field: f.field, operator: f.operator, value: f.value,
|
||||
})),
|
||||
link_filters: this.link_filters,
|
||||
},
|
||||
async: true,
|
||||
callback: (r) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue