
0x9d8e
29.04.2017
16:55:28
Это что касается данных. Лишние подробности опустил.
Есть система оплаты, которая, если брать только оплату товаров и услуг состоит из двух классов. Один отвечает за саму оплату, её способ (создать Payment, подтвердить платёж). Второй вызывается исключительно предыдущим и отвечает за цель, назначение платежа (в данном случае тупо задать заказу статус "оплачен", либо откатить обратно).
Оно тоже как-бы готово и всё ништяк.
Но это пока платёж представлял из себя просто сумму в рублях, которую надо оплатить или списать с лицевого счёта.

Google


0x9d8e
29.04.2017
17:04:19
Как вдруг появилась логика, которой надо сунуть свои щупальца во всё сразу.
У юзера появились подписки, второй личный счёт (не в рублях, а "в курьерах").
Подписка влияет на скидку, на активность обоих лицевых счетов (и на их пополнение за одно). Т.е. если активна подписка, то за доставку пытаемся снять "балл" со счёта бесплатных доставок (при этом заказ может требовать 0, 1 или 2 доставки). Если, скажем. требуется 2 доставки, а на счету доставок всего одна, то надо будет снять одну с этого счёта, а за вторую рублями. Если подписка не активна, то и счета личные неактивны, так что всё в рублях. При неактивной подписке доставка оплачивается в рублях, но цена зависит от общей суммы заказа.
Далее рубли по тому-же принципу списываются сколько комжно с личевого счёта, а остальное уже идёт к оплате через платёж.
При этом платёж атомарен. Т.е. списывать рубли/баллы с личных счетов нужно в тот же момент, когда подтверждается платёж. Он подтверждается или сразу (если там сумма к оплате 0 и всё с личных счетов) или платёжным сервисом или администратором.
Выходит так, что после создания заказа нужно всё это дело подсчитать (на самом деле при любом изменении заказа пересчитывать и выводить). И потом сделать собственно платёж.


Sergey
29.04.2017
17:18:50

0x9d8e
29.04.2017
17:21:19
В плане данных получается, что платёж должен иметь три суммы вместо одной:
Сумма в рублях к оплате;
Сумма в рублях для списания с баланса;
Сумма в баллах на бесплатную доставку;

Sergey
29.04.2017
17:21:50
я не так давно писал шутки ради моковый блокчейн

0x9d8e
29.04.2017
17:21:54
А в плане логики нужно где-то эту лабуду считать перед созданием платежа.

Sergey
29.04.2017
17:21:56
и у меня у юзера было 3 баланса
balance, unconfirmedBalance, garantedBalance
и норм было

0x9d8e
29.04.2017
17:22:52
Либо ещё варант, что платёж должен включать помимо назначений платежа ещё и "источники" платежей, а сам никаких сумм не иметь.

Google

0x9d8e
29.04.2017
17:28:19
Даже не знаю как эту хрень назвать, которая считает такой вот итог по заказу. Плюс нужно платёж на основе этого итога создавать.

Sergey
29.04.2017
17:31:30
ладно, дай почитаю что ты написал целиком)

0x9d8e
29.04.2017
17:31:56

Sergey
29.04.2017
17:32:39

0x9d8e
29.04.2017
17:39:33
*лан, пропускаю филосовствования почему я перешел от того, чтобы логику с данными смешивать*
Меня более всего беспокоит собственно блин вышеописанная логика-осьминог
Встроить это как-то в компонент, отвечающий за платежи никуда не годится, ибо платежи далеко не только заказы хавают.
Выходит нужен ещё один компонент, который будет хм... Во-первых считать это всё. Во-вторых создавать соответвтующий платёж. (Или же не надо это смешивать...)
Как бы эту хрень на два метода назвать
Фактически это такая оферта в коде. Включающая в себя цены, скидки, условия, работу с лицемым счётом, всякими баллами.

Sergey
29.04.2017
17:51:19
тут короч все упирается в то что тебе надо - максимально гибкая система с проблемами с производительностью
или же "решить задачу"

0x9d8e
29.04.2017
17:55:07
Ну значит у меня прикольная процедуррщина, при этом не лишенная полиморфизма, да и инкапсуляции

Sergey
29.04.2017
17:58:51
ну то есть если ты выстроил слой доменной модели поверх модели данных - вполне верю
ну мол реально ж интересно, а то заинтриговал и все

Google


0x9d8e
29.04.2017
18:18:14
Конкретно платёж запилил так:
Есть собственно те самые AR: PaymentModel и PaymentItemModel.
Т.к. на высшем уровне бизнес-логика тут предполагает фактически три действия:
- Взять что-то, сделать из этого платёж/счёт;
- Подтвердить оплату;
При этом после подтверждения оплаты должны быть оказаны некие услуги, которые подразумевает это "что-то".
То делаем класс Payments и интерфейс PaymentServiceInterface.
Payments имеет методы:
make, // создаёт платёж правильным образом
addModel, //добавляет в этот платёж цель (заказ/подписку и т.п.)
confirm, // подтверждает оплату
cancel. // отменяет оплату
PaymentServiceInterface имеет почти то-же самое:
construct
addModel,
confirfirm<
cancel,
commit
commit нужен для того, чтобы cancel и confirm могли быть отменеы ещё до реального применения, а так-же могли бы накидать исключений. После коммита услуги уже оказаны и рыпаться поздно (и исключений он уже не кидает).
В общем чего я расписываю.
payment = Payments.make(User, Type, InvoceId);
payment.add(Order);
payment.add(Order2);
payment.add(Packet);
.....
payment.comfirm().commit();
Это что "снаружи".
Внутри он на каждое назначение (добавленное через .add()) дёрнет класс реализующий PaymentServiceInterface (сам класс определяется типом назначения, у расзных разный) и подёргает соответствующие методы.
Там уж от реализации зависит. В случае order'ов заказы статусы получат и ещё какаая-то такая хрень произойдёт. В случае подписок там будет юзеру подписа назначена/продлена, всякие баллы начислены и т.п.).
Лан. Пришло время принять волевое решение и назвать класс NevedomayaHernya и запилить хоть что-то.


Sergey
29.04.2017
18:46:19
у тебя куча зон ответственности - там ты одним классом не обойдешься что бы все было ок

0x9d8e
29.04.2017
18:55:35
Конкретно то что мне нужно сделать можно одним методом вообще сделать. Эта логика не дробится уже.
Зона ответственности тут "посчитать итоговый итог с учётом всех-всех условий, баллов, счетов"
Соответственно знать этой теме надо о заказе и юзере

Sergei
29.04.2017
19:16:03

0x9d8e
29.04.2017
19:17:35

0x9d8e
29.04.2017
19:19:00
Сейчас подумал почему-бы не запилить просто класс-обёртку над любым "покупаемым" объектом, который бы расширял их функциональность тремя методами, да и всё.
И назвать его Total

Sergei
29.04.2017
19:20:19

0x9d8e
29.04.2017
19:20:28
total = new Total(Order)
и можно во вьюшку передать, да отчёт нарисовать
а можно по нему платёж создать
Payments.make(total)

Sergei
29.04.2017
19:27:20

0x9d8e
29.04.2017
19:29:04
Что в классе Order?
Юзер, данные по доставке, список товаров/услуг и из количества. Ну и статусы всякие.

Google

Sergei
29.04.2017
19:29:49
И куда идёт этот Order?

0x9d8e
29.04.2017
19:32:17
Много куда. Данные из него есть в личном кабинете. Есть в админке. Печатаются для курьеров. Ну и платёж по нему создаётся (сейчас).
Условно говоря я хочу сейчас вместо
payment = Payments::make(Order):
сделать
total = Total::make(Order);
payment = Payments::make(total);
Ибо раньше у Order была цена (просто число в рублях), а теперь всё заморочено и нужен "кто-то" кто эти заморочки разрулит насколько возможно.

Admin
ERROR: S client not available

0x9d8e
29.04.2017
19:35:22
Вроде как норм выходит
Если только этот момент не изменится ещё каким-то невероятным образом, что уже нельзя будет так реализовать ?

Sergei
29.04.2017
19:36:24
Ты можешь рефакторить?
рефактори
а потом уже вводи новую фичу, если ты чувствуешь что скоро упрёшься в что то похожее то так и будет, только вырулить может и не получиться
Что такое Payments?


0x9d8e
29.04.2017
19:38:53
Да как бы ещё три дня назад всё было ништяк, а ноые условия сделали введи необходимость сделать что-то, что я вот только сейчас более-менее понял как сделать.
Что такое Payments?
Есть два таких класса, один это просто структура данных, а другой обрабатывает платёж. Тут это второе, но их можно было бы даже в один слить.
Отвечает он за то, что создаёт платёж, добавляет в него всякие назначения (блин, я в вышестоящих примерах хрень написал, не так оно работает), например тот же Order. Ну и подтверждает/отменяет оплату. Внутри там ещё юзаются классы (реализующие специальный интерфейс), которые реализуют "оказание услуг" которые стоят за назначениями (в случае заказа это тупо статус "оплачен" ему проставить, но где-то и сложные дела).
В реале оно как-то так юзается:
payment = Payments::make(User, type, invoice);
payment.add(Order);
payment.add(....);
....
payment.confirm();

Sergei
29.04.2017
19:48:20
type что это?

0x9d8e
29.04.2017
19:52:33
type что это?
Число (из константы класса). Означает способ оплаты.
invoiceId тоже число и нужно для внешних платёжных сервисов (гоню, строка)

Sergei
29.04.2017
20:06:14

Max
02.05.2017
00:56:19
День добрый. Вопрос знающим\имеющим опыт с клиент-серверными приложениями.
В общем, представим, что я пилю аналог anki - тобишь это клиент с локальной бд на телефоне и десктопе, и веб-версия с мастер бд.
Соответственно, юз кейс - если я пользуюсь приложением без интернета, данные сначала идут в локальную бд, с появлением интернета - синхронизируются с бд где-то на сервере (отправка локальных данных, получение новых).
Вопрос - какой самый простой способ это реализовать? На ум приходит только оборачивание всех моих юз кейсов (добавить карточку, удалить, обновить)
в паттерн command, и соответсвенно класть эти command-ы в очередь. Далее, при появлении интернета, доставать их из очереди и отправлять их на сервер (через rest api, еще как-то).

da horsie
02.05.2017
00:58:14
нормальное решение. почему сомневаешься?

Google

Max
02.05.2017
01:01:22
у меня изначальная цель этого всего - запилить свой велосипед, плюс попробовать DDD (правда, леплю на питоне, а там примеров DDD немного)

da horsie
02.05.2017
01:05:19
Решение подходящее. Если реализовать его в минимально необходимом виде, будет хорошо, без оверинжиниринга

Max
02.05.2017
01:14:28
И как я понимаю, юз кейсы начинают лепить как command-класс, а не как простой метод, как раз таки в случае нескольких платформ?

da horsie
02.05.2017
03:26:55

Sergey
02.05.2017
05:28:05
ну и опять же не понятно зачем тебе command bus

Roman
02.05.2017
15:10:02
всем привет. какой паттерн больше к api подходит? я нашел два похожих - посредник и фасад

Aleh
02.05.2017
15:27:09
интересный вопрос, что такое api в твоем вопросе?
для создания api подходит просто public интерфейс у объекта :)

Roman
02.05.2017
15:30:35
ну я понимаю апи это проект, который в зависимости от полученного запроса (например в _POST) дергает либо заранее выбранные запросы к базе или к внешнему API
я просто начал класс писать, а он начал слишком много знать и уметь

f4rt~
02.05.2017
15:32:04

Aleh
02.05.2017
15:32:49
посмотри на sinatra/finatra/silex/express/miku