Возникала необходимость вручную предоставить клиенту персональную скидку при обработке заказа в панели управления. Стандартный miniShop2 позволяет просто переписать поле «Стоимость» (cost), но у этого подхода есть две проблемы:
Человеческий фактор:
Если менеджер ошибся или скидку нужно изменить, исходная стоимость заказа теряется. Повторный пересчет идет от уже уменьшенной суммы.
Скрытые пометки:
Менеджеру нужно видеть статус клиента (например, «Постоянный покупатель 10%»), но выводить это в имя пользователя нельзя — клиент увидит пометку в системных письмах.
В этой статье мы создадим изолированную систему ручных скидок (от 1 до 20%) с защитой от перезаписи базовой цены, возможностью полной отмены скидки (сброс на 0) и выводом скрытых служебных заметок из профиля пользователя.
Шаг 1. Подготовка базы данных
Для хранения процента скидки и неприкосновенной первоначальной стоимости добавим две колонки в таблицу заказов modx_ms2_orders.
Выполните SQL-запрос
ALTER TABLE `modx_ms2_orders`
ADD `discount_percent` INT(3) NOT NULL DEFAULT '0',
ADD `discount_original_cost` DECIMAL(15,2) NOT NULL DEFAULT '0.00';
Шаг 2. Серверный обработчик (PHP)
Создаем файл по адресу assets/components/minishop2/discount.php. Этот скрипт изолирован от ядра, работает через подготовленные выражения PDO, защищает исходную цену от изменений при повторных пересчетах, а при отправке 0 полностью откатывает заказ к исходному состоянию. Также он умеет читать скрытое поле comment из профиля покупателя.
<?php
define('MODX_API_MODE', true);
$modxRoot = '/var/www/www-root/data/www/site.ru/';
/**
обратите внимание на путь! возможно Вам подойдет конструкция ниже
$modxRoot = dirname(__DIR__, 3) . '/';
if (!file_exists($modxRoot . 'config.core.php')) {
$modxRoot = $_SERVER['DOCUMENT_ROOT'] . '/';
}
**/
require_once $modxRoot . 'config.core.php';
require_once MODX_CORE_PATH . 'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('mgr');
header('Content-Type: application/json; charset=utf-8');
if (!$modx->hasPermission('save_document')) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'Нет прав'], JSON_UNESCAPED_UNICODE);
exit;
}
$orderId = isset($_POST['order_id']) ? (int)$_POST['order_id'] : 0;
$percent = isset($_POST['percent']) ? (int)$_POST['percent'] : 0;
if (!$orderId) {
echo json_encode(['success' => false, 'message' => 'Не указан ID заказа'], JSON_UNESCAPED_UNICODE);
exit;
}
$table = $modx->getTableName('msOrder');
$stmt = $modx->prepare("SELECT id, user_id, cost, discount_original_cost, discount_percent FROM {$table} WHERE id = ? LIMIT 1");
$stmt->execute([$orderId]);
$order = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$order) {
echo json_encode(['success' => false, 'message' => 'Заказ не найден'], JSON_UNESCAPED_UNICODE);
exit;
}
// Извлечение комментария из профиля покупателя
$userComment = '';
if (!empty($order['user_id'])) {
$userTable = $modx->getTableName('modUserProfile');
$userStmt = $modx->prepare("SELECT comment FROM {$userTable} WHERE internalKey = ? LIMIT 1");
$userStmt->execute([$order['user_id']]);
$userProfile = $userStmt->fetch(PDO::FETCH_ASSOC);
if ($userProfile && !empty($userProfile['comment'])) {
$userComment = trim($userProfile['comment']);
}
}
if ($percent === -1) {
echo json_encode([
'success' => true,
'order_id' => $orderId,
'original_cost' => (float)$order['discount_original_cost'],
'discount_percent' => (int)$order['discount_percent'],
'cost' => (float)$order['cost'],
'user_comment' => $userComment
], JSON_UNESCAPED_UNICODE);
exit;
}
if ($percent < 0 || $percent > 10) {
echo json_encode(['success' => false, 'message' => 'Скидка должна быть от 0 до 10%'], JSON_UNESCAPED_UNICODE);
exit;
}
$originalCost = (float)$order['discount_original_cost'];
if ($originalCost <= 0) {
$originalCost = (float)$order['cost'];
}
if ($originalCost <= 0) {
echo json_encode(['success' => false, 'message' => 'Стоимость заказа равна 0'], JSON_UNESCAPED_UNICODE);
exit;
}
// Если менеджер ввел 0 — сбрасываем и очищаем скидку
if ($percent === 0) {
$newCost = $originalCost;
$resetOriginalCost = 0;
$update = $modx->prepare("UPDATE {$table} SET discount_original_cost = ?, discount_percent = ?, cost = ? WHERE id = ? LIMIT 1");
$result = $update->execute([$resetOriginalCost, $percent, $newCost, $orderId]);
} else {
$discount = round($originalCost * $percent / 100, 2);
$newCost = round($originalCost - $discount, 2);
$update = $modx->prepare("UPDATE {$table} SET discount_original_cost = ?, discount_percent = ?, cost = ? WHERE id = ? LIMIT 1");
$result = $update->execute([$originalCost, $percent, $newCost, $orderId]);
}
if (!$result) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Не удалось сохранить скидку'], JSON_UNESCAPED_UNICODE);
exit;
}
echo json_encode([
'success' => true,
'order_id' => $orderId,
'original_cost' => $originalCost,
'discount_percent' => $percent,
'cost' => $newCost,
'user_comment' => $userComment
], JSON_UNESCAPED_UNICODE);