Compare commits

..

71 Commits

Author SHA1 Message Date
Mekan1206
a5bc322170 Enhance MigrationController and ShieldSeeder for improved data migration and role management
- Added new migrators: ModelHasRolesMigrator and OnlinePaymentsMigrator to MigrationController.
- Introduced a test method in MigrationController to facilitate online payments migration.
- Updated ShieldSeeder to include role IDs for better role management and added new roles with specific IDs.
2025-12-21 20:58:10 +05:00
Mekan1206
749208ac97 Add new migrators to MigrationController for enhanced data handling
- Included CardOrdersMigrator, CardPinOrdersMigrator, and VisaMasterSettingsMigrator to the MigrationController.
- Updated the index method to incorporate new migrators for improved migration processes.
2025-12-21 20:00:14 +05:00
Mekan1206
1870583441 Add Laravel Sanctum for API authentication and update routes
- Included `laravel/sanctum` in `composer.json` for lightweight API authentication.
- Updated `User` model to use `HasApiTokens` trait for token management.
- Configured API routing in `bootstrap/app.php`.
- Modified `DatabaseSeeder` to include `ShieldSeeder` and adjusted `FillJsonData` seeder method.
- Changed JSON data path in `ProvincesMigrator` for testing purposes.
- Updated web routes to utilize `MigrationController` for better organization.
2025-12-21 19:50:38 +05:00
Mekan1206
76c05ebe7c Refactor ActivityLogModule and clean up seeders
- Adjusted indentation in ActivityLogModule methods for consistency.
- Simplified ActivityLogRepository class by removing unnecessary lines.
- Updated FillJsonData seeder to streamline the run method.
- Modified various Migrator classes to change JSON data paths for testing and added sequence reset statements for better database integrity.
2025-12-21 19:16:26 +05:00
Mekan1206
515731003c Remove activity log migration files and update FillJsonData seeder to include ActionEventsMigrator. Clean up LoanOrdersMigrator comments for clarity. 2025-12-21 18:57:21 +05:00
Mekan1206
a9c7ec6b80 Remove pxlrbt/filament-activity-log dependency from composer.json and update composer.lock. Enhance LoginController validation by adding a rule to exclude a specific username. Minor adjustments in migration files for activity log to improve code organization. 2025-12-21 17:51:38 +05:00
Mekan1206
4038d47582 add composer require spatie/laravel-activitylog 2025-12-21 06:42:41 +05:00
Mekan1206
326987d6de Add phone or username placeholder in login view and update Turkish translations
- Updated the login view to include a placeholder for phone or username input.
- Added a new Turkish translation for the phone or username placeholder to enhance user guidance.
2025-12-21 06:20:41 +05:00
Mekan1206
f433fc3e41 Remove unused Blade components and templates from the Filament package to streamline the codebase. This includes deleting various components related to forms, notifications, pagination, and widgets, enhancing maintainability and reducing clutter. 2025-12-21 06:15:33 +05:00
Mekan1206
5361c00e7b images better 2025-12-21 05:31:08 +05:00
Mekan1206
5e37bd1a76 Enhance ListRecords pages with tab functionality and default sorting
- Added getTabs method to ListCardPinOrders, ListLoanOrders, and ListLoanOrderMobiles pages to display order statuses for system users.
- Implemented default sorting by 'created_at' in LoanOrdersTable and LoanOrderMobilesTable for improved data organization.
- Updated ManageCards page to ensure proper type declaration for getTitle method.
2025-12-21 05:21:53 +05:00
Mekan1206
5a53b90272 Add default sorting to CardPinOrdersTable by creation date
- Updated CardPinOrdersTable to default sort by 'created_at' in descending order for improved data visibility.
2025-12-21 05:11:21 +05:00
Mekan1206
59548a486f Enhance CardOrder model and SMS functionality
- Added unique ID generation and SMS notification upon CardOrder creation.
- Updated CardOrdersTable to default sort by creation date.
- Implemented logging for SMS sending in SmsRepository for better debugging.
2025-12-21 05:05:28 +05:00
Mekan1206
c0bfe974ad Add avatar functionality to User model
- Implemented HasAvatar contract in User model to support avatar management.
- Added getFilamentAvatarUrl method to return the default avatar URL.
2025-12-21 04:20:45 +05:00
Mekan1206
895c5f6226 Update ManageCards page and localization for card creation
- Added a label for the 'Add card' action in the ManageCards page.
- Updated Turkish translations for card creation actions and notifications to improve clarity and consistency.
2025-12-21 04:13:47 +05:00
Mekan1206
88d84ac457 Add title method to ManageCards page for improved user experience 2025-12-21 04:01:05 +05:00
Mekan1206
94ad59ce24 Enhance user role management and update Filament panel middleware
- Added new user roles: operator, operator_card, operator_loan, client, and currency_maintainer in ShieldSeeder.
- Included EnsureUserHasRole middleware in the Filament panel for improved access control.
2025-12-21 03:49:55 +05:00
Mekan1206
b1630ea623 Add policy mappings for VisaMasterPaymentOrder and OnlinePayment models 2025-12-21 03:44:14 +05:00
Mekan1206
6a700fbd4b Enhance user role checks and update card order tabs visibility
- Updated the isSystemUser method to include currency maintainers in role checks.
- Modified getTabs method in ListCardOrders to return an empty array for non-system users.
- Added a dehydrate state function for Turkmen phone numbers in UserForm schema.
2025-12-21 03:38:52 +05:00
Mekan1206
8e548126b2 Refactor VisaMasterPaymentOrdersMigrator to enhance data migration process
- Updated the migration logic to insert records into the 'visa_master_payment_orders' table.
- Improved handling of sender and receiver data by decoding JSON fields and providing fallback values.
- Added a test route in web.php to trigger the migration for debugging purposes.
2025-12-21 03:18:50 +05:00
Mekan1206
2ec9b28a60 Refactor VisaMasterPaymentOrder components and enhance seeding process
- Updated record title attribute in VisaMasterPaymentOrderResource to 'unique_id'.
- Improved schema layout in VisaMasterPaymentOrderForm and VisaMasterPaymentOrderInfolist for better user experience.
- Added 'unique_id' field to VisaMasterPaymentOrderInfolist with styling adjustments.
- Implemented BelongsToBranch interface in VisaMasterPaymentOrder model and added a boot method for loan order creation.
- Expanded FillJsonData seeder to include migration for VisaMasterPaymentOrders.
2025-12-21 02:58:15 +05:00
Mekan1206
4fc242bc7d Update dependencies and enhance components
- Added "halaxa/json-machine" dependency to composer.json.
- Updated content hash in composer.lock to reflect changes.
- Improved SpatieMediaLibraryFileEntry component documentation.
- Expanded FillJsonData seeder to include new migrators for card types, orders, and pin orders.
- Updated Tailwind CSS version in app.css.
- Refactored various JavaScript components for better performance and readability.
- Added a test route in web.php for debugging purpose
2025-12-21 02:41:27 +05:00
Mekan1206
6df3a27383 ignore database/data folder 2025-12-20 02:38:06 +05:00
Mekan1206
7111b1db09 Enhance SpatieMediaLibraryFileEntry component and update PHPStan configuration
- Added a new method to retrieve media for the entry in SpatieMediaLibraryFileEntry component.
- Updated PHPStan configuration to exclude the SpatieMediaLibraryFileEntry.php file from analysis.
2025-12-20 02:34:19 +05:00
Mekan1206
c4ee279d91 Refactor VisaMasterPaymentOrderInfolist and SpatieMediaLibraryFileEntry components
- Cleaned up imports and improved code formatting for better readability.
- Adjusted layout in VisaMasterPaymentOrderInfolist schema for consistent column spans.
- Enhanced SpatieMediaLibraryFileEntry component by streamlining property definitions and ensuring consistent formatting.
2025-12-20 02:30:36 +05:00
Mekan1206
14c4ea5791 Update subNavigationPosition in CardsCluster to Top 2025-12-20 02:28:48 +05:00
Mekan1206
01a0aa8ca1 dont ignore public/build 2025-12-20 00:56:53 +05:00
Mekan1206
97fea41b62 WIP 2025-12-20 00:40:22 +05:00
Mekan1206
5568d32a31 Update project name and enable seeders in DatabaseSeeder
- Changed project name in package-lock.json from 'backend_tbbank' to 'online'.
- Enabled UsersTableSeeder and ShieldSeeder in DatabaseSeeder for data seeding.
2025-12-20 00:29:34 +05:00
4e78ff77cc wip 2025-12-19 17:18:36 +05:00
4c0917e6ba Refactor media display logic in SpatieMediaLibraryFileEntry component
- Simplified media handling by removing the check for images only.
- Updated grid layout for media items to use a consistent column size.
- Enhanced modal functionality to open specific image previews based on item ID.
- Improved code readability by renaming variables and streamlining the foreach loop.
2025-12-09 01:40:07 +05:00
c56e3383d1 wip 2025-12-09 01:26:57 +05:00
967501d58f wip 2025-12-09 00:54:13 +05:00
88fdc3aa7f Update dependencies and refine Filament configuration
- Upgraded @tailwindcss/vite and tailwindcss to version 4.1.17 in package.json.
- Modified Vite configuration to include a new input file for Filament theme.
- Added AdvancedFileUpload component to VisaMasterPaymentOrderForm.
- Removed unused SpatieMediaLibraryFileUpload from VisaMasterPaymentOrderInfolist.
- Enhanced VisaMasterPaymentOrderInfolist schema for better layout and organization.
- Set Vite theme path in WorkPanelProvider for improved styling.
2025-12-08 21:47:06 +05:00
183916a62a add filament-upload-pro 2025-11-18 01:50:54 +05:00
a9490e132d wip 2025-11-18 01:46:06 +05:00
438e5a3f43 Add View Page for VisaMasterPaymentOrder and Update Schema
- Introduced ViewVisaMasterPaymentOrder page for displaying payment order details.
- Updated VisaMasterPaymentOrderResource to include a route for the new view page.
- Enhanced VisaMasterPaymentOrderInfolist schema to include location details and conditional visibility for notes.
- Enabled ViewAction in VisaMasterPaymentOrdersTable for accessing the new view page.
- Modified VisaMasterPaymentOrder model to allow nullable notes property.
2025-11-18 01:09:35 +05:00
cbd469c97f wip 2025-11-18 00:37:21 +05:00
bc45f2756e some stan 2025-11-18 00:34:40 +05:00
73448548e7 wip 2025-11-18 00:30:35 +05:00
f0e9767e78 wip 2025-11-18 00:23:04 +05:00
0e39450849 wip 2025-11-18 00:21:26 +05:00
4c83d41eb0 wip 2025-11-18 00:19:28 +05:00
bccf52a8fb wip 2025-11-18 00:19:04 +05:00
6e03c4d218 wip 2025-11-18 00:16:52 +05:00
53f8c893ca wip 2025-11-18 00:16:04 +05:00
52d070f4e5 wip 2025-11-18 00:13:08 +05:00
209f3899b5 wip 2025-11-18 00:11:11 +05:00
58d6ef0a9a Add navigation sort order to clusters and update profile panel sorting 2025-11-17 23:56:51 +05:00
1a0756fdca wip 2025-11-17 23:37:18 +05:00
f506972c91 wip 2025-11-16 18:05:56 +05:00
19abe08a90 wip 2025-11-16 18:04:18 +05:00
6428c9e20c wip 2025-11-16 17:29:03 +05:00
9d66f21854 wip 2025-11-16 17:27:33 +05:00
da5bb6e99b wip 2025-11-16 17:24:55 +05:00
680d5d4130 wip 2025-11-16 17:23:26 +05:00
f73a510984 wip 2025-11-16 17:20:40 +05:00
4b7c3da3d4 wip 2025-11-16 17:20:09 +05:00
b0877399eb wip 2025-11-16 17:17:23 +05:00
3b5b7f10c4 wip 2025-11-16 17:13:18 +05:00
45e95725cd wip 2025-11-16 17:09:54 +05:00
a98a41efab wip 2025-11-16 17:06:44 +05:00
3911e8e21a wip 2025-11-16 17:03:30 +05:00
dc871f36d4 wip 2025-11-16 17:00:58 +05:00
2dd06d0e4f wip 2025-11-16 16:50:55 +05:00
a9e5f7ece8 wip 2025-11-16 16:48:37 +05:00
7e7d583973 wip 2025-11-16 16:45:36 +05:00
ba6d703893 wip 2025-11-16 16:41:37 +05:00
2bb9ec2ae2 wip 2025-11-16 16:40:06 +05:00
1d67616cdb wip 2025-11-16 16:37:19 +05:00
5a37d56cfb wip 2025-11-16 16:31:16 +05:00
306 changed files with 7588 additions and 15833 deletions

2
.gitignore vendored
View File

@@ -11,9 +11,9 @@
/.phpunit.cache
/.vscode
/.zed
/database/data/
/auth.json
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key

View File

@@ -21,7 +21,12 @@ class ListCardOrders extends ListRecords
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));

View File

@@ -26,6 +26,7 @@ class CardOrdersTable
->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', 'desc')
->columns([
TextColumn::make('unique_id')
->label(__('ID'))

View File

@@ -5,15 +5,23 @@ namespace App\Filament\Clusters\Cards\Cards\Pages;
use App\Filament\Clusters\Cards\Cards\CardResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ManageRecords;
use Illuminate\Contracts\Support\Htmlable;
class ManageCards extends ManageRecords
{
protected static string $resource = CardResource::class;
public function getTitle(): string|Htmlable
{
return __('My cards');
}
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
CreateAction::make()
->label(__('Add card'))
->createAnother(false),
];
}
}

View File

@@ -9,9 +9,11 @@ use Filament\Support\Icons\Heroicon;
class CardsCluster extends Cluster
{
protected static ?int $navigationSort = 1;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCreditCard;
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Start;
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Top;
public static function getNavigationLabel(): string
{

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages;
use App\Filament\Clusters\Cards\Resources\CardPinOrders\CardPinOrderResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListCardPinOrders extends ListRecords
{
@@ -16,4 +18,23 @@ class ListCardPinOrders extends ListRecords
CreateAction::make(),
];
}
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
}

View File

@@ -20,6 +20,7 @@ class CardPinOrdersTable
->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', 'desc')
->columns([
TextColumn::make('id')
->label('ID'),

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Loans\LoanOrders\Pages;
use App\Filament\Clusters\Loans\LoanOrders\LoanOrderResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListLoanOrders extends ListRecords
{
@@ -16,4 +18,23 @@ class ListLoanOrders extends ListRecords
CreateAction::make(),
];
}
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
}

View File

@@ -25,6 +25,7 @@ class LoanOrdersTable
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', 'desc')
->columns([
TextColumn::make('id')
->label('ID')

View File

@@ -9,6 +9,8 @@ use Filament\Support\Icons\Heroicon;
class LoansCluster extends Cluster
{
protected static ?int $navigationSort = 2;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedBanknotes;
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Top;

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages;
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\LoanOrderMobileResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListLoanOrderMobiles extends ListRecords
{
@@ -16,4 +18,23 @@ class ListLoanOrderMobiles extends ListRecords
CreateAction::make(),
];
}
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
}

View File

@@ -25,6 +25,7 @@ class LoanOrderMobilesTable
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', 'desc')
->columns([
TextColumn::make('id')
->label('ID')

View File

@@ -3,8 +3,10 @@
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages;
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\LoanPaidOffLetterResource;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Schemas\Components\Tabs\Tab;
class ListLoanPaidOffLetters extends ListRecords
{
@@ -16,4 +18,23 @@ class ListLoanPaidOffLetters extends ListRecords
CreateAction::make(),
];
}
public function getTabs(): array
{
if (! user()->isSystemUser()) {
return [];
}
$data = [];
foreach (array_keys(OrderStatusRepository::statusClasses()) as $status) {
if ($status === '') {
$data[null] = Tab::make(__('All'));
} else {
$data[$status] = Tab::make(OrderStatusRepository::statusFormatted($status))->query(fn ($query) => $query->where('status', $status));
}
}
return $data;
}
}

View File

@@ -20,6 +20,7 @@ class LoanPaidOffLettersTable
->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', 'desc')
->columns([
TextColumn::make('id')
->label('ID')

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Clusters\OnlinePayments;
use BackedEnum;
use Filament\Clusters\Cluster;
use Filament\Pages\Enums\SubNavigationPosition;
use Filament\Support\Icons\Heroicon;
class OnlinePaymentsCluster extends Cluster
{
protected static ?int $navigationSort = 5;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedServerStack;
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Top;
public static function getNavigationLabel(): string
{
return __('Online payments');
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments;
use App\Filament\Clusters\OnlinePayments\OnlinePaymentsCluster;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Pages\EditOnlinePayment;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Pages\ListOnlinePayments;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Schemas\OnlinePaymentForm;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Tables\OnlinePaymentsTable;
use App\Modules\OnlinePayment\Models\OnlinePayment;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class OnlinePaymentResource extends Resource
{
protected static ?string $model = OnlinePayment::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
protected static ?string $cluster = OnlinePaymentsCluster::class;
protected static ?string $recordTitleAttribute = 'orderId';
public static function form(Schema $schema): Schema
{
return OnlinePaymentForm::configure($schema);
}
public static function table(Table $table): Table
{
return OnlinePaymentsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListOnlinePayments::route('/'),
'edit' => EditOnlinePayment::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Pages;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\OnlinePaymentResource;
use Filament\Resources\Pages\CreateRecord;
class CreateOnlinePayment extends CreateRecord
{
protected static string $resource = OnlinePaymentResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Pages;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\OnlinePaymentResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditOnlinePayment extends EditRecord
{
protected static string $resource = OnlinePaymentResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Pages;
use App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\OnlinePaymentResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListOnlinePayments extends ListRecords
{
protected static string $resource = OnlinePaymentResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,157 @@
<?php
namespace App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Schemas;
use App\Modules\OnlinePayment\Repositories\OnlinePaymentRepository;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Fieldset;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
class OnlinePaymentForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Section::make()
->columnSpanFull()
->columns([
'default' => 1,
'md' => 2,
'xl' => 3,
])
->schema([
// Payment Information
Fieldset::make(__('Payment Information'))
->columns([
'default' => 1,
'md' => 2,
])
->schema([
TextInput::make('amount')
->label(__('Amount'))
->required()
->numeric()
->suffix('TMT')
->rules(['required', 'numeric', 'min:0']),
TextInput::make('description')
->label(__('Description'))
->required()
->maxLength(255),
TextInput::make('orderNumber')
->label(__('Order Number'))
->maxLength(255)
->helperText(__('Leave empty to auto-generate')),
Select::make('paymentStatus')
->label(__('Payment Status'))
->options(OnlinePaymentRepository::statusValues())
->default(OnlinePaymentRepository::PENDING)
->required(),
]),
// Card Information
Fieldset::make(__('Card Information'))
->columns([
'default' => 1,
'md' => 2,
])
->schema([
TextInput::make('cardholderName')
->label(__('Cardholder Name'))
->maxLength(255),
TextInput::make('pan')
->label(__('Card Number (PAN)'))
->maxLength(255)
->mask('9999 9999 9999 9999')
->placeholder('1234 5678 9012 3456'),
TextInput::make('expiration')
->label(__('Expiration Date'))
->mask('99/99')
->placeholder('MM/YY'),
TextInput::make('approvalCode')
->label(__('Approval Code'))
->maxLength(255),
]),
// Additional Information
Fieldset::make(__('Additional Information'))
->columns([
'default' => 1,
'md' => 2,
])
->schema([
TextInput::make('booking_number')
->label(__('Booking Number'))
->maxLength(255),
TextInput::make('depositedAmount')
->label(__('Deposited Amount'))
->numeric()
->suffix('TMT'),
TextInput::make('refunded_amount')
->label(__('Refunded Amount'))
->numeric()
->suffix('TMT'),
TextInput::make('username')
->label(__('Username'))
->maxLength(255)
->helperText(__('Payment provider username')),
]),
// URLs
Fieldset::make(__('URLs'))
->columns([
'default' => 1,
'md' => 2,
])
->schema([
TextInput::make('formUrl')
->label(__('Form URL'))
->url()
->maxLength(255),
TextInput::make('successUrl')
->label(__('Success URL'))
->url()
->maxLength(255),
TextInput::make('errorUrl')
->label(__('Error URL'))
->url()
->maxLength(255),
]),
// API Information
Fieldset::make(__('API Information'))
->columns([
'default' => 1,
'md' => 2,
])
->schema([
TextInput::make('api_client')
->label(__('API Client'))
->maxLength(255),
TextInput::make('callbackStatus')
->label(__('Callback Status'))
->maxLength(255),
TextInput::make('orderId')
->label(__('Order ID'))
->maxLength(255)
->helperText(__('External order identifier')),
]),
]),
]);
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace App\Filament\Clusters\OnlinePayments\Resources\OnlinePayments\Tables;
use App\Modules\OnlinePayment\Repositories\OnlinePaymentRepository;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class OnlinePaymentsTable
{
public static function configure(Table $table): Table
{
return $table
->defaultSort('created_at', direction: 'desc')
->columns([
TextColumn::make('id')
->label(__('ID'))
->sortable(),
TextColumn::make('orderNumber')
->label(__('Order Number'))
->searchable()
->sortable(),
TextColumn::make('amount')
->label(__('Amount'))
->money('TMT')
->sortable(),
TextColumn::make('description')
->label(__('Description'))
->limit(50),
TextColumn::make('paymentStatus')
->label(__('Payment Status'))
->badge()
->color(fn (string $state): string => match ($state) {
OnlinePaymentRepository::PAID => 'success',
OnlinePaymentRepository::FAILED => 'danger',
default => 'warning',
})
->formatStateUsing(fn (string $state): string => OnlinePaymentRepository::statusValues()[$state] ?? $state)
->sortable(),
TextColumn::make('cardholderName')
->label(__('Cardholder Name'))
->searchable()
->sortable(),
TextColumn::make('pan')
->label(__('Card Number'))
->formatStateUsing(fn (string $state): string => $state ? '**** **** **** '.substr($state, -4) : '-')
->searchable(),
TextColumn::make('orderId')
->label(__('Order ID'))
->searchable()
->sortable(),
TextColumn::make('username')
->label(__('Username'))
->searchable()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('created_at')
->label(__('Created At'))
->dateTime()
->sortable()
->toggleable(),
TextColumn::make('updated_at')
->label(__('Updated At'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -9,6 +9,8 @@ use Filament\Support\Icons\Heroicon;
class UsersCluster extends Cluster
{
protected static ?int $navigationSort = 6;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedUsers;
protected static string|BackedEnum|null $activeNavigationIcon = Heroicon::Users;

View File

@@ -2,9 +2,11 @@
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages;
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Schemas\VisaMasterPaymentOrderInfolist;
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\VisaMasterPaymentOrderResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
class ViewVisaMasterPaymentOrder extends ViewRecord
@@ -18,4 +20,9 @@ class ViewVisaMasterPaymentOrder extends ViewRecord
->icon(Heroicon::OutlinedPencil),
];
}
public function infolist(Schema $schema): Schema
{
return VisaMasterPaymentOrderInfolist::configure($schema);
}
}

View File

@@ -22,6 +22,7 @@ use Filament\Schemas\Components\Wizard\Step;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Facades\Auth;
use RalphJSmit\Filament\Upload\Filament\Forms\Components\AdvancedFileUpload;
class VisaMasterPaymentOrderForm
{
@@ -146,10 +147,9 @@ class VisaMasterPaymentOrderForm
->columnSpanFull()
->columns(2)
->schema([
SpatieMediaLibraryFileUpload::make('sender_passport_local')
->collection('sender_passport_local')
->label(__('Ugradyja degişli Türkmenistanyň raýatynyň (içki milli) pasportynyň asyl görnüşi we göçürmesi'))
->required(),
AdvancedFileUpload::make('sender_passport_local')
->spatieMediaLibrary(collection: 'sender_passport_local')
->multiple(),
SpatieMediaLibraryFileUpload::make('sender_passport_international')
->collection('sender_passport_international')

View File

@@ -2,11 +2,12 @@
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Schemas;
use App\Filament\Infolists\Components\SpatieMediaLibraryFileEntry;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use App\Modules\Region\Repositories\RegionRepository;
use App\Modules\TurkmenPassport\Repositories\TurkmenPassportRepository;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
use Filament\Infolists\Components\IconEntry;
use Filament\Infolists\Components\SpatieMediaLibraryImageEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Fieldset;
use Filament\Schemas\Components\Section;
@@ -14,6 +15,7 @@ use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Str;
class VisaMasterPaymentOrderInfolist
{
@@ -23,8 +25,13 @@ class VisaMasterPaymentOrderInfolist
->components([
Section::make()
->columnSpanFull()
->columns(3)
->columns(4)
->components([
TextEntry::make('unique_id')
->label(__('Order ID'))
->columnSpan(1)
->extraAttributes(['style' => 'text-transform:uppercase;font-size:1.5em;font-weight:bold;']),
TextEntry::make('type')
->label(__('Payment type'))
->extraAttributes(['style' => 'text-transform:uppercase;font-size:1.5em;font-weight:bold;']),
@@ -43,90 +50,93 @@ class VisaMasterPaymentOrderInfolist
->trueColor('success')
->falseColor('danger'),
Fieldset::make(__('Location'))
->schema([
TextEntry::make('region')
->label(__('Region'))
->formatStateUsing(fn (string $state): string => RegionRepository::label($state)),
TextEntry::make('branch.name')
->label(__('Branch'))
->placeholder('-'),
])
->columnSpan(2),
TextEntry::make('notes')
->label(__('Bellik'))
->html()
->columnSpanFull()
->visible(fn (VisaMasterPaymentOrder $record): bool => ! is_null($record->notes) && $record->notes != '' && $record->notes != '<p></p>' && Str::length($record->notes) > 7)
->columnSpan(2)
->placeholder('-'),
]),
Tabs::make('Order Information')
->tabs([
Tab::make(__('Order type and bank'))
->schema([
Fieldset::make(__('Location'))
->schema([
TextEntry::make('region')
->label(__('Region'))
->formatStateUsing(fn ($state) => RegionRepository::values()[$state] ?? $state),
TextEntry::make('branch.name')
->label(__('Branch'))
->placeholder('-'),
]),
]),
Tab::make(__('Payment sender data'))
->columns(8)
->schema([
TextEntry::make('sender_full_name')
->label(__('Name, Surname, Patronic name'))
->columnSpan(4)
->placeholder('-'),
Fieldset::make(__('Data'))
->columnSpan(8)
->columns(8)
->schema([
TextEntry::make('sender_full_name')
->label(__('Name, Surname, Patronic name'))
->columnSpan(4)
->placeholder('-'),
TextEntry::make('sender_passport')
->label(__('Passport serie and number'))
->formatStateUsing(function ($record) {
$serie = TurkmenPassportRepository::values()[$record->sender_passport_serie] ?? $record->sender_passport_serie;
TextEntry::make('sender_passport')
->label(__('Passport serie and number'))
->formatStateUsing(function ($record) {
$serie = TurkmenPassportRepository::values()[$record->sender_passport_serie] ?? $record->sender_passport_serie;
return $serie.' '.$record->sender_passport_number;
})
->columnSpan(2)
->placeholder('-'),
return $serie.' '.$record->sender_passport_number;
})
->columnSpan(2)
->placeholder('-'),
TextEntry::make('phone')
->label(__('Phone'))
->formatStateUsing(fn ($state) => '+993 '.$state)
->columnSpan(2)
->placeholder('-'),
TextEntry::make('phone')
->label(__('Phone'))
->formatStateUsing(fn ($state) => '+993 '.$state)
->columnSpan(2)
->placeholder('-'),
TextEntry::make('sender_deposit_account')
->label(__('Deposit account'))
->columnSpan(4)
->placeholder('-'),
TextEntry::make('sender_deposit_account')
->label(__('Deposit account'))
->columnSpan(4)
->placeholder('-'),
TextEntry::make('address')
->label(__('Address'))
->columnSpan(4)
->placeholder('-'),
TextEntry::make('address')
->label(__('Address'))
->columnSpan(4)
->placeholder('-'),
]),
Section::make(__('Files'))
->description('PNG, JPEG, PDF')
->columnSpanFull()
->columns(2)
->schema([
SpatieMediaLibraryImageEntry::make('sender_passport_local')
SpatieMediaLibraryFileEntry::make('sender_passport_local')
->collection('sender_passport_local')
->label(__('Ugradyja degişli Türkmenistanyň raýatynyň (içki milli) pasportynyň asyl görnüşi we göçürmesi')),
SpatieMediaLibraryImageEntry::make('sender_passport_international')
SpatieMediaLibraryFileEntry::make('sender_passport_international')
->collection('sender_passport_international')
->label(__('Ugradyja degişli Türkmenistandan çykmak we Türkmenistana girmek üçin pasportynyň asyl görnüşi we göçürmesi')),
SpatieMediaLibraryImageEntry::make('sender_travel_stamp_on_passport')
SpatieMediaLibraryFileEntry::make('sender_travel_stamp_on_passport')
->collection('sender_travel_stamp_on_passport')
->label(__('Ugradyja degişli Türkmenistandan çykmak we Türkmenistana girmek üçin pasportyndaky daşary döwletine gidendigi we daşary döwlete barandygy baradaky (ştampyň) bellenen sahypasynyň göçürmesi')),
SpatieMediaLibraryImageEntry::make('sender_proof_of_kinship')
SpatieMediaLibraryFileEntry::make('sender_proof_of_kinship')
->collection('sender_proof_of_kinship')
->label(__('Ugradyjynyň we kabul edijiniň (talybyň) özara garyndaşlyk derejesini tassyklaýjy resminamalarynyň göçürmesi')),
SpatieMediaLibraryImageEntry::make('sender_passport_local_old')
SpatieMediaLibraryFileEntry::make('sender_passport_local_old')
->collection('sender_passport_local_old')
->label(__('Ugradyjy we kabul ediji (talyp) 2015-nji ýyldan soňra Türkmenistanyň raýatynyň pasportyny ikinji gezek alan bolsa, onda birinji gezek alan pasportynyň seriýasy baradaky maglumat')),
SpatieMediaLibraryImageEntry::make('sender_passport_local_old_replacement')
SpatieMediaLibraryFileEntry::make('sender_passport_local_old_replacement')
->collection('sender_passport_local_old_replacement')
->label(__('Ugradyjy we kabul ediji (talyp) 2015-nji ýyldan soňra Türkmenistanyň raýatynyň pasportyny ikinji gezek alandan soňra birinji gezek alan pasportynyň seriýasy baradaky maglumaty bilmeýän ,bolsa onda polisiýanyň degişli edaralaryndan birinji alan pasportynyň seriýasy baradaky güwänamasy')),
]),
@@ -155,42 +165,42 @@ class VisaMasterPaymentOrderInfolist
->columnSpanFull()
->columns(2)
->schema([
SpatieMediaLibraryImageEntry::make('receiver_requisite')
SpatieMediaLibraryFileEntry::make('receiver_requisite')
->collection('receiver_requisite')
->label(__('Talyba degişli walýuta "VISA" kartyň rekwizitleri'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_document_stating_he_is_studying')
SpatieMediaLibraryFileEntry::make('receiver_document_stating_he_is_studying')
->collection('receiver_document_stating_he_is_studying')
->label(__('Talybyň daşary ýurt döwletiniň ýokary okuw mekdebinde okaýandygy baradaky güwänamasy'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_ticket')
SpatieMediaLibraryFileEntry::make('receiver_ticket')
->collection('receiver_ticket')
->label(__('Talybyň bilediniň göçürmesi'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_passport_local')
SpatieMediaLibraryFileEntry::make('receiver_passport_local')
->collection('receiver_passport_local')
->label(__('Talyba degişli Türkmenistanyň raýatynyň (içki milli) pasportynyň asyl görnüşi we göçürmesi'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_passport_international')
SpatieMediaLibraryFileEntry::make('receiver_passport_international')
->collection('receiver_passport_international')
->label(__('Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin (zagran) pasportynyň göçürmesi'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_visa')
SpatieMediaLibraryFileEntry::make('receiver_visa')
->collection('receiver_visa')
->label(__('Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin pasportyndaky daşary ýurtda galyp okap bilýändigi baradaky berlen möhleti hereket edýän rugsatnamasynyň (wizasynyň) bellenen sahypasynyň göçürmesi'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_travel_stamp_on_passport')
SpatieMediaLibraryFileEntry::make('receiver_travel_stamp_on_passport')
->collection('receiver_travel_stamp_on_passport')
->label(__('Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin pasportyndaky Türkmenistandan çykandygy we daşary ýurt döwletine girendigi baradaky ştamplaryň (seneli ştampyň) bellenen sahypasynyň göçürmesi'))
->columnSpan(1),
SpatieMediaLibraryImageEntry::make('receiver_document_stating_he_is_studying_2')
SpatieMediaLibraryFileEntry::make('receiver_document_stating_he_is_studying_2')
->collection('receiver_document_stating_he_is_studying_2')
->label(__('Talybyň daşary ýurt döwletiniň ýokary okuw mekdebinde okaýandygy baradaky güwänamasyndaky maglumatyň doly takyk däl ýagdaýynda takyk däl maglumatyň sebäpleri baradaky daşary ýurt döwletiniň ýokary okuw mekdebinden haty'))
->columnSpan(1),

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Tables;
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
use App\Modules\Region\Repositories\RegionRepository;
use Filament\Actions\BulkActionGroup;
@@ -14,6 +15,7 @@ use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;
class VisaMasterPaymentOrdersTable
@@ -21,6 +23,10 @@ class VisaMasterPaymentOrdersTable
public static function configure(Table $table): Table
{
return $table
->modifyQueryUsing(function (Builder $query) {
DefaultQueryForResourceIndexRepository::make($query);
})
->defaultSort('created_at', direction: 'desc')
->columns([
TextColumn::make('id')
->label(__('ID'))
@@ -67,7 +73,7 @@ class VisaMasterPaymentOrdersTable
TrashedFilter::make(),
])
->recordActions([
// ViewAction::make(),
ViewAction::make(),
EditAction::make(),
])
->toolbarActions([

View File

@@ -25,7 +25,7 @@ class VisaMasterPaymentOrderResource extends Resource
protected static ?string $cluster = VisaMasterPaymentsCluster::class;
protected static ?string $recordTitleAttribute = 'id';
protected static ?string $recordTitleAttribute = 'unique_id';
protected static string|BackedEnum|null $navigationIcon = 'icon-visa-plain';
@@ -66,7 +66,7 @@ class VisaMasterPaymentOrderResource extends Resource
return [
'index' => ListVisaMasterPaymentOrders::route('/'),
'create' => CreateVisaMasterPaymentOrder::route('/create'),
'view' => ViewVisaMasterPaymentOrder::route('/{record}'),
'view' => ViewVisaMasterPaymentOrder::route('/{record}/view'),
'edit' => EditVisaMasterPaymentOrder::route('/{record}/edit'),
];
}

View File

@@ -8,6 +8,8 @@ use Filament\Pages\Enums\SubNavigationPosition;
class VisaMasterPaymentsCluster extends Cluster
{
protected static ?int $navigationSort = 3;
protected static string|BackedEnum|null $navigationIcon = 'icon-visa-plain';
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Top;

View File

@@ -0,0 +1,174 @@
<?php
namespace App\Filament\Infolists\Components;
use Closure;
use Filament\Actions\Action;
use Filament\Infolists\Components\Entry;
use Filament\Support\Concerns\HasMediaFilter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Spatie\MediaLibrary\MediaCollections\Models\Collections\MediaCollection;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Throwable;
class SpatieMediaLibraryFileEntry extends Entry
{
use HasMediaFilter;
public function getViewMediaActionName(): string
{
return 'view_media_'.$this->getName();
}
protected function setUp(): void
{
parent::setUp();
$this->registerActions([
Action::make($this->getViewMediaActionName())
->label(__('Watch Full'))
->modalContent(fn (array $arguments) => view('filament.infolists.components.image-modal', ['url' => $arguments['url']]))
->modalSubmitAction(false)
->modalCancelAction(false)
->modalWidth('5xl'),
]);
}
protected string $view = 'filament.infolists.components.spatie-media-library-file-entry';
protected string|Closure|null $collection = null;
protected string|Closure|null $conversion = null;
protected string|Closure $visibility = 'private';
protected bool|Closure $isDownloadable = true;
protected bool|Closure $isPreviewable = true;
public function collection(string|Closure|null $collection): static
{
$this->collection = $collection;
return $this;
}
public function conversion(string|Closure|null $conversion): static
{
$this->conversion = $conversion;
return $this;
}
public function visibility(string|Closure $visibility): static
{
$this->visibility = $visibility;
return $this;
}
public function downloadable(bool|Closure $condition = true): static
{
$this->isDownloadable = $condition;
return $this;
}
public function previewable(bool|Closure $condition = true): static
{
$this->isPreviewable = $condition;
return $this;
}
public function getCollection(): ?string
{
return $this->evaluate($this->collection);
}
public function getConversion(): ?string
{
return $this->evaluate($this->conversion);
}
public function getVisibility(): string
{
return (string) $this->evaluate($this->visibility);
}
public function isDownloadable(): bool
{
return (bool) $this->evaluate($this->isDownloadable);
}
public function isPreviewable(): bool
{
return (bool) $this->evaluate($this->isPreviewable);
}
public function getMediaUrl(Media $media, ?string $conversion = null): string
{
if ($this->getVisibility() === 'private') {
try {
return $media->getTemporaryUrl(
now()->addMinutes(30)->endOfHour(),
$conversion ?? '',
);
} catch (Throwable $exception) {
// This driver does not support creating temporary URLs.
}
}
return $media->getUrl($conversion ?? '');
}
/**
* Get the media for the entry
*
* @return Collection<array-key, Media>
*/
public function getMedia(): Collection
{
$record = $this->getRecord();
if (! $record) {
return collect([]);
}
if ($this->hasStateRelationship($record)) {
$record = $this->getStateRelationshipResults($record);
}
$records = Arr::wrap($record);
$allMedia = collect([]);
$collection = $this->getCollection() ?? 'default';
foreach ($records as $record) {
/** @var Model $record */
$media = $record->getRelationValue('media');
if (! $media) {
continue;
}
$filteredMedia = $media
->when(
is_string($collection),
fn (MediaCollection $mediaCollection) => $mediaCollection->filter(fn (Media $media): bool => $media->getAttributeValue('collection_name') === $collection),
)
->when(
$this->hasMediaFilter(),
fn (Collection $media) => $this->filterMedia($media)
)
->sortBy('order_column');
$allMedia = $allMedia->merge($filteredMedia);
}
return $allMedia;
}
}

View File

@@ -32,6 +32,7 @@ class UserForm
->unique(ignoreRecord: true)
->mask('99 99 99 99')
->prefix('+993')
->dehydrateStateUsing(fn ($state) => unMaskTurkmenNumber($state))
->rules([
new PhoneNumberVerificationRule,
])

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Database\Seeders\Migrators\ActionEventsMigrator;
use Database\Seeders\Migrators\BranchUserMigrator;
use Database\Seeders\Migrators\CurrencyRatesMigrator;
use Database\Seeders\Migrators\LoanOrderRequiredDocsMigrator;
use Database\Seeders\Migrators\LoanOrdersMigrator;
use Database\Seeders\Migrators\LoanTypesMigrator;
use Database\Seeders\Migrators\MediaMigrator;
use Database\Seeders\Migrators\ProvincesMigrator;
use Database\Seeders\Migrators\BranchesMigrator;
use Database\Seeders\Migrators\UsersMigrator;
use Database\Seeders\Migrators\CardStatesMigrator;
use Database\Seeders\Migrators\CardTypesMigrator;
use Database\Seeders\Migrators\VisaMasterPaymentOrdersMigrator;
use Database\Seeders\Migrators\VerificationsMigrator;
use Database\Seeders\Migrators\PersonalAccessTokensMigrator;
use Database\Seeders\Migrators\CardOrdersMigrator;
use Database\Seeders\Migrators\VisaMasterSettingsMigrator;
use Database\Seeders\Migrators\CardPinOrdersMigrator;
use Database\Seeders\Migrators\ModelHasRolesMigrator;
use Database\Seeders\Migrators\OnlinePaymentsMigrator;
class MigrationController extends Controller
{
public function index()
{
return $this->test();
$migrators = [
new ActionEventsMigrator(),
new UsersMigrator(),
new ProvincesMigrator(),
new BranchesMigrator(),
new BranchUserMigrator(),
new CardStatesMigrator(),
new CardTypesMigrator(),
new VerificationsMigrator(),
new CurrencyRatesMigrator(),
new LoanOrderRequiredDocsMigrator(),
new PersonalAccessTokensMigrator(),
new LoanTypesMigrator(),
new CardOrdersMigrator(),
new CardPinOrdersMigrator(),
new LoanOrdersMigrator(),
new ModelHasRolesMigrator(),
new VisaMasterPaymentOrdersMigrator(),
new OnlinePaymentsMigrator(),
new MediaMigrator(),
];
foreach ($migrators as $migrator) {
$migrator->migrate();
}
return 'done';
}
public function test()
{
(new OnlinePaymentsMigrator())->migrate();
return 'done';
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserHasRole
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
// if user does not have any role, add role "client"
/** @var \App\Models\User */
$user = $request->user();
if ($user->roles->count() == 0) {
$user->assignRole('client');
}
return $next($request);
}
}

View File

@@ -4,11 +4,13 @@ namespace App\Models;
use App\Modules\UserAdjustments\Traits\UserAdjustments;
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasAvatar;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Date;
use Laravel\Sanctum\HasApiTokens;
/**
* @property int $id
@@ -20,13 +22,14 @@ use Illuminate\Support\Facades\Date;
* @property Date|null $created_at
* @property Date|null $updated_at
*/
class User extends Authenticatable implements FilamentUser
class User extends Authenticatable implements FilamentUser, HasAvatar
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory;
use Notifiable;
use UserAdjustments;
use HasApiTokens;
/**
* The attributes that are mass assignable.
@@ -56,4 +59,12 @@ class User extends Authenticatable implements FilamentUser
{
return true;
}
/**
* Get the avatar URL for the user.
*/
public function getFilamentAvatarUrl(): ?string
{
return '/assets/images/avatar.png';
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Modules\ActivityLog;
use App\Modules\Makeable;
use App\Modules\ModuleContract;
class ActivityLogModule implements ModuleContract
{
use Makeable;
/**
* Module is enabled
*/
protected bool $enabled = true;
/**
* Check if is module enabled
*/
public function isEnabled(): bool
{
return $this->enabled;
}
/**
* Disable module
*/
public function disable(): void
{
$this->enabled = false;
}
/**
* Enable module
*/
public function enable(): void
{
$this->enabled = true;
}
/**
* Check if module has a filament resource
*/
public function hasFilamentResource(): bool
{
return false;
}
/**
* Get module composer requirements
*/
public function getComposerRequirements(): array
{
return [];
}
/**
* Get module composer suggestions
*/
public function getComposerSuggestions(): array
{
return [];
}
}

View File

@@ -0,0 +1,5 @@
<?php
namespace App\Modules\ActivityLog\Repositories;
class ActivityLogRepository {}

View File

@@ -14,6 +14,7 @@ use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
class LoginController extends Controller
{
@@ -113,7 +114,7 @@ class LoginController extends Controller
protected function validateLogin(Request $request): void
{
$request->validate([
$this->username() => ['required', 'string', 'max:250'],
$this->username() => ['required', 'string', 'max:250', Rule::notIn('65999990', 'ulanyjy_ady')],
'password' => ['required', 'string', 'max:250'],
]);
}

View File

@@ -30,4 +30,5 @@ return [
'go_back' => 'Yza',
'successfully_changed_phone' => 'Telefon belgiňiz üýtgedildi',
'resend' => 'Täze tassyklaýyş belgi ugratmak',
'phone_or_username_placeholder' => 'meselem: 65999990 yada ulanyjy_ady',
];

View File

@@ -49,11 +49,12 @@ async function login(event) {
id="username"
type="text"
name="username"
placeholder="+99365999990 {{ __('or') }} {{ __('module.base-auth::base.username') }}"
placeholder="65999990 {{ __('or') }} {{ __('module.base-auth::base.username') }}"
autofocus=""
value="{{ old('username') }}"
>
<span class="text-gray-500 text-xs">{{ __('module.base-auth::base.phone_or_username_placeholder') }}</span>
<span id="username-error-box" class="text-red-500 text-italic error-box"></span>
</div>

View File

@@ -109,7 +109,16 @@ class CardOrder extends Model implements BelongsToBranch, HasStatus
parent::boot();
static::creating(LoanOrderRepository::creating());
static::created(LoanOrderRepository::created());
static::created(function ($model) {
$uniqueId = LoanOrderRepository::generateUniqueId($model);
$model->update(['unique_id' => $uniqueId]);
sendSMS(
$model->phone,
__('module.card-order::base.card_order_created', ['order_id' => $uniqueId])
);
});
}
/**

View File

@@ -19,7 +19,7 @@ class CardOrderRepository
/** @var \App\Modules\Branch\Models\Branch */
$branch = $record->branch;
return OnlinePaymentRepository::make(relatedModel: $record)
return OnlinePaymentRepository::make(relatedModel: $record, apiClient: 'billing')
->setPaymentProvider(
HalkbankOnlinePaymentRepository::make()
->setUsername($branch->billingUsername())

View File

@@ -0,0 +1,5 @@
<?php
return [
'card_order_created' => 'Kart sargydyňyz :order_id belgi bilen hasaba alyndy. Sargydy tassyklamak üçin operatorymyz habarlaşar.',
];

View File

@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace App\Modules\CurrencyRate\Policies;
use App\Modules\CurrencyRate\Models\CurrencyRate;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Foundation\Auth\User as AuthUser;
class CurrencyRatePolicy
{
use HandlesAuthorization;
public function viewAny(AuthUser $authUser): bool
{
return $authUser->can('ViewAny:CurrencyRate');
}
public function view(AuthUser $authUser, CurrencyRate $currencyRate): bool
{
return $authUser->can('View:CurrencyRate');
}
public function create(AuthUser $authUser): bool
{
return $authUser->can('Create:CurrencyRate');
}
public function update(AuthUser $authUser, CurrencyRate $currencyRate): bool
{
return $authUser->can('Update:CurrencyRate');
}
public function delete(AuthUser $authUser, CurrencyRate $currencyRate): bool
{
return $authUser->can('Delete:CurrencyRate');
}
public function restore(AuthUser $authUser, CurrencyRate $currencyRate): bool
{
return $authUser->can('Restore:CurrencyRate');
}
public function forceDelete(AuthUser $authUser, CurrencyRate $currencyRate): bool
{
return $authUser->can('ForceDelete:CurrencyRate');
}
public function forceDeleteAny(AuthUser $authUser): bool
{
return $authUser->can('ForceDeleteAny:CurrencyRate');
}
public function restoreAny(AuthUser $authUser): bool
{
return $authUser->can('RestoreAny:CurrencyRate');
}
public function replicate(AuthUser $authUser, CurrencyRate $currencyRate): bool
{
return $authUser->can('Replicate:CurrencyRate');
}
public function reorder(AuthUser $authUser): bool
{
return $authUser->can('Reorder:CurrencyRate');
}
}

View File

@@ -23,14 +23,20 @@ class HalkbankOnlinePaymentRepository implements PaymentProviderContract
protected string $returnUrl = '',
protected string $description = '',
) {
$this->username = config()->string('module.halkbank-online-payment.username');
$this->password = config()->string('module.halkbank-online-payment.password');
$this->returnUrl = config()->string('module.halkbank-online-payment.returnUrl');
$this->orderNumber = $this->generateOrderNumber();
$this->username = $username !== '' ? $username : config()->string('module.halkbank-online-payment.username');
$this->password = $password !== '' ? $password : config()->string('module.halkbank-online-payment.password');
$this->amount = $amount;
$this->orderNumber = $orderNumber !== '' ? $orderNumber : $this->generateOrderNumber();
$this->returnUrl = $returnUrl !== '' ? $returnUrl : config()->string('module.halkbank-online-payment.returnUrl');
$this->description = $description !== '' ? $description : __('Payment');
}
/**
* Send request to gatewat
* Send request to gateway
*/
public function sendRequest(): Response
{

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Modules\OnlinePayment\Policies;
use App\Models\User;
use App\Modules\OnlinePayment\Models\OnlinePayment;
use Illuminate\Auth\Access\HandlesAuthorization;
class OnlinePaymentPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
return $user->can('ViewAny:OnlinePayment');
}
public function view(User $user, OnlinePayment $onlinePayment): bool
{
return $user->can('View:OnlinePayment');
}
public function create(User $user): bool
{
return $user->can('Create:OnlinePayment');
}
public function update(User $user, OnlinePayment $onlinePayment): bool
{
return $user->can('Update:OnlinePayment');
}
public function delete(User $user, OnlinePayment $onlinePayment): bool
{
return $user->can('Delete:OnlinePayment');
}
public function restore(User $user, OnlinePayment $onlinePayment): bool
{
return $user->can('Restore:OnlinePayment');
}
public function forceDelete(User $user, OnlinePayment $onlinePayment): bool
{
return $user->can('ForceDelete:OnlinePayment');
}
}

View File

@@ -8,6 +8,8 @@ use App\Modules\OnlinePayment\Models\OnlinePayment;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
class OnlinePaymentRepository
{
@@ -48,6 +50,11 @@ class OnlinePaymentRepository
*/
protected OnlinePayment $onlinePayment;
/**
* API client
*/
protected string $apiClient;
/**
* If payment is successful
*/
@@ -68,9 +75,10 @@ class OnlinePaymentRepository
*/
protected string $paymentLink;
public function __construct(?Model $relatedModel = null)
public function __construct(?Model $relatedModel = null, string $apiClient = '')
{
$this->relatedModel = $relatedModel;
$this->apiClient = $apiClient;
}
/**
@@ -166,6 +174,21 @@ class OnlinePaymentRepository
$this->paymentLink = string($this->response['formUrl']);
$this->createHistory();
} else {
Config::set('logging.channels.halkbank_payment_error', [
'driver' => 'single',
'path' => storage_path('logs/halkbank_payment_error.log'),
'level' => 'debug',
]);
Log::channel('halkbank_payment_error')
->error('Payment error', [
'response' => [
'title' => 'REGISTER',
'error' => $this->response->body(),
'file_line' => __FILE__.':'.__LINE__,
],
]);
}
return $this;
@@ -194,6 +217,7 @@ class OnlinePaymentRepository
'errorUrl' => $this->provider->returnUrl(),
'username' => $this->provider->username(),
'paymentStatus' => self::PENDING,
'api_client' => $this->apiClient,
];
if ($this->relatedModel) {
@@ -236,16 +260,19 @@ class OnlinePaymentRepository
/** @var \App\Modules\Branch\Models\Branch */
$bankBranch = $relatedResource->branch;
if (! $bankBranch || is_null($bankBranch->billing_username) || is_null($bankBranch->billing_password)) { // @phpstan-ignore-line
return $this->paymentFailed('(BRANCH NOT FOUND)');
$username = $bankBranch->offsetExists($paymentHistory->api_client.'_username') ? $bankBranch->{$paymentHistory->api_client.'_username'} : '';
$password = $bankBranch->offsetExists($paymentHistory->api_client.'_password') ? $bankBranch->{$paymentHistory->api_client.'_password'} : '';
if ($username === '' || $password === '') {
return $this->paymentFailed('(USERNAME OR PASSWORD NOT FOUND)');
}
$this->provider->setUsername($bankBranch->billing_username);
$this->provider->setPassword($bankBranch->billing_password);
$this->provider->setUsername($username);
$this->provider->setPassword($password);
$response = $this->provider->checkPayment($orderId);
if ($response['errorCode'] == '99') {
return $this->paymentFailed('(REQUEST FAILURE)');
if ($response['errorCode'] != '0') {
return $this->paymentFailed($response['errorMessage']); // @phpstan-ignore-line
}
return $response['paymentAmountInfo']['depositedAmount'] > 0 // @phpstan-ignore-line

View File

@@ -15,6 +15,8 @@ class SmsRepository
public static function sendSMS(string|int $phone, string|int $message): mixed
{
if (app()->environment('local')) {
info('Sending SMS to '.$phone.' with message: '.$message);
return true;
}

View File

@@ -57,6 +57,6 @@ trait RoleCheckers
*/
public function isSystemUser(): bool
{
return $this->isAdmin() || $this->isOperator();
return $this->isAdmin() || $this->isOperator() || $this->isCurrencyMaintainer();
}
}

View File

@@ -4,7 +4,6 @@ namespace App\Modules\VisaMasterPaymentOrder\Filament\Actions;
use App\Modules\CurrencyRate\Models\CurrencyRate;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterSettings;
use App\Modules\VisaMasterPaymentOrder\Repositories\VisaMasterPaymentOrderRepository;
use Filament\Actions\Action;
use Filament\Forms\Components\TextInput;
@@ -25,9 +24,7 @@ class PayVisaMasterPaymentAction
->schema(function () {
$usd_to_tmt = floatval(CurrencyRate::where('currency_from', 'USD')->where('currency_to', 'TMT')->first('value')?->value);
$payment_warning_text = VisaMasterSettings::where('name', 'payment_warning_text')->first();
if (! $usd_to_tmt || ! $payment_warning_text) {
if (! $usd_to_tmt) {
return [];
}
@@ -89,12 +86,12 @@ class PayVisaMasterPaymentAction
}),
TextInput::make('usd_rate')
->label(__('USD ekwalendi'))
->label(__('USD rate'))
->suffix('USD')
->readOnly(),
TextInput::make('total_amount')
->label(__('Total amount'))
->label(__('Total'))
->suffix('TMT')
->readOnly(),
]),

View File

@@ -3,7 +3,9 @@
namespace App\Modules\VisaMasterPaymentOrder\Models;
use App\Models\User;
use App\Modules\Branch\Interfaces\BelongsToBranch;
use App\Modules\Branch\Models\Branch;
use App\Modules\LoanOrder\Repositories\LoanOrderRepository;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -25,7 +27,7 @@ use Spatie\MediaLibrary\InteractsWithMedia;
* @property array<string, string> $payment_reciever
* @property array<string, string> $documents
* @property string $status
* @property string $notes
* @property ?string $notes
* @property string $sender_full_name
* @property string $sender_passport_serie
* @property string $sender_passport_number
@@ -35,7 +37,7 @@ use Spatie\MediaLibrary\InteractsWithMedia;
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at
*/
class VisaMasterPaymentOrder extends Model implements HasMedia
class VisaMasterPaymentOrder extends Model implements BelongsToBranch, HasMedia
{
use InteractsWithMedia;
use SoftDeletes;
@@ -52,28 +54,6 @@ class VisaMasterPaymentOrder extends Model implements HasMedia
'payment_reciever' => 'array',
];
/**
* Media collections
*/
public function registerMediaCollections(): void
{
$this->addMediaCollection('receiver_requisite')->singleFile();
$this->addMediaCollection('receiver_document_stating_he_is_studying')->singleFile();
$this->addMediaCollection('receiver_ticket')->singleFile();
$this->addMediaCollection('receiver_passport_local')->singleFile();
$this->addMediaCollection('receiver_passport_international')->singleFile();
$this->addMediaCollection('receiver_visa')->singleFile();
$this->addMediaCollection('receiver_travel_stamp_on_passport')->singleFile();
$this->addMediaCollection('receiver_document_stating_he_is_studying_2')->singleFile();
$this->addMediaCollection('sender_passport_local')->singleFile();
$this->addMediaCollection('sender_passport_international')->singleFile();
$this->addMediaCollection('sender_travel_stamp_on_passport')->singleFile();
$this->addMediaCollection('sender_proof_of_kinship')->singleFile();
$this->addMediaCollection('sender_passport_local_old')->singleFile();
$this->addMediaCollection('sender_passport_local_old_replacement')->singleFile();
}
/**
* User
*
@@ -118,89 +98,34 @@ class VisaMasterPaymentOrder extends Model implements HasMedia
}
/**
* Required files
*
* @return array<int, array<string, bool|string>>
* Media collections
*/
public static function reciverFiles(): array
public function registerMediaCollections(): void
{
return [
[
'required' => true,
'code' => 'requisite',
'name' => 'Talyba degişli walýuta “VISA” kartyň rekwizitleri',
],
[
'required' => false,
'code' => 'document_stating_he_is_studying',
'name' => 'Talybyň daşary ýurt döwletiniň ýokary okuw mekdebinde okaýandygy baradaky güwänamasy',
],
[
'required' => false,
'code' => 'passport_local',
'name' => 'Talyba degişli Türkmenistanyň raýatynyň (içki milli) pasportynyň asyl görnüşi we göçürmesi',
],
[
'required' => false,
'code' => 'passport_international',
'name' => 'Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin (zagran) pasportynyň göçürmesi',
],
[
'required' => false,
'code' => 'visa',
'name' => 'Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin pasportyndaky daşary ýurtda galyp okap bilýändigi baradaky berlen möhleti hereket edýän rugsatnamasynyň (wizasynyň) bellenen sahypasynyň göçürmesi',
],
[
'required' => false,
'code' => 'travel_stamp_on_passport',
'name' => 'Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin pasportyndaky Türkmenistandan çykandygy we daşary ýurt döwletine girendigi baradaky ştamplaryň (seneli ştampyň) bellenen sahypasynyň göçürmesi',
],
[
'required' => false,
'code' => 'document_stating_he_is_studying_2',
'name' => 'Talybyň daşary ýurt döwletiniň ýokary okuw mekdebinde okaýandygy baradaky güwänamasyndaky maglumatyň doly takyk däl ýagdaýynda takyk däl maglumatyň sebäpleri baradaky daşary ýurt döwletiniň ýokary okuw mekdebinden haty',
],
];
$this->addMediaCollection('receiver_requisite')->singleFile();
$this->addMediaCollection('receiver_document_stating_he_is_studying')->singleFile();
$this->addMediaCollection('receiver_ticket')->singleFile();
$this->addMediaCollection('receiver_passport_local')->singleFile();
$this->addMediaCollection('receiver_passport_international')->singleFile();
$this->addMediaCollection('receiver_visa')->singleFile();
$this->addMediaCollection('receiver_travel_stamp_on_passport')->singleFile();
$this->addMediaCollection('receiver_document_stating_he_is_studying_2')->singleFile();
$this->addMediaCollection('sender_passport_local')->singleFile();
$this->addMediaCollection('sender_passport_international')->singleFile();
$this->addMediaCollection('sender_travel_stamp_on_passport')->singleFile();
$this->addMediaCollection('sender_proof_of_kinship')->singleFile();
$this->addMediaCollection('sender_passport_local_old')->singleFile();
$this->addMediaCollection('sender_passport_local_old_replacement')->singleFile();
}
/**
* Sender files
*
* @return array<int, array<string, bool|string>>
* "boot" method for model
*/
public static function senderFiles(): array
protected static function boot()
{
return [
[
'required' => true,
'code' => 'passport_local',
'name' => 'Ugradyja degişli Türkmenistanyň raýatynyň (içki milli) pasportynyň asyl görnüşi we göçürmesi',
],
[
'required' => false,
'code' => 'passport_international',
'name' => 'Ugradyja degişli Türkmenistandan çykmak we Türkmenistana girmek üçin pasportynyň asyl görnüşi we göçürmesi',
],
[
'required' => false,
'code' => 'travel_stamp_on_passport',
'name' => 'Ugradyja degişli Türkmenistandan çykmak we Türkmenistana girmek üçin pasportyndaky daşary döwletine gidendigi we daşary döwlete barandygy baradaky (ştampyň) bellenen sahypasynyň göçürmesi',
],
[
'required' => true,
'code' => 'proof_of_kinship',
'name' => 'Ugradyjynyň we kabul edijiniň (talybyň) özara garyndaşlyk derejesini tassyklaýjy resminamalarynyň göçürmesi',
],
[
'required' => false,
'code' => 'passport_local_old',
'name' => 'Ugradyjy we kabul ediji (talyp) 2015-nji ýyldan soňra Türkmenistanyň raýatynyň pasportyny ikinji gezek alan bolsa, onda birinji gezek alan pasportynyň seriýasy baradaky maglumat',
],
[
'required' => false,
'code' => 'passport_local_old_replacement',
'name' => 'Ugradyjy we kabul ediji (talyp) 2015-nji ýyldan soňra Türkmenistanyň raýatynyň pasportyny ikinji gezek alandan soňra birinji gezek alan pasportynyň seriýasy baradaky maglumaty bilmeýän ,bolsa onda polisiýanyň degişli edaralaryndan birinji alan pasportynyň seriýasy baradaky güwänamasy',
],
];
parent::boot();
static::created(LoanOrderRepository::created());
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Modules\VisaMasterPaymentOrder\Policies;
use App\Models\User;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrderItem;
use Illuminate\Auth\Access\HandlesAuthorization;
class VisaMasterPaymentOrderItemPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
return $user->can('ViewAny:VisaMasterPaymentOrderItem');
}
public function view(User $user, VisaMasterPaymentOrderItem $visaMasterPaymentOrderItem): bool
{
return $user->can('View:VisaMasterPaymentOrderItem');
}
public function create(User $user): bool
{
return $user->can('Create:VisaMasterPaymentOrderItem');
}
public function update(User $user, VisaMasterPaymentOrderItem $visaMasterPaymentOrderItem): bool
{
return $user->can('Update:VisaMasterPaymentOrderItem');
}
public function delete(User $user, VisaMasterPaymentOrderItem $visaMasterPaymentOrderItem): bool
{
return $user->can('Delete:VisaMasterPaymentOrderItem');
}
public function restore(User $user, VisaMasterPaymentOrderItem $visaMasterPaymentOrderItem): bool
{
return $user->can('Restore:VisaMasterPaymentOrderItem');
}
public function forceDelete(User $user, VisaMasterPaymentOrderItem $visaMasterPaymentOrderItem): bool
{
return $user->can('ForceDelete:VisaMasterPaymentOrderItem');
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Modules\VisaMasterPaymentOrder\Policies;
use App\Models\User;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
use Illuminate\Auth\Access\HandlesAuthorization;
class VisaMasterPaymentOrderPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
return $user->can('ViewAny:VisaMasterPaymentOrder');
}
public function view(User $user, VisaMasterPaymentOrder $visaMasterPaymentOrder): bool
{
return $user->can('View:VisaMasterPaymentOrder');
}
public function create(User $user): bool
{
return $user->can('Create:VisaMasterPaymentOrder');
}
public function update(User $user, VisaMasterPaymentOrder $visaMasterPaymentOrder): bool
{
return $user->can('Update:VisaMasterPaymentOrder');
}
public function delete(User $user, VisaMasterPaymentOrder $visaMasterPaymentOrder): bool
{
return $user->can('Delete:VisaMasterPaymentOrder');
}
public function restore(User $user, VisaMasterPaymentOrder $visaMasterPaymentOrder): bool
{
return $user->can('Restore:VisaMasterPaymentOrder');
}
public function forceDelete(User $user, VisaMasterPaymentOrder $visaMasterPaymentOrder): bool
{
return $user->can('ForceDelete:VisaMasterPaymentOrder');
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Modules\VisaMasterPaymentOrder\Policies;
use App\Models\User;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterSettings;
use Illuminate\Auth\Access\HandlesAuthorization;
class VisaMasterSettingsPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
return $user->can('ViewAny:VisaMasterSettings');
}
public function view(User $user, VisaMasterSettings $visaMasterSettings): bool
{
return $user->can('View:VisaMasterSettings');
}
public function create(User $user): bool
{
return $user->can('Create:VisaMasterSettings');
}
public function update(User $user, VisaMasterSettings $visaMasterSettings): bool
{
return $user->can('Update:VisaMasterSettings');
}
public function delete(User $user, VisaMasterSettings $visaMasterSettings): bool
{
return $user->can('Delete:VisaMasterSettings');
}
public function restore(User $user, VisaMasterSettings $visaMasterSettings): bool
{
return $user->can('Restore:VisaMasterSettings');
}
public function forceDelete(User $user, VisaMasterSettings $visaMasterSettings): bool
{
return $user->can('ForceDelete:VisaMasterSettings');
}
}

View File

@@ -87,11 +87,11 @@ class VisaMasterPaymentOrderRepository
/** @var \App\Modules\Branch\Models\Branch */
$branch = $record->branch;
return OnlinePaymentRepository::make(relatedModel: $record)
return OnlinePaymentRepository::make(relatedModel: $record, apiClient: 'billing_visa_master')
->setPaymentProvider(
HalkbankOnlinePaymentRepository::make(
username: $branch->billingUsername(),
password: $branch->billingPassword(),
username: $branch->billing_visa_master_username,
password: $branch->billing_visa_master_password,
amount: $amount,
returnUrl: route('halkbank-online-payment.store'),
description: 'Visa/Master tölegi'

View File

@@ -8,6 +8,18 @@ use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
\App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder::class => \App\Modules\VisaMasterPaymentOrder\Policies\VisaMasterPaymentOrderPolicy::class,
\App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrderItem::class => \App\Modules\VisaMasterPaymentOrder\Policies\VisaMasterPaymentOrderItemPolicy::class,
\App\Modules\VisaMasterPaymentOrder\Models\VisaMasterSettings::class => \App\Modules\VisaMasterPaymentOrder\Policies\VisaMasterSettingsPolicy::class,
\App\Modules\OnlinePayment\Models\OnlinePayment::class => \App\Modules\OnlinePayment\Policies\OnlinePaymentPolicy::class,
];
/**
* Register services.
*/

View File

@@ -3,6 +3,7 @@
namespace App\Providers\Filament;
use App\Http\Middleware\EnsureProfileIsFilled;
use App\Http\Middleware\EnsureUserHasRole;
use App\Livewire\UserProfileFields;
use App\Modules\BaseAuth\Middleware\RedirectIfUserPhoneIsUnVerfied;
use BezhanSalleh\FilamentShield\FilamentShieldPlugin;
@@ -15,6 +16,7 @@ use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets\AccountWidget;
use Filament\Widgets\FilamentInfoWidget;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
@@ -22,13 +24,12 @@ use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Joaopaulolndev\FilamentEditProfile\FilamentEditProfilePlugin;
use RalphJSmit\Filament\Upload\FilamentUpload;
class WorkPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
// #content\.form-actions > div
return $panel
->default()
->id('work')
@@ -45,6 +46,7 @@ class WorkPanelProvider extends PanelProvider
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
->widgets([
AccountWidget::class,
FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
@@ -66,14 +68,19 @@ class WorkPanelProvider extends PanelProvider
->setTitle(__('My profile'))
->setNavigationLabel(__('My profile'))
->setIcon('heroicon-o-user-circle')
->setSort(4)
->shouldShowEditProfileForm(false)
->customProfileComponents([
UserProfileFields::class,
]),
FilamentUpload::make(),
])
->authMiddleware([
Authenticate::class,
EnsureProfileIsFilled::class,
EnsureUserHasRole::class,
])
->spa()
->databaseTransactions()
@@ -84,6 +91,7 @@ class WorkPanelProvider extends PanelProvider
'primary' => Color::Indigo,
'success' => Color::Emerald,
'warning' => Color::Orange,
]);
])
->viteTheme('resources/css/filament/work/theme.css');
}
}

View File

@@ -7,6 +7,7 @@ use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)

View File

@@ -12,12 +12,16 @@
"bezhansalleh/filament-shield": "^4.0",
"filament/filament": "^4.0",
"filament/spatie-laravel-media-library-plugin": "^4.0",
"halaxa/json-machine": "^1.2",
"joaopaulolndev/filament-edit-profile": "^2.0",
"laravel/framework": "^12.0",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.10.1",
"laravel/ui": "^4.6",
"mpdf/mpdf": "^8.2",
"phpoffice/phpword": "dev-master",
"ralphjsmit/laravel-filament-upload": "^1.1",
"spatie/laravel-activitylog": "^4.10",
"spatie/laravel-medialibrary": "^11.17",
"spatie/laravel-translatable": "^6.11",
"stevebauman/location": "^7.6"
@@ -49,6 +53,12 @@
"Tests\\": "tests/"
}
},
"repositories": [
{
"type": "composer",
"url": "https://satis.ralphjsmit.com"
}
],
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
@@ -89,7 +99,8 @@
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"php-http/discovery": true
"php-http/discovery": true,
"ralphjsmit/packages": true
}
},
"minimum-stability": "stable",

2094
composer.lock generated

File diff suppressed because it is too large Load Diff

52
config/activitylog.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
return [
/*
* If set to false, no activities will be saved to the database.
*/
'enabled' => env('ACTIVITY_LOGGER_ENABLED', true),
/*
* When the clean-command is executed, all recording activities older than
* the number of days specified here will be deleted.
*/
'delete_records_older_than_days' => 365,
/*
* If no log name is passed to the activity() helper
* we use this default log name.
*/
'default_log_name' => 'default',
/*
* You can specify an auth driver here that gets user models.
* If this is null we'll use the current Laravel auth driver.
*/
'default_auth_driver' => null,
/*
* If set to true, the subject returns soft deleted models.
*/
'subject_returns_soft_deleted_models' => false,
/*
* This model will be used to log activity.
* It should implement the Spatie\Activitylog\Contracts\Activity interface
* and extend Illuminate\Database\Eloquent\Model.
*/
'activity_model' => \Spatie\Activitylog\Models\Activity::class,
/*
* This is the name of the table that will be created by the migration and
* used by the Activity model shipped with this package.
*/
'table_name' => env('ACTIVITY_LOGGER_TABLE_NAME', 'activity_log'),
/*
* This is the database connection that will be used by the migration and
* the Activity model shipped with this package. In case it's not set
* Laravel's database.default will be used instead.
*/
'database_connection' => env('ACTIVITY_LOGGER_DB_CONNECTION'),
];

84
config/sanctum.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort(),
// Sanctum::currentRequestHost(),
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],
];

View File

@@ -8,25 +8,27 @@ return new class extends Migration
{
public function up(): void
{
Schema::create('media', function (Blueprint $table) {
$table->id();
if (! Schema::hasTable('media')) {
Schema::create('media', function (Blueprint $table) {
$table->id();
$table->morphs('model');
$table->uuid()->nullable()->unique();
$table->string('collection_name');
$table->string('name');
$table->string('file_name');
$table->string('mime_type')->nullable();
$table->string('disk');
$table->string('conversions_disk')->nullable();
$table->unsignedBigInteger('size');
$table->json('manipulations');
$table->json('custom_properties');
$table->json('generated_conversions');
$table->json('responsive_images');
$table->unsignedInteger('order_column')->nullable()->index();
$table->morphs('model');
$table->uuid()->nullable()->unique();
$table->string('collection_name');
$table->string('name');
$table->string('file_name');
$table->string('mime_type')->nullable();
$table->string('disk');
$table->string('conversions_disk')->nullable();
$table->unsignedBigInteger('size');
$table->json('manipulations');
$table->json('custom_properties');
$table->json('generated_conversions');
$table->json('responsive_images');
$table->unsignedInteger('order_column')->nullable()->index();
$table->nullableTimestamps();
});
$table->nullableTimestamps();
});
}
}
};

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('action_events', function (Blueprint $table) {
$table->id();
$table->string('batch_id')->nullable();
$table->unsignedBigInteger('user_id')->nullable()->index();
$table->string('name')->index();
$table->string('actionable_type')->nullable()->index();
$table->unsignedBigInteger('actionable_id')->nullable()->index();
$table->string('target_type')->nullable()->index();
$table->unsignedBigInteger('target_id')->nullable()->index();
$table->string('model_type')->nullable()->index();
$table->unsignedBigInteger('model_id')->nullable()->index();
$table->text('fields')->nullable();
$table->string('status')->index()->default('finished');
$table->text('exception')->nullable();
$table->json('original')->nullable();
$table->json('changes')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('action_events');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->text('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable()->index();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};

View File

@@ -13,9 +13,7 @@ class DatabaseSeeder extends Seeder
public function run(): void
{
$this->call([
// UsersTableSeeder::class,
// ShieldSeeder::class,
// FillJsonData::class,
ShieldSeeder::class,
]);
}
}

View File

@@ -9,8 +9,78 @@ class FillJsonData extends Seeder
/**
* Run the database seeds.
*/
public function run(): void
public function run(): void
{
// provinces
}
protected function seedUsers(): void
{
(new Migrators\UsersMigrator)->migrate();
}
protected function seedLoanTypes(): void
{
(new Migrators\LoanTypesMigrator)->migrate();
}
protected function seedProvinces(): void
{
(new Migrators\ProvincesMigrator)->migrate();
}
protected function seedBranches(): void
{
(new Migrators\BranchesMigrator)->migrate();
}
protected function loanOrderRequiredDocs(): void
{
(new Migrators\LoanOrderRequiredDocsMigrator)->migrate();
}
protected function seedLoanOrders(): void
{
(new Migrators\LoanOrdersMigrator)->migrate();
}
protected function seedCardStates(): void
{
(new Migrators\CardStatesMigrator)->migrate();
}
protected function seedCardTypes(): void
{
(new Migrators\CardTypesMigrator)->migrate();
}
protected function cardOrders(): void
{
(new Migrators\CardOrdersMigrator)->migrate();
}
protected function cardPinOrders(): void
{
(new Migrators\CardPinOrdersMigrator)->migrate();
}
protected function seedVisaMasterPaymentOrders(): void
{
(new Migrators\VisaMasterPaymentOrdersMigrator)->migrate();
}
protected function seedActionEvents(): void
{
(new Migrators\ActionEventsMigrator)->migrate();
}
protected function seedBranchUser(): void
{
(new Migrators\BranchUserMigrator)->migrate();
}
protected function seedCurrencyRates(): void
{
(new Migrators\CurrencyRatesMigrator)->migrate();
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class ActionEventsMigrator
{
public function migrate(): void
{
DB::table('action_events')->truncate();
$path = database_path('data/tested/action_events.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('action_events')->insert((array) $item);
}
DB::statement("SELECT setval('action_events_id_seq', (SELECT MAX(id) from action_events));");
DB::statement("SELECT nextval('action_events_id_seq');");
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class BranchUserMigrator
{
public function migrate(): void
{
DB::table('branch_user')->truncate();
$path = database_path('data/tested/branch_user.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('branch_user')->insert((array) $item);
DB::statement("SELECT setval('branch_user_id_seq', (SELECT MAX(id) from branch_user));");
DB::statement("SELECT nextval('branch_user_id_seq');");
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class BranchesMigrator
{
public function migrate(): void
{
DB::table('branches')->truncate();
$path = database_path('data/tested/branches.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('branches')
->insert($data);
}
DB::statement("SELECT setval('branches_id_seq', (SELECT MAX(id) from branches));");
DB::statement("SELECT nextval('branches_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class CardOrdersMigrator
{
public function migrate(): void
{
DB::table('card_orders')->truncate();
$path = database_path('data/tested/card_orders.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('card_orders')
->insert($data);
}
DB::statement("SELECT setval('card_orders_id_seq', (SELECT MAX(id) from card_orders));");
DB::statement("SELECT nextval('card_orders_id_seq');");
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class CardPinOrdersMigrator
{
public function migrate(): void
{
DB::table('card_pin_orders')->truncate();
$path = database_path('data/tested/card_pins.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
if (! empty($data['deleted_at'])) {
continue;
}
unset($data['deleted_at']);
DB::table('card_pin_orders')
->insert($data);
}
DB::statement("SELECT setval('card_pin_orders_id_seq', (SELECT MAX(id) from card_pin_orders));");
DB::statement("SELECT nextval('card_pin_orders_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class CardStatesMigrator
{
public function migrate(): void
{
DB::table('card_states')->truncate();
$path = database_path('data/tested/card_states.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('card_states')
->insert($data);
}
DB::statement("SELECT setval('card_states_id_seq', (SELECT MAX(id) from card_states));");
DB::statement("SELECT nextval('card_states_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class CardTypesMigrator
{
public function migrate(): void
{
DB::table('card_types')->truncate();
$path = database_path('data/tested/card_types.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('card_types')
->insert($data);
}
DB::statement("SELECT setval('card_types_id_seq', (SELECT MAX(id) from card_types));");
DB::statement("SELECT nextval('card_types_id_seq');");
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class CurrencyRatesMigrator
{
public function migrate(): void
{
DB::table('currency_rates')->truncate();
$path = database_path('data/tested/currency_rates.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('currency_rates')->insert((array) $item);
}
DB::statement("SELECT setval('currency_rates_id_seq', (SELECT MAX(id) from currency_rates));");
DB::statement("SELECT nextval('currency_rates_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class LoanOrderRequiredDocsMigrator
{
public function migrate(): void
{
DB::table('loan_order_required_docs')->truncate();
$path = database_path('data/tested/loan_order_required_docs.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('loan_order_required_docs')
->insert($data);
}
DB::statement("SELECT setval('loan_order_required_docs_id_seq', (SELECT MAX(id) from loan_order_required_docs));");
DB::statement("SELECT nextval('loan_order_required_docs_id_seq');");
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class LoanOrdersMigrator
{
public function migrate(): void
{
DB::table('loan_orders')->truncate();
$path = database_path('data/tested/loan_orders.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('loan_orders')->insert((array) $item);
}
DB::statement("SELECT setval('loan_orders_id_seq', (SELECT MAX(id) from loan_orders));");
DB::statement("SELECT nextval('loan_orders_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class LoanTypesMigrator
{
public function migrate(): void
{
DB::table('loan_types')->truncate();
$path = database_path('data/tested/loan_types.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('loan_types')
->insert($data);
}
DB::statement("SELECT setval('loan_types_id_seq', (SELECT MAX(id) from loan_types));");
DB::statement("SELECT nextval('loan_types_id_seq');");
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class MediaMigrator
{
public function migrate(): void
{
DB::table('media')->truncate();
$path = database_path('data/tested/media.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
DB::table('media')->insert((array) $item);
}
DB::statement("SELECT setval('media_id_seq', (SELECT MAX(id) from media));");
DB::statement("SELECT nextval('media_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class ModelHasRolesMigrator
{
public function migrate(): void
{
DB::table('model_has_roles')->truncate();
$path = database_path('data/tested/model_has_roles.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('model_has_roles')
->insert($data);
}
DB::statement("SELECT setval('model_has_roles_id_seq', (SELECT MAX(id) from model_has_roles));");
DB::statement("SELECT nextval('model_has_roles_id_seq');");
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Database\Seeders\Migrators;
use App\Modules\CardOrder\Models\CardOrder;
use App\Modules\CardPinOrder\Models\CardPinOrder;
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class OnlinePaymentsMigrator
{
public function migrate(): void
{
DB::table('online_payments')->truncate();
$path = database_path('data/tested/online_payment_histories.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
if ($data['online_paymantable_type']) {
if ($data['online_paymantable_type'] == 'App\Models\Order\Card\Requisite\CardRequisite') {
continue;
}
$data['online_paymantable_type'] = match ($data['online_paymantable_type']) {
'App\Models\Order\Card\CardOrder' => CardOrder::class,
'App\Models\Order\Card\CardPin\CardPin' => CardPinOrder::class,
// 'App\Modules\SberPaymentOrder\Models\SberPaymentOrder' => SberPaymentOrder::class,
'App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder' => VisaMasterPaymentOrder::class,
'\App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder' => VisaMasterPaymentOrder::class,
};
}
DB::table('online_payments')
->insert($data);
}
DB::statement("SELECT setval('online_payments_id_seq', (SELECT MAX(id) from online_payments));");
DB::statement("SELECT nextval('online_payments_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class PersonalAccessTokensMigrator
{
public function migrate(): void
{
DB::table('personal_access_tokens')->truncate();
$path = database_path('data/tested/personal_access_tokens.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('personal_access_tokens')
->insert($data);
}
DB::statement("SELECT setval('personal_access_tokens_id_seq', (SELECT MAX(id) from personal_access_tokens));");
DB::statement("SELECT nextval('personal_access_tokens_id_seq');");
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class ProvincesMigrator
{
public function migrate(): void
{
DB::table('provinces')->truncate();
$path = database_path('data/tested/provinces.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('provinces')
->insert($data);
}
DB::statement("SELECT setval('provinces_id_seq', (SELECT MAX(id) from provinces));");
DB::statement("SELECT nextval('provinces_id_seq');");
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class UsersMigrator
{
public function migrate(): void
{
DB::table('users')->truncate();
$path = database_path('data/nurmuhammetsdb/users.json');
$data = File::json($path);
foreach ($data as $user) {
DB::table('users')
->insert([
'id' => $user['id'],
'name' => $user['name'],
'email' => $user['email'],
'email_verified_at' => $user['email_verified_at'],
'password' => $user['password'],
'remember_token' => $user['remember_token'],
'created_at' => $user['created_at'],
'updated_at' => $user['updated_at'],
'username' => $user['username'],
'first_name' => $this->extractFirstName($user['name']),
'last_name' => $this->extractLastName($user['name']),
'phone' => $user['phone'],
'phone_verified_at' => $user['phone_verified_at'],
'locale' => $user['locale'],
'password_must_be_changed' => $user['password_must_be_changed'],
'options' => $user['options'],
'must_fill_profile' => false,
'custom_fields' => null,
'active' => $user['active'],
]);
}
DB::statement("SELECT setval('users_id_seq', (SELECT MAX(id) from users));");
DB::statement("SELECT nextval('users_id_seq');");
}
protected function extractFirstName(string $name): string
{
return explode(' ', $name)[0] ?? '';
}
protected function extractLastName(string $name): string
{
return explode(' ', $name)[1] ?? '';
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class VerificationsMigrator
{
public function migrate(): void
{
DB::table('verifications')->truncate();
$path = database_path('data/tested/verifications.json');
$rawData = File::json($path);
foreach ($rawData as $data) {
DB::table('verifications')
->insert($data);
}
DB::statement("SELECT setval('verifications_id_seq', (SELECT MAX(id) from verifications));");
DB::statement("SELECT nextval('verifications_id_seq');");
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Database\Seeders\Migrators;
use Illuminate\Support\Facades\DB;
use JsonMachine\Items;
class VisaMasterPaymentOrdersMigrator
{
public function migrate(): void
{
DB::table('visa_master_payment_orders')->truncate();
$path = database_path('data/nurmuhammetsdb/visa_master_payment_orders.json');
$items = Items::fromFile($path);
foreach ($items as $id => $item) {
if (! $item) {
continue;
}
$sender_datas = json_decode($item->sender_datas);
$payment_reciever = json_decode($item->payment_reciever);
$sender_full_name = $item->sender_full_name ?: ($sender_datas[0]->full_name ?? '');
$sender_passport_serie = $item->sender_passport_serie ?: ($sender_datas[0]->passport_serie ?? '');
$sender_passport_number = $item->sender_passport_number ?: ($sender_datas[0]->passport_number ?? '');
DB::table('visa_master_payment_orders')->insert([
'id' => $item->id,
'unique_id' => $item->unique_id,
'type' => $item->type,
'passport_name' => $item->passport_name,
'passport_surname' => $item->passport_surname,
'phone' => unMaskTurkmenNumber($item->phone),
'email' => $item->email,
'region' => $item->region,
'branch_id' => $item->branch_id,
'address' => $item->address,
'status' => $item->status,
'notes' => $item->notes,
'sender_full_name' => $sender_full_name,
'sender_passport_serie' => $sender_passport_serie,
'sender_passport_number' => $sender_passport_number,
'sender_deposit_account' => $item->sender_deposit_account,
'reciever_full_name' => $payment_reciever[0]->full_name ?? '',
'reciever_passport_serie' => $payment_reciever[0]->passport_serie ?? '',
'reciever_passport_number' => $payment_reciever[0]->passport_number ?? '',
'sender_datas' => $item->sender_datas,
'payment_reciever' => $item->payment_reciever,
'documents' => $item->documents,
'created_at' => $item->created_at,
'updated_at' => $item->updated_at,
'paid' => $item->paid,
'deleted_at' => $item->deleted_at,
]);
}
DB::statement("SELECT setval('visa_master_payment_orders_id_seq', (SELECT MAX(id) from visa_master_payment_orders));");
DB::statement("SELECT nextval('visa_master_payment_orders_id_seq');");
}
}

View File

@@ -13,7 +13,7 @@ class ShieldSeeder extends Seeder
{
app()[PermissionRegistrar::class]->forgetCachedPermissions();
$rolesWithPermissions = '[{"name":"super_admin","guard_name":"web","permissions":["ViewAny:Role","View:Role","Create:Role","Update:Role","Delete:Role","Restore:Role","ForceDelete:Role","ForceDeleteAny:Role","RestoreAny:Role","Replicate:Role","Reorder:Role"]}]';
$rolesWithPermissions = '[{"id":2,"name":"super_admin","guard_name":"web","permissions":["ViewAny:Role","View:Role","Create:Role","Update:Role","Delete:Role","Restore:Role","ForceDelete:Role","ForceDeleteAny:Role","RestoreAny:Role","Replicate:Role","Reorder:Role"]}]';
$directPermissions = '[]';
static::makeRolesWithPermissions($rolesWithPermissions);
@@ -32,9 +32,35 @@ class ShieldSeeder extends Seeder
$additionalRoles = collect([
[
'id' => 3,
'name' => 'admin',
'guard_name' => 'web',
],
[
'id' => 4,
'name' => 'operator',
'guard_name' => 'web',
],
[
'id' => 10,
'name' => 'operator_card',
'guard_name' => 'web',
],
[
'id' => 11,
'name' => 'operator_loan',
'guard_name' => 'web',
],
[
'id' => 12,
'name' => 'client',
'guard_name' => 'web',
],
[
'id' => 6,
'name' => 'currency_maintainer',
'guard_name' => 'web',
],
])->map(fn ($role) => [
...$role,
'created_at' => now(),
@@ -54,6 +80,7 @@ class ShieldSeeder extends Seeder
foreach ($rolePlusPermissions as $rolePlusPermission) {
$role = $roleModel::firstOrCreate([
'id' => $rolePlusPermission['id'],
'name' => $rolePlusPermission['name'],
'guard_name' => $rolePlusPermission['guard_name'],
]);

View File

@@ -722,5 +722,14 @@
"Payment error": "Töleg näsazlygy",
"Problem connecting on HALKBANK SYSTEM": "Halkbank ulgamyna birikmekde näsazlyk",
"Error has been captured": "Näsazlyk ulgam tarapyndan ýazga alyndy",
"Please try again later": "Täzeden geçirmek üçin synanyşyňyz"
"Please try again later": "Täzeden geçirmek üçin synanyşyňyz",
"Payment amount, USD rate, and total amount are required. Please try again.": "Töleg möçberi, USD kursy we toplam möçberi töleg edilmeli. Täzeden geçirmek üçin synanyşyňyz.",
"Payment": "Töleg",
"Online payments": "Onlaýn tölegler",
"USD rate": "USD kursy",
"Total": "Jemi",
"Data": "Maglumatlar",
"Watch Full": "Giňişleýin",
"Order ID": "Sargyt belgisi",
"Add card": "Kart goşmak"
}

View File

@@ -8,16 +8,16 @@ return [
'modal' => [
'heading' => ':label döret',
'heading' => ':label goşmak',
'actions' => [
'create' => [
'label' => 'Döret',
'label' => 'Goşmak',
],
'create_another' => [
'label' => 'Döret we başgasyny döret',
'label' => 'Goşmak we başgasyny goşmak',
],
],
@@ -27,7 +27,7 @@ return [
'notifications' => [
'created' => [
'title' => 'Döredildi',
'title' => 'Goşuldy',
],
],

View File

@@ -625,20 +625,20 @@ return [
'create_option' => [
'label' => 'Döret',
'label' => 'Goş',
'modal' => [
'heading' => 'Döret',
'heading' => 'Goş',
'actions' => [
'create' => [
'label' => 'Döret',
'label' => 'Goş',
],
'create_another' => [
'label' => 'Döret we başgasyny döret',
'label' => 'Goş we başgasyny goş',
],
],

View File

@@ -0,0 +1,7 @@
<?php
// translations for Hugomyb/FilamentMediaAction
return [
'loading' => 'Loading...',
'unsupported-media-type' => 'Unsupported media type.',
];

View File

@@ -0,0 +1,6 @@
<?php
return [
'loading' => 'Chargement...',
'unsupported-media-type' => 'Type de média non pris en charge.',
];

View File

@@ -0,0 +1,7 @@
<?php
// translations for Hugomyb/FilamentMediaAction
return [
'loading' => 'Caricamento...',
'unsupported-media-type' => 'Tipo di file non supportato.',
];

2226
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,11 +7,11 @@
"dev": "vite"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0",
"@tailwindcss/vite": "^4.1.17",
"axios": "^1.11.0",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^2.0.0",
"tailwindcss": "^4.0.0",
"tailwindcss": "^4.1.17",
"vite": "^7.0.7"
}
}

View File

@@ -18,6 +18,6 @@ parameters:
- '#BelongsToMany does not specify its types: TRelatedModel, TDeclaringModel, TPivotModel, TAccessor#'
- '#translatableTabs#'
#
# excludePaths:
# - ./*/*/FileToBeExcluded.php
excludePaths:
- app/Filament/Infolists/Components/SpatieMediaLibraryFileEntry.php

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
{
"resources/css/filament/work/theme.css": {
"file": "assets/theme-D6od5FeK.css",
"src": "resources/css/filament/work/theme.css",
"isEntry": true,
"name": "theme",
"names": [
"theme.css"
]
}
}

View File

@@ -0,0 +1 @@
.FIE_topbar-buttons-wrapper,.FIE_topbar-reset-button{display:none!important}.FIE_canvas-node{background:none!important}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More