From da8f834f1734afc18ad4f368d76c778c46c1bff1 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Sat, 8 Jul 2023 23:48:46 +0300 Subject: [PATCH] WIP --- ...4_cashier_details_create_status_column.php | 28 ++++++++++ src/Casts/InfoCast.php | 48 ++++++++++++++++ src/Concerns/Config/Payment/Drivers.php | 13 +++++ src/Concerns/Events/Notifiable.php | 25 +++++++++ src/Data/Config/Payment/StatusData.php | 13 ++++- src/Data/Models/InfoData.php | 37 +++++++++++++ src/Events/BaseEvent.php | 27 +++++++++ src/Events/CreatedEvent.php | 22 ++++++++ src/Events/FailedEvent.php | 22 ++++++++ src/Events/RefundedEvent.php | 22 ++++++++ src/Events/SuccessEvent.php | 22 ++++++++ src/Events/WaitRefundEvent.php | 22 ++++++++ src/Models/Details.php | 6 +- src/Observers/PaymentDetailsObserver.php | 55 +++++++++++++++++-- src/Observers/PaymentObserver.php | 42 +++++++++++--- src/Services/DriverManager.php | 15 +---- src/Services/Statuses.php | 2 +- 17 files changed, 390 insertions(+), 31 deletions(-) create mode 100644 database/migrations/private/2023_07_08_223554_cashier_details_create_status_column.php create mode 100644 src/Casts/InfoCast.php create mode 100644 src/Concerns/Events/Notifiable.php create mode 100644 src/Data/Models/InfoData.php create mode 100644 src/Events/BaseEvent.php create mode 100644 src/Events/CreatedEvent.php create mode 100644 src/Events/FailedEvent.php create mode 100644 src/Events/RefundedEvent.php create mode 100644 src/Events/SuccessEvent.php create mode 100644 src/Events/WaitRefundEvent.php diff --git a/database/migrations/private/2023_07_08_223554_cashier_details_create_status_column.php b/database/migrations/private/2023_07_08_223554_cashier_details_create_status_column.php new file mode 100644 index 00000000..7e74b8a6 --- /dev/null +++ b/database/migrations/private/2023_07_08_223554_cashier_details_create_status_column.php @@ -0,0 +1,28 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +use CashierProvider\Core\Concerns\Migrations\PrivateMigration; +use Illuminate\Database\Schema\Blueprint; + +new class extends PrivateMigration { + public function up(): void + { + $this->connection()->table($this->table(), function (Blueprint $table) { + $table->string('status')->nullable()->after('operation_id'); + }); + } +}; diff --git a/src/Casts/InfoCast.php b/src/Casts/InfoCast.php new file mode 100644 index 00000000..a00e5277 --- /dev/null +++ b/src/Casts/InfoCast.php @@ -0,0 +1,48 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Casts; + +use CashierProvider\Core\Concerns\Config\Payment\Drivers; +use CashierProvider\Core\Data\Models\InfoData; +use Illuminate\Contracts\Database\Eloquent\CastsAttributes; +use Illuminate\Database\Eloquent\Model; + +class InfoCast implements CastsAttributes +{ + use Drivers; + + public function get(Model $model, string $key, mixed $value, array $attributes): InfoData + { + $instance = static::driverByModel($model->parent)->details; + + return call_user_func([$instance, 'from'], json_decode($value, true)); + } + + /** + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @param \Spatie\LaravelData\Data $value + * @param array $attributes + * + * @return string + */ + public function set(Model $model, string $key, mixed $value, array $attributes): string + { + return $value->toJson(JSON_UNESCAPED_SLASHES ^ JSON_UNESCAPED_UNICODE); + } +} diff --git a/src/Concerns/Config/Payment/Drivers.php b/src/Concerns/Config/Payment/Drivers.php index a85a32b1..94577554 100644 --- a/src/Concerns/Config/Payment/Drivers.php +++ b/src/Concerns/Config/Payment/Drivers.php @@ -17,6 +17,7 @@ namespace CashierProvider\Core\Concerns\Config\Payment; +use CashierProvider\Core\Concerns\Transformers\EnumsTransformer; use CashierProvider\Core\Data\Config\DriverData; use CashierProvider\Core\Exceptions\Internal\UnknownDriverConfigException; use CashierProvider\Core\Facades\Config; @@ -25,6 +26,9 @@ trait Drivers { + use Attributes; + use EnumsTransformer; + protected static function drivers(): Collection { return Config::payment()->drivers; @@ -38,4 +42,13 @@ protected static function driver(int|string $name, Model $payment): DriverData throw new UnknownDriverConfigException($name, $payment->getKey()); } + + protected static function driverByModel(Model $payment): DriverData + { + $name = $payment->getAttribute( + static::attribute()->type + ); + + return static::driver(static::transformFromEnum($name), $payment); + } } diff --git a/src/Concerns/Events/Notifiable.php b/src/Concerns/Events/Notifiable.php new file mode 100644 index 00000000..6dffcb59 --- /dev/null +++ b/src/Concerns/Events/Notifiable.php @@ -0,0 +1,25 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Concerns\Events; + +use Illuminate\Database\Eloquent\Model; + +trait Notifiable +{ + protected static function event(Model $payment): void {} +} diff --git a/src/Data/Config/Payment/StatusData.php b/src/Data/Config/Payment/StatusData.php index bbaa61bb..739b58ec 100644 --- a/src/Data/Config/Payment/StatusData.php +++ b/src/Data/Config/Payment/StatusData.php @@ -35,7 +35,7 @@ class StatusData extends Data public mixed $failed; - public function get(StatusEnum $status): mixed + public function fromEnum(StatusEnum $status): mixed { return match ($status) { StatusEnum::new => $this->new, @@ -46,6 +46,17 @@ public function get(StatusEnum $status): mixed }; } + public function toEnum(int|string $status): StatusEnum + { + return match ($status) { + $this->new => StatusEnum::new, + $this->success => StatusEnum::success, + $this->refund => StatusEnum::refund, + $this->waitRefund => StatusEnum::waitRefund, + $this->failed => StatusEnum::failed, + }; + } + public function inProgress(): array { return [ diff --git a/src/Data/Models/InfoData.php b/src/Data/Models/InfoData.php new file mode 100644 index 00000000..729188b1 --- /dev/null +++ b/src/Data/Models/InfoData.php @@ -0,0 +1,37 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +namespace CashierProvider\Core\Data\Models; + +use CashierProvider\Core\Concerns\Config\Payment\Payments; +use CashierProvider\Core\Concerns\Transformers\EnumsTransformer; +use CashierProvider\Core\Enums\StatusEnum; +use Spatie\LaravelData\Data; +use UnitEnum; + +abstract class InfoData extends Data +{ + use EnumsTransformer; + use Payments; + + public UnitEnum|int|string|null $status; + + public function statusToEnum(): StatusEnum + { + return static::payment()->status->toEnum( + static::transformFromEnum($this->status) + ); + } +} diff --git a/src/Events/BaseEvent.php b/src/Events/BaseEvent.php new file mode 100644 index 00000000..4cb54d04 --- /dev/null +++ b/src/Events/BaseEvent.php @@ -0,0 +1,27 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Events; + +use Illuminate\Database\Eloquent\Model; + +abstract class BaseEvent +{ + public function __construct( + public Model $payment + ) {} +} diff --git a/src/Events/CreatedEvent.php b/src/Events/CreatedEvent.php new file mode 100644 index 00000000..90ed0bd9 --- /dev/null +++ b/src/Events/CreatedEvent.php @@ -0,0 +1,22 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Events; + +class CreatedEvent extends BaseEvent +{ +} diff --git a/src/Events/FailedEvent.php b/src/Events/FailedEvent.php new file mode 100644 index 00000000..e8bbf6d1 --- /dev/null +++ b/src/Events/FailedEvent.php @@ -0,0 +1,22 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Events; + +class FailedEvent extends BaseEvent +{ +} diff --git a/src/Events/RefundedEvent.php b/src/Events/RefundedEvent.php new file mode 100644 index 00000000..fbbef650 --- /dev/null +++ b/src/Events/RefundedEvent.php @@ -0,0 +1,22 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Events; + +class RefundedEvent extends BaseEvent +{ +} diff --git a/src/Events/SuccessEvent.php b/src/Events/SuccessEvent.php new file mode 100644 index 00000000..7231eaba --- /dev/null +++ b/src/Events/SuccessEvent.php @@ -0,0 +1,22 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Events; + +class SuccessEvent extends BaseEvent +{ +} diff --git a/src/Events/WaitRefundEvent.php b/src/Events/WaitRefundEvent.php new file mode 100644 index 00000000..e4ed285f --- /dev/null +++ b/src/Events/WaitRefundEvent.php @@ -0,0 +1,22 @@ + + * @copyright 2023 Andrey Helldar + * @license MIT + * + * @see https://github.com/cashier-provider + */ + +declare(strict_types=1); + +namespace CashierProvider\Core\Events; + +class WaitRefundEvent extends BaseEvent +{ +} diff --git a/src/Models/Details.php b/src/Models/Details.php index fad057d7..2fb658e3 100644 --- a/src/Models/Details.php +++ b/src/Models/Details.php @@ -17,7 +17,9 @@ namespace CashierProvider\Core\Models; +use CashierProvider\Core\Casts\InfoCast; use CashierProvider\Core\Concerns\Config\Details as DetailsConcern; +use CashierProvider\Core\Enums\StatusEnum; use CashierProvider\Core\Facades\Config; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\Relation; @@ -30,11 +32,13 @@ class Details extends Model 'payment_id', 'external_id', 'operation_id', + 'status', 'info', ]; protected $casts = [ - 'info' => 'json', + 'info' => InfoCast::class, + 'status' => StatusEnum::class, ]; protected $touches = [ diff --git a/src/Observers/PaymentDetailsObserver.php b/src/Observers/PaymentDetailsObserver.php index 962bd212..9d66c179 100644 --- a/src/Observers/PaymentDetailsObserver.php +++ b/src/Observers/PaymentDetailsObserver.php @@ -17,17 +17,62 @@ namespace CashierProvider\Core\Observers; +use CashierProvider\Core\Concerns\Config\Payment\Attributes; +use CashierProvider\Core\Concerns\Config\Payment\Drivers; +use CashierProvider\Core\Concerns\Config\Payment\Payments; +use CashierProvider\Core\Enums\StatusEnum; +use CashierProvider\Core\Events\CreatedEvent; +use CashierProvider\Core\Events\FailedEvent; +use CashierProvider\Core\Events\RefundedEvent; +use CashierProvider\Core\Events\SuccessEvent; +use CashierProvider\Core\Events\WaitRefundEvent; use CashierProvider\Core\Models\Details; +use CashierProvider\Core\Services\Job; +use Illuminate\Database\Eloquent\Model; class PaymentDetailsObserver { - public function created(Details $details): void {} + use Attributes; + use Drivers; + use Payments; - public function updated(Details $details): void {} + public function saving(Details $model): void + { + if ($model->isDirty('info') && $model->status !== null) { + $model->status = $model->info->statusToEnum(); + } + } - public function deleted(Details $details): void {} + public function saved(Details $model): void + { + if ($model->isClean()) { + return; + } - public function restored(Details $details): void {} + if ($model->wasChanged('status')) { + $this->updateStatus($model->parent, $model->status); + $this->event($model->parent, $model->status); + } - public function forceDeleted(Details $details): void {} + Job::model($model->parent)->verify(); + } + + protected function updateStatus(Model $payment, StatusEnum $status): void + { + $value = static::payment()->status->fromEnum($status); + $field = static::attribute()->status; + + $payment->update([$field => $value]); + } + + protected function event(Model $payment, StatusEnum $status): void + { + match ($status) { + StatusEnum::new => event(new CreatedEvent($payment)), + StatusEnum::refund => event(new RefundedEvent($payment)), + StatusEnum::waitRefund => event(new WaitRefundEvent($payment)), + StatusEnum::success => event(new SuccessEvent($payment)), + StatusEnum::failed => event(new FailedEvent($payment)), + }; + } } diff --git a/src/Observers/PaymentObserver.php b/src/Observers/PaymentObserver.php index 49311ad4..bae765b9 100644 --- a/src/Observers/PaymentObserver.php +++ b/src/Observers/PaymentObserver.php @@ -17,17 +17,41 @@ namespace CashierProvider\Core\Observers; +use CashierProvider\Core\Concerns\Config\Payment\Attributes; +use CashierProvider\Core\Concerns\Permissions\Allowable; +use CashierProvider\Core\Services\Job; +use DragonCode\Support\Facades\Helpers\Arr; use Illuminate\Database\Eloquent\Model; class PaymentObserver { - public function created(Model $payment): void {} - - public function updated(Model $payment): void {} - - public function deleted(Model $payment): void {} - - public function restored(Model $payment): void {} - - public function forceDeleted(Model $payment): void {} + use Attributes; + use Allowable; + + public function created(Model $payment): void + { + Job::model($payment)->start(); + } + + public function updated(Model $payment): void + { + if ($this->wasChanged($payment)) { + Job::model($payment)->verify(); + } + } + + protected function wasChanged(Model $payment): bool + { + return $payment->wasChanged( + $this->exceptFields($payment) + ); + } + + protected function exceptFields(Model $payment): array + { + return Arr::of($payment->getChanges())->except([ + static::attribute()->status, + static::attribute()->createdAt, + ])->keys()->toArray(); + } } diff --git a/src/Services/DriverManager.php b/src/Services/DriverManager.php index 6383c0aa..74b5890c 100644 --- a/src/Services/DriverManager.php +++ b/src/Services/DriverManager.php @@ -17,18 +17,14 @@ namespace CashierProvider\Core\Services; -use CashierProvider\Core\Concerns\Config\Payment\Attributes; use CashierProvider\Core\Concerns\Config\Payment\Drivers; use CashierProvider\Core\Concerns\Helpers\Validatable; -use CashierProvider\Core\Concerns\Transformers\EnumsTransformer; use CashierProvider\Core\Data\Config\DriverData; use Illuminate\Database\Eloquent\Model; class DriverManager { - use Attributes; use Drivers; - use EnumsTransformer; use Validatable; public static function find(Model $payment): Driver @@ -45,15 +41,6 @@ protected static function call(DriverData $data, Model $payment): Driver protected static function data(Model $payment): ?DriverData { - return static::driver(static::type($payment), $payment); - } - - protected static function type(Model $payment): string|int - { - $type = $payment->getAttribute( - static::attribute()->type - ); - - return static::transformFromEnum($type); + return static::driverByModel($payment); } } diff --git a/src/Services/Statuses.php b/src/Services/Statuses.php index 6fecab57..bf215fdb 100644 --- a/src/Services/Statuses.php +++ b/src/Services/Statuses.php @@ -107,7 +107,7 @@ protected function hasCashier(array|string $statuses, ?StatusEnum $status): bool protected function hasModel(array|string $statuses, StatusEnum $status): bool { $statuses = Arr::of((array) $statuses) - ->map(fn (mixed $value) => static::payment()->status->get($status)) + ->map(fn (mixed $value) => static::payment()->status->fromEnum($status)) ->toArray(); return $this->has($status, $statuses);