From 778bd9030cc629016266fbfd5257d3fe1e2b8561 Mon Sep 17 00:00:00 2001 From: Nurmuhammet Allanov Date: Sat, 24 May 2025 14:27:43 +0500 Subject: [PATCH] wip --- app/Http/Controllers/ApiTesterController.php | 46 ++--- .../Card/CardTransaction/CardTransaction.php | 12 +- .../Repositories/DateHelperRepository.php | 91 ++++++++++ .../Actions/DownloadCardTransaction.php | 104 +++++++++++ .../Card/CardTransaction/CardTransaction.php | 151 ++++++++++++++++ app/Repos/System/Nova/NovaMenuRepo.php | 2 + ..._142230_create_card_transactions_table.php | 13 +- lang/tk.json | 4 +- resources/css/vendor/nova/css/additional.css | 6 + resources/js/vendor/nova/js/additional.js | 169 ------------------ .../download-card-transaction.blade.php | 0 11 files changed, 386 insertions(+), 212 deletions(-) create mode 100644 app/Nova/Resources/Order/Card/CardTransaction/Actions/DownloadCardTransaction.php create mode 100644 app/Nova/Resources/Order/Card/CardTransaction/CardTransaction.php create mode 100644 resources/views/orders/cards/card-transaction/download-card-transaction.blade.php diff --git a/app/Http/Controllers/ApiTesterController.php b/app/Http/Controllers/ApiTesterController.php index 2b8e8bf..349bcfb 100644 --- a/app/Http/Controllers/ApiTesterController.php +++ b/app/Http/Controllers/ApiTesterController.php @@ -2,51 +2,25 @@ namespace App\Http\Controllers; +use App\Repos\System\Settings\Legal\PassportRepo; use Illuminate\Http\Request; +use Illuminate\Validation\Rule; class ApiTesterController extends Controller { public function index(Request $request) { - $data = $request->validate([ - 'passport_serie' => 'I-AH', - 'passport_number' => '152304', - 'card_number_masked' => '993403******8088', - 'card_expire_date' => '02/34', + $request->validate([ + 'passport_serie' => ['required', 'string', Rule::in(PassportRepo::values())], + 'passport_number' => ['required', 'numeric', 'digits:6'], + 'card_number_masked' => ['required', 'string', 'max:255'], + 'card_expire_date' => ['required', 'string', 'max:255'], + 'start_date' => ['required', 'date'], + 'end_date' => ['required', 'date'], ]); - return $data; + // $this->fetchApi($data['foo']); // return "
{$response}
"; } - - public function fetchApi( - string $passport_serie, - string $passport_number, - string $card_number_masked, - string $card_expire_date - ) { - $curl = curl_init(); - curl_setopt_array($curl, [ - CURLOPT_URL => 'http://10.3.158.102:9999/api/clientinfo/all', - CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => '', - CURLOPT_MAXREDIRS => 10, - CURLOPT_TIMEOUT => 0, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => 'POST', - CURLOPT_POSTFIELDS => sprintf('{ "idSeria": "%s", "idNo": "%s", "clientType": "recipient", "cardMaskNumber": "%s", "expDate": "%s", "fromDate" : "01.01.2020", "toDate" : "09.05.2025" }', $passport_serie, $passport_number, $card_number_masked, $card_expire_date), - CURLOPT_HTTPHEADER => [ - 'Authorization: Basic dGJ1c2VyOlFBWndzeDEyMw==', - 'Content-Type: application/json', - ], - ]); - - $response = curl_exec($curl); - - curl_close($curl); - - return $response; - } } diff --git a/app/Models/Order/Card/CardTransaction/CardTransaction.php b/app/Models/Order/Card/CardTransaction/CardTransaction.php index 7aaf5a3..9597520 100644 --- a/app/Models/Order/Card/CardTransaction/CardTransaction.php +++ b/app/Models/Order/Card/CardTransaction/CardTransaction.php @@ -4,16 +4,22 @@ namespace App\Models\Order\Card\CardTransaction; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; use Laravel\Nova\Actions\Actionable; /** + * @property int $id * @property string $passport_serie - * @property string $passport_number - * @property string $card_number_masked - * @property string $card_expire_date + * @property string $passport_id + * @property string $card_number + * @property string $card_month + * @property string $card_year + * @property \Illuminate\Support\Carbon $created_at + * @property \Illuminate\Support\Carbon $updated_at */ class CardTransaction extends Model { use Actionable; use HasFactory; + use SoftDeletes; } diff --git a/app/Modules/DateHelper/Repositories/DateHelperRepository.php b/app/Modules/DateHelper/Repositories/DateHelperRepository.php index 2f97cb6..e1032ad 100644 --- a/app/Modules/DateHelper/Repositories/DateHelperRepository.php +++ b/app/Modules/DateHelper/Repositories/DateHelperRepository.php @@ -20,6 +20,24 @@ class DateHelperRepository return $month; } + public static function staticNumberMonths(): array + { + return [ + '01' => '01', + '02' => '02', + '03' => '03', + '04' => '04', + '05' => '05', + '06' => '06', + '07' => '07', + '08' => '08', + '09' => '09', + '10' => '10', + '11' => '11', + '12' => '12', + ]; + } + /** * Years until * @@ -39,4 +57,77 @@ class DateHelperRepository return $years; } + + public static function staticNumberYears(): array + { + return [ + '2024' => '2024', + '2025' => '2025', + '2026' => '2026', + '2027' => '2027', + '2028' => '2028', + '2029' => '2029', + '2030' => '2030', + '2031' => '2031', + '2032' => '2032', + '2033' => '2033', + '2034' => '2034', + '2035' => '2035', + '2036' => '2036', + '2037' => '2037', + '2038' => '2038', + '2039' => '2039', + '2040' => '2040', + '2041' => '2041', + '2042' => '2042', + '2043' => '2043', + '2044' => '2044', + '2045' => '2045', + '2046' => '2046', + '2047' => '2047', + '2048' => '2048', + '2049' => '2049', + '2050' => '2050', + '2051' => '2051', + '2052' => '2052', + '2053' => '2053', + '2054' => '2054', + '2055' => '2055', + '2056' => '2056', + '2057' => '2057', + '2058' => '2058', + '2059' => '2059', + '2060' => '2060', + '2061' => '2061', + '2062' => '2062', + '2063' => '2063', + '2064' => '2064', + '2065' => '2065', + '2066' => '2066', + '2067' => '2067', + '2068' => '2068', + '2069' => '2069', + '2070' => '2070', + '2071' => '2071', + '2072' => '2072', + '2073' => '2073', + '2074' => '2074', + '2075' => '2075', + '2076' => '2076', + '2077' => '2077', + '2078' => '2078', + '2079' => '2079', + '2080' => '2080', + '2081' => '2081', + '2082' => '2082', + '2083' => '2083', + '2084' => '2084', + '2085' => '2085', + '2086' => '2086', + '2087' => '2087', + '2088' => '2088', + '2089' => '2089', + '2090' => '2090', + ]; + } } diff --git a/app/Nova/Resources/Order/Card/CardTransaction/Actions/DownloadCardTransaction.php b/app/Nova/Resources/Order/Card/CardTransaction/Actions/DownloadCardTransaction.php new file mode 100644 index 0000000..72c120d --- /dev/null +++ b/app/Nova/Resources/Order/Card/CardTransaction/Actions/DownloadCardTransaction.php @@ -0,0 +1,104 @@ +first(); + + $start_date = Carbon::create($fields['start_date']); + $end_date = Carbon::create($fields['end_date']); + + $response = $this->fetchApi( + passport_serie: $model->passport_serie, + passport_id: $model->passport_id, + card_number_masked: Str::mask($model->card_number, '*', 6, 6), + card_expire_date: $model->card_month .'/'. substr($model->card_year, 2), + start_date: $start_date->format('d.m.Y'), + end_date: $end_date->format('d.m.Y'), + ); + + info($response); + } + + /** + * Get the fields available on the action. + * + * @param \Laravel\Nova\Http\Requests\NovaRequest $request + * @return array + */ + public function fields(NovaRequest $request): array + { + return [ + Date::make(__('Start date'), 'start_date') + ->default(date('Y-m-d', strtotime('-6 months'))) + ->rules('required'), + + Date::make(__('End date'), 'end_date') + ->default(date('Y-m-d')) + ->rules('required'), + ]; + } + + public function fetchApi( + string $passport_serie, + string $passport_id, + string $card_number_masked, + string $card_expire_date, + string $start_date, + string $end_date + ) { + $curl = curl_init(); + curl_setopt_array($curl, [ + CURLOPT_URL => 'http://10.3.158.102:9999/api/clientinfo/all', + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => sprintf('{ "idSeria": "%s", "idNo": "%s", "clientType": "recipient", "cardMaskNumber": "%s", "expDate": "%s", "fromDate" : "%s", "toDate" : "%s" }', $passport_serie, $passport_id, $card_number_masked, $card_expire_date, $start_date, $end_date), + CURLOPT_HTTPHEADER => [ + 'Authorization: Basic dGJ1c2VyOlFBWndzeDEyMw==', + 'Content-Type: application/json', + ], + ]); + + $response = curl_exec($curl); + + curl_close($curl); + + return $response; + } +} diff --git a/app/Nova/Resources/Order/Card/CardTransaction/CardTransaction.php b/app/Nova/Resources/Order/Card/CardTransaction/CardTransaction.php new file mode 100644 index 0000000..e817880 --- /dev/null +++ b/app/Nova/Resources/Order/Card/CardTransaction/CardTransaction.php @@ -0,0 +1,151 @@ + + */ + public static $model = \App\Models\Order\Card\CardTransaction\CardTransaction::class; + + /** + * The single value that should be used to represent the resource when being displayed. + * + * @var string + */ + public static $title = 'unique_id'; + + /** + * The columns that should be searched. + * + * @var array + */ + public static $search = [ + 'unique_id', + ]; + + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return __('Card transactions'); + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return __('Card transaction'); + } + + /** + * Get the fields displayed by the resource. + * + * @param \Laravel\Nova\Http\Requests\NovaRequest $request + * @return array + */ + public function fields(NovaRequest $request): array + { + return [ + ID::make()->sortable(), + + Hidden::make('user_id') + ->default(auth()->id()) + ->hideWhenUpdating(), + + Select::make(__('Passport serie'), 'passport_serie') + ->displayUsingLabels() + ->searchable() + ->options(PassportRepo::values()) + ->size('w-1/2') + ->rules('required'), + + NovaInputmask::make(__('Passport id'), 'passport_id') + ->mask('999999') + ->size('w-1/2') + ->rules('required', 'numeric', 'digits:6'), + + NovaInputmask::make(__('Card number'), 'card_number') + ->mask('9999-9999-9999-9999') + ->storeRawValue() + ->size('md:w-1/2') + ->rules('required', 'digits:16'), + + Select::make(__('Card').' '.__('Expiration month'), 'card_month') + ->searchable() + ->options(DateHelperRepository::staticNumberMonths()) + ->size('md:w-1/4') + ->rules('required'), + + Select::make(__('Card').' '.__('Expiration year'), 'card_year') + ->searchable() + ->options(DateHelperRepository::staticNumberYears()) + ->size('md:w-1/4') + ->rules('required'), + ]; + } + + /** + * Get the cards available for the request. + * + * @param \Laravel\Nova\Http\Requests\NovaRequest $request + * @return array + */ + public function cards(NovaRequest $request) + { + return []; + } + + /** + * Get the filters available for the resource. + * + * @param \Laravel\Nova\Http\Requests\NovaRequest $request + * @return array + */ + public function filters(NovaRequest $request) + { + return []; + } + + /** + * Get the lenses available for the resource. + * + * @param \Laravel\Nova\Http\Requests\NovaRequest $request + * @return array + */ + public function lenses(NovaRequest $request) + { + return []; + } + + /** + * Get the actions available for the resource. + * + * @param \Laravel\Nova\Http\Requests\NovaRequest $request + * @return array + */ + public function actions(NovaRequest $request) + { + return [ + DownloadCardTransaction::make() + ->icon('arrow-down-tray') + ->sole(), + ]; + } +} diff --git a/app/Repos/System/Nova/NovaMenuRepo.php b/app/Repos/System/Nova/NovaMenuRepo.php index c6f258d..090c795 100644 --- a/app/Repos/System/Nova/NovaMenuRepo.php +++ b/app/Repos/System/Nova/NovaMenuRepo.php @@ -11,6 +11,7 @@ use App\Nova\Resources\CurrencyRate; use App\Nova\Resources\NovaVisaMasterSetting; use App\Nova\Resources\Order\Card\CardOrder; use App\Nova\Resources\Order\Card\CardState; +use App\Nova\Resources\Order\Card\CardTransaction\CardTransaction; use App\Nova\Resources\Order\Card\CardType; use App\Nova\Resources\Order\Card\Pin\CardPin; use App\Nova\Resources\Order\Card\Requisite\CardRequisite; @@ -58,6 +59,7 @@ class NovaMenuRepo MenuItem::resource(CardOrder::class)->name(__('Order new card')), MenuItem::resource(CardRequisite::class), MenuItem::resource(CardPin::class), + MenuItem::resource(CardTransaction::class), ])->collapsedByDefault(), MenuGroup::make(__('International payments'), [ diff --git a/database/migrations/2025_05_21_142230_create_card_transactions_table.php b/database/migrations/2025_05_21_142230_create_card_transactions_table.php index 3bdb447..93aa86b 100644 --- a/database/migrations/2025_05_21_142230_create_card_transactions_table.php +++ b/database/migrations/2025_05_21_142230_create_card_transactions_table.php @@ -13,11 +13,18 @@ return new class extends Migration { Schema::create('card_transactions', function (Blueprint $table) { $table->id(); + $table->string('unique_id')->nullable()->unique(); + $table->string('passport_serie'); - $table->string('passport_number'); - $table->string('card_number_masked'); - $table->string('card_expire_date'); + $table->string('passport_id'); + $table->string('card_number'); + $table->string('card_month'); + $table->string('card_year'); + + $table->foreignId('user_id')->constrained('users')->restrictOnDelete(); + $table->timestamps(); + $table->softDeletes(); }); } diff --git a/lang/tk.json b/lang/tk.json index 6aa1bd0..20d676c 100644 --- a/lang/tk.json +++ b/lang/tk.json @@ -342,5 +342,7 @@ "Settings": "Sazlamalar", "Loan order created": "Karz sargydy döredildi", "Loan order updated": "Karz sargydy üýtgedildi", - "Loan order deleted": "Karz sargydy pozuldy" + "Loan order deleted": "Karz sargydy pozuldy", + "Card transaction": "Kart herekedi", + "Card transactions": "Kart hereketleri" } diff --git a/resources/css/vendor/nova/css/additional.css b/resources/css/vendor/nova/css/additional.css index 5ee8fb7..c5b01e5 100644 --- a/resources/css/vendor/nova/css/additional.css +++ b/resources/css/vendor/nova/css/additional.css @@ -42,3 +42,9 @@ button[dusk="create-and-add-another-button"] { .o1-table thead tr th:first-child { padding-left: 5px; } + +@media (min-width: 768px) { + .md\:w-1\/2 { + width: 50%; + } +} diff --git a/resources/js/vendor/nova/js/additional.js b/resources/js/vendor/nova/js/additional.js index bf74b69..f79bfd8 100644 --- a/resources/js/vendor/nova/js/additional.js +++ b/resources/js/vendor/nova/js/additional.js @@ -166,172 +166,3 @@ async function fetchCardHistory(passport_serie, passport_id, card_number, card_e Nova.$progress.done() }); } - -// window.LaravelNovaWizardStore = { -// data: { -// steps: 0, -// currentStep: 1, -// }, - -// fields: { -// buttonsContainerElement: {}, -// cancelFormButton: {}, -// createFormButton: {}, -// prevButtonElement: {}, -// nextButtonElement: {}, -// }, - -// nextStep() { -// if (this.data.steps > 0 && this.data.currentStep < this.data.steps) { -// document.querySelector(`div[wizard-step="${this.data.currentStep}"]`).style.display = 'none'; - -// this.data.currentStep++; - -// document.querySelector(`div[wizard-step="${this.data.currentStep}"]`).style.display = 'inherit'; - -// return; -// } - -// if (this.data.currentStep === this.data.steps) { -// this.hideNextButton() -// this.showFormSubmitButton() -// } else { -// this.hideFormSubmitButton() -// this.showNextButton() -// } -// }, - -// prevStep() { -// if (this.data.currentStep > 1) { -// document.querySelector(`div[wizard-step="${this.data.currentStep}"]`).style.display = 'none'; - -// this.data.currentStep--; - -// document.querySelector(`div[wizard-step="${this.data.currentStep}"]`).style.display = 'inherit'; -// } -// }, - -// hideNovaFormButtons() { -// this.fields.cancelFormButton = document.querySelector('button[dusk="cancel-create-button"]'); -// this.fields.createFormButton = document.querySelector('button[dusk="create-button"]'); - -// this.fields.buttonsContainerElement = this.fields.createFormButton.parentNode; -// this.hideFormSubmitButton(); -// this.hideFormCancelButton(); -// }, - -// addWizardButtons() { -// this.fields.buttonsContainerElement.insertAdjacentHTML('afterbegin', this.nextButtonTemplate()); -// this.fields.buttonsContainerElement.insertAdjacentHTML('afterbegin', this.prevButtonTemplate()); - -// this.fields.nextButtonElement = document.getElementById('laravel-nova-wizard-next-button'); -// this.fields.prevButtonElement = document.getElementById('laravel-nova-wizard-prev-button'); - -// this.fields.nextButtonElement.addEventListener('click', () => { -// this.nextStep() -// }) - -// this.fields.prevButtonElement.addEventListener('click', () => { -// this.prevStep() -// }) -// }, - -// nextButtonTemplate() { -// return ` -// -// `; -// }, - -// prevButtonTemplate() { -// return ` -// -// `; -// }, - -// hidePrevButton() { -// this.fields.prevButtonElement.style.display = 'none' -// }, - -// showPrevButton() { -// this.fields.prevButtonElement.style.display = 'inherit' -// }, - -// hideNextButton() { -// this.fields.nextButtonElement.style.display = 'none' -// }, - -// showNextButton() { -// this.fields.nextButtonElement.style.display = 'inherit' -// }, - -// showFormSubmitButton() { -// this.fields.createFormButton.style.display = 'inherit'; -// }, - -// hideFormSubmitButton() { -// this.fields.createFormButton.style.display = 'none'; -// }, - -// hideFormCancelButton() { -// this.fields.cancelFormButton.style.display = 'none'; -// } -// }; - -// function setupMultiStepWizard() { -// let refreshIntervalId = setInterval(() => { -// let formElement = document.querySelector('form'); - -// if (formElement) { -// clearInterval(refreshIntervalId) - -// // Div container -// let fieldsContainerElement = formElement.firstChild; -// // Div elements -// let fieldElements = Array.from(fieldsContainerElement.children); - -// // if there a less than 2 divs, no need to wizard it! -// if (fieldElements.length < 2) { -// return; -// } - -// LaravelNovaWizardStore.data.steps = fieldElements.length; -// LaravelNovaWizardStore.hideNovaFormButtons() -// LaravelNovaWizardStore.addWizardButtons() - -// let loopCount = 0; -// fieldElements.forEach(item => { -// loopCount++; -// item.setAttribute('wizard-step', loopCount) - -// if (loopCount === 1) { -// return; -// } - -// item.style.display = 'none' -// }) -// } -// }, 300); -// } - -// Nova.$on('liftedOff', () => { -// if (Nova.$router.page.component === 'Nova.Create') { -// setupMultiStepWizard() -// } -// }) - -// Nova.$router.on('success', (event) => { -// if (event.detail.page.component === 'Nova.Create') { -// setupMultiStepWizard() -// } -// }) - -// document.addEventListener('inertia:navigate', () => { -// console.log('page is updating') -// }) - -// // when app is booting -// Nova.booting((app, store) => {}) diff --git a/resources/views/orders/cards/card-transaction/download-card-transaction.blade.php b/resources/views/orders/cards/card-transaction/download-card-transaction.blade.php new file mode 100644 index 0000000..e69de29