From 1e9bad12c58535c6294db004868089e7f9425142 Mon Sep 17 00:00:00 2001 From: Nurmuhammet Allanov Date: Tue, 28 Oct 2025 23:03:41 +0500 Subject: [PATCH] modular composer requirements aborts if missing --- .../Clusters/Cards/Cards/CardResource.php | 17 +++- .../CardRequisite/CardRequisiteModule.php | 16 +++- .../Repositories/CardRequisiteRepository.php | 90 ++++++++++++++++++ .../Resources/Docs/card-requisite.docx | Bin 0 -> 24386 bytes app/Modules/ModuleRepository.php | 10 ++ app/Modules/ModuleServiceProvider.php | 24 ++++- app/Modules/module-helpers.php | 8 ++ 7 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 app/Modules/CardRequisite/Resources/Docs/card-requisite.docx diff --git a/app/Filament/Clusters/Cards/Cards/CardResource.php b/app/Filament/Clusters/Cards/Cards/CardResource.php index b22e9e7..fbdb024 100644 --- a/app/Filament/Clusters/Cards/Cards/CardResource.php +++ b/app/Filament/Clusters/Cards/Cards/CardResource.php @@ -7,6 +7,7 @@ use App\Filament\Clusters\Cards\CardsCluster; use App\Modules\AppHelpers\Repositories\DateHelper; use App\Modules\Card\Models\Card; use App\Modules\CardBalance\Repositories\CardBalanceRepository; +use App\Modules\CardRequisite\Repositories\CardRequisiteRepository; use App\Modules\CardTransaction\Repositories\CardTransactionRepository; use BackedEnum; use Filament\Actions\Action; @@ -124,15 +125,15 @@ class CardResource extends Resource ->recordActions([ Action::make('card_balance') ->label(__('Card balance')) - ->icon('heroicon-m-credit-card') + ->icon('heroicon-o-credit-card') ->requiresConfirmation(false) ->modal() ->modalContent(fn (Card $record): View => CardBalanceRepository::make()->showCardBalance($record)) ->modalFooterActions([]), - Action::make('card_transaction') - ->label(__('Card transaction')) - ->icon('heroicon-m-arrows-right-left') + Action::make('card_transactions') + ->label(__('Card transactions')) + ->icon('heroicon-o-arrows-right-left') ->requiresConfirmation() ->modalIcon('heroicon-m-arrows-right-left') ->schema([ @@ -148,11 +149,17 @@ class CardResource extends Resource ->required() ->beforeOrEqual('today'), ]) - ->openUrlInNewTab() ->action( fn (array $data, Card $record, Component $livewire) => CardTransactionRepository::make()->downloadCardTransaction($data, $record, $livewire) ), + Action::make('card_requisite') + ->label(__('Card requisite')) + ->icon('heroicon-o-document-text') + ->requiresConfirmation() + ->modalIcon('heroicon-o-document-text') + ->action(fn (Card $record, Component $livewire) => CardRequisiteRepository::make()->downloadCardRequisite($record, $livewire)), + EditAction::make() ->label(''), DeleteAction::make() diff --git a/app/Modules/CardRequisite/CardRequisiteModule.php b/app/Modules/CardRequisite/CardRequisiteModule.php index 96cb916..e2dc866 100644 --- a/app/Modules/CardRequisite/CardRequisiteModule.php +++ b/app/Modules/CardRequisite/CardRequisiteModule.php @@ -2,6 +2,8 @@ namespace App\Modules\CardRequisite; +use App\Modules\Core\ModulePackage; +use App\Modules\Core\ModulePackageType; use App\Modules\Makeable; use App\Modules\ModuleContract; @@ -51,7 +53,19 @@ class CardRequisiteModule implements ModuleContract */ public function getComposerRequirements(): array { - return []; + return [ + new ModulePackage( + type: ModulePackageType::MODULE, + name: 'CardTransaction', + message: 'Required for API', + ), + new ModulePackage( + type: ModulePackageType::PACKAGE, + name: 'phpoffice/phpword', + message: 'Required for docx file generation', + version: 'dev-master', + ), + ]; } /** diff --git a/app/Modules/CardRequisite/Repositories/CardRequisiteRepository.php b/app/Modules/CardRequisite/Repositories/CardRequisiteRepository.php index 000870a..75e2fee 100644 --- a/app/Modules/CardRequisite/Repositories/CardRequisiteRepository.php +++ b/app/Modules/CardRequisite/Repositories/CardRequisiteRepository.php @@ -2,9 +2,99 @@ namespace App\Modules\CardRequisite\Repositories; +use App\Modules\Card\Models\Card; +use App\Modules\CardTransaction\Repositories\CardTransactionRepository; use App\Modules\Makeable; +use Filament\Notifications\Notification; +use Illuminate\Support\Str; +use Livewire\Component; class CardRequisiteRepository { use Makeable; + + public function downloadCardRequisite(Card $record, Component $livewire) + { + /** @var \App\Modules\CardTransaction\Types\CardTransactionResponse */ + $response = $this->fetchApi($record); + + if ($response->errCode != 0) { + Notification::make() + ->danger() + ->title($response->message) + ->send(); + + return; + } + + $path = $this->generateFile($record, $response); + + // return ActionResponse::download( + // name: 'kart-rekwizit.docx', + // url: url($path) + // ); + } + + /** + * Fetch api + * + * @return object + */ + public function fetchApi(Card $record) + { + $date = today()->format('d.m.Y'); + + $response = CardTransactionRepository::make()->fetchApi( + passport_serie: user()->passport_serie(), + passport_id: user()->passport_id(), + card_number_masked: Str::mask($record->number, '*', 6, 6), + card_expire_date: $record->month.'/'.substr($record->year, 2), + start_date: $date, + end_date: $date, + ); + + return Str::isJson($response) + ? json_decode($response) + : emptyClass(errCode: 1, message: 'Connection issue to VP'); + } + + /** + * Generate file + * + * @param \App\Models\Order\Card\Requisite\CardRequisite $model + * @param \App\Nova\Resources\Order\Card\CardTransaction\Actions\ResponseTypes\AzatApiClientInfoAllResponse $data + * @return string + */ + public function generateFile($model, $data) + { + $doc_path = app_path('Nova/Resources/Order/Card/Requisite/Docs/card-requisite.docx'); + + $templateProcessor = new TemplateProcessor($doc_path); + $templateProcessor->setValues([ + 'year' => date('Y'), + 'name' => $data->clientName, + 'contract' => $data->cardAccountNumber, + 'bank' => $data->depName, + 'hasap' => $data->accountNumber, + 'sb' => $data->inn, + 'bab' => $data->mfo, + 'card_type' => $data->cardName, + 'card_number' => $data->cardPan, + 'phone' => $data->mobilPhone ?? '-', + 'contract_date' => '---YOK---', + 'card_order_date' => '---YOK---', + 'card_given_date' => '---YOK---', + ]); + + $unique_folder_name = Str::snake(str_replace(':', '-', $model->created_at->toDateTimeString())); + $dir = public_path("files/card-requisite/{$unique_folder_name}"); + + File::makeDirectory($dir, 0777, true, true); + + $filePath = $dir."/{$model->id}.docx"; + + $templateProcessor->saveAs($filePath); + + return "files/card-requisite/{$unique_folder_name}/{$model->id}.docx"; + } } diff --git a/app/Modules/CardRequisite/Resources/Docs/card-requisite.docx b/app/Modules/CardRequisite/Resources/Docs/card-requisite.docx new file mode 100644 index 0000000000000000000000000000000000000000..08e1e4540aab1c5076d6a798c94df1ffa50daf29 GIT binary patch literal 24386 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 PkiSPrL;s@p_tk#@CR$~P literal 0 HcmV?d00001 diff --git a/app/Modules/ModuleRepository.php b/app/Modules/ModuleRepository.php index 0cfbf33..f2172bb 100644 --- a/app/Modules/ModuleRepository.php +++ b/app/Modules/ModuleRepository.php @@ -126,4 +126,14 @@ class ModuleRepository { return $this->allModules; } + + /** + * Check if module exists + * + * @param string $moduleName + */ + public function moduleExists(string $moduleName): bool + { + return $this->modules->contains(fn (BaseModule $module) => $module->name === $moduleName); + } } diff --git a/app/Modules/ModuleServiceProvider.php b/app/Modules/ModuleServiceProvider.php index 9a082f0..cd4e5fb 100644 --- a/app/Modules/ModuleServiceProvider.php +++ b/app/Modules/ModuleServiceProvider.php @@ -2,6 +2,10 @@ namespace App\Modules; +use App\Modules\Core\ModulePackage; +use App\Modules\Core\ModulePackageType; +use Composer\Composer; +use Composer\InstalledVersions; use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Str; @@ -57,9 +61,25 @@ class ModuleServiceProvider extends ServiceProvider */ public function verifyModuleComposerRequirements(BaseModule $module): void { - // foreach ($module->app->getComposerRequirements() as $requirement) { + foreach ($module->app->getComposerRequirements() as $package) { + if ($package->type === ModulePackageType::PACKAGE) { + if (! InstalledVersions::isInstalled($package->name)) { + abort( + code: 500, + message: "{$package->name} must be installed (module: {$module->name})" + ); + } + } - // } + if ($package->type === ModulePackageType::MODULE) { + if (! module_exists($package->name)) { + abort( + code: 500, + message: "{$package->name} module must be installed (module: {$module->name})" + ); + } + } + } } /** diff --git a/app/Modules/module-helpers.php b/app/Modules/module-helpers.php index 960fd60..73a734c 100644 --- a/app/Modules/module-helpers.php +++ b/app/Modules/module-helpers.php @@ -46,6 +46,14 @@ function emptyModule(): ModuleContract return modular()->emptyModule(); } +/** + * Module exists + */ +function module_exists(string $moduleName) +{ + return modular()->moduleExists($moduleName); +} + /** * Create an anonymous class that acts as a dynamic object. *