@Tim2345

Подсчёт баланса пользователя в срезке даты?

Подскажите пожалуйста, как подсчитать правильно баланс пользователя.

Таблица всех начислений / списаний хранится в следующем виде:

618aaabdaf6a8209590126.png

Status:
1 - начислено
2 - списано
3 - отменено

Paid (bool) - заказ оплачен

К примеру, начислили бонус за регистрацию +100 бонусов с сроком годности 5 дней,
далее он списал 10% от суммы заказа -10 бонусов и ему с этого заказа вернётся кэшбек в 5% / 5 бонусов.
Бонусный счёт его будет равен 95 бонусов.

Всё хорошо, но, если у приветственных бонусов (100) выйдет срок действия, то подсчёт будет в минус, а должно остаться 5 бонусов и 90 не учитываться.
Подсчёт:

$paid_1 = Db::getInstance()->getValue('
            SELECT SUM(points)
            FROM '._DB_PREFIX_.'bonus_account 
            WHERE id_customer = '.(int)$id_customer.'
            AND paid = 1
            AND status = 1
            AND date_add <= "'.date('Y-m-d H:i:s').'"
            AND date_bonus_to >= "'.date('Y-m-d H:i:s').'"');
 $paid_0 = Db::getInstance()->getValue('
            SELECT SUM(points)
            FROM '._DB_PREFIX_.'bonus_account 
            WHERE id_customer = '.(int)$id_customer.'
            AND paid = 1
            AND status = 2
            AND date_add <= "'.date('Y-m-d H:i:s').'"
            AND date_bonus_to >= "'.date('Y-m-d H:i:s').'"');
        $end_result = ((float)$paid_1 - (float)$paid_0);
        if ($end_result < 0) {
            return 0;
        } else {
            return $end_result;
        }


Тестовые данные Создание базы данных

CREATE TABLE `ps_bonus_account` (
  `id_bonusaccount` int(11) NOT NULL,
  `id_customer` int(10) UNSIGNED NOT NULL,
  `id_order` int(10) UNSIGNED NOT NULL,
  `id_cart_rule` int(10) UNSIGNED NOT NULL,
  `points` decimal(20,6) NOT NULL DEFAULT '0.000000',
  `comment` text NOT NULL,
  `status` int(10) UNSIGNED NOT NULL,
  `paid` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
  `type` varchar(20) NOT NULL,
  `date_add` datetime DEFAULT NULL,
  `date_bonus_to` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `ps_bonus_account` (`id_bonusaccount`, `id_customer`, `id_order`, `id_cart_rule`, `points`, `comment`, `status`, `paid`, `type`, `date_add`, `date_bonus_to`) VALUES
(218, 518, 278, 50, '5.000000', 'Бонусы за заказ', 1, 1, 'order', '2021-11-09 21:45:16', '2022-12-09 21:45:16'),
(219, 518, 278, 50, '10.000000', 'Оплата заказа', 2, 1, 'order', '2021-11-09 21:45:17', '2022-12-09 21:45:16'),
(220, 518, 0, 0, '100.000000', 'За регистрацию', 1, 1, 'no_order', '2021-11-09 21:57:40', '2021-11-08 21:57:40');

Как правильно сделать подсчёт с учётом сгоревших бонусов?
Спасибо!
  • Вопрос задан
  • 212 просмотров
Решения вопроса 1
rozhnev
@rozhnev Куратор тега PHP
Fullstack programmer, DBA, медленно, дорого
SELECT
	GREATEST(0, -- return 0 in case negative balance
		SUM(
			IF(`status` = 1 AND `date_bonus_to` > NOW() , `points`, 0) -- bonus added and not expired
			- IF(`status` = 2, `points`, 0) -- bonus used
		)
	) `balance`
FROM `ps_bonus_account`
WHERE  
	`id_customer` = 518 AND
	`paid` = 1 
GROUP BY `id_customer`;


SQL fiddle
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
DmitriyEntelis
@DmitriyEntelis
Думаю за деньги
Вообще это выглядит как плохая и неочевидная архитектура.

Начисление/списание - это факт который должен происходить в транзакции в конкретный момент времени.
Если у Вас есть "протухающие" бонусы - соответственно нужно по крону с пользователей их вычитать, создавая новые записи в момент протухания.

Если уж совсем никак - надо добавить в текущую логику 3й запрос: количество протухших бонусов
select sum(points) from ... where date_end < now() and points > 0


Текущие бонусы = начисленные - потраченные - протухшие.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы