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