Compare commits
165 Commits
68d544b9c3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5bc322170 | ||
|
|
749208ac97 | ||
|
|
1870583441 | ||
|
|
76c05ebe7c | ||
|
|
515731003c | ||
|
|
a9c7ec6b80 | ||
|
|
4038d47582 | ||
|
|
326987d6de | ||
|
|
f433fc3e41 | ||
|
|
5361c00e7b | ||
|
|
5e37bd1a76 | ||
|
|
5a53b90272 | ||
|
|
59548a486f | ||
|
|
c0bfe974ad | ||
|
|
895c5f6226 | ||
|
|
88d84ac457 | ||
|
|
94ad59ce24 | ||
|
|
b1630ea623 | ||
|
|
6a700fbd4b | ||
|
|
8e548126b2 | ||
|
|
2ec9b28a60 | ||
|
|
4fc242bc7d | ||
|
|
6df3a27383 | ||
|
|
7111b1db09 | ||
|
|
c4ee279d91 | ||
|
|
14c4ea5791 | ||
|
|
01a0aa8ca1 | ||
|
|
97fea41b62 | ||
|
|
5568d32a31 | ||
| 4e78ff77cc | |||
| 4c0917e6ba | |||
| c56e3383d1 | |||
| 967501d58f | |||
| 88fdc3aa7f | |||
| 183916a62a | |||
| a9490e132d | |||
| 438e5a3f43 | |||
| cbd469c97f | |||
| bc45f2756e | |||
| 73448548e7 | |||
| f0e9767e78 | |||
| 0e39450849 | |||
| 4c83d41eb0 | |||
| bccf52a8fb | |||
| 6e03c4d218 | |||
| 53f8c893ca | |||
| 52d070f4e5 | |||
| 209f3899b5 | |||
| 58d6ef0a9a | |||
| 1a0756fdca | |||
| f506972c91 | |||
| 19abe08a90 | |||
| 6428c9e20c | |||
| 9d66f21854 | |||
| da5bb6e99b | |||
| 680d5d4130 | |||
| f73a510984 | |||
| 4b7c3da3d4 | |||
| b0877399eb | |||
| 3b5b7f10c4 | |||
| 45e95725cd | |||
| a98a41efab | |||
| 3911e8e21a | |||
| dc871f36d4 | |||
| 2dd06d0e4f | |||
| a9e5f7ece8 | |||
| 7e7d583973 | |||
| ba6d703893 | |||
| 2bb9ec2ae2 | |||
| 1d67616cdb | |||
| 5a37d56cfb | |||
| c1b3a58c3a | |||
| c94ac5d12d | |||
| c24f7cbac6 | |||
| 8637c22ed7 | |||
| 2659aae278 | |||
| 038b5ea2fb | |||
| 54e11dcbb4 | |||
| 3ea35f6bca | |||
| b67fd61bf8 | |||
| 816a6c2f60 | |||
| 294ec0144d | |||
| c2e9198dbc | |||
| 074fe44ab3 | |||
| 31ab39b21c | |||
| 7bdd5243bd | |||
| 0da1efe5c3 | |||
| 8c24f00382 | |||
| 60f7efd6ba | |||
| c16bb98ed3 | |||
| 0779e4b9f6 | |||
| 9be16228f7 | |||
| 84f551ddc6 | |||
| 96415c2bc1 | |||
| 8c33cc6645 | |||
| cc3a9cd854 | |||
| 65a47e8028 | |||
| 310590010c | |||
| 84c4a584a0 | |||
| 1f31b020e8 | |||
| 10a08d5f45 | |||
| 504ddfbf8d | |||
| 516c17326c | |||
| e9f95b7ca8 | |||
| e79d77625f | |||
| 3953ee93b9 | |||
| b728a374a5 | |||
| 3369e97a3c | |||
| 5f2760713f | |||
| 09c0bec901 | |||
| 38b9908e1e | |||
| 870aba0bcf | |||
| c147f47876 | |||
| 6c38642af8 | |||
| fadda1f0d2 | |||
| 7119ae4cb7 | |||
| af0f24a6b6 | |||
| 711b5373da | |||
| e9e9f7dbd5 | |||
| 2df920af47 | |||
| 9c799ac105 | |||
| 44f00a8f5d | |||
| 8c1b128df2 | |||
| 3916f7f8ea | |||
| 074e07a04a | |||
| bdcb4811c4 | |||
| fa304450cb | |||
| ed95be1d39 | |||
| eb79c6db49 | |||
| 0f5d1098a0 | |||
| 96c8f860da | |||
| af2687cefc | |||
| de63b29a45 | |||
| e8595117ee | |||
| 92b067b939 | |||
| 94badf95b8 | |||
| 7f394b90fa | |||
| 45fbde31c7 | |||
| e27aa026fd | |||
| 13ad714b22 | |||
| 386e74374b | |||
| 910a7dd1b2 | |||
| 90b5a6bd6f | |||
| f8cf227f1d | |||
| 475cc9f30d | |||
| eaa8ecf1d4 | |||
| da6c5134fb | |||
| e0ceeeb73d | |||
| 4368fe1e4f | |||
| 10aa4095af | |||
| 968d37c67b | |||
| 3f21f55c39 | |||
| 80973d5b85 | |||
| b80651519f | |||
| 21bd0c0a68 | |||
| b9007a59a6 | |||
| 6f1de4531e | |||
| 8078242cf9 | |||
| feb2928cb4 | |||
| e61f5d315e | |||
| b858e02bf3 | |||
| 1873486d13 | |||
| 5d3ea6d787 | |||
| 834527647d | |||
| 11f99caf42 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,9 +11,9 @@
|
||||
/.phpunit.cache
|
||||
/.vscode
|
||||
/.zed
|
||||
/database/data/
|
||||
/auth.json
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
|
||||
66
README.md
66
README.md
@@ -1,61 +1,11 @@
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||
CREATE USER 'nurmuhammet'@'%' IDENTIFIED BY 'K}#zL9@}QkR>MAHMYTJ';
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'nurmuhammet'@'%' WITH GRANT OPTION;
|
||||
CREATE USER 'nurmuhammet'@'localhost' IDENTIFIED BY 'K}#zL9@}QkR>MAHMYTJ';
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'nurmuhammet'@'localhost' WITH GRANT OPTION;
|
||||
create database nurmuhammetsdb;
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## About Laravel
|
||||
ALTER USER ahat WITH PASSWORD 'K}#zL9@}QkR>MAHMYTJ';
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||
|
||||
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||
|
||||
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||
|
||||
## Learning Laravel
|
||||
|
||||
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||
|
||||
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||
|
||||
## Laravel Sponsors
|
||||
|
||||
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||
|
||||
### Premium Partners
|
||||
|
||||
- **[Vehikl](https://vehikl.com)**
|
||||
- **[Tighten Co.](https://tighten.co)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Redberry](https://redberry.international/laravel-development)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||
|
||||
## License
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
SELECT setval('users_id_seq', (SELECT MAX(id) from users));
|
||||
SELECT nextval('users_id_seq');
|
||||
|
||||
@@ -3,23 +3,36 @@
|
||||
namespace App\Filament\Clusters\Cards\CardOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\Cards\CardOrders\CardOrderResource;
|
||||
use App\Modules\CardOrder\Repositories\CardOrderRepository;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class CreateCardOrder extends CreateRecord
|
||||
{
|
||||
protected static string $resource = CardOrderResource::class;
|
||||
|
||||
/**
|
||||
* @return array<int, \Filament\Actions\Action>
|
||||
*/
|
||||
protected function getFormActions(): array
|
||||
{
|
||||
return [
|
||||
$this->getCreateFormAction(),
|
||||
$this->getCancelFormAction(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
$defaultUrl = $this->getResource()::getUrl('index');
|
||||
$defaultUrl = string($this->getResource()::getUrl('index'));
|
||||
|
||||
return $defaultUrl;
|
||||
/** @var \App\Modules\CardOrder\Models\CardOrder */
|
||||
$record = $this->record;
|
||||
|
||||
// $payment = (new OnlinePaymentRepo)->payCardOrder($resource);
|
||||
$onlinePayment = CardOrderRepository::make()
|
||||
->createOnlinePaymentOrder($record);
|
||||
|
||||
// $payment['status'] === 'success'
|
||||
// ? URL::remote($payment['url'])
|
||||
// : $defaultUrl;
|
||||
return $onlinePayment->successful()
|
||||
? $onlinePayment->paymentLink()
|
||||
: $defaultUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Clusters\Cards\CardOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\Cards\CardOrders\CardOrderResource;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
@@ -15,6 +16,11 @@ class EditCardOrder extends EditRecord
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('save_top')
|
||||
->label(__('filament-panels::resources/pages/edit-record.form.actions.save.label'))
|
||||
->submit(null)
|
||||
->action('save'),
|
||||
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
namespace App\Filament\Clusters\Cards\CardOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\Cards\CardOrders\CardOrderResource;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
|
||||
class ListCardOrders extends ListRecords
|
||||
{
|
||||
@@ -16,4 +18,23 @@ class ListCardOrders 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Clusters\Cards\CardOrders\Schemas;
|
||||
|
||||
use App\Modules\Country\Repositories\CountryRepository;
|
||||
use App\Modules\FilamentPermission\Repositories\FilamentPermissionRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\PhoneNumberVerification\Rules\PhoneNumberVerificationRule;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
@@ -12,7 +13,6 @@ use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Schemas\Components\Fieldset;
|
||||
@@ -21,6 +21,8 @@ use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Wizard;
|
||||
use Filament\Schemas\Components\Wizard\Step;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -32,22 +34,27 @@ class CardOrderForm
|
||||
->components([
|
||||
Hidden::make('user_id')->default(Auth::id()),
|
||||
|
||||
Section::make(__('New loan order'))
|
||||
Section::make(__('New card order'))
|
||||
->columnSpan(4)
|
||||
->columns(4)
|
||||
->disabled(fn (string $context): bool => FilamentPermissionRepository::forClients())
|
||||
->hidden(fn (string $context) => FilamentPermissionRepository::defaultSystemInput($context))
|
||||
->components([
|
||||
Select::make('status')
|
||||
->label(__('Status'))
|
||||
->options(OrderStatusRepository::statusValues())
|
||||
->default(OrderStatusRepository::defaultStatus())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
|
||||
Toggle::make('paid')
|
||||
->label(__('Paid'))
|
||||
->inline(false)
|
||||
->required(),
|
||||
->disabled(true)
|
||||
->onIcon(Heroicon::CheckCircle)
|
||||
->offIcon(Heroicon::XCircle)
|
||||
->onColor('success')
|
||||
->offColor('danger'),
|
||||
|
||||
RichEditor::make('notes')
|
||||
->label(__('Bellik'))
|
||||
@@ -60,13 +67,13 @@ class CardOrderForm
|
||||
Fieldset::make(__('Loan type and amount'))
|
||||
->schema([
|
||||
Select::make('card_state_id')
|
||||
->relationship('cardState', 'name')
|
||||
->relationship('cardState', 'name', fn (Builder $query) => $query->orderByTranslation('name'))
|
||||
->label(__('Card state'))
|
||||
->native(false)
|
||||
->required(),
|
||||
|
||||
Select::make('card_type_id')
|
||||
->relationship('cardType', 'name')
|
||||
->relationship('cardType', 'name', fn (Builder $query) => $query->orderByTranslation('name'))
|
||||
->label(__('Card type'))
|
||||
->native(false)
|
||||
->required(),
|
||||
@@ -84,6 +91,8 @@ class CardOrderForm
|
||||
Select::make('branch_id')
|
||||
->label(__('Branch'))
|
||||
->relationship('branch', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
@@ -247,21 +256,7 @@ class CardOrderForm
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
])->columnSpan(4),
|
||||
])->columnSpanFull(),
|
||||
|
||||
// Textarea::make('passport_one')
|
||||
// ->required()
|
||||
// ->columnSpanFull(),
|
||||
// Textarea::make('passport_two')
|
||||
// ->required()
|
||||
// ->columnSpanFull(),
|
||||
// Textarea::make('passport_three')
|
||||
// ->required()
|
||||
// ->columnSpanFull(),
|
||||
// Textarea::make('passport_four')
|
||||
// ->required()
|
||||
// ->columnSpanFull(),
|
||||
|
||||
])->columnSpanFull()->skippable(fn (string $context) => $context === 'edit'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace App\Filament\Clusters\Cards\CardOrders\Tables;
|
||||
|
||||
use App\Modules\CardOrder\Filament\Actions\PayCardOrderAction;
|
||||
use App\Modules\CardOrder\Models\CardOrder;
|
||||
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
@@ -13,17 +16,30 @@ use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class CardOrdersTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
DefaultQueryForResourceIndexRepository::make($query);
|
||||
})
|
||||
->defaultSort('created_at', 'desc')
|
||||
->columns([
|
||||
TextColumn::make('unique_id')
|
||||
->label(__('ID'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label(__('Status'))
|
||||
->color(OrderStatusRepository::statusColorMatching())
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->badge()
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('cardState.name')
|
||||
->label(__('Reason'))
|
||||
->searchable(),
|
||||
@@ -62,10 +78,6 @@ class CardOrdersTable
|
||||
->label(__('Phone'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('updated_at')
|
||||
->label(__('Updated At'))
|
||||
->dateTime()
|
||||
@@ -81,6 +93,9 @@ class CardOrdersTable
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
PayCardOrderAction::make()
|
||||
->hidden(fn (CardOrder $record) => $record->paid),
|
||||
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
|
||||
@@ -5,17 +5,15 @@ namespace App\Filament\Clusters\Cards\Cards;
|
||||
use App\Filament\Clusters\Cards\Cards\Pages\ManageCards;
|
||||
use App\Filament\Clusters\Cards\CardsCluster;
|
||||
use App\Modules\AppHelpers\Repositories\DateHelper;
|
||||
use App\Modules\Card\Filament\Actions\CheckCardBalanceAction;
|
||||
use App\Modules\Card\Filament\Actions\DownloadCardRequisteAction;
|
||||
use App\Modules\Card\Filament\Actions\DownloadCardTransactionAction;
|
||||
use App\Modules\Card\Models\Card;
|
||||
use App\Modules\CardBalance\Repositories\CardBalanceRepository;
|
||||
use App\Modules\CardRequisite\Repositories\CardRequisiteRepository;
|
||||
use App\Modules\CardTransaction\Repositories\CardTransactionRepository;
|
||||
use BackedEnum;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
@@ -24,9 +22,7 @@ use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Livewire\Component;
|
||||
|
||||
class CardResource extends Resource
|
||||
{
|
||||
@@ -94,6 +90,10 @@ class CardResource extends Resource
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
if (user()->isAdmin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query->where('user_id', user()->id);
|
||||
})
|
||||
->columns([
|
||||
@@ -127,42 +127,9 @@ class CardResource extends Resource
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
Action::make('card_balance')
|
||||
->label(__('Card balance'))
|
||||
->icon('heroicon-o-credit-card')
|
||||
->requiresConfirmation(false)
|
||||
->modal()
|
||||
->modalContent(fn (Card $record): View => CardBalanceRepository::make()->showCardBalance($record))
|
||||
->modalFooterActions([]),
|
||||
|
||||
Action::make('card_transactions')
|
||||
->label(__('Card transactions'))
|
||||
->icon('heroicon-o-arrows-right-left')
|
||||
->requiresConfirmation()
|
||||
->modalIcon('heroicon-m-arrows-right-left')
|
||||
->schema([
|
||||
DatePicker::make('start_date')
|
||||
->label(__('Start date'))
|
||||
->native(false)
|
||||
->required()
|
||||
->beforeOrEqual('today'),
|
||||
|
||||
DatePicker::make('end_date')
|
||||
->label(__('End date'))
|
||||
->native(false)
|
||||
->required()
|
||||
->beforeOrEqual('today'),
|
||||
])
|
||||
->action(
|
||||
fn (array $data, Card $record, Component $livewire) => CardTransactionRepository::make()->downloadCardTransaction($data, $record, $livewire)
|
||||
),
|
||||
|
||||
Action::make('card_requisite')
|
||||
->label(__('Card requisite'))
|
||||
->icon('heroicon-o-document-text')
|
||||
->requiresConfirmation()
|
||||
->modalIcon('heroicon-o-document-text')
|
||||
->action(fn (Card $record) => CardRequisiteRepository::make()->downloadCardRequisite($record)),
|
||||
CheckCardBalanceAction::make(),
|
||||
DownloadCardTransactionAction::make(),
|
||||
DownloadCardRequisteAction::make(),
|
||||
|
||||
EditAction::make()
|
||||
->label(''),
|
||||
|
||||
@@ -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),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ 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::Top;
|
||||
@@ -17,4 +19,9 @@ class CardsCluster extends Cluster
|
||||
{
|
||||
return __('Cards');
|
||||
}
|
||||
|
||||
public static function getClusterBreadcrumb(): string
|
||||
{
|
||||
return __('Cards');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders;
|
||||
|
||||
use App\Filament\Clusters\Cards\CardsCluster;
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages\CreateCardPinOrder;
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages\EditCardPinOrder;
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages\ListCardPinOrders;
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\Schemas\CardPinOrderForm;
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\Tables\CardPinOrdersTable;
|
||||
use App\Modules\CardPinOrder\Models\CardPinOrder;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class CardPinOrderResource extends Resource
|
||||
{
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static ?string $model = CardPinOrder::class;
|
||||
|
||||
protected static ?string $cluster = CardsCluster::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCreditCard;
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('Forgot card pin');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('Pin order');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('Pin orders');
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return CardPinOrderForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return CardPinOrdersTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListCardPinOrders::route('/'),
|
||||
'create' => CreateCardPinOrder::route('/create'),
|
||||
'edit' => EditCardPinOrder::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\CardPinOrderResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateCardPinOrder extends CreateRecord
|
||||
{
|
||||
protected static string $resource = CardPinOrderResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\Cards\Resources\CardPinOrders\CardPinOrderResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditCardPinOrder extends EditRecord
|
||||
{
|
||||
protected static string $resource = CardPinOrderResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
{
|
||||
protected static string $resource = CardPinOrderResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Schemas;
|
||||
|
||||
use App\Modules\FilamentPermission\Repositories\FilamentPermissionRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\PhoneNumberVerification\Rules\PhoneNumberVerificationRule;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use App\Modules\TurkmenPassport\Repositories\TurkmenPassportRepository;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\FusedGroup;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CardPinOrderForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Hidden::make('user_id')->default(Auth::id()),
|
||||
|
||||
Section::make(__('New card pin order'))
|
||||
->columnSpanFull()
|
||||
->disabled(fn (string $context): bool => FilamentPermissionRepository::forClients())
|
||||
->hidden(fn (string $context) => FilamentPermissionRepository::defaultSystemInput($context))
|
||||
->components([
|
||||
Select::make('status')
|
||||
->label(__('Status'))
|
||||
->options(OrderStatusRepository::statusValues())
|
||||
->default(OrderStatusRepository::defaultStatus())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpanFull(),
|
||||
|
||||
RichEditor::make('notes')
|
||||
->label(__('Bellik'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
|
||||
Section::make(__('New card pin order'))
|
||||
->columnSpanFull()
|
||||
->columns(6)
|
||||
->components([
|
||||
Select::make('card_type_id')
|
||||
->relationship('cardType', 'name', fn (Builder $query) => $query->orderByTranslation('name'))
|
||||
->label(__('Card type'))
|
||||
->native(false)
|
||||
->columnSpan(3)
|
||||
->required(),
|
||||
|
||||
TextInput::make('card_number')
|
||||
->label(__('Card number'))
|
||||
->mask('9999 9999 9999 9999')
|
||||
->maxLength(255)
|
||||
->columnSpan(3)
|
||||
->required(),
|
||||
|
||||
Select::make('region')
|
||||
->label(__('Region'))
|
||||
->options(RegionRepository::values())
|
||||
->live()
|
||||
->afterStateUpdated(fn (callable $set) => $set('branch_id', null))
|
||||
->columnSpan(3)
|
||||
->required(),
|
||||
|
||||
Select::make('branch_id')
|
||||
->label(__('Branch'))
|
||||
->relationship('branch', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
}
|
||||
})
|
||||
->columnSpan(3)
|
||||
->required(),
|
||||
|
||||
TextInput::make('customer_name')
|
||||
->label(__('Name'))
|
||||
->columnSpan(2)
|
||||
->default(user()->first_name)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->autocomplete(Str::random(10))
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->columnSpan(2)
|
||||
->default(user()->last_name)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('customer_patronic_name')
|
||||
->label(__('Patronic name'))
|
||||
->columnSpan(2)
|
||||
->default(user()->getOption('patronic_name'))
|
||||
->maxLength(255)
|
||||
->columnSpan(2),
|
||||
|
||||
DatePicker::make('born_at')
|
||||
->displayFormat('d.m.Y')
|
||||
->label(__('Birth date'))
|
||||
->native(false)
|
||||
->columnSpan(2)
|
||||
->default(user()->getOption('born_at'))
|
||||
->required()
|
||||
->beforeOrEqual('today')
|
||||
->columnSpan(2),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->default(user()->getOption('passport_serie'))
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('passport_id')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->default(user()->getOption('passport_id'))
|
||||
->mask('999999'),
|
||||
])
|
||||
->columnSpan(2)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
TextInput::make('phone')
|
||||
->label(__('Phone'))
|
||||
->required()
|
||||
->mask('99 99 99 99')
|
||||
->prefix('+993')
|
||||
->default(user()->phone)
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2),
|
||||
|
||||
FileUpload::make('passport_one')
|
||||
->label(__('Passport (page 1)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(3),
|
||||
|
||||
FileUpload::make('passport_two')
|
||||
->label(__('Passport (page 2-3)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(3),
|
||||
|
||||
FileUpload::make('passport_three')
|
||||
->label(__('Passport (page 8-9)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(3),
|
||||
|
||||
FileUpload::make('passport_four')
|
||||
->label(__('Passport (page 32)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(3),
|
||||
]),
|
||||
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Cards\Resources\CardPinOrders\Tables;
|
||||
|
||||
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class CardPinOrdersTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
DefaultQueryForResourceIndexRepository::make($query);
|
||||
})
|
||||
->defaultSort('created_at', 'desc')
|
||||
->columns([
|
||||
TextColumn::make('id')
|
||||
->label('ID'),
|
||||
|
||||
TextColumn::make('cardType.name')
|
||||
->label(__('Card type'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('created_at')
|
||||
->label(__('Created At'))
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('region')
|
||||
->label(__('Region'))
|
||||
->formatStateUsing(fn (string $state): string => RegionRepository::label($state))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('branch.name')
|
||||
->label(__('Branch'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_name')
|
||||
->label(__('Name'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('phone')
|
||||
->label(__('Phone'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label(__('Status'))
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->sortable()
|
||||
->badge()
|
||||
->searchable(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,7 @@ namespace App\Filament\Clusters\Loans\LoanOrders;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Pages\CreateLoanOrder;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Pages\EditLoanOrder;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Pages\ListLoanOrders;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Pages\ViewLoanOrder;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Schemas\LoanOrderForm;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Schemas\LoanOrderInfolist;
|
||||
use App\Filament\Clusters\Loans\LoanOrders\Tables\LoanOrdersTable;
|
||||
use App\Filament\Clusters\Loans\LoansCluster;
|
||||
use App\Modules\LoanOrder\Models\LoanOrder;
|
||||
@@ -53,11 +51,6 @@ class LoanOrderResource extends Resource
|
||||
return LoanOrderForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function infolist(Schema $schema): Schema
|
||||
{
|
||||
return LoanOrderInfolist::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return LoanOrdersTable::configure($table);
|
||||
@@ -75,7 +68,6 @@ class LoanOrderResource extends Resource
|
||||
return [
|
||||
'index' => ListLoanOrders::route('/'),
|
||||
'create' => CreateLoanOrder::route('/create'),
|
||||
'view' => ViewLoanOrder::route('/{record}'),
|
||||
'edit' => EditLoanOrder::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Filament\Clusters\Loans\LoanOrders\LoanOrderResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditLoanOrder extends EditRecord
|
||||
@@ -16,7 +15,6 @@ class EditLoanOrder extends EditRecord
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
ViewAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Clusters\Loans\LoanOrders\Schemas;
|
||||
|
||||
use App\Modules\FilamentPermission\Repositories\FilamentPermissionRepository;
|
||||
use App\Modules\LoanOrder\Models\LoanOrderRequiredDocs;
|
||||
use App\Modules\LoanOrder\Repositories\LoanOrderRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
@@ -22,6 +23,7 @@ use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Wizard;
|
||||
use Filament\Schemas\Components\Wizard\Step;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -38,6 +40,8 @@ class LoanOrderForm
|
||||
Section::make(__('New loan order'))
|
||||
->columnSpan(4)
|
||||
->columns(4)
|
||||
->disabled(fn (string $context): bool => FilamentPermissionRepository::forClients())
|
||||
->hidden(fn (string $context) => FilamentPermissionRepository::defaultSystemInput($context))
|
||||
->components([
|
||||
Select::make('status')
|
||||
->label(__('Status'))
|
||||
@@ -84,13 +88,12 @@ class LoanOrderForm
|
||||
->schema([
|
||||
Select::make('loan_type')
|
||||
->label(__('Loan type'))
|
||||
->relationship('loanType', 'name')
|
||||
->relationship('loanType', 'name', fn (Builder $query) => $query->orderByTranslation('name'))
|
||||
->required(),
|
||||
|
||||
TextInput::make('loan_amount')
|
||||
->label(__('Loan amount'))
|
||||
->numeric()
|
||||
->required()
|
||||
->minValue(1)
|
||||
->maxValue(40000)
|
||||
->suffix('TMT')
|
||||
@@ -109,6 +112,8 @@ class LoanOrderForm
|
||||
Select::make('branch_id')
|
||||
->label(__('Branch'))
|
||||
->relationship('branch', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
@@ -125,18 +130,21 @@ class LoanOrderForm
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->autocomplete(Str::random(10)),
|
||||
->autocomplete(Str::random(10))
|
||||
->default(user()->first_name),
|
||||
|
||||
TextInput::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
->maxLength(255)
|
||||
->default(user()->last_name),
|
||||
|
||||
TextInput::make('customer_patronic_name')
|
||||
->label(__('Patronic name'))
|
||||
->columnSpan(2)
|
||||
->maxLength(255),
|
||||
->maxLength(255)
|
||||
->default(user()->getOption('patronic_name')),
|
||||
|
||||
DatePicker::make('born_at')
|
||||
->displayFormat('d.m.Y')
|
||||
@@ -144,7 +152,8 @@ class LoanOrderForm
|
||||
->native(false)
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->beforeOrEqual('today'),
|
||||
->beforeOrEqual('today')
|
||||
->default(user()->getOption('born_at')),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('passport_serie')
|
||||
@@ -152,13 +161,15 @@ class LoanOrderForm
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
->columnSpan(1)
|
||||
->default(user()->getOption('passport_serie')),
|
||||
|
||||
TextInput::make('passport_id')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->mask('999999'),
|
||||
->mask('999999')
|
||||
->default(user()->getOption('passport_id')),
|
||||
])
|
||||
->columnSpan(3)
|
||||
->label(__('Passport serie and number'))
|
||||
@@ -171,37 +182,43 @@ class LoanOrderForm
|
||||
->native(false)
|
||||
->closeOnDateSelection()
|
||||
->beforeOrEqual('today')
|
||||
->required(),
|
||||
->required()
|
||||
->default(user()->getOption('passport_given_at')),
|
||||
|
||||
TextInput::make('born_place')
|
||||
->columnSpan(3)
|
||||
->label(__('Born place (passport)'))
|
||||
->maxLength(255)
|
||||
->required(),
|
||||
->required()
|
||||
->default(user()->getOption('born_place')),
|
||||
|
||||
TextInput::make('passport_given_by')
|
||||
->label(__('Passport given by'))
|
||||
->columnSpan(4)
|
||||
->maxLength(255)
|
||||
->required(),
|
||||
->required()
|
||||
->default(user()->getOption('passport_given_by')),
|
||||
|
||||
TextInput::make('passport_address')
|
||||
->columnSpan(4)
|
||||
->label(__('Proscription for home'))
|
||||
->maxLength(255)
|
||||
->required(),
|
||||
->required()
|
||||
->default(user()->getOption('passport_address')),
|
||||
|
||||
TextInput::make('real_address')
|
||||
->label(__('Current home address'))
|
||||
->columnSpan(4)
|
||||
->maxLength(255)
|
||||
->required(),
|
||||
->required()
|
||||
->default(user()->getOption('real_address')),
|
||||
|
||||
TextInput::make('email')
|
||||
->label(__('Email'))
|
||||
->email()
|
||||
->maxLength(255)
|
||||
->columnSpan(2),
|
||||
->columnSpan(2)
|
||||
->default(user()->getOption('email')),
|
||||
|
||||
TextInput::make('phone')
|
||||
->label(__('Phone'))
|
||||
@@ -211,7 +228,8 @@ class LoanOrderForm
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2),
|
||||
->columnSpan(2)
|
||||
->default(user()->phone),
|
||||
|
||||
TextInput::make('phone_additional')
|
||||
->label(__('Additional phone'))
|
||||
@@ -281,12 +299,14 @@ class LoanOrderForm
|
||||
->options(RegionRepository::values())
|
||||
->columnSpan(1)
|
||||
->live()
|
||||
->afterStateUpdated(fn (callable $set) => $set('branch_id', null))
|
||||
->afterStateUpdated(fn (callable $set) => $set('work_province_id', null))
|
||||
->required(),
|
||||
|
||||
Select::make('work_province_id')
|
||||
->label(__('Work province'))
|
||||
->relationship('workProvince', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('work_region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
@@ -325,9 +345,10 @@ class LoanOrderForm
|
||||
->displayFormat('d.m.Y')
|
||||
->beforeOrEqual('today')
|
||||
->required()
|
||||
->native(false)
|
||||
->columnSpan(1),
|
||||
]),
|
||||
])->columnSpan(4),
|
||||
])->columnSpan(4)->skippable(fn (string $context) => $context === 'edit'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,71 +2,90 @@
|
||||
|
||||
namespace App\Filament\Clusters\Loans\LoanOrders\Tables;
|
||||
|
||||
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class LoanOrdersTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
$query->where('source', 'web');
|
||||
|
||||
DefaultQueryForResourceIndexRepository::make($query);
|
||||
})
|
||||
->defaultSort('created_at', 'desc')
|
||||
->columns([
|
||||
TextColumn::make('id')
|
||||
->label('ID')
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('loanType.name')
|
||||
->label('Тип кредита')
|
||||
->label(__('Loan type'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('region')
|
||||
->label('Регион')
|
||||
->label(__('Region'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
->searchable()
|
||||
->formatStateUsing(fn (string $state) => RegionRepository::label($state)),
|
||||
|
||||
TextColumn::make('branch.name')
|
||||
->label('Филиал')
|
||||
->label(__('Branch'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_name')
|
||||
->label('Имя клиента')
|
||||
->label(__('Name'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_surname')
|
||||
->label('Фамилия клиента')
|
||||
->label(__('Surname'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('phone')
|
||||
->label('Телефон')
|
||||
->label(__('Phone'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label('Статус')
|
||||
->label(__('Status'))
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->badge()
|
||||
->color(OrderStatusRepository::statusColorMatching())
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state)),
|
||||
|
||||
TextColumn::make('created_at')
|
||||
->label('Дата создания')
|
||||
->label(__('Created At'))
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(),
|
||||
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->label(__('Updated At'))
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
TextColumn::make('deleted_at')
|
||||
->label(__('Deleted At'))
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
@@ -75,7 +94,6 @@ class LoanOrdersTable
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
|
||||
@@ -22,6 +22,7 @@ class LoanForm
|
||||
->default(user()->getOption('passport_id')),
|
||||
|
||||
TextInput::make('account_number')
|
||||
->label(__('Account number'))
|
||||
->required()
|
||||
->string()
|
||||
->maxLength(23),
|
||||
|
||||
@@ -2,19 +2,30 @@
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Loans\Tables;
|
||||
|
||||
use App\Modules\Loan\Filaments\Actions\ShowLoanRemainingAction;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class LoansTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
if (user()->isAdmin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query->where('user_id', user()->id);
|
||||
})
|
||||
->columns([
|
||||
TextColumn::make('account_number')
|
||||
->label(__('Account number'))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
@@ -31,7 +42,9 @@ class LoansTable
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
ShowLoanRemainingAction::make(),
|
||||
EditAction::make(),
|
||||
DeleteAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles;
|
||||
|
||||
use App\Filament\Clusters\Loans\LoansCluster;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages\CreateLoanOrderMobile;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages\EditLoanOrderMobile;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages\ListLoanOrderMobiles;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Schemas\LoanOrderMobileForm;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Tables\LoanOrderMobilesTable;
|
||||
use App\Modules\LoanOrderMobile\Models\LoanOrderMobile;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class LoanOrderMobileResource extends Resource
|
||||
{
|
||||
protected static ?string $model = LoanOrderMobile::class;
|
||||
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDevicePhoneMobile;
|
||||
|
||||
protected static string|BackedEnum|null $activeNavigationIcon = Heroicon::DevicePhoneMobile;
|
||||
|
||||
protected static ?string $cluster = LoansCluster::class;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'unique_id';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('module.loan-order::loan-order.loan_order').' (mobile app)';
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('module.loan-order::loan-order.loan_order').' (mobile app)';
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('module.loan-order::loan-order.loan_orders').' (mobile app)';
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return LoanOrderMobileForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return LoanOrderMobilesTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListLoanOrderMobiles::route('/'),
|
||||
'create' => CreateLoanOrderMobile::route('/create'),
|
||||
'edit' => EditLoanOrderMobile::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Builder<\App\Modules\LoanOrder\Models\LoanOrder>
|
||||
*/
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages;
|
||||
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\LoanOrderMobileResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateLoanOrderMobile extends CreateRecord
|
||||
{
|
||||
protected static string $resource = LoanOrderMobileResource::class;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Pages;
|
||||
|
||||
use App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\LoanOrderMobileResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditLoanOrderMobile extends EditRecord
|
||||
{
|
||||
protected static string $resource = LoanOrderMobileResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
{
|
||||
protected static string $resource = LoanOrderMobileResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Schemas;
|
||||
|
||||
use App\Modules\AppHelpers\Repositories\DateHelper;
|
||||
use App\Modules\LoanOrder\Models\LoanOrderRequiredDocs;
|
||||
use App\Modules\LoanOrder\Repositories\LoanOrderRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\PersonStates\Repositories\EducationRepository;
|
||||
use App\Modules\PersonStates\Repositories\MarriageRepository;
|
||||
use App\Modules\PhoneNumberVerification\Rules\PhoneNumberVerificationRule;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use App\Modules\TurkmenPassport\Repositories\TurkmenPassportRepository;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\Fieldset;
|
||||
use Filament\Schemas\Components\FusedGroup;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class LoanOrderMobileForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->columns(4)
|
||||
->components([
|
||||
Hidden::make('source')->default('mobile'),
|
||||
Hidden::make('user_id')->default(Auth::id()),
|
||||
|
||||
Section::make(__('New loan order'))
|
||||
->columnSpan(4)
|
||||
->columns(4)
|
||||
->components([
|
||||
Select::make('status')
|
||||
->label(__('Status'))
|
||||
->options(OrderStatusRepository::statusValues())
|
||||
->default(OrderStatusRepository::defaultStatus())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
|
||||
Select::make('satisfiable')
|
||||
->label(__('Loan history'))
|
||||
->options(LoanOrderRepository::satisfiableValues())
|
||||
->native(false)
|
||||
->columnSpan(2),
|
||||
|
||||
Select::make('loan_order_required_doc_id')
|
||||
->label(__('Required documents'))
|
||||
->relationship('requiredDocs', 'name')
|
||||
->searchable()
|
||||
->native(false)
|
||||
->preload()
|
||||
->live()
|
||||
->afterStateUpdated(function ($state, callable $set) {
|
||||
if ($state) {
|
||||
/** @var null|LoanOrderRequiredDocs */
|
||||
$requiredDoc = LoanOrderRequiredDocs::find($state);
|
||||
|
||||
if ($requiredDoc) {
|
||||
$set('notes', $requiredDoc->value);
|
||||
}
|
||||
}
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
RichEditor::make('notes')
|
||||
->label(__('Bellik'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
|
||||
Tabs::make('Loan Order')
|
||||
->tabs([
|
||||
Tab::make(__('Loan & Bank'))
|
||||
->schema([
|
||||
Fieldset::make(__('Loan type and amount'))
|
||||
->schema([
|
||||
Select::make('loan_type')
|
||||
->label(__('Loan type'))
|
||||
->relationship('loanType', 'name', fn (Builder $query) => $query->orderByTranslation('name')->where('id', 2))
|
||||
->required(),
|
||||
|
||||
TextInput::make('loan_amount')
|
||||
->label(__('Loan amount'))
|
||||
->numeric()
|
||||
->required()
|
||||
->minValue(1)
|
||||
->maxValue(40000)
|
||||
->suffix('TMT')
|
||||
->belowContent(__('Max is 40 000 TMT'))
|
||||
->live(),
|
||||
]),
|
||||
|
||||
Fieldset::make(__('Location'))
|
||||
->schema([
|
||||
Select::make('region')
|
||||
->label(__('Region'))
|
||||
->options(RegionRepository::values())
|
||||
->live()
|
||||
->afterStateUpdated(fn (callable $set) => $set('branch_id', null))
|
||||
->required(),
|
||||
|
||||
Select::make('branch_id')
|
||||
->label(__('Branch'))
|
||||
->relationship('branch', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
}
|
||||
})
|
||||
->required(),
|
||||
]),
|
||||
]),
|
||||
Tab::make(__('Personal information'))
|
||||
->columns(8)
|
||||
->schema([
|
||||
TextInput::make('customer_name')
|
||||
->label(__('Name'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->autocomplete(Str::random(10))
|
||||
->default(user()->first_name),
|
||||
|
||||
TextInput::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->default(user()->last_name),
|
||||
|
||||
TextInput::make('customer_patronic_name')
|
||||
->label(__('Patronic name'))
|
||||
->columnSpan(2)
|
||||
->maxLength(255)
|
||||
->default(user()->getOption('patronic_name')),
|
||||
|
||||
DatePicker::make('born_at')
|
||||
->displayFormat('d.m.Y')
|
||||
->label(__('Birth date'))
|
||||
->native(false)
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->beforeOrEqual('today')
|
||||
->default(user()->getOption('born_at')),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->default(user()->getOption('passport_serie')),
|
||||
|
||||
TextInput::make('passport_id')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->mask('999999')
|
||||
->default(user()->getOption('passport_id')),
|
||||
])
|
||||
->columnSpan(3)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
DatePicker::make('passport_given_at')
|
||||
->label(__('Passport given date'))
|
||||
->columnSpan(2)
|
||||
->displayFormat('d.m.Y')
|
||||
->native(false)
|
||||
->closeOnDateSelection()
|
||||
->beforeOrEqual('today')
|
||||
->required()
|
||||
->default(user()->getOption('passport_given_at')),
|
||||
|
||||
TextInput::make('born_place')
|
||||
->columnSpan(3)
|
||||
->label(__('Born place (passport)'))
|
||||
->maxLength(255)
|
||||
->required()
|
||||
->default(user()->getOption('born_place')),
|
||||
|
||||
TextInput::make('passport_given_by')
|
||||
->label(__('Passport given by'))
|
||||
->columnSpan(4)
|
||||
->maxLength(255)
|
||||
->required()
|
||||
->default(user()->getOption('passport_given_by')),
|
||||
|
||||
TextInput::make('passport_address')
|
||||
->columnSpan(4)
|
||||
->label(__('Proscription for home'))
|
||||
->maxLength(255)
|
||||
->required()
|
||||
->default(user()->getOption('passport_address')),
|
||||
|
||||
TextInput::make('real_address')
|
||||
->label(__('Current home address'))
|
||||
->columnSpan(4)
|
||||
->maxLength(255)
|
||||
->required()
|
||||
->default(user()->getOption('real_address')),
|
||||
|
||||
TextInput::make('email')
|
||||
->label(__('Email'))
|
||||
->email()
|
||||
->maxLength(255)
|
||||
->columnSpan(2)
|
||||
->default(user()->getOption('email')),
|
||||
|
||||
TextInput::make('phone')
|
||||
->label(__('Phone'))
|
||||
->required()
|
||||
->mask('99 99 99 99')
|
||||
->prefix('+993')
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2)
|
||||
->default(user()->phone),
|
||||
|
||||
TextInput::make('phone_additional')
|
||||
->label(__('Additional phone'))
|
||||
->mask('99 99 99 99')
|
||||
->prefix('+993')
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('phone_home')
|
||||
->label(__('Home phone'))
|
||||
->numeric()
|
||||
->prefix('+993')
|
||||
->columnSpan(2),
|
||||
|
||||
Select::make('education')
|
||||
->columnSpan(2)
|
||||
->label(__('Education'))
|
||||
->options(EducationRepository::values())
|
||||
->native(false)
|
||||
->required(),
|
||||
|
||||
Select::make('marriage_status')
|
||||
->columnSpan(2)
|
||||
->label(__('Marital status'))
|
||||
->options(MarriageRepository::values())
|
||||
->native(false)
|
||||
->required(),
|
||||
]),
|
||||
Tab::make(__('Salary card'))
|
||||
->columns(6)
|
||||
->schema([
|
||||
TextInput::make('card_number')
|
||||
->label(__('Card number'))
|
||||
->mask('9999 9999 9999 9999')
|
||||
->dehydrateStateUsing(fn ($state) => str_replace(' ', '', $state))
|
||||
->columnSpan(2)
|
||||
->required(),
|
||||
|
||||
TextInput::make('card_name')
|
||||
->label(__('Card name'))
|
||||
->maxLength(255)
|
||||
->columnSpan(2)
|
||||
->required(),
|
||||
|
||||
Select::make('card_month')
|
||||
->label(__('Card month'))
|
||||
->options(DateHelper::staticNumberMonths())
|
||||
->native(false)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
|
||||
Select::make('card_year')
|
||||
->label(__('Card year'))
|
||||
->options(DateHelper::staticNumberYears())
|
||||
->native(false)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
]),
|
||||
Tab::make(__('Pasport files'))
|
||||
->columns(4)
|
||||
->schema([
|
||||
FileUpload::make('passport_one')
|
||||
->label(__('Passport (page 1)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
|
||||
FileUpload::make('passport_two')
|
||||
->label(__('Passport (page 2-3)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
|
||||
FileUpload::make('passport_three')
|
||||
->label(__('Passport (page 8-9)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
|
||||
FileUpload::make('passport_four')
|
||||
->label(__('Passport (page 32)'))
|
||||
->image()
|
||||
->maxSize(4096)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
]),
|
||||
Tab::make(__('Work'))
|
||||
->columns(4)
|
||||
->schema([
|
||||
Select::make('work_region')
|
||||
->label(__('Work region'))
|
||||
->options(RegionRepository::values())
|
||||
->columnSpan(1)
|
||||
->live()
|
||||
->afterStateUpdated(fn (callable $set) => $set('work_province_id', null))
|
||||
->required(),
|
||||
|
||||
Select::make('work_province_id')
|
||||
->label(__('Work province'))
|
||||
->relationship('workProvince', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('work_region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
}
|
||||
})
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
|
||||
TextInput::make('work_company')
|
||||
->label(__('Work company name'))
|
||||
->maxLength(255)
|
||||
->required()
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('work_company_accountant_number')
|
||||
->label(__('HR number'))
|
||||
->prefix('+993')
|
||||
->numeric()
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('work_position')
|
||||
->label(__('Work position'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('work_salary')
|
||||
->label(__('Salary'))
|
||||
->numeric()
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
|
||||
DatePicker::make('work_started_at')
|
||||
->label(__('Work started at'))
|
||||
->displayFormat('d.m.Y')
|
||||
->beforeOrEqual('today')
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
]),
|
||||
Tab::make(__('Guarantor').' 1')
|
||||
->columns(6)
|
||||
->schema([
|
||||
TextInput::make('guarantor_name')
|
||||
->label(__('Guarantor').' '.__('Name'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('guarantor_surname')
|
||||
->label(__('Guarantor').' '.__('Surname'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('guarantor_patronic_name')
|
||||
->label(__('Guarantor').' '.__('Patronic name'))
|
||||
->columnSpan(2)
|
||||
->maxLength(255),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('guarantor_passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('guarantor_passport_id')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->mask('999999'),
|
||||
])
|
||||
->columnSpan(3)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
TextInput::make('guarantor_note')
|
||||
->label(__('Guarantor').' '.__('Salary'))
|
||||
->columnSpan(3)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('guarantor_card_number')
|
||||
->label(__('Card number'))
|
||||
->mask('9999 9999 9999 9999')
|
||||
->dehydrateStateUsing(fn ($state) => str_replace(' ', '', $state))
|
||||
->columnSpan(2)
|
||||
->required(),
|
||||
|
||||
TextInput::make('guarantor_card_name')
|
||||
->label(__('Card name'))
|
||||
->maxLength(255)
|
||||
->columnSpan(2)
|
||||
->required(),
|
||||
|
||||
Select::make('guarantor_card_month')
|
||||
->label(__('Card month'))
|
||||
->options(DateHelper::staticNumberMonths())
|
||||
->native(false)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
|
||||
Select::make('guarantor_card_year')
|
||||
->label(__('Card year'))
|
||||
->options(DateHelper::staticNumberYears())
|
||||
->native(false)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
]),
|
||||
Tab::make(__('Guarantor').' 2')
|
||||
->columns(6)
|
||||
->hidden(function (Get $get): bool {
|
||||
$loan_amount = $get('loan_amount') ? string($get('loan_amount')) : 1;
|
||||
|
||||
return ! ($loan_amount && intval($loan_amount) > 20000);
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('guarantor_2_name')
|
||||
->label(__('Guarantor').' '.__('Name'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('guarantor_2_surname')
|
||||
->label(__('Guarantor').' '.__('Surname'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('guarantor_2_patronic_name')
|
||||
->label(__('Guarantor').' '.__('Patronic name'))
|
||||
->columnSpan(2)
|
||||
->maxLength(255),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('guarantor_2_passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('guarantor_2_passport_id')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->mask('999999'),
|
||||
])
|
||||
->columnSpan(3)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
TextInput::make('guarantor_2_note')
|
||||
->label(__('Guarantor').' '.__('Salary'))
|
||||
->columnSpan(3)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('guarantor_2_card_number')
|
||||
->label(__('Card number'))
|
||||
->mask('9999 9999 9999 9999')
|
||||
->dehydrateStateUsing(fn ($state) => str_replace(' ', '', $state))
|
||||
->columnSpan(2)
|
||||
->required(),
|
||||
|
||||
TextInput::make('guarantor_2_card_name')
|
||||
->label(__('Card name'))
|
||||
->maxLength(255)
|
||||
->columnSpan(2)
|
||||
->required(),
|
||||
|
||||
Select::make('guarantor_2_card_month')
|
||||
->label(__('Card month'))
|
||||
->options(DateHelper::staticNumberMonths())
|
||||
->native(false)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
|
||||
Select::make('guarantor_2_card_year')
|
||||
->label(__('Card year'))
|
||||
->options(DateHelper::staticNumberYears())
|
||||
->native(false)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
]),
|
||||
])->columnSpan(4),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Schemas;
|
||||
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class LoanOrderMobileInfolist
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->columns(3)
|
||||
->components([
|
||||
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanOrderMobiles\Tables;
|
||||
|
||||
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class LoanOrderMobilesTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
$query->where('source', 'mobile');
|
||||
|
||||
DefaultQueryForResourceIndexRepository::make($query);
|
||||
})
|
||||
->defaultSort('created_at', 'desc')
|
||||
->columns([
|
||||
TextColumn::make('id')
|
||||
->label('ID')
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('region')
|
||||
->label(__('Region'))
|
||||
->sortable()
|
||||
->searchable()
|
||||
->formatStateUsing(fn (string $state) => RegionRepository::label($state)),
|
||||
|
||||
TextColumn::make('branch.name')
|
||||
->label(__('Branch'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_name')
|
||||
->label(__('Name'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('phone')
|
||||
->label(__('Phone'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label(__('Status'))
|
||||
->sortable()
|
||||
->searchable()
|
||||
->badge()
|
||||
->color(OrderStatusRepository::statusColorMatching())
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state)),
|
||||
|
||||
TextColumn::make('created_at')
|
||||
->label(__('Created At'))
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(),
|
||||
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->label(__('Updated At'))
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
TextColumn::make('deleted_at')
|
||||
->label(__('Deleted At'))
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters;
|
||||
|
||||
use App\Filament\Clusters\Loans\LoansCluster;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages\CreateLoanPaidOffLetter;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages\EditLoanPaidOffLetter;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages\ListLoanPaidOffLetters;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Schemas\LoanPaidOffLetterForm;
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Tables\LoanPaidOffLettersTable;
|
||||
use App\Modules\LoanPaidOffLetter\Models\LoanPaidOffLetter;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
class LoanPaidOffLetterResource extends Resource
|
||||
{
|
||||
protected static ?int $navigationSort = 3;
|
||||
|
||||
protected static ?string $model = LoanPaidOffLetter::class;
|
||||
|
||||
protected static ?string $cluster = LoansCluster::class;
|
||||
|
||||
public static function getNavigationIcon(): string|BackedEnum|Htmlable|null
|
||||
{
|
||||
return Heroicon::OutlinedDocumentText;
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('Loan paid off letters');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('Loan paid off letter');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('Loan paid off letters');
|
||||
}
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'loan_reason';
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return LoanPaidOffLetterForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return LoanPaidOffLettersTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListLoanPaidOffLetters::route('/'),
|
||||
'create' => CreateLoanPaidOffLetter::route('/create'),
|
||||
'edit' => EditLoanPaidOffLetter::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages;
|
||||
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\LoanPaidOffLetterResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateLoanPaidOffLetter extends CreateRecord
|
||||
{
|
||||
protected static string $resource = LoanPaidOffLetterResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Pages;
|
||||
|
||||
use App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\LoanPaidOffLetterResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditLoanPaidOffLetter extends EditRecord
|
||||
{
|
||||
protected static string $resource = LoanPaidOffLetterResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
{
|
||||
protected static string $resource = LoanPaidOffLetterResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Schemas;
|
||||
|
||||
use App\Modules\FilamentPermission\Repositories\FilamentPermissionRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\PhoneNumberVerification\Rules\PhoneNumberVerificationRule;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use App\Modules\TurkmenPassport\Repositories\TurkmenPassportRepository;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\FusedGroup;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class LoanPaidOffLetterForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->columns(6)
|
||||
->components([
|
||||
Hidden::make('user_id')->default(Auth::id()),
|
||||
|
||||
Section::make(__('New loan paid off letter'))
|
||||
->columnSpan(4)
|
||||
->columns(6)
|
||||
->components([
|
||||
Select::make('region')
|
||||
->label(__('Region'))
|
||||
->options(RegionRepository::values())
|
||||
->live()
|
||||
->afterStateUpdated(fn (callable $set) => $set('branch_id', null))
|
||||
->columnSpan(3)
|
||||
->required(),
|
||||
|
||||
Select::make('branch_id')
|
||||
->label(__('Branch'))
|
||||
->relationship('branch', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
}
|
||||
})
|
||||
->columnSpan(3)
|
||||
->required(),
|
||||
|
||||
TextInput::make('customer_name')
|
||||
->label(__('Name'))
|
||||
->columnSpan(2)
|
||||
->default(user()->first_name)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->autocomplete(Str::random(10))
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->columnSpan(2)
|
||||
->default(user()->last_name)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('customer_patronic_name')
|
||||
->label(__('Patronic name'))
|
||||
->columnSpan(2)
|
||||
->default(user()->getOption('patronic_name'))
|
||||
->maxLength(255)
|
||||
->columnSpan(2),
|
||||
|
||||
DatePicker::make('born_at')
|
||||
->displayFormat('d.m.Y')
|
||||
->label(__('Birth date'))
|
||||
->native(false)
|
||||
->columnSpan(2)
|
||||
->default(user()->getOption('born_at'))
|
||||
->required()
|
||||
->beforeOrEqual('today')
|
||||
->columnSpan(2),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->default(user()->getOption('passport_serie'))
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('passport_id')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->default(user()->getOption('passport_id'))
|
||||
->mask('999999'),
|
||||
])
|
||||
->columnSpan(2)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
TextInput::make('phone')
|
||||
->label(__('Phone'))
|
||||
->required()
|
||||
->mask('99 99 99 99')
|
||||
->prefix('+993')
|
||||
->default(user()->phone)
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('loan_contract_number')
|
||||
->label(__('Loan contract number'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255),
|
||||
|
||||
DatePicker::make('loan_contract_date')
|
||||
->displayFormat('d.m.Y')
|
||||
->label(__('Loan contract date'))
|
||||
->native(false)
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->beforeOrEqual('today')
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('loan_amount')
|
||||
->label(__('Loan amount'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->numeric()
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('loan_reason')
|
||||
->label(__('Loan reason'))
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpan(6),
|
||||
]),
|
||||
|
||||
Section::make(__('By operator'))
|
||||
->columnSpan(2)
|
||||
->disabled(fn (string $context): bool => FilamentPermissionRepository::forClients())
|
||||
->hidden(fn (string $context) => FilamentPermissionRepository::defaultSystemInput($context))
|
||||
->components([
|
||||
Select::make('status')
|
||||
->label(__('Status'))
|
||||
->options(OrderStatusRepository::statusValues())
|
||||
->default(OrderStatusRepository::defaultStatus())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpanFull(),
|
||||
|
||||
RichEditor::make('notes')
|
||||
->label(__('Bellik'))
|
||||
->toolbarButtons([
|
||||
'h2',
|
||||
'italic',
|
||||
'orderedList',
|
||||
'bold',
|
||||
'strike',
|
||||
'underline',
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
FileUpload::make('loan_file')
|
||||
->label(__('Loan paid off letter file'))
|
||||
->columnSpanFull()
|
||||
->maxSize(4096)
|
||||
->columnSpan(2)
|
||||
->downloadable()
|
||||
->previewable(false),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Loans\Resources\LoanPaidOffLetters\Tables;
|
||||
|
||||
use App\Modules\DefaultQueryForResourceIndex\Repositories\DefaultQueryForResourceIndexRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class LoanPaidOffLettersTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->modifyQueryUsing(function (Builder $query) {
|
||||
DefaultQueryForResourceIndexRepository::make($query);
|
||||
})
|
||||
->defaultSort('created_at', 'desc')
|
||||
->columns([
|
||||
TextColumn::make('id')
|
||||
->label('ID')
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('region')
|
||||
->label(__('Region'))
|
||||
->formatStateUsing(fn (string $state) => RegionRepository::label($state)),
|
||||
|
||||
TextColumn::make('branch.name')
|
||||
->label(__('Branch')),
|
||||
|
||||
TextColumn::make('customer_name')
|
||||
->label(__('Name'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('customer_surname')
|
||||
->label(__('Surname'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('phone')
|
||||
->label(__('Phone'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label(__('Status'))
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->sortable()
|
||||
->badge()
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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')),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\CurrencyRates;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\Pages\CreateCurrencyRate;
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\Pages\EditCurrencyRate;
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\Pages\ListCurrencyRates;
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\Schemas\CurrencyRateForm;
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\Tables\CurrencyRatesTable;
|
||||
use App\Filament\Clusters\Settings\SettingsCluster;
|
||||
use App\Modules\CurrencyRate\Models\CurrencyRate;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class CurrencyRateResource extends Resource
|
||||
{
|
||||
protected static ?string $model = CurrencyRate::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCurrencyDollar;
|
||||
|
||||
protected static ?string $cluster = SettingsCluster::class;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return __('Currencies');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('Currency rate');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('Currency rates');
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return CurrencyRateForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return CurrencyRatesTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListCurrencyRates::route('/'),
|
||||
'create' => CreateCurrencyRate::route('/create'),
|
||||
'edit' => EditCurrencyRate::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\CurrencyRates\Pages;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\CurrencyRateResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateCurrencyRate extends CreateRecord
|
||||
{
|
||||
protected static string $resource = CurrencyRateResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\CurrencyRates\Pages;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\CurrencyRateResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditCurrencyRate extends EditRecord
|
||||
{
|
||||
protected static string $resource = CurrencyRateResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\CurrencyRates\Pages;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\CurrencyRates\CurrencyRateResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListCurrencyRates extends ListRecords
|
||||
{
|
||||
protected static string $resource = CurrencyRateResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\CurrencyRates\Schemas;
|
||||
|
||||
use App\Modules\CurrencyRate\Models\CurrencyRate;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class CurrencyRateForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Select::make('currency_from')
|
||||
->label(__('Currency from'))
|
||||
->native(false)
|
||||
->searchable()
|
||||
->options(CurrencyRate::currencies())
|
||||
->rules('required')
|
||||
->belowLabel('1 möçberi'),
|
||||
|
||||
Select::make('currency_to')
|
||||
->label(__('Currency to'))
|
||||
->native(false)
|
||||
->searchable()
|
||||
->options(CurrencyRate::currencies())
|
||||
->rules('required')
|
||||
->belowLabel('1 möçberi'),
|
||||
|
||||
TextInput::make('value')
|
||||
->label(__('Currency value'))
|
||||
->required()
|
||||
->numeric()
|
||||
->belowLabel('Bitin däl sanlary "." bilen ýazmaly'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\CurrencyRates\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class CurrencyRatesTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('currency_from')
|
||||
->label(__('Currency from'))
|
||||
->searchable(),
|
||||
TextColumn::make('currency_to')
|
||||
->label(__('Currency to'))
|
||||
->searchable(),
|
||||
TextColumn::make('value')
|
||||
->label(__('Currency value'))
|
||||
->searchable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Pages;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\VisaMasterSettingsResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateVisaMasterSettings extends CreateRecord
|
||||
{
|
||||
protected static string $resource = VisaMasterSettingsResource::class;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Pages;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\VisaMasterSettingsResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditVisaMasterSettings extends EditRecord
|
||||
{
|
||||
protected static string $resource = VisaMasterSettingsResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Pages;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\VisaMasterSettingsResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListVisaMasterSettings extends ListRecords
|
||||
{
|
||||
protected static string $resource = VisaMasterSettingsResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Schemas;
|
||||
|
||||
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterSettings;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class VisaMasterSettingsForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Select::make('name')
|
||||
->label(__('Type'))
|
||||
->options(VisaMasterSettings::types())
|
||||
->native(false)
|
||||
->required(),
|
||||
|
||||
TextInput::make('display_name')
|
||||
->label(__('Name'))
|
||||
->required()
|
||||
->string()
|
||||
->maxLength(255)
|
||||
->readonly(! user()->isMe()),
|
||||
|
||||
RichEditor::make('value')
|
||||
->label(__('Content'))
|
||||
->required()
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class VisaMasterSettingsTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->searchable(),
|
||||
TextColumn::make('display_name')
|
||||
->searchable(),
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Settings\Resources\VisaMasterSettings;
|
||||
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Pages\CreateVisaMasterSettings;
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Pages\EditVisaMasterSettings;
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Pages\ListVisaMasterSettings;
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Schemas\VisaMasterSettingsForm;
|
||||
use App\Filament\Clusters\Settings\Resources\VisaMasterSettings\Tables\VisaMasterSettingsTable;
|
||||
use App\Filament\Clusters\Settings\SettingsCluster;
|
||||
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterSettings;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class VisaMasterSettingsResource extends Resource
|
||||
{
|
||||
protected static ?string $model = VisaMasterSettings::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentText;
|
||||
|
||||
protected static ?string $cluster = SettingsCluster::class;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'display_name';
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return __('Currencies');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('Warning text');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('Warning text');
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return VisaMasterSettingsForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return VisaMasterSettingsTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListVisaMasterSettings::route('/'),
|
||||
'create' => CreateVisaMasterSettings::route('/create'),
|
||||
'edit' => EditVisaMasterSettings::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ use Filament\Support\Icons\Heroicon;
|
||||
|
||||
class SettingsCluster extends Cluster
|
||||
{
|
||||
protected static ?int $navigationSort = 100;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCog8Tooth;
|
||||
|
||||
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::End;
|
||||
|
||||
24
app/Filament/Clusters/Users/UsersCluster.php
Normal file
24
app/Filament/Clusters/Users/UsersCluster.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\Users;
|
||||
|
||||
use BackedEnum;
|
||||
use Filament\Clusters\Cluster;
|
||||
use Filament\Pages\Enums\SubNavigationPosition;
|
||||
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;
|
||||
|
||||
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::Top;
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('Users');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\VisaMasterPaymentOrderResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateVisaMasterPaymentOrder extends CreateRecord
|
||||
{
|
||||
protected static string $resource = VisaMasterPaymentOrderResource::class;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\VisaMasterPaymentOrderResource;
|
||||
use App\Modules\VisaMasterPaymentOrder\Filament\Actions\PayVisaMasterPaymentAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
|
||||
class EditVisaMasterPaymentOrder extends EditRecord
|
||||
{
|
||||
protected static string $resource = VisaMasterPaymentOrderResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
PayVisaMasterPaymentAction::make(),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getTitle(): string|Htmlable
|
||||
{
|
||||
return __('Order details');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages;
|
||||
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\VisaMasterPaymentOrderResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListVisaMasterPaymentOrders extends ListRecords
|
||||
{
|
||||
protected static string $resource = VisaMasterPaymentOrderResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
{
|
||||
protected static string $resource = VisaMasterPaymentOrderResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
EditAction::make()
|
||||
->icon(Heroicon::OutlinedPencil),
|
||||
];
|
||||
}
|
||||
|
||||
public function infolist(Schema $schema): Schema
|
||||
{
|
||||
return VisaMasterPaymentOrderInfolist::configure($schema);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Schemas;
|
||||
|
||||
use App\Modules\FilamentPermission\Repositories\FilamentPermissionRepository;
|
||||
use App\Modules\OrderStatus\Repositories\OrderStatusRepository;
|
||||
use App\Modules\PhoneNumberVerification\Rules\PhoneNumberVerificationRule;
|
||||
use App\Modules\Region\Repositories\RegionRepository;
|
||||
use App\Modules\TurkmenPassport\Repositories\TurkmenPassportRepository;
|
||||
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\RichEditor;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\SpatieMediaLibraryFileUpload;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Schemas\Components\Fieldset;
|
||||
use Filament\Schemas\Components\FusedGroup;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Wizard;
|
||||
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
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Hidden::make('user_id')->default(Auth::id()),
|
||||
|
||||
Section::make()
|
||||
->columnSpan(4)
|
||||
->columns(4)
|
||||
->disabled(fn (string $context): bool => FilamentPermissionRepository::forClients())
|
||||
->components([
|
||||
Select::make('status')
|
||||
->label(__('Status'))
|
||||
->options(OrderStatusRepository::statusValues())
|
||||
->default(OrderStatusRepository::defaultStatus())
|
||||
->native(false)
|
||||
->columnSpan(2),
|
||||
|
||||
Toggle::make('paid')
|
||||
->label(sprintf('%s (%s)', __('Paid'), __('This month')))
|
||||
->inline(false)
|
||||
->disabled(true)
|
||||
->onIcon(Heroicon::CheckCircle)
|
||||
->offIcon(Heroicon::XCircle)
|
||||
->onColor('success')
|
||||
->offColor('danger'),
|
||||
|
||||
RichEditor::make('notes')
|
||||
->label(__('Bellik'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
|
||||
Wizard::make([
|
||||
Step::make(__('Order type and bank'))
|
||||
->schema([
|
||||
Fieldset::make(__('Order type'))
|
||||
->schema([
|
||||
Select::make('type')
|
||||
->label(__('Type'))
|
||||
->options(VisaMasterPaymentOrder::applicationTypes())
|
||||
->native(false)
|
||||
->required(),
|
||||
]),
|
||||
|
||||
Fieldset::make(__('Location'))
|
||||
->schema([
|
||||
Select::make('region')
|
||||
->label(__('Region'))
|
||||
->options(RegionRepository::values())
|
||||
->live()
|
||||
->afterStateUpdated(fn (callable $set) => $set('branch_id', null))
|
||||
->required(),
|
||||
|
||||
Select::make('branch_id')
|
||||
->label(__('Branch'))
|
||||
->relationship('branch', 'name', function ($query, callable $get) {
|
||||
$query->orderByTranslation('name');
|
||||
|
||||
$region = $get('region');
|
||||
if ($region) {
|
||||
$query->where('region', $region);
|
||||
}
|
||||
})
|
||||
->required(),
|
||||
]),
|
||||
]),
|
||||
Step::make(__('Payment sender data'))
|
||||
->columns(8)
|
||||
->schema([
|
||||
TextInput::make('sender_full_name')
|
||||
->label(__('Name, Surname, Patronic name'))
|
||||
->columnSpan(4)
|
||||
->default(user()->fullName())
|
||||
->required(),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('sender_passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->default(user()->getOption('passport_serie')),
|
||||
|
||||
TextInput::make('sender_passport_number')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->mask('999999')
|
||||
->default(user()->getOption('passport_id')),
|
||||
])
|
||||
->columnSpan(2)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
TextInput::make('phone')
|
||||
->label(__('Phone'))
|
||||
->required()
|
||||
->mask('99 99 99 99')
|
||||
->prefix('+993')
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2)
|
||||
->default(user()->phone),
|
||||
|
||||
TextInput::make('sender_deposit_account')
|
||||
->label(__('Deposit account'))
|
||||
->columnSpan(4)
|
||||
->required(),
|
||||
|
||||
TextInput::make('address')
|
||||
->label(__('Address'))
|
||||
->columnSpan(4)
|
||||
->required(),
|
||||
|
||||
Section::make(__('Files'))
|
||||
->description('PNG, JPEG, PDF')
|
||||
->columnSpanFull()
|
||||
->columns(2)
|
||||
->schema([
|
||||
AdvancedFileUpload::make('sender_passport_local')
|
||||
->spatieMediaLibrary(collection: 'sender_passport_local')
|
||||
->multiple(),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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')),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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'))
|
||||
->required(),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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')),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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')),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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')),
|
||||
]),
|
||||
]),
|
||||
|
||||
Step::make(__('Payee information'))
|
||||
->columns(8)
|
||||
->schema([
|
||||
TextInput::make('reciever_full_name')
|
||||
->label(__('Name, Surname, Patronic name'))
|
||||
->columnSpan(5)
|
||||
->required(),
|
||||
|
||||
FusedGroup::make([
|
||||
Select::make('reciever_passport_serie')
|
||||
->label(__('Passport serie'))
|
||||
->options(TurkmenPassportRepository::values())
|
||||
->native(false)
|
||||
->required()
|
||||
->columnSpan(1),
|
||||
|
||||
TextInput::make('reciever_passport_number')
|
||||
->label(__('Passport number'))
|
||||
->required()
|
||||
->columnSpan(1)
|
||||
->mask('999999'),
|
||||
])
|
||||
->columnSpan(3)
|
||||
->label(__('Passport serie and number'))
|
||||
->columns(2),
|
||||
|
||||
Section::make(__('Files'))
|
||||
->description('PNG, JPEG, PDF')
|
||||
->columnSpanFull()
|
||||
->columns(2)
|
||||
->schema([
|
||||
SpatieMediaLibraryFileUpload::make('receiver_requisite')
|
||||
->collection('receiver_requisite')
|
||||
->label(__('Talyba degişli walýuta "VISA" kartyň rekwizitleri'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1)
|
||||
->required(),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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'))
|
||||
->maxSize(4096)
|
||||
->openable()
|
||||
->columnSpan(1),
|
||||
|
||||
SpatieMediaLibraryFileUpload::make('receiver_ticket')
|
||||
->collection('receiver_ticket')
|
||||
->label(__('Talybyň bilediniň göçürmesi'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1),
|
||||
|
||||
SpatieMediaLibraryFileUpload::make('receiver_passport_international')
|
||||
->collection('receiver_passport_international')
|
||||
->label(__('Talybyň Türkmenistandan çykmak we Türkmenistana girmek üçin (zagran) pasportynyň göçürmesi'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1),
|
||||
|
||||
SpatieMediaLibraryFileUpload::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'))
|
||||
->maxSize(4096)
|
||||
->columnSpan(1),
|
||||
]),
|
||||
]),
|
||||
|
||||
])->columnSpanFull()->skippable(fn (string $context) => $context === 'edit'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
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\TextEntry;
|
||||
use Filament\Schemas\Components\Fieldset;
|
||||
use Filament\Schemas\Components\Section;
|
||||
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
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Section::make()
|
||||
->columnSpanFull()
|
||||
->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;']),
|
||||
|
||||
TextEntry::make('status')
|
||||
->label(__('Status'))
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->extraAttributes(['style' => 'text-transform:uppercase;font-size:1.2em;font-weight:bold;'])
|
||||
->color(OrderStatusRepository::statusColorMatching()),
|
||||
|
||||
IconEntry::make('paid')
|
||||
->label(sprintf('%s (%s)', __('Paid'), __('This month')))
|
||||
->boolean()
|
||||
->trueIcon(Heroicon::CheckCircle)
|
||||
->falseIcon(Heroicon::XCircle)
|
||||
->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()
|
||||
->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(__('Payment sender data'))
|
||||
->columns(8)
|
||||
->schema([
|
||||
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;
|
||||
|
||||
return $serie.' '.$record->sender_passport_number;
|
||||
})
|
||||
->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('address')
|
||||
->label(__('Address'))
|
||||
->columnSpan(4)
|
||||
->placeholder('-'),
|
||||
]),
|
||||
|
||||
Section::make(__('Files'))
|
||||
->description('PNG, JPEG, PDF')
|
||||
->columnSpanFull()
|
||||
->columns(2)
|
||||
->schema([
|
||||
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')),
|
||||
|
||||
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')),
|
||||
|
||||
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')),
|
||||
|
||||
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')),
|
||||
|
||||
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')),
|
||||
|
||||
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')),
|
||||
]),
|
||||
]),
|
||||
|
||||
Tab::make(__('Payee information'))
|
||||
->columns(8)
|
||||
->schema([
|
||||
TextEntry::make('reciever_full_name')
|
||||
->label(__('Name, Surname, Patronic name'))
|
||||
->columnSpan(5)
|
||||
->placeholder('-'),
|
||||
|
||||
TextEntry::make('reciever_passport')
|
||||
->label(__('Passport serie and number'))
|
||||
->formatStateUsing(function ($record) {
|
||||
$serie = TurkmenPassportRepository::values()[$record->reciever_passport_serie] ?? $record->reciever_passport_serie;
|
||||
|
||||
return $serie.' '.$record->reciever_passport_number;
|
||||
})
|
||||
->columnSpan(3)
|
||||
->placeholder('-'),
|
||||
|
||||
Section::make(__('Files'))
|
||||
->description('PNG, JPEG, PDF')
|
||||
->columnSpanFull()
|
||||
->columns(2)
|
||||
->schema([
|
||||
SpatieMediaLibraryFileEntry::make('receiver_requisite')
|
||||
->collection('receiver_requisite')
|
||||
->label(__('Talyba degişli walýuta "VISA" kartyň rekwizitleri'))
|
||||
->columnSpan(1),
|
||||
|
||||
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),
|
||||
|
||||
SpatieMediaLibraryFileEntry::make('receiver_ticket')
|
||||
->collection('receiver_ticket')
|
||||
->label(__('Talybyň bilediniň göçürmesi'))
|
||||
->columnSpan(1),
|
||||
|
||||
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),
|
||||
|
||||
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),
|
||||
|
||||
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),
|
||||
|
||||
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),
|
||||
|
||||
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),
|
||||
]),
|
||||
]),
|
||||
])->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
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
|
||||
{
|
||||
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'))
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('type')
|
||||
->label(__('Type'))
|
||||
->formatStateUsing(fn (string $state) => Str::upper($state)),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label(__('Status'))
|
||||
->color(OrderStatusRepository::statusColorMatching())
|
||||
->formatStateUsing(fn (string $state) => OrderStatusRepository::statusFormatted($state))
|
||||
->badge(),
|
||||
|
||||
TextColumn::make('created_at')
|
||||
->label(__('Created At'))
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('region')
|
||||
->label(__('Region'))
|
||||
->formatStateUsing(fn (string $state): string => RegionRepository::label($state))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('branch.name')
|
||||
->label(__('Branch'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('sender_full_name')
|
||||
->label(__('Full Name'))
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('phone')
|
||||
->label(__('Phone'))
|
||||
->searchable(),
|
||||
|
||||
IconColumn::make('paid')
|
||||
->label(sprintf('%s (%s)', __('Paid'), __('This month')))
|
||||
->boolean(),
|
||||
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
ViewAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
ForceDeleteBulkAction::make(),
|
||||
RestoreBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders;
|
||||
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages\CreateVisaMasterPaymentOrder;
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages\EditVisaMasterPaymentOrder;
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages\ListVisaMasterPaymentOrders;
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Pages\ViewVisaMasterPaymentOrder;
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Schemas\VisaMasterPaymentOrderForm;
|
||||
use App\Filament\Clusters\VisaMasterPayments\Resources\VisaMasterPaymentOrders\Tables\VisaMasterPaymentOrdersTable;
|
||||
use App\Filament\Clusters\VisaMasterPayments\VisaMasterPaymentsCluster;
|
||||
use App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class VisaMasterPaymentOrderResource extends Resource
|
||||
{
|
||||
protected static ?int $navigationSort = 1;
|
||||
|
||||
protected static ?string $model = VisaMasterPaymentOrder::class;
|
||||
|
||||
protected static ?string $cluster = VisaMasterPaymentsCluster::class;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'unique_id';
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = 'icon-visa-plain';
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return __('Visa/Master payments');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('Visa/Master payment');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('Visa/Master payments');
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return VisaMasterPaymentOrderForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return VisaMasterPaymentOrdersTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListVisaMasterPaymentOrders::route('/'),
|
||||
'create' => CreateVisaMasterPaymentOrder::route('/create'),
|
||||
'view' => ViewVisaMasterPaymentOrder::route('/{record}/view'),
|
||||
'edit' => EditVisaMasterPaymentOrder::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query for the record route binding
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder<\App\Modules\VisaMasterPaymentOrder\Models\VisaMasterPaymentOrder>
|
||||
*/
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Clusters\VisaMasterPayments;
|
||||
|
||||
use BackedEnum;
|
||||
use Filament\Clusters\Cluster;
|
||||
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;
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('International payments');
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
11
app/Filament/Resources/Users/Pages/CreateUser.php
Normal file
11
app/Filament/Resources/Users/Pages/CreateUser.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Users\Pages;
|
||||
|
||||
use App\Filament\Resources\Users\UserResource;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateUser extends CreateRecord
|
||||
{
|
||||
protected static string $resource = UserResource::class;
|
||||
}
|
||||
19
app/Filament/Resources/Users/Pages/EditUser.php
Normal file
19
app/Filament/Resources/Users/Pages/EditUser.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Users\Pages;
|
||||
|
||||
use App\Filament\Resources\Users\UserResource;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditUser extends EditRecord
|
||||
{
|
||||
protected static string $resource = UserResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Filament/Resources/Users/Pages/ListUsers.php
Normal file
19
app/Filament/Resources/Users/Pages/ListUsers.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Users\Pages;
|
||||
|
||||
use App\Filament\Resources\Users\UserResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListUsers extends ListRecords
|
||||
{
|
||||
protected static string $resource = UserResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
72
app/Filament/Resources/Users/Schemas/UserForm.php
Normal file
72
app/Filament/Resources/Users/Schemas/UserForm.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Users\Schemas;
|
||||
|
||||
use App\Modules\PhoneNumberVerification\Rules\PhoneNumberVerificationRule;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class UserForm
|
||||
{
|
||||
public static function configure(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->columns(6)
|
||||
->components([
|
||||
TextInput::make('name')
|
||||
->label(__('Full Name'))
|
||||
->required()
|
||||
->columnSpan(3),
|
||||
|
||||
TextInput::make('username')
|
||||
->label(__('Username'))
|
||||
->required()
|
||||
->unique(ignoreRecord: true)
|
||||
->columnSpan(3),
|
||||
|
||||
TextInput::make('phone')
|
||||
->label(__('Phone'))
|
||||
->unique(ignoreRecord: true)
|
||||
->mask('99 99 99 99')
|
||||
->prefix('+993')
|
||||
->dehydrateStateUsing(fn ($state) => unMaskTurkmenNumber($state))
|
||||
->rules([
|
||||
new PhoneNumberVerificationRule,
|
||||
])
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('email')
|
||||
->label(__('Email'))
|
||||
->email()
|
||||
->unique(ignoreRecord: true)
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('password')
|
||||
->label(__('Password'))
|
||||
->password()
|
||||
->dehydrateStateUsing(fn ($state) => Hash::make($state))
|
||||
->dehydrated(fn ($state) => filled($state))
|
||||
->required(fn (string $context): bool => $context === 'create')
|
||||
->columnSpan(2),
|
||||
|
||||
Select::make('roles')
|
||||
->label(__('Roles'))
|
||||
->relationship('roles', 'name')
|
||||
->multiple()
|
||||
->preload()
|
||||
->native(false)
|
||||
->columnSpan(3),
|
||||
|
||||
Select::make('branches')
|
||||
->label(__('Branches'))
|
||||
->relationship('branches', 'name', fn (Builder $query) => $query->distinct('id')->orderBy('id'))
|
||||
->multiple()
|
||||
->preload()
|
||||
->native(false)
|
||||
->columnSpan(3),
|
||||
]);
|
||||
}
|
||||
}
|
||||
57
app/Filament/Resources/Users/Tables/UsersTable.php
Normal file
57
app/Filament/Resources/Users/Tables/UsersTable.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Users\Tables;
|
||||
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class UsersTable
|
||||
{
|
||||
public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->defaultSort('created_at', direction: 'desc')
|
||||
->columns([
|
||||
TextColumn::make('id'),
|
||||
|
||||
TextColumn::make('first_name')
|
||||
->label(__('First name'))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('last_name')
|
||||
->label(__('Last name'))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('username')
|
||||
->label(__('Username'))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('phone')
|
||||
->label(__('Phone number'))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('email')
|
||||
->label(__('Email'))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
])
|
||||
->filters([
|
||||
//
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
70
app/Filament/Resources/Users/UserResource.php
Normal file
70
app/Filament/Resources/Users/UserResource.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Users;
|
||||
|
||||
use App\Filament\Clusters\Users\UsersCluster;
|
||||
use App\Filament\Resources\Users\Pages\CreateUser;
|
||||
use App\Filament\Resources\Users\Pages\EditUser;
|
||||
use App\Filament\Resources\Users\Pages\ListUsers;
|
||||
use App\Filament\Resources\Users\Schemas\UserForm;
|
||||
use App\Filament\Resources\Users\Tables\UsersTable;
|
||||
use App\Models\User;
|
||||
use BackedEnum;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class UserResource extends Resource
|
||||
{
|
||||
protected static ?string $model = User::class;
|
||||
|
||||
protected static ?string $cluster = UsersCluster::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedUsers;
|
||||
|
||||
protected static string|BackedEnum|null $activeNavigationIcon = Heroicon::Users;
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'phone';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return __('Users');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return __('User');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return __('Users');
|
||||
}
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return UserForm::configure($schema);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return UsersTable::configure($table);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ListUsers::route('/'),
|
||||
'create' => CreateUser::route('/create'),
|
||||
'edit' => EditUser::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
69
app/Http/Controllers/MigrationController.php
Normal file
69
app/Http/Controllers/MigrationController.php
Normal 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';
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,11 @@ class EnsureProfileIsFilled
|
||||
/** @var \App\Models\User */
|
||||
$user = $request->user();
|
||||
|
||||
// Skip if user is system user...
|
||||
if ($user->isSystemUser()) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
// 1. If user is not logged in, or profile is already complete, do nothing.
|
||||
// (Based on your logic: must_fill_profile == true means complete)
|
||||
if (! $user->must_fill_profile) {
|
||||
|
||||
28
app/Http/Middleware/EnsureUserHasRole.php
Normal file
28
app/Http/Middleware/EnsureUserHasRole.php
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
64
app/Modules/ActivityLog/ActivityLogModule.php
Normal file
64
app/Modules/ActivityLog/ActivityLogModule.php
Normal 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 [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\ActivityLog\Repositories;
|
||||
|
||||
class ActivityLogRepository {}
|
||||
10
app/Modules/AppHelpers/Contracts/HasFailedMethod.php
Normal file
10
app/Modules/AppHelpers/Contracts/HasFailedMethod.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\AppHelpers\Contracts;
|
||||
|
||||
interface HasFailedMethod
|
||||
{
|
||||
public function failed(): bool;
|
||||
|
||||
public function successful(): bool;
|
||||
}
|
||||
@@ -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'],
|
||||
]);
|
||||
}
|
||||
@@ -159,6 +160,10 @@ class LoginController extends Controller
|
||||
$request->session()->put('auth.password_confirmed_at', time());
|
||||
}
|
||||
|
||||
if ($user->roles->count() == 0) {
|
||||
$user->assignRole('client');
|
||||
}
|
||||
|
||||
return $this->sendLoginResponse($request);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ class RegisterController extends Controller
|
||||
'must_fill_profile' => true,
|
||||
]);
|
||||
|
||||
$user->assignRole('client');
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,18 @@ class RedirectIfUserPhoneIsUnVerfied
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (Auth::check() && is_null($request->user()?->phone_verified_at)) {
|
||||
return redirect()->route('sms-verification');
|
||||
if (Auth::check()) {
|
||||
/** @var \App\Models\User */
|
||||
$user = $request->user();
|
||||
|
||||
// Skip if user is system user...
|
||||
if ($user->isSystemUser()) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (is_null($user->phone_verified_at)) {
|
||||
return redirect()->route('sms-verification');
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
@@ -16,8 +16,13 @@ class RedirectIfUserPhoneIsVerfied
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (Auth::check() && ! is_null($request->user()?->phone_verified_at)) {
|
||||
return redirect()->route(config()->string('module.base-auth.redirect_path'));
|
||||
if (Auth::check()) {
|
||||
/** @var \App\Models\User */
|
||||
$user = $request->user();
|
||||
|
||||
if (! is_null($user->phone_verified_at) || $user->isSystemUser()) {
|
||||
return redirect(config()->string('module.base-auth.redirect_path'));
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
@@ -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',
|
||||
];
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Modules\Branch\Interfaces;
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $branch_id
|
||||
* @property \App\Modules\Branch\Models\Branch $branch
|
||||
*
|
||||
* @phpstan-require-extends \Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
|
||||
@@ -12,8 +12,8 @@ use Spatie\Translatable\HasTranslations;
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $unique_code
|
||||
* @property array<string, string> $name
|
||||
* @property array<string, string>|null $address
|
||||
* @property string $name
|
||||
* @property string|null $address
|
||||
* @property string $region
|
||||
* @property int|null $province_id
|
||||
* @property array<string, string>|null $phone_numbers
|
||||
@@ -77,4 +77,20 @@ class Branch extends Model
|
||||
{
|
||||
return $this->belongsToMany(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing username
|
||||
*/
|
||||
public function billingUsername(): string
|
||||
{
|
||||
return $this->billing_username ?: '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing password
|
||||
*/
|
||||
public function billingPassword(): string
|
||||
{
|
||||
return $this->billing_password ?: '-';
|
||||
}
|
||||
}
|
||||
|
||||
34
app/Modules/Branch/Models/UserBranch.php
Normal file
34
app/Modules/Branch/Models/UserBranch.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Branch\Models;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class UserBranch extends Pivot
|
||||
{
|
||||
public $incrementing = true;
|
||||
|
||||
protected $table = 'branch_user';
|
||||
|
||||
/**
|
||||
* Branch
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<Branch, $this>
|
||||
*/
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<User, $this>
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
69
app/Modules/Branch/Policies/BranchPolicy.php
Normal file
69
app/Modules/Branch/Policies/BranchPolicy.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Branch\Policies;
|
||||
|
||||
use App\Modules\Branch\Models\Branch;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
|
||||
class BranchPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:Branch');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, Branch $branch): bool
|
||||
{
|
||||
return $authUser->can('View:Branch');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:Branch');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, Branch $branch): bool
|
||||
{
|
||||
return $authUser->can('Update:Branch');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, Branch $branch): bool
|
||||
{
|
||||
return $authUser->can('Delete:Branch');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, Branch $branch): bool
|
||||
{
|
||||
return $authUser->can('Restore:Branch');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, Branch $branch): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:Branch');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:Branch');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:Branch');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, Branch $branch): bool
|
||||
{
|
||||
return $authUser->can('Replicate:Branch');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:Branch');
|
||||
}
|
||||
}
|
||||
22
app/Modules/Card/Filament/Actions/CheckCardBalanceAction.php
Normal file
22
app/Modules/Card/Filament/Actions/CheckCardBalanceAction.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Card\Filament\Actions;
|
||||
|
||||
use App\Modules\Card\Models\Card;
|
||||
use App\Modules\CardBalance\Repositories\CardBalanceRepository;
|
||||
use Filament\Actions\Action;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
class CheckCardBalanceAction
|
||||
{
|
||||
public static function make(): Action
|
||||
{
|
||||
return Action::make('card_balance')
|
||||
->label(__('Card balance'))
|
||||
->icon('heroicon-o-credit-card')
|
||||
->requiresConfirmation(false)
|
||||
->modal()
|
||||
->modalContent(fn (Card $record): View => CardBalanceRepository::make()->showCardBalance($record))
|
||||
->modalFooterActions([]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Card\Filament\Actions;
|
||||
|
||||
use App\Modules\Card\Models\Card;
|
||||
use App\Modules\CardRequisite\Repositories\CardRequisiteRepository;
|
||||
use Filament\Actions\Action;
|
||||
|
||||
class DownloadCardRequisteAction
|
||||
{
|
||||
public static function make(): Action
|
||||
{
|
||||
return Action::make('card_requisite')
|
||||
->label(__('Card requisite'))
|
||||
->icon('heroicon-o-document-text')
|
||||
->requiresConfirmation()
|
||||
->modalIcon('heroicon-o-document-text')
|
||||
->action(fn (Card $record) => CardRequisiteRepository::make()->downloadCardRequisite($record));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Card\Filament\Actions;
|
||||
|
||||
use App\Modules\Card\Models\Card;
|
||||
use App\Modules\CardTransaction\Repositories\CardTransactionRepository;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Livewire\Component;
|
||||
|
||||
class DownloadCardTransactionAction
|
||||
{
|
||||
public static function make(): Action
|
||||
{
|
||||
return Action::make('card_transactions')
|
||||
->label(__('Card transactions'))
|
||||
->icon('heroicon-o-arrows-right-left')
|
||||
->requiresConfirmation()
|
||||
->modalIcon('heroicon-m-arrows-right-left')
|
||||
->schema([
|
||||
DatePicker::make('start_date')
|
||||
->label(__('Start date'))
|
||||
->native(false)
|
||||
->required()
|
||||
->beforeOrEqual('today'),
|
||||
|
||||
DatePicker::make('end_date')
|
||||
->label(__('End date'))
|
||||
->native(false)
|
||||
->required()
|
||||
->beforeOrEqual('today'),
|
||||
])
|
||||
->action(
|
||||
fn (array $data, Card $record, Component $livewire) => CardTransactionRepository::make()->downloadCardTransaction($data, $record, $livewire)
|
||||
);
|
||||
}
|
||||
}
|
||||
69
app/Modules/Card/Policies/CardPolicy.php
Normal file
69
app/Modules/Card/Policies/CardPolicy.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\Card\Policies;
|
||||
|
||||
use App\Modules\Card\Models\Card;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
|
||||
class CardPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:Card');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, Card $card): bool
|
||||
{
|
||||
return $authUser->can('View:Card');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:Card');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, Card $card): bool
|
||||
{
|
||||
return $authUser->can('Update:Card');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, Card $card): bool
|
||||
{
|
||||
return $authUser->can('Delete:Card');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, Card $card): bool
|
||||
{
|
||||
return $authUser->can('Restore:Card');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, Card $card): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:Card');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:Card');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:Card');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, Card $card): bool
|
||||
{
|
||||
return $authUser->can('Replicate:Card');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:Card');
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,16 @@ class CardOrderModule implements ModuleContract
|
||||
name: 'Branch',
|
||||
message: 'This module is used for branches.',
|
||||
),
|
||||
new ModulePackage(
|
||||
type: ModulePackageType::MODULE,
|
||||
name: 'OrderStatus',
|
||||
message: 'Supports orders.',
|
||||
),
|
||||
new ModulePackage(
|
||||
type: ModulePackageType::MODULE,
|
||||
name: 'OnlinePayment',
|
||||
message: 'Is online payable.',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ return new class extends Migration
|
||||
|
||||
$table->text('notes')->nullable();
|
||||
|
||||
$table->foreignId('user_id')->constrained('users')->restrictOnDelete();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
|
||||
$table->boolean('paid')->default(false);
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\CardOrder\Filament\Actions;
|
||||
|
||||
use App\Modules\CardOrder\Models\CardOrder;
|
||||
use App\Modules\CardOrder\Repositories\CardOrderRepository;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Notifications\Notification;
|
||||
|
||||
class PayCardOrderAction
|
||||
{
|
||||
public static function make(): Action
|
||||
{
|
||||
return Action::make('card_order_pay')
|
||||
->label(__('Pay'))
|
||||
->icon('heroicon-o-credit-card')
|
||||
->requiresConfirmation()
|
||||
->action(function (CardOrder $record) {
|
||||
$onlinePayment = CardOrderRepository::make()
|
||||
->createOnlinePaymentOrder($record);
|
||||
|
||||
if ($onlinePayment->successful()) {
|
||||
Notification::make()
|
||||
->success()
|
||||
->title('Sending')
|
||||
->send();
|
||||
|
||||
return redirect()->away($onlinePayment->paymentLink());
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->danger()
|
||||
->title('Could not send')
|
||||
->send();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,23 @@ 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])
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Price for card
|
||||
*/
|
||||
public function priceAmount(): int|float|string
|
||||
{
|
||||
return $this->cardState->price ?? 32;
|
||||
}
|
||||
}
|
||||
|
||||
69
app/Modules/CardOrder/Policies/CardOrderPolicy.php
Normal file
69
app/Modules/CardOrder/Policies/CardOrderPolicy.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Modules\CardOrder\Policies;
|
||||
|
||||
use App\Modules\CardOrder\Models\CardOrder;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
|
||||
class CardOrderPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:CardOrder');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, CardOrder $cardOrder): bool
|
||||
{
|
||||
return $authUser->can('View:CardOrder');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:CardOrder');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, CardOrder $cardOrder): bool
|
||||
{
|
||||
return $authUser->can('Update:CardOrder');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, CardOrder $cardOrder): bool
|
||||
{
|
||||
return $authUser->can('Delete:CardOrder');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, CardOrder $cardOrder): bool
|
||||
{
|
||||
return $authUser->can('Restore:CardOrder');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, CardOrder $cardOrder): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:CardOrder');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:CardOrder');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:CardOrder');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, CardOrder $cardOrder): bool
|
||||
{
|
||||
return $authUser->can('Replicate:CardOrder');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:CardOrder');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user