bonusProvider = $bonusProvider; $this->discountGenerator = $discountGenerator; } public function exchange(int $id, ?int $userId = null): bool { if (!$userId) { if (!($userId = Contexts::get(UserContext::class)->getActiveId())) { throw new \InvalidArgumentException('There is no active user neither userId argument was not specified'); } } return sqlGetConnection()->transactional(function () use ($id, $userId) { if (!($item = $this->getExchangeItem($id))) { throw new \RuntimeException('Bonus program exchange item not found'); } $userPoints = $this->bonusProvider->getActivePointsAmount($userId); if ($userPoints < $item['points']) { return false; } // generate new coupon for specified user $generated = $this->generateUserCoupon($item, (int) $item['id_discount'], (int) $userId); if (($generated['count'] ?? 0) > 0) { // subtract points from user sqlQueryBuilder() ->insert('bonus_points') ->directValues( [ 'id_user' => $userId, 'points' => toDecimal($item['points'])->mul(\DecimalConstants::negativeOne()), 'date_created' => date('Y-m-d H:i:s'), 'note' => sprintf(translate_shop('exchangeLogMessage', 'bonus_program'), $item['points'], $item['name']), 'status' => 'active', ] )->execute(); return true; } return false; }); } public function getExchangeItem(int $id): ?array { $item = sqlQueryBuilder() ->select('*') ->from('bonus_points_exchange') ->where( Operator::equals( [ 'id' => $id, 'active' => 1, ] ) ) ->orderBy('id', 'DESC') ->forUpdate() ->execute()->fetchAssociative(); if (!$item) { return null; } return $item; } protected function generateUserCoupon(array $item, int $discountId, int $userId): array { return $this->discountGenerator->generateNewCoupons(id_discount: $discountId, userId: $userId); } }