1final class RefundService
2{
3 public function decide(Refund $refund): Decision
4 {
5 if ($refund->daysSincePurchase > 14) {
6 return Decision::reject('минуло більше 14 днів');
7 }
8
9 if ($refund->amount <= 500_00 && ! $refund->customer->isSuspicious()) {
10 return $this->bot->refund($refund);
11 } elseif ($refund->amount <= 5_000_00) {
12 return $this->support->assignOperator($refund);
13 } elseif ($refund->customer->isVip()) {
14 return $this->support->assignSeniorOperator($refund);
15 }
16
17 return $this->managers->review($refund);
18 }
19}
1<?php
2
3final readonly class Refund
4{
5 public function __construct(public string $order, public int $amount, public int $days) {}
6}
7
81abstract class RefundHandler
9{
10 private ?RefundHandler $next = null;
11
12 public function then(RefundHandler $next): RefundHandler
13 {
14 $this->next = $next;
15
16 return $next;
17 }
18
19 public function handle(Refund $refund): string
20 {
21 return $this->next?->handle($refund) ?? 'ніхто не взявся';
22 }
23}
24
252final class TooLate extends RefundHandler
26{
27 public function handle(Refund $refund): string
28 {
29 return $refund->days > 14 ? 'відмова: минуло більше 14 днів' : parent::handle($refund);
30 }
31}
32
33final class AutoRefund extends RefundHandler
34{
35 public function handle(Refund $refund): string
36 {
37 return $refund->amount <= 500 ? 'бот повернув гроші одразу' : parent::handle($refund);
38 }
39}
40
41final class Operator extends RefundHandler
42{
43 public function handle(Refund $refund): string
44 {
45 return $refund->amount <= 5000 ? 'оператор підтвердить сьогодні' : parent::handle($refund);
46 }
47}
48
493final class Manager extends RefundHandler
50{
51 public function handle(Refund $refund): string
52 {
53 return 'менеджер розгляне вручну';
54 }
55}
56
574$chain = new TooLate();
58$chain->then(new AutoRefund())->then(new Operator())->then(new Manager());
59
60$refunds = [
61 new Refund('UA-1042', amount: 320, days: 3),
62 new Refund('UA-1043', amount: 2400, days: 10),
63 new Refund('UA-1044', amount: 18000, days: 5),
64 new Refund('UA-1045', amount: 320, days: 30),
65];
66
67foreach ($refunds as $refund) {
68 printf("%s, %6d грн: %s\n", $refund->order, $refund->amount, $chain->handle($refund));
69}