Сайт состоит из нескольких частей:
GET /search
- api для поиска услуг.Параметры:
date
- Дата. ['required', 'date', 'after_or_equal:today']a
- id активностей. ['array', 'exists:activities,id']members
- Количество участников. ['integer', 'min:1']time_from
- Время начала поиска. ['date_format:H:i:s']time_to
- Время конца поиска. ['date_format:H:i:s']price_from
- Цена от. ['integer', 'min:0', 'max:200000']price_to
- Цена до. ['integer', 'min:0', 'max:200000']c
- Удобства. ['array', Rule::in(['parking', 'placement', 'rest_zone', 'shower', 'for_kids', 'canteen', 'own_food', 'bar', 'photographer', 'wifi'])]/prebuy
Перед совершением покупки необходимо проверить возможность совершения покупки и забронировать сеанс.
Если сеанс невозможно купить, то будет возвращена 418 ошибка с текстом "Сеанс занят".
Параметры:
service_id
=> ['required', 'exists:services,id'],date
=> ['required', 'date', 'after_or_equal:today'],time
=> ['required', 'date_format:H:i:s'],duration
=> ['required', 'integer'],members
=> ['required', 'integer', 'min:1'],/cart/clean
Очищение корзины.
Параметры:
service_id
=> ['required', 'exists:services,id'],date
=> ['required', 'date', 'after_or_equal:today'],time
=> ['required', 'date_format:H:i:s'],duration
=> ['required', 'integer'],members
=> ['required', 'integer', 'min:1'],Если пользователь в корзине нажимает на "Крестик", то вызывается этот метод и забронированный сеанс снова становится доступен для покупки.
Метод всегда возращает okResponse
. Доступен только авторизованным пользователям.
/buy/seance
Покупка сеанса
Параметры:
service_id
- ID услуги. ['required', 'exists:services,id']date
- Дата. ['required', 'date', 'after_or_equal:today']time
- Время. ['required', 'date_format:H:i:s']members
Кол-во участников- . ['required', 'integer', 'min:1']is_gift
- true если подарок. ['required', 'boolean']promocode
- code промокода. ['exists:promocodes,code']payment_method
- Способ оплаты. ['required', Rule::in(['cash', 'acquiring'])]clients
- Массив клиентов. ['array']duration
- Продолжительность сеанса. ['integer']additional
- Массив дополнительных услуг. ['array']Пример корректных данных:
/certificate/buy
Покупка сертификата
Параметры:
value
=> ['required', 'integer', 'min:1000', 'max:300000']appearance
=> ['required',]package
=> ['required', 'in:envelope,virtual']payment_method
=> ['required', Rule::in(config('consts.payment_method'))]email
=> ['required', 'email']address
=> ['required_if:package,envelope']/certificate/activate
Активация сертификата
Параметры:
code
- Код сертификатаИспользуемые далее переменные возрщаются при вызове метода /search
(в каждом элементе полученного массива) и при вызове метода /prebuy
Цена на конкретную услугу вычисляется по следующему алгоритму (псевдокод):
if ($this->datetime->isWeekend()) {
$base_price = $this->option['pwe'];
} elseif ($this->datetime->isFriday() && $this->datetime->toTimeString() > '18:00:00') {
$base_price = $this->option['pfa'];
} elseif ($this->datetime->isWeekday() && $this->datetime->toTimeString() > '18:00:00') {
$base_price = $this->option['pda'];
} else {
$base_price = $this->option['pdb'];
}
if ($this->service->price_type == 'team') {
$price = $base_price;
} elseif ($this->service->price_type == 'fix_client') {
$price = $this->service->fix_price + $base_price * $this->members;
} else {
$price = $base_price * $this->members;
}
if (promocode) { // Промокод и его значение получается отдельным запросом.
$price -= promocode->value;
}
Если коротко, то формула такая:
price = (base_price * (customer_type == 'team' ? 1 : members)) * (100 - max(discounts)) / 100 + (each_additional * each_additional_price) - promocode_value
Если у пользователя на балансе есть какое-то количество денег, то при оплате онлайн происходит следующее:
С баланса списывается min(balance, price) рублей
, если price
был меньше balance
, т
о сумма оплаты онлайн = 0 и мы просто говорим пользователю, что покупка прошла успешно (как при оплате наличными)
Соответственно нужно оповестить пользователя об этом (написать, что N рублей будет списано с баланса).
payment_type
автоматически становится acquiring
и не может стать cash
если:
prepayment_amount
== 100Для покупки в подарок пользователь может выбрать кого-то из своих "друзей".
На бекенде "друзья" называются "Локальными клиентами".
Чтобы получить список локальных клиентов пользователя, существует запрос -
GET /v1/user/locals
Логика работы следующая: При покупке "в подарок" дергается этот запрос и пользователь может выбрать одного из своих "локальных клиентов". Помимо выбора, он может ввести данные нового локального клиента. При следующих покупках эти данные будут возвращаться в запросе.
Чтобы активировать промокод, необходимо сделать POST /v1/promocode/check
Передается одно поле - promocode
- код промокода.
Если промокод существует и доступен для активации, то будет возвращено число - сумма в рублях, на которую действует введенный промокод.
Если промокод недействителен, то будет выброшена ошибка валидации.
Если prepayment_amount
== 100, то доступна только оплата онлайн 100% от цены
Если prepayment_amount
== 0, то доступна оплата 100% онлайн и оплата 100% в клубе
Если 0 < prepayment_amount
< 100, то действует следующая логика:
Если выбрана оплата онлайн, то 100% от цены оплачивается онлайн.
Если выбрана оплата в клубе, то покупка делится на 2 части:
$cash
- оплата в клубе, $acquiring
- оплата онлайн.
Эти переменные вычисляются по следующему алгоритму:
$cash = (int) (price * (100 - prepayment_amount) / 100)
$acquiring = price - $cash