From 339476f63da0a44a1f95f52ff9f0896a0f68e810 Mon Sep 17 00:00:00 2001 From: Ivan Bochkarev Date: Mon, 25 May 2026 12:31:23 +0600 Subject: [PATCH 1/2] fix(manager): show draft orders toggle and grid filter params (#302) Vue orders grid lacked a way to include draft rows despite ms3_order_show_drafts, and column filters were sent without the filter_ prefix expected by the API. --- .../controllers/mgr/orders.class.php | 1 + .../minishop3/lexicon/en/vue.inc.php | 1 + .../minishop3/lexicon/ru/vue.inc.php | 1 + .../Api/Manager/OrdersController.php | 38 ++++++++++++-- vueManager/src/components/OrdersGrid.vue | 49 ++++++++++++++++++- 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/core/components/minishop3/controllers/mgr/orders.class.php b/core/components/minishop3/controllers/mgr/orders.class.php index 04175c16..a93259c7 100644 --- a/core/components/minishop3/controllers/mgr/orders.class.php +++ b/core/components/minishop3/controllers/mgr/orders.class.php @@ -38,6 +38,7 @@ public function loadCustomCssJs() $this->addJavascript($this->ms3->config['jsUrl'] . 'mgr/orders/orders.wrapper.js'); $config = $this->ms3->config; + $config['order_show_drafts'] = (bool) $this->modx->getOption('ms3_order_show_drafts', null, false); $this->addHtml(''); $this->addCss($this->ms3->config['assetsUrl'] . 'css/mgr/vue-dist/primeicons.min.css'); diff --git a/core/components/minishop3/lexicon/en/vue.inc.php b/core/components/minishop3/lexicon/en/vue.inc.php index 31b56923..07cf4a2a 100644 --- a/core/components/minishop3/lexicon/en/vue.inc.php +++ b/core/components/minishop3/lexicon/en/vue.inc.php @@ -489,6 +489,7 @@ $_lang['orders_title'] = 'Orders'; $_lang['orders_month'] = 'Orders'; $_lang['orders_month_sum'] = 'Total sum'; +$_lang['ms3_orders_show_drafts'] = 'Show drafts'; $_lang['order_num'] = 'Number'; $_lang['order_customer'] = 'Customer'; $_lang['order_status'] = 'Status'; diff --git a/core/components/minishop3/lexicon/ru/vue.inc.php b/core/components/minishop3/lexicon/ru/vue.inc.php index 93520236..bfc4a939 100644 --- a/core/components/minishop3/lexicon/ru/vue.inc.php +++ b/core/components/minishop3/lexicon/ru/vue.inc.php @@ -489,6 +489,7 @@ $_lang['orders_title'] = 'Заказы'; $_lang['orders_month'] = 'Заказов'; $_lang['orders_month_sum'] = 'На сумму'; +$_lang['ms3_orders_show_drafts'] = 'Показывать черновики'; $_lang['order_num'] = 'Номер'; $_lang['order_customer'] = 'Клиент'; $_lang['order_status'] = 'Статус'; diff --git a/core/components/minishop3/src/Controllers/Api/Manager/OrdersController.php b/core/components/minishop3/src/Controllers/Api/Manager/OrdersController.php index 58cec930..9cae208a 100644 --- a/core/components/minishop3/src/Controllers/Api/Manager/OrdersController.php +++ b/core/components/minishop3/src/Controllers/Api/Manager/OrdersController.php @@ -155,11 +155,7 @@ public function getList(array $params = []): array } } - $showDrafts = $this->modx->getOption('ms3_order_show_drafts', null, false); - if (!$showDrafts) { - $statusDrafts = (int) $this->modx->getOption('ms3_status_draft', null, 1) ?: 1; - $c->where(['status_id:!=' => $statusDrafts]); - } + $this->applyDraftVisibilityFilter($c, $params); if (!empty($query)) { if (is_numeric($query)) { @@ -1535,6 +1531,38 @@ protected function getOrdersStats(array $params = []): array ]; } + /** + * Whether draft orders should be included in manager list/stats queries. + * + * Request param `show_drafts` overrides the system setting `ms3_order_show_drafts`. + */ + protected function shouldShowDrafts(array $params): bool + { + if (array_key_exists('show_drafts', $params)) { + $value = $params['show_drafts']; + if ($value === '' || $value === null) { + return (bool) $this->modx->getOption('ms3_order_show_drafts', null, false); + } + + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + + return (bool) $this->modx->getOption('ms3_order_show_drafts', null, false); + } + + /** + * Exclude draft status from query unless drafts are explicitly shown. + */ + protected function applyDraftVisibilityFilter($c, array $params): void + { + if ($this->shouldShowDrafts($params)) { + return; + } + + $statusDrafts = (int) $this->modx->getOption('ms3_status_draft', null, 1) ?: 1; + $c->where(['status_id:!=' => $statusDrafts]); + } + /** * Apply filter to query * diff --git a/vueManager/src/components/OrdersGrid.vue b/vueManager/src/components/OrdersGrid.vue index 711f1c7f..6936dcf2 100644 --- a/vueManager/src/components/OrdersGrid.vue +++ b/vueManager/src/components/OrdersGrid.vue @@ -2,6 +2,7 @@ import { useLexicon } from '@vuetools/useLexicon' import Button from 'primevue/button' import Card from 'primevue/card' +import Checkbox from 'primevue/checkbox' import Column from 'primevue/column' import ConfirmDialog from 'primevue/confirmdialog' import DataTable from 'primevue/datatable' @@ -20,6 +21,20 @@ import ActionsColumn from './ActionsColumn.vue' const toast = useToast() const { _ } = useLexicon() +const ms3Config = typeof ms3 !== 'undefined' ? ms3.config : null +const showDrafts = ref(Boolean(ms3Config?.order_show_drafts)) + +/** Filter keys sent as direct API params (not filter_ prefix). */ +const DIRECT_FILTER_KEYS = new Set([ + 'query', + 'status_id', + 'delivery_id', + 'payment_id', + 'context_key', + 'createdon_from', + 'createdon_to', +]) + // Bulk selection const { selectedItems, @@ -73,13 +88,13 @@ async function loadOrders() { limit: rows.value, sort: sortField.value, dir: sortOrder.value === 1 ? 'ASC' : 'DESC', + show_drafts: showDrafts.value ? 1 : 0, } // Apply filter values Object.keys(filterValues.value).forEach(key => { const value = filterValues.value[key] if (value !== null && value !== undefined && value !== '') { - // Handle daterange type const filterConfig = filters.value[key] if (filterConfig?.type === 'daterange' && Array.isArray(value)) { if (value[0]) { @@ -90,8 +105,10 @@ async function loadOrders() { } } else if (filterConfig?.type === 'datepicker' && value) { params[key] = formatDateForApi(value) - } else { + } else if (DIRECT_FILTER_KEYS.has(key)) { params[key] = value + } else { + params[`filter_${key}`] = value } } }) @@ -373,6 +390,11 @@ const hasActiveFilters = computed(() => { return Object.values(filterValues.value).some(v => v !== null && v !== '' && v !== undefined) }) +function toggleShowDrafts() { + first.value = 0 + loadOrders() +} + /** * Load grid configuration */ @@ -648,6 +670,15 @@ onMounted(async () => {
+
+ + +
-
+
{{ _('orders_month') }}: {{ stats.month_total }} @@ -855,6 +855,7 @@ onMounted(async () => { gap: 1.5rem; font-size: 0.9rem; color: var(--ms3-text-muted); + cursor: help; } .stat-item {