From b34b7c19d679fbcb51ec192bba95ca86fa5fac96 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 3 Apr 2026 06:59:39 +0800 Subject: [PATCH] Update: laravel 8 to 12, php 7.3 to php 8.3, Jenkinsfile, Unit/Feature testing, vapor, docker --- .env.example | 2 +- .env.testing | 12 ++ .gitignore | 3 + 503.html | 7 + Jenkinsfile | 46 ++++- .../Eloquent/Filters/IsNotFullyRefunded.php | 3 +- .../Eloquent/Filters/IsPartialRefund.php | 5 +- app/Classes/Jobs/SendWelcomeVoucherEmail.php | 2 +- .../Validators/UserCreateValidation.php | 7 +- .../Validators/UserRegistrationValidation.php | 3 +- .../ControllersLogic/UpdateCompanyLogic.php | 4 +- .../DataTransferObjects/FileObject.php | 16 +- .../Services/ConvertsBase64ToFile.php | 54 ++--- .../Documents/Services/CreatesFiles.php | 11 +- .../Segments/Services/CreatesConstant.php | 2 +- .../Segments/Services/UpdatesConstant.php | 2 +- .../Standards/Rules/CanCreateSegment.php | 8 +- .../CreateInvoiceTransactionV2Processor.php | 3 +- app/Console/Kernel.php | 121 ------------ app/Exceptions/Handler.php | 68 ------- .../AWS/AWSImageUploadController.php | 2 +- .../ImportStatementInvoiceController.php | 2 +- app/Http/Kernel.php | 85 -------- .../Middleware/RedirectIfAuthenticated.php | 1 - app/Http/Middleware/TrustProxies.php | 9 +- app/Http/Middleware/ValidateToken.php | 18 +- app/Logging/CloudWatchLoggerFactory.php | 2 +- app/Models/AbstractModel.php | 13 +- app/Models/AccountStatement.php | 16 +- app/Models/Address.php | 32 +-- app/Models/Affiliate.php | 22 ++- app/Models/Announcement.php | 4 - app/Models/Bank.php | 19 +- app/Models/BillGroup.php | 12 +- app/Models/Booking.php | 28 ++- app/Models/Company.php | 28 ++- app/Models/Contact.php | 31 +-- app/Models/Country.php | 18 +- app/Models/Currency.php | 26 ++- app/Models/CurrencyRate.php | 12 +- app/Models/District.php | 20 +- app/Models/Document.php | 39 ++-- app/Models/Employee.php | 9 +- app/Models/File.php | 21 +- app/Models/KeyValuePair.php | 14 +- app/Models/Milestone.php | 13 +- app/Models/MilestoneProgress.php | 13 +- app/Models/ModelAttribute.php | 14 +- app/Models/Reward.php | 13 +- app/Models/SeasonalSegment.php | 32 +-- app/Models/Segment.php | 16 +- app/Models/SegmentConstant.php | 22 ++- app/Models/ServiceType.php | 30 +-- app/Models/State.php | 16 +- app/Models/StatementTransaction.php | 14 +- app/Models/Transaction.php | 16 +- app/Models/TransactionMappingLog.php | 14 +- app/Models/User.php | 2 +- app/Models/UserAffiliate.php | 16 +- app/Models/UserReward.php | 13 +- app/Models/VoucherEntityMapping.php | 13 +- app/Providers/AppServiceProvider.php | 8 + app/Providers/AuthServiceProvider.php | 2 - app/Providers/RouteServiceProvider.php | 97 --------- bootstrap/app.php | 184 +++++++++++++----- composer.json | 46 +++-- config/app.php | 3 +- config/cors.php | 2 +- config/filesystems.php | 4 +- config/hashing.php | 13 ++ ...020_11_28_060758_create_bookings_table.php | 2 +- ...34_create_statement_transactions_table.php | 2 +- ...d_invoice_status_to_booking_logs_table.php | 20 +- ...nvoice_generated_to_booking_logs_table.php | 20 +- ...oice_generated_from_booking_logs_table.php | 20 +- ...h_uuid_and_event_to_activity_log_table.php | 30 +++ ...tie_roles_and_permissions_guard_to_api.php | 36 ++++ .../seeds/AdminUserPermissionsTableSeeder.php | 94 ++++----- development.Dockerfile | 2 +- docker-setup/Dockerfile | 56 ++++-- docker-setup/docker-compose.yml | 14 +- phpunit.ci.xml | 39 ++++ phpunit.xml | 12 +- production.Dockerfile | 2 +- .../NewServiceAnnouncementComponent.vue | 2 +- .../EditCustomerCompanyTypeFormComponent.vue | 20 +- .../CustomerTransactionSectionComponent.vue | 2 +- resources/assets/vue/general/mixins/guards.js | 2 +- .../accounts/user_verification.blade.php | 6 +- resources/views/errors/503.blade.php | 8 + routes/account.php | 50 +++-- routes/accounting.php | 25 ++- routes/affiliate.php | 20 +- routes/announcement.php | 22 ++- routes/api.php | 31 +-- routes/apipub.php | 5 +- routes/bank.php | 23 ++- routes/billplz.php | 5 +- routes/booking.php | 82 +++++--- routes/company.php | 58 ++++-- routes/crud.php | 45 +++-- routes/currency.php | 19 +- routes/document.php | 20 +- routes/export.php | 4 +- routes/job.php | 7 +- routes/key_value_pair.php | 8 +- routes/milestone.php | 17 +- routes/rate.php | 22 ++- routes/receipt.php | 7 +- routes/remark.php | 17 +- routes/reward.php | 16 +- routes/segment.php | 26 ++- routes/segment_constant.php | 19 +- routes/transaction.php | 95 +++++---- routes/voucher.php | 16 +- routes/wallet.php | 20 +- routes/web.php | 66 ++++--- staging.Dockerfile | 2 +- test.Dockerfile | 3 + tests/Browser/DryRun/CreateBookingTest.php | 2 +- tests/Feature/Accounts/AuthenticationTest.php | 86 ++++++++ .../CreateSegmentLogicTest.php | 90 +++++++++ .../DeleteSegmentLogicTest.php | 94 +++++++++ .../FetchConstantLogicTest.php | 85 ++++++++ .../FetchSegmentLogicTest.php | 87 +++++++++ .../ControllersLogic/ListSegmentLogicTest.php | 88 +++++++++ .../UpdateConstantLogic2Test.php | 129 ++++++++++++ .../UpdateConstantLogicTest.php | 182 +++++++++++++++++ .../UpdateSegmentLogic2Test.php | 80 ++++++++ .../UpdateSegmentLogicTest.php | 96 +++++++++ .../ConvertsConstantDetailsToResourceTest.php | 105 ++++++++++ .../Segments/Services/CreatesConstantTest.php | 54 +++++ .../Services/CreatesSeasonalSegmentTest.php | 69 +++++++ .../Segments/Services/CreatesSegmentTest.php | 48 +++++ .../Segments/Services/DeletesSegmentTest.php | 44 +++++ .../Segments/Services/FetchesConstantTest.php | 94 +++++++++ .../Segments/Services/FetchesSegmentTest.php | 80 ++++++++ .../Segments/Services/ListsConstantsTest.php | 102 ++++++++++ .../Segments/Services/ListsSegmentsTest.php | 76 ++++++++ .../Segments/Services/UpdatesConstantTest.php | 60 ++++++ .../Segments/Services/UpdatesSegmentTest.php | 49 +++++ vapor.yml | 18 ++ 142 files changed, 3334 insertions(+), 1101 deletions(-) create mode 100644 .env.testing delete mode 100644 app/Console/Kernel.php delete mode 100644 app/Exceptions/Handler.php delete mode 100644 app/Http/Kernel.php delete mode 100644 app/Providers/RouteServiceProvider.php create mode 100644 database/migrations/2026_03_13_093615_add_batch_uuid_and_event_to_activity_log_table.php create mode 100644 database/migrations/2026_03_28_015715_update_spatie_roles_and_permissions_guard_to_api.php create mode 100644 phpunit.ci.xml create mode 100644 test.Dockerfile create mode 100644 tests/Feature/Accounts/AuthenticationTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/CreateSegmentLogicTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/DeleteSegmentLogicTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/FetchConstantLogicTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/FetchSegmentLogicTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/ListSegmentLogicTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogic2Test.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogicTest.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogic2Test.php create mode 100644 tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogicTest.php create mode 100644 tests/Unit/Modules/Segments/Services/ConvertsConstantDetailsToResourceTest.php create mode 100644 tests/Unit/Modules/Segments/Services/CreatesConstantTest.php create mode 100644 tests/Unit/Modules/Segments/Services/CreatesSeasonalSegmentTest.php create mode 100644 tests/Unit/Modules/Segments/Services/CreatesSegmentTest.php create mode 100644 tests/Unit/Modules/Segments/Services/DeletesSegmentTest.php create mode 100644 tests/Unit/Modules/Segments/Services/FetchesConstantTest.php create mode 100644 tests/Unit/Modules/Segments/Services/FetchesSegmentTest.php create mode 100644 tests/Unit/Modules/Segments/Services/ListsConstantsTest.php create mode 100644 tests/Unit/Modules/Segments/Services/ListsSegmentsTest.php create mode 100644 tests/Unit/Modules/Segments/Services/UpdatesConstantTest.php create mode 100644 tests/Unit/Modules/Segments/Services/UpdatesSegmentTest.php diff --git a/.env.example b/.env.example index c2daa69e..43314eaf 100644 --- a/.env.example +++ b/.env.example @@ -45,7 +45,7 @@ PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" -FILESYSTEM_DRIVER="documents" +FILESYSTEM_DISK="documents" JWT_SECRET= JWT_TTL=1440 diff --git a/.env.testing b/.env.testing new file mode 100644 index 00000000..c1122651 --- /dev/null +++ b/.env.testing @@ -0,0 +1,12 @@ +APP_NAME=Laravel +APP_ENV=testing + +APP_KEY=base64:utnZQgraE9iHT+4xCoDP2p7MdQmBweGyP0b6Mp1ksds= +JWT_SECRET=4DlpggxJJeV1nVeHPPf83mSGsoJEmA8bpuSFdFN0VCvwqkE084iYOqoed0q47Ee2 + +DB_CONNECTION=mysql +DB_HOST=172.18.0.3 +DB_PORT=3306 +DB_DATABASE=ci_test_exchange +DB_USERNAME=ci +DB_PASSWORD=bi9y@T8r diff --git a/.gitignore b/.gitignore index bc05095d..2a1aa394 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ **/.idea/ .env .env.backup +.env.testing.example .phpunit.result.cache Homestead.json Homestead.yaml @@ -31,3 +32,5 @@ public .env.production .env.staging .env.development +docz/* +.phpunit.cache/ diff --git a/503.html b/503.html index d8fbc8c3..46aa2f9b 100644 --- a/503.html +++ b/503.html @@ -19,12 +19,19 @@ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } +

We'll be back soon!

Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!

— CIEF EXCHANGE

+ + Go Back Home
diff --git a/Jenkinsfile b/Jenkinsfile index cd286f65..eca6a73d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,8 +9,8 @@ pipeline { agent { docker { - args '--group-add 992 -v /var/run/docker.sock:/var/run/docker.sock' - image '303644228504.dkr.ecr.ap-southeast-1.amazonaws.com/jenkins-pipeline-agent:latest' + args '--network ci-net --group-add 992 -v /var/run/docker.sock:/var/run/docker.sock' + image '303644228504.dkr.ecr.ap-southeast-1.amazonaws.com/jenkins-pipeline-agent-php-8.3:latest' registryCredentialsId "ecr:ap-southeast-1:aws-ec2-instance-iam-role" registryUrl "https://303644228504.dkr.ecr.ap-southeast-1.amazonaws.com" } @@ -53,6 +53,15 @@ pipeline { branch: GIT_BRANCH ) break + case "vapor/test": //cief todo: 137 + pusherKeyCredId = 'pusher-test-key' + pusherCluster = 'ap1' + git( + url: 'https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git', + credentialsId: 'gitlab-jenkins-localhost', + branch: GIT_BRANCH + ) + break case "origin/dillon/34-jenkins-vapor": git( url: 'https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git', @@ -84,7 +93,35 @@ pipeline { stage('Tests') { steps { - sh 'vendor/bin/phpunit tests/Unit' + // sh 'vendor/bin/phpunit tests/Unit' + sh ''' + set -e + + export APP_ENV=testing + # export APP_KEY=$(php -r "echo 'base64:'.base64_encode(random_bytes(32));") + # export JWT_SECRET=$(php -r "echo bin2hex(random_bytes(32));") + + # Show which PHP binary is used + which php + php -v + + # List PHP modules to confirm pdo_mysql + php -m | grep pdo_mysql || echo "pdo_mysql not loaded" + + # Show DB environment variables + echo "DB_CONNECTION=$DB_CONNECTION" + echo "DB_HOST=$DB_HOST" + echo "DB_PORT=$DB_PORT" + echo "DB_DATABASE=$DB_DATABASE" + echo "DB_USERNAME=$DB_USERNAME" + # Do NOT echo password in logs + + php artisan migrate:fresh --force + + vendor/bin/phpunit -c phpunit.ci.xml --group ok_to_run + # vendor/bin/phpunit --filter AuthenticationTest + # vendor/bin/phpunit -c phpunit.ci.xml --filter ListOrderTrackingLogicTest + ''' script{ currentBuild.description = 'Step 4 of 6 Completed' } @@ -107,6 +144,9 @@ pipeline { case "vapor/development": sh "vendor/bin/vapor deploy development --message='${gitCommitMessage}'" break + case "vapor/test": + sh "vendor/bin/vapor deploy test --message='${gitCommitMessage}'" + break case "origin/dillon/34-jenkins-vapor": sh "vendor/bin/vapor deploy development --message='${gitCommitMessage}'" break diff --git a/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php b/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php index fdbb2994..3351118f 100644 --- a/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php +++ b/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php @@ -4,7 +4,6 @@ namespace App\Classes\General\Eloquent\Filters; use App\Classes\ValueObjects\Constants\ApprovalStatus; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Facades\DB; class IsNotFullyRefunded implements Filter { @@ -19,6 +18,6 @@ class IsNotFullyRefunded implements Filter return $builder->withSum(['transactions as total_refund_amount' => function($q) { $q->refunds()->where('status', ApprovalStatus::APPROVED); }], 'original_amount') - ->having('total_refund_amount', '<', DB::raw('original_amount')); + ->havingRaw('total_refund_amount < original_amount'); } } diff --git a/app/Classes/General/Eloquent/Filters/IsPartialRefund.php b/app/Classes/General/Eloquent/Filters/IsPartialRefund.php index 1378a94c..74aeabfd 100644 --- a/app/Classes/General/Eloquent/Filters/IsPartialRefund.php +++ b/app/Classes/General/Eloquent/Filters/IsPartialRefund.php @@ -3,7 +3,6 @@ namespace App\Classes\General\Eloquent\Filters; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Facades\DB; class IsPartialRefund implements Filter { @@ -17,9 +16,9 @@ class IsPartialRefund implements Filter { return $builder->whereHas('owner', function ($q) use ($value) { if ($value) { - $q->where('original_amount', '!=', DB::raw('transactions.original_amount')); + $q->whereRaw('original_amount != transactions.original_amount'); } else { - $q->where('original_amount', DB::raw('transactions.original_amount')); + $q->whereRaw('original_amount = transactions.original_amount'); } }); } diff --git a/app/Classes/Jobs/SendWelcomeVoucherEmail.php b/app/Classes/Jobs/SendWelcomeVoucherEmail.php index 2fcc8dac..5f7734a7 100644 --- a/app/Classes/Jobs/SendWelcomeVoucherEmail.php +++ b/app/Classes/Jobs/SendWelcomeVoucherEmail.php @@ -46,7 +46,7 @@ class SendWelcomeVoucherEmail implements ShouldQueue { $currentDatetime = Carbon::now(); $dateToCompare = Carbon::parse($this->voucher->end_date); - if (!$this->user->hasAttribute($this->voucher->code."_EMAIL_COUNT") + if (!$this->user->hasCustomAttribute($this->voucher->code."_EMAIL_COUNT") && $this->user->rewards->where('voucher_id', $this->voucher->id)->count() > 0 && $currentDatetime->isBefore($dateToCompare)) { diff --git a/app/Classes/Modules/Accounts/Standards/Validators/UserCreateValidation.php b/app/Classes/Modules/Accounts/Standards/Validators/UserCreateValidation.php index 99ea60ac..aef4a022 100644 --- a/app/Classes/Modules/Accounts/Standards/Validators/UserCreateValidation.php +++ b/app/Classes/Modules/Accounts/Standards/Validators/UserCreateValidation.php @@ -4,6 +4,7 @@ namespace App\Classes\Modules\Accounts\Standards\Validators; use App\Classes\General\Abstracts\AbstractValidation; use App\Classes\Modules\Accounts\DataTransferObjects\UserObject; +use Illuminate\Validation\Rule; class UserCreateValidation extends AbstractValidation { @@ -28,9 +29,9 @@ class UserCreateValidation extends AbstractValidation protected function rules(): array { return [ - 'name' => 'required', - 'email' => 'required|unique:users', - 'password' => 'required', + 'name' => 'required', + 'email' => ['required', Rule::unique('users')], + 'password' => 'required', ]; } diff --git a/app/Classes/Modules/Accounts/Standards/Validators/UserRegistrationValidation.php b/app/Classes/Modules/Accounts/Standards/Validators/UserRegistrationValidation.php index 673b7961..611184f3 100644 --- a/app/Classes/Modules/Accounts/Standards/Validators/UserRegistrationValidation.php +++ b/app/Classes/Modules/Accounts/Standards/Validators/UserRegistrationValidation.php @@ -4,6 +4,7 @@ namespace App\Classes\Modules\Accounts\Standards\Validators; use App\Classes\General\Abstracts\AbstractValidation; use App\Classes\Modules\Accounts\DataTransferObjects\RegistrationObject; +use Illuminate\Validation\Rule; class UserRegistrationValidation extends AbstractValidation { @@ -32,7 +33,7 @@ class UserRegistrationValidation extends AbstractValidation { return [ 'name' => 'required', - 'email' => 'required|email|max:255|unique:users,email', + 'email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')], 'password' => 'required|min:6|confirmed', 'type' => 'required', 'status' => 'required' diff --git a/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyLogic.php b/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyLogic.php index 23cf9561..da2b455b 100644 --- a/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyLogic.php +++ b/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyLogic.php @@ -56,7 +56,7 @@ class UpdateCompanyLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { - $object = new CompanyObject($request->input('name'), $request->input('reference'), $request->input('type')); + $object = new CompanyObject($request->input('name'), $request->input('reference'), $request->input('business_type'), $request->input('type')); $this->canUpdateCompany->passes($object); @@ -67,4 +67,4 @@ class UpdateCompanyLogic extends AbstractControllerLogic return $this->resourceResponse(new CompanyResource($query)); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php b/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php index 2a425f7d..29069cd7 100644 --- a/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php +++ b/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php @@ -7,6 +7,7 @@ use App\Classes\General\Interfaces\DataTransferObject; use App\Classes\ValueObjects\Constants\FileType; use Illuminate\Support\Str; use Intervention\Image\ImageManager; +use Intervention\Image\Drivers\Gd\Driver; class FileObject implements DataTransferObject { @@ -28,7 +29,13 @@ class FileObject implements DataTransferObject */ public function getData() { - return in_array($this->getExtension(), ['pdf', 'excel', 'text']) ? $this->data : (new imageManager())->make($this->data); + // intervention/image v2: old + //return in_array($this->getExtension(), ['pdf', 'excel', 'text']) ? $this->data : (new imageManager())->make($this->data); + + // intervention/image v3: new + return in_array($this->getExtension(), ['pdf', 'excel', 'text']) + ? $this->data + : (new ImageManager(new Driver()))->read($this->data); } /** @@ -53,7 +60,7 @@ class FileObject implements DataTransferObject */ public function getExtension(): string { - if(array_key_exists($this->getMimeType(), FileType::EXTENSION)){ + if (array_key_exists($this->getMimeType(), FileType::EXTENSION)) { return FileType::EXTENSION[$this->getMimeType()]; } @@ -66,9 +73,10 @@ class FileObject implements DataTransferObject */ public function getDecodedData(): string { + // intervention/image v3: Use encode()->toDataUri() instead of encode('data-url')->encoded return in_array($this->getExtension(), ['pdf', 'excel', 'text']) ? - base64_decode((explode('base64,', $this->getData()))[1]): - $this->getData()->encode('data-url')->encoded; + base64_decode((explode('base64,', $this->getData()))[1]) : + $this->getData()->encode()->toDataUri(); } /** diff --git a/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php b/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php index f246fcfa..12839c27 100644 --- a/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php +++ b/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php @@ -32,7 +32,8 @@ class ConvertsBase64ToFile * @return array * @throws MalformedRequestException */ - public function convert($files = []){ + public function convert($files = []) + { foreach ($files as $file) { $object = new FileObject($file); @@ -48,41 +49,47 @@ class ConvertsBase64ToFile * @param FileObject $file * @throws MalformedRequestException */ - private function generatePDF(FileObject $file){ + private function generatePDF(FileObject $file) + { $filePath = $this->generateFile($file); - $this->updateFiles($file, [ 'original' => [ 'file' => $filePath ] ]); + $this->updateFiles($file, ['original' => ['file' => $filePath]]); } /** * @param FileObject $file * @throws MalformedRequestException */ - private function generateImage(FileObject $file){ + private function generateImage(FileObject $file) + { $fileInfo = []; foreach (['original' => null, 'large' => 800, 'medium' => 480, 'small' => 320] as $size => $value) { - $suffix = $size !== 'original' ? '_'.$size : ''; + $suffix = $size !== 'original' ? '_' . $size : ''; - if($size !== 'original') { - $thumbnail = $file->getData()->widen($value, function ($constraint) { + if ($size !== 'original') { + // intervention/image v2: old + // $thumbnail = $file->getData()->widen($value, function ($constraint) { + // $constraint->upsize(); + // })->heighten($value, function ($constraint) { + // $constraint->upsize(); + // }); + // $file->setData($thumbnail->encode('data-url')->encoded); - $constraint->upsize(); - })->heighten($value, function ($constraint) { + // intervention/image v3: Use scaleDown() instead of widen()/heighten() + // scaleDown() maintains aspect ratio and prevents upsizing by default + $thumbnail = $file->getData()->scaleDown(width: $value, height: $value); - $constraint->upsize(); - - }); - - $file->setData($thumbnail->encode('data-url')->encoded); + // intervention/image v3: Use encode()->toDataUri() instead of encode('data-url')->encoded + $file->setData($thumbnail->encode()->toDataUri()); } $filePath = $this->generateFile($file, $suffix); - $fileInfo[] = [ $size => [ 'file' => $filePath, 'width' => $file->getData()->width(), 'height' => $file->getData()->height() ]]; + $fileInfo[] = [$size => ['file' => $filePath, 'width' => $file->getData()->width(), 'height' => $file->getData()->height()]]; } @@ -97,16 +104,16 @@ class ConvertsBase64ToFile * @return string * @throws MalformedRequestException */ - private function generateFile(FileObject $file, string $suffix = '') { + private function generateFile(FileObject $file, string $suffix = '') + { $filesystemDriver = Storage::getDefaultDriver(); - if($filesystemDriver === 's3'){ - $filePath = 'documents/'.$this->path.'/'.$file->getFileName().$suffix.'.'.$file->getExtension(); + if ($filesystemDriver === 's3') { + $filePath = 'documents/' . $this->path . '/' . $file->getFileName() . $suffix . '.' . $file->getExtension(); Storage::put($filePath, $file->getDecodedData(), 's3'); return $filePath; - } - else{ - $filePath = $this->path.'/'.$file->getFileName().$suffix.'.'.$file->getExtension(); + } else { + $filePath = $this->path . '/' . $file->getFileName() . $suffix . '.' . $file->getExtension(); Storage::disk('documents')->put($filePath, $file->getDecodedData()); return $filePath; } @@ -117,10 +124,11 @@ class ConvertsBase64ToFile * @param array $fileInfo * @throws MalformedRequestException */ - private function updateFiles(FileObject $file, array $fileInfo){ + private function updateFiles(FileObject $file, array $fileInfo) + { $this->filesInfo[] = json_encode([ 'path' => $this->path, - 'filename' => $file->getFileName().'.'.$file->getExtension(), + 'filename' => $file->getFileName() . '.' . $file->getExtension(), 'mime_type' => $file->getMimeType(), 'extension' => $file->getExtension(), 'file_info' => $fileInfo diff --git a/app/Classes/Modules/Documents/Services/CreatesFiles.php b/app/Classes/Modules/Documents/Services/CreatesFiles.php index 30c85a13..79fdde1a 100644 --- a/app/Classes/Modules/Documents/Services/CreatesFiles.php +++ b/app/Classes/Modules/Documents/Services/CreatesFiles.php @@ -19,14 +19,19 @@ class CreatesFiles extends AbstractUpdateRelationshipRecord { $models = []; + // foreach ($object->getFiles() as $file) { + // $model = new File(['file' => $file]); + // $models[] = $this->handler($document->files(), $model); + // } + foreach ($object->getFiles() as $file) { - - $model = new File(['file' => $file]); + $fileData = is_string($file) ? json_decode($file, true) : $file; + $model = new File(['file' => $fileData]); $models[] = $this->handler($document->files(), $model); - } return $models; + } } \ No newline at end of file diff --git a/app/Classes/Modules/Segments/Services/CreatesConstant.php b/app/Classes/Modules/Segments/Services/CreatesConstant.php index b2addae8..4c52fb70 100644 --- a/app/Classes/Modules/Segments/Services/CreatesConstant.php +++ b/app/Classes/Modules/Segments/Services/CreatesConstant.php @@ -20,7 +20,7 @@ class CreatesConstant extends AbstractUpdateRelationshipRecord $model = new SegmentConstant(); $model->name = $object->getName(); $model->reference = $object->getReference(); - $model->detail = json_encode($object->getDetail()); + $model->detail = $object->getDetail(); return $this->handler($segment->constants(), $model); } diff --git a/app/Classes/Modules/Segments/Services/UpdatesConstant.php b/app/Classes/Modules/Segments/Services/UpdatesConstant.php index 13fb22c1..65568492 100644 --- a/app/Classes/Modules/Segments/Services/UpdatesConstant.php +++ b/app/Classes/Modules/Segments/Services/UpdatesConstant.php @@ -19,7 +19,7 @@ class UpdatesConstant extends AbstractUpdateRecord { $model->name = $object->getName(); $model->reference = $object->getReference(); - $model->detail = json_encode($object->getDetail()); + $model->detail = $object->getDetail(); return $this->handler($model); } diff --git a/app/Classes/Modules/Segments/Standards/Rules/CanCreateSegment.php b/app/Classes/Modules/Segments/Standards/Rules/CanCreateSegment.php index 82a783bc..13430e97 100644 --- a/app/Classes/Modules/Segments/Standards/Rules/CanCreateSegment.php +++ b/app/Classes/Modules/Segments/Standards/Rules/CanCreateSegment.php @@ -6,6 +6,7 @@ use App\Classes\General\Abstracts\AbstractRule; use App\Classes\Modules\Segments\DataTransferObjects\SegmentObject; use App\Classes\Modules\Segments\Standards\Validators\SegmentValidation; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Log; class CanCreateSegment extends AbstractRule { @@ -28,7 +29,10 @@ class CanCreateSegment extends AbstractRule protected function authorized($object): bool { // TODO Set Authorization rules - if (!Auth::user()->can('add segment')) { + /** @var \App\Models\User $user */ + $user = Auth::user(); + + if (!$user->can('add segment')) { return false; } @@ -53,4 +57,4 @@ class CanCreateSegment extends AbstractRule { return true; } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php index 027b4f76..c4bf3615 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php @@ -139,8 +139,7 @@ class CreateInvoiceTransactionV2Processor ->complete() ->first(); - if(!$purchaseOrder){ - //was use for $generateEInvoiceRefund true + if(!$purchaseOrder && $generateEInvoiceRefund){ $purchaseOrder = $booking->transactions() ->where('type', TransactionType::PURCHASE_ORDER) ->where('status', ApprovalStatus::PENDING_SUBMISSION) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php deleted file mode 100644 index cc9f1ff3..00000000 --- a/app/Console/Kernel.php +++ /dev/null @@ -1,121 +0,0 @@ -command('dummy-command') - // ->everyFiveMinutes() - // ->withoutOverlapping(); - - $schedule->command('housekeeping-s3-files-command') - ->dailyAt('01:00') - ->withoutOverlapping(); - - $schedule->command('password-reset-token-expriration-check-command') - ->everySixHours() - ->withoutOverlapping(); - - $schedule->command('new-user-registration-expire-check-command') - ->everySixHours() - ->withoutOverlapping(); - - if(env('APP_ENV') === 'production'){ - $schedule->command('email-do-to-vt-command') - ->dailyAt('10:00') - ->withoutOverlapping(); - - $schedule->command('seasonal-segmant-company-remove-command') - ->dailyAt('01:00') - ->withoutOverlapping(); - - $schedule->command('delete-bulk-download-files-command') - ->hourly() - ->withoutOverlapping(); - - $schedule->command('booking-expired-command') - ->dailyAt('02:00') - ->withoutOverlapping(); - - // DISABLED BY DEFAULT - // $schedule->command('purchase-order-autofill-command') - // ->dailyAt('03:00') - // ->withoutOverlapping(); - - // Push company module to Lark - $schedule->command('lark:push-company-module') - ->hourly() - ->withoutOverlapping(); - // Push booking module to Lark - $schedule->command('lark:push-booking-module') - ->hourly() - ->withoutOverlapping(); - } - } - //Commands Version 1: Before Laravel Vapor/AWS - else{ - // $schedule->command('inspire')->hourly(); - $schedule->command('mail:EmailDoToVTCommand')->dailyAt('10:00')->withoutOverlapping(); - - $schedule->command('seasonalSegmantCompany:remove') - ->dailyAt('01:00') - ->appendOutputTo(storage_path().'/logs/soft-delete-seasonal-segmant-company.log') - ->withoutOverlapping(); - - $schedule->command('delete:bulk-download-files') - ->hourly() - ->appendOutputTo(storage_path().'/logs/delete-bulk-download-files.log') - ->withoutOverlapping(); - - $schedule->command('booking:expired') - ->dailyAt('02:00') - ->appendOutputTo(storage_path().'/logs/expire-booking.log') - ->withoutOverlapping(); - - // $schedule->command('purchaseOrder:autoFill') - // ->dailyAt('03:00') - // ->withoutOverlapping(); - } - } - - /** - * Register the commands for the application. - * - * @return void - */ - protected function commands() - { - $this->load(__DIR__.'/Commands'); - - require base_path('routes/console.php'); - } -} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php deleted file mode 100644 index 4ee36f96..00000000 --- a/app/Exceptions/Handler.php +++ /dev/null @@ -1,68 +0,0 @@ -view('pages.errors.maintenance'); - } - - if ($exception instanceof AuthenticationException) { - return (new ApiResponseObject('Authentication', 'To keep your account secure we need to re-validate your account', HttpStatus::ACCESS_UNAUTHORISED))->handler(); - } - - return parent::render($request, $exception); - } -} diff --git a/app/Http/Controllers/AWS/AWSImageUploadController.php b/app/Http/Controllers/AWS/AWSImageUploadController.php index b0929c06..6f1f7d98 100644 --- a/app/Http/Controllers/AWS/AWSImageUploadController.php +++ b/app/Http/Controllers/AWS/AWSImageUploadController.php @@ -22,7 +22,7 @@ class AWSImageUploadController extends Controller public function imageUploadPost(Request $request) { $request->validate([ - 'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'image' => 'required|image:allow_svg|mimes:jpeg,png,jpg,gif,svg|max:2048', ]); $imageName = time().'.'.$request->image->extension(); diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index e4c35eb5..74d8f259 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -169,7 +169,7 @@ class ImportStatementInvoiceController } if ($transaction && $transaction->count() == 0) { - $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['net_total']))->whereRaw("DATE(posting_date) = '$date'")->first(); + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->whereRaw('FLOOR(statement_transactions.amount) = ?', [floor($row['net_total'])])->whereRaw("DATE(posting_date) = '$date'")->first(); } if ($transaction && $transaction->count() > 0) { diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php deleted file mode 100644 index 95479398..00000000 --- a/app/Http/Kernel.php +++ /dev/null @@ -1,85 +0,0 @@ - [ - EncryptCookies::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, - // \Illuminate\Session\Middleware\AuthenticateSession::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - VerifyCsrfToken::class, - \Illuminate\Routing\Middleware\SubstituteBindings::class, - \App\Http\Middleware\LogRequestPathMiddleware::class, - ], - - 'api' => [ - 'throttle:300,1', - \Illuminate\Routing\Middleware\SubstituteBindings::class, - \App\Http\Middleware\LogRequestPathMiddleware::class, - ], - - 'apipub' => [ - \Illuminate\Routing\Middleware\SubstituteBindings::class, - \App\Http\Middleware\LogRequestPathMiddleware::class, - ], - ]; - - /** - * The application's route middleware. - * - * These middleware may be assigned to groups or used individually. - * - * @var array - */ - protected $routeMiddleware = [ - 'auth' => Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, - 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, - 'can' => \Illuminate\Auth\Middleware\Authorize::class, - 'guest' => RedirectIfAuthenticated::class, - 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, - 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, - 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, - 'valid.token' => ValidateToken::class, - 'token.check' => \App\Http\Middleware\TokenCheckerMiddleware::class, - 'admin' => \App\Http\Middleware\EnsureUserIsAdmin::class, //cief maintenance - ]; -} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index bd955e53..bf890447 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -2,7 +2,6 @@ namespace App\Http\Middleware; -use App\Providers\RouteServiceProvider; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php index 14befceb..2bf6fd50 100644 --- a/app/Http/Middleware/TrustProxies.php +++ b/app/Http/Middleware/TrustProxies.php @@ -2,7 +2,7 @@ namespace App\Http\Middleware; -use Fideloper\Proxy\TrustProxies as Middleware; +use Illuminate\Http\Middleware\TrustProxies as Middleware; use Illuminate\Http\Request; class TrustProxies extends Middleware @@ -19,5 +19,10 @@ class TrustProxies extends Middleware * * @var int */ - protected $headers = Request::HEADER_X_FORWARDED_ALL; + protected $headers = + Request::HEADER_X_FORWARDED_FOR | + Request::HEADER_X_FORWARDED_HOST | + Request::HEADER_X_FORWARDED_PORT | + Request::HEADER_X_FORWARDED_PROTO | + Request::HEADER_X_FORWARDED_PREFIX; } diff --git a/app/Http/Middleware/ValidateToken.php b/app/Http/Middleware/ValidateToken.php index 846972aa..3f22c084 100644 --- a/app/Http/Middleware/ValidateToken.php +++ b/app/Http/Middleware/ValidateToken.php @@ -7,23 +7,9 @@ use App\Classes\ValueObjects\Constants\HttpStatus; use App\Classes\ValueObjects\Response\ApiResponseObject; use Closure; use Exception; -use Tymon\JWTAuth\JWT; class ValidateToken { - /** @var JWT */ - private $manager; - - /** - * ValidateToken constructor. - * @param JWT $manager - */ - public function __construct(JWT $manager) - { - $this->manager = $manager; - } - - /** * Checks if jwt token is valid. * @@ -35,9 +21,9 @@ class ValidateToken { try { - if(!$this->manager->check()){ throw new AccessUnauthorisedException(); } + if(!auth('api')->check()){ throw new AccessUnauthorisedException(); } - } catch (Exception $exception) { + } catch (Exception) { return (new ApiResponseObject('Authentication', 'To keep your account secure we need to re-validate your account', HttpStatus::ACCESS_UNAUTHORISED))->handler(); diff --git a/app/Logging/CloudWatchLoggerFactory.php b/app/Logging/CloudWatchLoggerFactory.php index 14c5da6e..eea59c90 100644 --- a/app/Logging/CloudWatchLoggerFactory.php +++ b/app/Logging/CloudWatchLoggerFactory.php @@ -3,7 +3,7 @@ namespace App\Logging; use Aws\CloudWatchLogs\CloudWatchLogsClient; -use Maxbanton\Cwh\Handler\CloudWatch; +use PhpNexus\Cwh\Handler\CloudWatch; use Monolog\Formatter\JsonFormatter; use Monolog\Logger; diff --git a/app/Models/AbstractModel.php b/app/Models/AbstractModel.php index 47d8754b..fb03d02f 100644 --- a/app/Models/AbstractModel.php +++ b/app/Models/AbstractModel.php @@ -6,12 +6,21 @@ namespace App\Models; use App\Classes\General\Interfaces\Notifiable; use Illuminate\Database\Eloquent\Model; use Spatie\Activitylog\Traits\LogsActivity; +use Spatie\Activitylog\LogOptions; use Illuminate\Database\Eloquent\Relations\MorphTo; class AbstractModel extends Model implements Notifiable { use LogsActivity; - protected static $logFillable = true; + + /** + * Get the options for logging activity. + */ + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->logFillable(); + } /** * @return MorphTo @@ -36,4 +45,4 @@ class AbstractModel extends Model implements Notifiable { return $this->MorphTo('causer'); } -} \ No newline at end of file +} diff --git a/app/Models/AccountStatement.php b/app/Models/AccountStatement.php index 2f5b0e8c..dc4ffae3 100644 --- a/app/Models/AccountStatement.php +++ b/app/Models/AccountStatement.php @@ -20,10 +20,18 @@ class AccountStatement extends Model 'mapped_rows', ]; - protected $casts = [ - 'date_from' => 'date', - 'date_to' => 'date', - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'date_from' => 'date', + 'date_to' => 'date', + ]; + } public function account() { diff --git a/app/Models/Address.php b/app/Models/Address.php index d240d714..1c221b14 100644 --- a/app/Models/Address.php +++ b/app/Models/Address.php @@ -9,22 +9,32 @@ use Illuminate\Database\Eloquent\Builder; * Class Address * @package App\Models * - * @property \App\Models\Country country_id - * @property \App\Models\Company company_id - * @property \App\Models\State state_id - * @property \App\Models\District district_id - * @property string postcode - * @property string street_one - * @property string street_two - * @property integer billing_type + * @property int $country_id + * @property int $company_id + * @property int $state_id + * @property int $district_id + * @property string $postcode + * @property string $street_one + * @property string $street_two + * @property int $billing_type */ class Address extends AbstractModel { use SoftDeletes; protected $table = 'addresses'; - - protected $dates = ['deleted_at']; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return BelongsTo @@ -64,6 +74,6 @@ class Address extends AbstractModel */ public function scopeDefault(Builder $query) { - return $query->where('billing', '=',true)->first(); + return $query->where('billing', '=', true)->first(); } } diff --git a/app/Models/Affiliate.php b/app/Models/Affiliate.php index 71d0115a..40ee25b0 100644 --- a/app/Models/Affiliate.php +++ b/app/Models/Affiliate.php @@ -11,7 +11,6 @@ class Affiliate extends AbstractModel use SoftDeletes; protected $table = 'affiliates'; - protected $dates = ['deleted_at']; protected $fillable = [ 'code', @@ -24,12 +23,21 @@ class Affiliate extends AbstractModel 'orders_count' ]; - protected $casts = [ - 'is_active' => 'boolean', - 'clicks_count' => 'integer', - 'registrations_count' => 'integer', - 'orders_count' => 'integer' - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'is_active' => 'boolean', + 'clicks_count' => 'integer', + 'registrations_count' => 'integer', + 'orders_count' => 'integer', + 'deleted_at' => 'datetime', + ]; + } /** * @return BelongsTo diff --git a/app/Models/Announcement.php b/app/Models/Announcement.php index b0094a6c..8bacbcab 100644 --- a/app/Models/Announcement.php +++ b/app/Models/Announcement.php @@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\SoftDeletes; /** * Class Announcement * @package App\Models - * */ class Announcement extends AbstractModel { @@ -16,9 +15,6 @@ class Announcement extends AbstractModel protected $table = 'announcements'; - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany - **/ public function segments(): BelongsToMany { return $this->BelongsToMany(Segment::class); diff --git a/app/Models/Bank.php b/app/Models/Bank.php index 42cdf3df..07c1d02a 100644 --- a/app/Models/Bank.php +++ b/app/Models/Bank.php @@ -14,22 +14,21 @@ use App\Classes\General\Interfaces\KeyValueInterface; * Class Bank * @package App\Models * - * @property \App\Models\Country country_id - * @property \App\Models\Company company_id - * @property string bank_name - * @property string holder_name - * @property string account_no - * @property int type - * @property int default - * @property int status + * @property int $country_id + * @property int $company_id + * @property string $bank_name + * @property string $holder_name + * @property string $account_no + * @property int $type + * @property int $default + * @property int $status */ class Bank extends AbstractModel implements KeyValueInterface { use SoftDeletes; /** - * - * @var array + * @var array */ protected $fillable = [ 'company_id', diff --git a/app/Models/BillGroup.php b/app/Models/BillGroup.php index 9270d8e8..348dc20f 100644 --- a/app/Models/BillGroup.php +++ b/app/Models/BillGroup.php @@ -19,7 +19,17 @@ class BillGroup extends Model implements Documentable, Transactionable protected $table = 'bill_groups'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return MorphMany diff --git a/app/Models/Booking.php b/app/Models/Booking.php index d488c1e4..e627adba 100644 --- a/app/Models/Booking.php +++ b/app/Models/Booking.php @@ -19,13 +19,13 @@ use Staudenmeir\EloquentHasManyDeep\HasRelationships; * Class Booking * @package App\Models * - * @property \App\Models\Company company_id - * @property \App\Models\Bank transferable_bank_id - * @property string marking - * @property string reference - * @property float fix_amount - * @property int convertible_currency_id - * @property int conversion_currency_id + * @property int $company_id + * @property int $transferable_bank_id + * @property string $marking + * @property string $reference + * @property float $fix_amount + * @property int $convertible_currency_id + * @property int $conversion_currency_id */ class Booking extends AbstractModel implements Documentable, Transactionable, Voucherifiable, KeyValueInterface { @@ -35,7 +35,17 @@ class Booking extends AbstractModel implements Documentable, Transactionable, Vo protected $table = 'bookings'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return BelongsTo @@ -106,7 +116,7 @@ class Booking extends AbstractModel implements Documentable, Transactionable, Vo */ public function bills(): hasManyDeep { - return $this->hasManyDeep(Transaction::class, [Transaction::class.' as alias'], [['owner_type', 'owner_id'], ['owner_type', 'owner_id']], [null, null]); + return $this->hasManyDeep(Transaction::class, [Transaction::class . ' as alias'], [['owner_type', 'owner_id'], ['owner_type', 'owner_id']], [null, null]); } public function modelAttributes(): MorphMany diff --git a/app/Models/Company.php b/app/Models/Company.php index 54ae1e23..fee2f4ad 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -20,13 +20,13 @@ use Staudenmeir\EloquentHasManyDeep\HasRelationships; * Class Company * @package App\Models * - * @property \App\Models\Country country_id - * @property \App\Models\State state_id - * @property \App\Models\District district_id - * @property string postcode - * @property string street_one - * @property string street_two - * @property integer billing_type + * @property int $country_id + * @property int $state_id + * @property int $district_id + * @property string $postcode + * @property string $street_one + * @property string $street_two + * @property int $billing_type */ class Company extends AbstractModel implements Documentable { @@ -35,8 +35,18 @@ class Company extends AbstractModel implements Documentable protected $table = 'companies'; - protected $dates = ['deleted_at', 'created_at']; - + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + 'created_at' => 'datetime', + ]; + } /** * @return HasMany diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 0a54d3f7..bdc18175 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -10,12 +10,12 @@ use Illuminate\Database\Eloquent\SoftDeletes; * Class Contact * @package App\Models * - * @property \App\Models\Country country_id - * @property \App\Models\Company company_id - * @property string reference - * @property string phone - * @property string email - * @property string wechat_id + * @property int $country_id + * @property int $company_id + * @property string $reference + * @property string $phone + * @property string $email + * @property string $wechat_id */ class Contact extends AbstractModel { @@ -23,20 +23,27 @@ class Contact extends AbstractModel protected $table = 'contacts'; - protected $dates = ['deleted_at']; - /** - * @return \Illuminate\Database\Eloquent\Relations\HasOne - **/ + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } + public function company(): HasOne { return $this->hasOne(Company::class); } /** - * @return belongsTo + * @return BelongsTo **/ - public function country(): belongsTo + public function country(): BelongsTo { return $this->belongsTo(Country::class); } diff --git a/app/Models/Country.php b/app/Models/Country.php index 3232366a..add21cef 100644 --- a/app/Models/Country.php +++ b/app/Models/Country.php @@ -9,9 +9,9 @@ use Illuminate\Database\Eloquent\SoftDeletes; * Class Country * @package App\Models * - * @property string name - * @property string short_code - * @property string phone_code + * @property string $name + * @property string $short_code + * @property string $phone_code */ class Country extends AbstractModel { @@ -19,7 +19,17 @@ class Country extends AbstractModel protected $table = 'countries'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } protected $fillable = ['name', 'short_code', 'phone_code']; diff --git a/app/Models/Currency.php b/app/Models/Currency.php index cf3b4a6f..bdb34b22 100644 --- a/app/Models/Currency.php +++ b/app/Models/Currency.php @@ -6,16 +6,16 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Database\Eloquent\Relations\hasMany; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * Class Currency * @package App\Models * - * @property \App\Models\Country country_id - * @property string name - * @property string short_code - * @property string symbol + * @property int $country_id + * @property string $name + * @property string $short_code + * @property string $symbol */ class Currency extends AbstractModel @@ -24,7 +24,17 @@ class Currency extends AbstractModel protected $table = 'currencies'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return BelongsTo @@ -35,9 +45,9 @@ class Currency extends AbstractModel } /** - * @return hasMany + * @return HasMany */ - public function rates(): hasMany + public function rates(): HasMany { return $this->hasMany(CurrencyRate::class, 'currency_id'); } diff --git a/app/Models/CurrencyRate.php b/app/Models/CurrencyRate.php index ca8cad92..0c87fd36 100644 --- a/app/Models/CurrencyRate.php +++ b/app/Models/CurrencyRate.php @@ -12,5 +12,15 @@ class CurrencyRate extends AbstractModel protected $fillable = ['currency_id', 'selling', 'payment_method_type']; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } } diff --git a/app/Models/District.php b/app/Models/District.php index 13a90f85..cf6f1b57 100644 --- a/app/Models/District.php +++ b/app/Models/District.php @@ -10,10 +10,10 @@ use Illuminate\Database\Eloquent\SoftDeletes; * Class District * @package App\Models * - * @property \App\Models\Country country_id - * @property \App\Models\State state_id - * @property string name - * @property string postcode + * @property int $country_id + * @property int $state_id + * @property string $name + * @property string $postcode */ class District extends AbstractModel { @@ -21,7 +21,17 @@ class District extends AbstractModel protected $table = 'districts'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return BelongsTo diff --git a/app/Models/Document.php b/app/Models/Document.php index eb3f8c77..eaa57fc1 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -7,22 +7,21 @@ use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Database\Eloquent\Relations\hasMany; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * Class Document * @package App\Models - * @version August 4, 2020, 4:36 am * - * @property int owner_id - * @property int owner_type - * @property int document_type - * @property string reference - * @property int status - * @property \App\Models\User approver - * @property timestamp issued_date - * @property timestamp expired_date - * @property timestamp approved_date + * @property int $owner_id + * @property int $owner_type + * @property int $document_type + * @property string $reference + * @property int $status + * @property int $approver + * @property string $issued_date + * @property string $expired_date + * @property string $approved_date */ class Document extends AbstractModel { @@ -30,7 +29,17 @@ class Document extends AbstractModel protected $table = 'documents'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return \Illuminate\Database\Eloquent\Relations\MorphTo @@ -41,9 +50,9 @@ class Document extends AbstractModel } /** - * @return hasMany + * @return HasMany */ - public function files(): hasMany + public function files(): HasMany { return $this->hasMany(File::class, 'document_id'); } @@ -51,7 +60,7 @@ class Document extends AbstractModel /** * @return HasOne */ - public function approver(): hasOne + public function approver(): HasOne { return $this->hasOne(User::class, 'id', 'approver'); } diff --git a/app/Models/Employee.php b/app/Models/Employee.php index 6d133186..027d8134 100644 --- a/app/Models/Employee.php +++ b/app/Models/Employee.php @@ -6,11 +6,11 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; /** - * Class CompanyEmployee + * Class Employee * @package App\Models * - * @property \App\Models\Company company_id - * @property \App\Models\User user_id + * @property int $company_id + * @property int $user_id */ class Employee extends AbstractModel { @@ -24,9 +24,6 @@ class Employee extends AbstractModel return $this->HasMany(Company::class, 'company_id', 'id'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasOne - **/ public function user(): HasOne { return $this->hasOne(User::class, 'user_id', 'id'); diff --git a/app/Models/File.php b/app/Models/File.php index 6707fd9f..6a0db405 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -8,11 +8,10 @@ use Illuminate\Database\Eloquent\SoftDeletes; /** * Class File * @package App\Models - * @version August 4, 2020, 4:36 am * - * @property \App\Models\Document document_id - * @property text file - * @property int file_type_id + * @property int $document_id + * @property object $file + * @property int $file_type_id */ class File extends AbstractModel { @@ -22,10 +21,16 @@ class File extends AbstractModel protected $fillable = ['file']; - protected $dates = ['deleted_at']; - - public function getFileAttribute($value) + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array { - return $value ? json_decode($value) : []; + return [ + 'file' => 'object', + 'deleted_at' => 'datetime', + ]; } } diff --git a/app/Models/KeyValuePair.php b/app/Models/KeyValuePair.php index ea6c54dc..182418fe 100644 --- a/app/Models/KeyValuePair.php +++ b/app/Models/KeyValuePair.php @@ -8,8 +8,6 @@ class KeyValuePair extends AbstractModel { use SoftDeletes; - protected $dates = ['deleted_at']; - protected $table = 'key_value_pairs'; protected $fillable = [ @@ -19,6 +17,18 @@ class KeyValuePair extends AbstractModel 'value', ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } + public function owner(): MorphTo { return $this->morphTo(); diff --git a/app/Models/Milestone.php b/app/Models/Milestone.php index 391410cc..1710a5d5 100644 --- a/app/Models/Milestone.php +++ b/app/Models/Milestone.php @@ -8,7 +8,18 @@ class Milestone extends AbstractModel use SoftDeletes; protected $table = 'milestones'; - protected $dates = ['deleted_at']; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } public function progress() { diff --git a/app/Models/MilestoneProgress.php b/app/Models/MilestoneProgress.php index 7e03cba0..fda8bdee 100644 --- a/app/Models/MilestoneProgress.php +++ b/app/Models/MilestoneProgress.php @@ -9,7 +9,18 @@ class MilestoneProgress extends AbstractModel use SoftDeletes; protected $table = 'milestone_progress'; - protected $dates = ['deleted_at']; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } public function milestone() { diff --git a/app/Models/ModelAttribute.php b/app/Models/ModelAttribute.php index bbd3511c..7fbd1fb0 100644 --- a/app/Models/ModelAttribute.php +++ b/app/Models/ModelAttribute.php @@ -15,9 +15,17 @@ class ModelAttribute extends Model "value" ]; - protected $casts = [ - "value" => "array" - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + "value" => "array", + ]; + } public function owner(): morphTo { diff --git a/app/Models/Reward.php b/app/Models/Reward.php index 7dbdc5a9..af285c43 100644 --- a/app/Models/Reward.php +++ b/app/Models/Reward.php @@ -10,7 +10,18 @@ class Reward extends AbstractModel use SoftDeletes; protected $table = 'rewards'; - protected $dates = ['deleted_at']; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } public function milestones() { diff --git a/app/Models/SeasonalSegment.php b/app/Models/SeasonalSegment.php index 30bb1796..672f58f7 100644 --- a/app/Models/SeasonalSegment.php +++ b/app/Models/SeasonalSegment.php @@ -11,13 +11,13 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; * Class SeasonalSegment * @package App\Models * - * @property \App\Models\Company company_id - * @property \App\Models\Bank transferable_bank_id - * @property string marking - * @property string reference - * @property float fix_amount - * @property int convertible_currency_id - * @property int conversion_currency_id + * @property int $company_id + * @property int $transferable_bank_id + * @property string $marking + * @property string $reference + * @property float $fix_amount + * @property int $convertible_currency_id + * @property int $conversion_currency_id */ class SeasonalSegment extends Model { @@ -27,11 +27,19 @@ class SeasonalSegment extends Model protected $table = 'seasonal_segment'; - protected $dates = [ - 'starting_on', - 'ending_on', - 'deleted_at', - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'starting_on' => 'datetime', + 'ending_on' => 'datetime', + 'deleted_at' => 'datetime', + ]; + } /** * @return BelongsTo diff --git a/app/Models/Segment.php b/app/Models/Segment.php index 339e8e86..a50953ee 100644 --- a/app/Models/Segment.php +++ b/app/Models/Segment.php @@ -9,8 +9,8 @@ use Illuminate\Database\Eloquent\SoftDeletes; * Class Segment * @package App\Models * - * @property string name - * @property string reference + * @property string $name + * @property string $reference */ class Segment extends AbstractModel { @@ -18,7 +18,17 @@ class Segment extends AbstractModel protected $table = 'segments'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return HasMany diff --git a/app/Models/SegmentConstant.php b/app/Models/SegmentConstant.php index b7fda276..c946dc13 100644 --- a/app/Models/SegmentConstant.php +++ b/app/Models/SegmentConstant.php @@ -10,8 +10,8 @@ use Illuminate\Database\Eloquent\SoftDeletes; * Class SegmentConstant * @package App\Models * - * @property \App\Models\Segment segment_id - * @property string detail + * @property int $segment_id + * @property object $detail */ class SegmentConstant extends AbstractModel { @@ -19,15 +19,17 @@ class SegmentConstant extends AbstractModel protected $table = 'segment_constants'; - protected $dates = ['deleted_at']; - - // protected $casts = [ - // 'detail' => 'array', - // ]; - - public function getDetailAttribute($value) + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array { - return $value ? json_decode($value) : []; + return [ + 'detail' => 'object', + 'deleted_at' => 'datetime', + ]; } /** diff --git a/app/Models/ServiceType.php b/app/Models/ServiceType.php index b3cac31b..b2a97263 100644 --- a/app/Models/ServiceType.php +++ b/app/Models/ServiceType.php @@ -13,7 +13,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @package App\Models * @version February 16, 2021, 9:04 pm * - * @property string name + * @property string $name */ class ServiceType extends AbstractModel { @@ -23,46 +23,46 @@ class ServiceType extends AbstractModel protected $table = 'service_types'; - - - protected $dates = ['deleted_at']; - public $fillable = [ 'name' ]; /** - * The attributes that should be casted to native types. + * Get the attributes that should be cast. * - * @var array + * @return array */ - protected $casts = [ - 'name' => 'string' - ]; + protected function casts(): array + { + return [ + 'name' => 'string', + 'deleted_at' => 'datetime', + ]; + } /** * Validation rules * - * @var array + * @var array */ public static $rules = [ 'name' => 'required' ]; /** - * @return hasMany + * @return HasMany */ - public function rates(): hasMany + public function rates(): HasMany { return $this->hasMany(CurrencyRate::class, 'service_id'); } /** - * @return hasMany + * @return HasMany */ - public function constants(): hasMany + public function constants(): HasMany { return $this->hasMany(SegmentConstant::class, 'detail->id') ->whereIn('reference', [SegmentConstants::SERVICE_TYPE, SegmentConstants::CUSTOM_SERVICE_TYPE]); diff --git a/app/Models/State.php b/app/Models/State.php index fa920454..4ae74e9f 100644 --- a/app/Models/State.php +++ b/app/Models/State.php @@ -9,8 +9,8 @@ use Illuminate\Database\Eloquent\SoftDeletes; * Class State * @package App\Models * - * @property \App\Models\Country country_id - * @property string name + * @property int $country_id + * @property string $name */ class State extends AbstractModel { @@ -18,7 +18,17 @@ class State extends AbstractModel protected $table = 'states'; - protected $dates = ['deleted_at']; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return HasOne diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index 4bba7903..1f81e7cb 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -30,9 +30,17 @@ class StatementTransaction extends Model 'end_balance', ]; - protected $casts = [ - 'posting_date' => 'datetime', - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'posting_date' => 'datetime', + ]; + } public function account() { diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index c84c0238..b59f4878 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -29,12 +29,20 @@ class Transaction extends AbstractModel implements Documentable, Transactionable use SoftDeletes; use LogData; - protected $casts = [ - 'type' => 'int' - ]; - protected $table = 'transactions'; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'type' => 'int', + ]; + } + public function owner(): morphTo { return $this->morphTo(); diff --git a/app/Models/TransactionMappingLog.php b/app/Models/TransactionMappingLog.php index e9ddab33..78fb29b2 100644 --- a/app/Models/TransactionMappingLog.php +++ b/app/Models/TransactionMappingLog.php @@ -9,9 +9,17 @@ class TransactionMappingLog extends Model { protected $fillable = ['imported_by','data','imported_date','type']; - protected $casts = [ - 'data' => 'array', - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'data' => 'array', + ]; + } public static function boot() { parent::boot(); diff --git a/app/Models/User.php b/app/Models/User.php index d396fc20..9c182865 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -104,7 +104,7 @@ class User extends AbstractModel implements return $this->HasMany(UserReward::class, 'user_id', 'id'); } - public function hasAttribute(string $key, $value = null): bool + public function hasCustomAttribute(string $key, $value = null): bool { $query = $this->attributesKVP()->where('key', $key); diff --git a/app/Models/UserAffiliate.php b/app/Models/UserAffiliate.php index bf8792e5..4b41c6e5 100644 --- a/app/Models/UserAffiliate.php +++ b/app/Models/UserAffiliate.php @@ -15,10 +15,18 @@ class UserAffiliate extends AbstractModel 'registered_at' ]; - protected $dates = [ - 'clicked_at', - 'registered_at' - ]; + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'clicked_at' => 'datetime', + 'registered_at' => 'datetime', + ]; + } /** * @return BelongsTo diff --git a/app/Models/UserReward.php b/app/Models/UserReward.php index 40309447..8fb3254f 100644 --- a/app/Models/UserReward.php +++ b/app/Models/UserReward.php @@ -9,7 +9,18 @@ class UserReward extends AbstractModel use SoftDeletes; protected $table = 'user_rewards'; - protected $dates = ['deleted_at']; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } public function reward() { diff --git a/app/Models/VoucherEntityMapping.php b/app/Models/VoucherEntityMapping.php index 2df0eacd..3c38e1ab 100644 --- a/app/Models/VoucherEntityMapping.php +++ b/app/Models/VoucherEntityMapping.php @@ -10,7 +10,18 @@ class VoucherEntityMapping extends AbstractModel use SoftDeletes; protected $table = 'voucher_entity_mappings'; - protected $dates = ['deleted_at']; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'deleted_at' => 'datetime', + ]; + } /** * @return \Illuminate\Database\Eloquent\Relations\MorphTo diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 4aeff6bd..4e1d6c11 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,9 @@ namespace App\Providers; use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider; +use Illuminate\Cache\RateLimiting\Limit; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\RateLimiter; class AppServiceProvider extends ServiceProvider { @@ -27,5 +30,10 @@ class AppServiceProvider extends ServiceProvider if (!file_exists(storage_path('framework/sessions'))) { mkdir(storage_path('framework/sessions'), 0777, true); } + + //From Shipping Portal + // RateLimiter::for('api', function (Request $request) { + // return Limit::perMinute(300)->by($request->user()?->id ?: $request->ip()); + // }); } } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 31a1ad6f..cd3e3159 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -23,8 +23,6 @@ class AuthServiceProvider extends ServiceProvider */ public function boot() { - $this->registerPolicies(); - // } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php deleted file mode 100644 index 334e7629..00000000 --- a/app/Providers/RouteServiceProvider.php +++ /dev/null @@ -1,97 +0,0 @@ -mapApiRoutes(); - - $this->mapWebRoutes(); - - $this->mapApiPubRoutes(); - - // - } - - /** - * Define the "web" routes for the application. - * - * These routes all receive session state, CSRF protection, etc. - * - * @return void - */ - protected function mapWebRoutes() - { - Route::middleware('web') - ->namespace($this->namespace) - ->group(base_path('routes/web.php')); - } - - /** - * Define the "api" routes for the application. - * - * These routes are typically stateless. - * - * @return void - */ - protected function mapApiRoutes() - { - Route::prefix('api') - ->middleware('api') - ->namespace($this->namespace) - ->group(base_path('routes/api.php')); - } - - /** - * Define the "apipub" routes for the application. - * - * These routes are typically stateless. - * - * @return void - */ - protected function mapApiPubRoutes() - { - Route::prefix('public/api') - ->middleware('apipub') - ->namespace($this->namespace) - ->group(base_path('routes/apipub.php')); - } -} diff --git a/bootstrap/app.php b/bootstrap/app.php index 037e17df..1f01a2a1 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,55 +1,147 @@ withRouting( + web: __DIR__ . '/../routes/web.php', + api: __DIR__ . '/../routes/api.php', + commands: __DIR__ . '/../routes/console.php', + health: '/up', + then: function () { + // Load public API routes (not loaded in api.php) + Route::middleware('apipub') + ->prefix('public/api') + ->group(base_path('routes/apipub.php')); + }, + ) + ->withMiddleware(function (Middleware $middleware) { + // '*' trusts all proxies, required for correct IP/HTTPS detection behind AWS ALB/Vapor + $middleware->trustProxies(at: '*'); -/* -|-------------------------------------------------------------------------- -| Bind Important Interfaces -|-------------------------------------------------------------------------- -| -| Next, we need to bind some important interfaces into the container so -| we will be able to resolve them when needed. The kernels serve the -| incoming requests to this application from both the web and CLI. -| -*/ + $middleware->web(append: [ + \App\Http\Middleware\LogRequestPathMiddleware::class, + ]); -$app->singleton( - Illuminate\Contracts\Http\Kernel::class, - App\Http\Kernel::class -); + $middleware->api(append: [ + \App\Http\Middleware\LogRequestPathMiddleware::class, + ]); -$app->singleton( - Illuminate\Contracts\Console\Kernel::class, - App\Console\Kernel::class -); + $middleware->api(prepend: [ + 'throttle:300,1', + ]); -$app->singleton( - Illuminate\Contracts\Debug\ExceptionHandler::class, - App\Exceptions\Handler::class -); + $middleware->validateCsrfTokens(except: [ -/* -|-------------------------------------------------------------------------- -| Return The Application -|-------------------------------------------------------------------------- -| -| This script returns the application instance. The instance is given to -| the calling script so we can separate the building of the instances -| from the actual running of the application and sending responses. -| -*/ + ]); -return $app; + $middleware->alias([ + 'valid.token' => ValidateToken::class, + 'token.check' => \App\Http\Middleware\TokenCheckerMiddleware::class, + 'admin' => \App\Http\Middleware\EnsureUserIsAdmin::class, + ]); + + $middleware->appendToGroup('apipub', [ + \Illuminate\Routing\Middleware\SubstituteBindings::class, + \App\Http\Middleware\LogRequestPathMiddleware::class, + ]); + + }) + ->withExceptions(function (Exceptions $exceptions) { + // Custom exception rendering + // $exceptions->render(function (MaintenanceModeException $e, $request) { + // return response()->view('pages.errors.maintenance'); + // }); + + $exceptions->render(function (AuthenticationException $e, $request) { + return (new ApiResponseObject( + 'Authentication', + 'To keep your account secure, we need to re-validate it.', + HttpStatus::ACCESS_UNAUTHORISED + ))->handler(); + }); + + // Don't flash these inputs + $exceptions->dontFlash([ + 'password', + 'password_confirmation', + ]); + }) + ->withCommands([ + __DIR__ . '/../app/Console/Commands', + __DIR__ . '/../app/Console/Commands/V2', + ]) + ->withSchedule(function ($schedule) { + // Commands Version 2: Laravel Vapor/AWS + $isEnabled = env('COMMANDS_V2_ENABLED', false); + if ($isEnabled) { + $schedule->command('housekeeping-s3-files-command') + ->dailyAt('01:00') + ->withoutOverlapping(); + + $schedule->command('password-reset-token-expriration-check-command') + ->everySixHours() + ->withoutOverlapping(); + + $schedule->command('new-user-registration-expire-check-command') + ->everySixHours() + ->withoutOverlapping(); + + if (env('APP_ENV') === 'production') { + $schedule->command('email-do-to-vt-command') + ->dailyAt('10:00') + ->withoutOverlapping(); + + $schedule->command('seasonal-segmant-company-remove-command') + ->dailyAt('01:00') + ->withoutOverlapping(); + + $schedule->command('delete-bulk-download-files-command') + ->hourly() + ->withoutOverlapping(); + + $schedule->command('booking-expired-command') + ->dailyAt('02:00') + ->withoutOverlapping(); + + // Push company module to Lark + $schedule->command('lark:push-company-module') + ->hourly() + ->withoutOverlapping(); + + // Push booking module to Lark + $schedule->command('lark:push-booking-module') + ->hourly() + ->withoutOverlapping(); + } + } + // Commands Version 1: Before Laravel Vapor/AWS + else { + $schedule->command('mail:EmailDoToVTCommand') + ->dailyAt('10:00') + ->withoutOverlapping(); + + $schedule->command('seasonalSegmantCompany:remove') + ->dailyAt('01:00') + ->appendOutputTo(storage_path() . '/logs/soft-delete-seasonal-segmant-company.log') + ->withoutOverlapping(); + + $schedule->command('delete:bulk-download-files') + ->hourly() + ->appendOutputTo(storage_path() . '/logs/delete-bulk-download-files.log') + ->withoutOverlapping(); + + $schedule->command('booking:expired') + ->dailyAt('02:00') + ->appendOutputTo(storage_path() . '/logs/expire-booking.log') + ->withoutOverlapping(); + } + }) + ->create(); diff --git a/composer.json b/composer.json index 2f54ef18..a7270ee8 100644 --- a/composer.json +++ b/composer.json @@ -8,52 +8,50 @@ ], "license": "MIT", "require": { - "php": "^7.2.5", + "php": "^8.3", "ext-bcmath": "*", "ext-fileinfo": "*", "ext-json": "*", "ext-zip": "*", - "barryvdh/laravel-dompdf": "^0.9.0", + "barryvdh/laravel-dompdf": "^3.1", "carlos-meneses/laravel-mpdf": "^2.1", - "doctrine/dbal": "^2.12.1", - "fideloper/proxy": "^4.2", - "fruitcake/laravel-cors": "^1.0", - "guzzlehttp/guzzle": "^7.0.1", - "intervention/image": "^2.5", + "doctrine/dbal": "^3.0|^4.0", + "guzzlehttp/guzzle": "^7.4", + "intervention/image": "^2.7|^3.0", "kwn/number-to-words": "^2.11", - "laravel/framework": "^8.0", - "laravel/tinker": "^2.0", + "laravel/framework": "^12.0", + "laravel/tinker": "^2.9", "laravel/vapor-cli": "^1.55", "laravel/vapor-core": "^2.33", + "league/flysystem-aws-s3-v3": "^3.0", "maatwebsite/excel": "^3.1", - "maxbanton/cwh": "^2.0", + "phpnexus/cwh": "^3.0", "mpdf/mpdf": "^8.1", "pusher/pusher-php-server": "^7.2", - "rinvex/countries": "^6.1", + "rinvex/countries": "^9.0", "rspective/voucherify": " v2.0.*", "smalot/pdfparser": "^2.2", - "spatie/laravel-activitylog": "^3.14", - "spatie/laravel-permission": "^3.17", + "spatie/laravel-activitylog": "^4.10", + "spatie/laravel-permission": "^7.0", "staudenmeir/eloquent-has-many-deep": "^1.7", "timehunter/laravel-google-recaptcha-v3": "~2.5", - "tymon/jwt-auth": "^1.0", + "symfony/http-client": "^7.4", + "symfony/mailgun-mailer": "^7.4", + "tymon/jwt-auth": "^2.0", "webklex/laravel-pdfmerger": "^1.3" }, "require-dev": { - "facade/ignition": "^2.3.6", - "fzaninotto/faker": "^1.9.1", - "laravel/dusk": "^6.23", - "mockery/mockery": "^1.3.1", - "nunomaduro/collision": "^5.0", - "phpunit/phpunit": "^9.0" + "fakerphp/faker": "^1.20", + "laravel/dusk": "^8.0", + "mockery/mockery": "^1.5", + "nunomaduro/collision": "^8.5", + "phpunit/phpunit": "^11.5", + "spatie/laravel-ignition": "^2.5" }, "config": { "optimize-autoloader": true, "preferred-install": "dist", - "sort-packages": true, - "audit": { - "block-insecure": false - } + "sort-packages": true }, "extra": { "laravel": { diff --git a/config/app.php b/config/app.php index fd0bbe8f..07bad5e7 100644 --- a/config/app.php +++ b/config/app.php @@ -173,7 +173,6 @@ return [ App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, - App\Providers\RouteServiceProvider::class, // Third Parties Spatie\Permission\PermissionServiceProvider::class, @@ -233,7 +232,7 @@ return [ 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, - 'PDF' => Barryvdh\DomPDF\Facade::class, + 'PDF' => Barryvdh\DomPDF\Facade\Pdf::class, 'MPDF' => Mccarlosen\LaravelMpdf\Facades\LaravelMpdf::class, 'GoogleReCaptchaV3'=> TimeHunter\LaravelGoogleReCaptchaV3\Facades\GoogleReCaptchaV3::class, 'PDFMerger' => Webklex\PDFMerger\Facades\PDFMergerFacade::class diff --git a/config/cors.php b/config/cors.php index 558369dc..1466424a 100644 --- a/config/cors.php +++ b/config/cors.php @@ -15,7 +15,7 @@ return [ | */ - 'paths' => ['api/*'], + 'paths' => ['api/*', 'public/api/*'], 'allowed_methods' => ['*'], diff --git a/config/filesystems.php b/config/filesystems.php index 3094b721..a7a91b80 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -13,7 +13,7 @@ return [ | */ - 'default' => env('FILESYSTEM_DRIVER', 'local'), + 'default' => env('FILESYSTEM_DISK', env('FILESYSTEM_DRIVER', 'local')), /* |-------------------------------------------------------------------------- @@ -45,7 +45,7 @@ return [ 'local' => [ 'driver' => 'local', - 'root' => storage_path('app'), + 'root' => storage_path('app/private'), ], 'public' => [ diff --git a/config/hashing.php b/config/hashing.php index 84257708..d783a1e1 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -49,4 +49,17 @@ return [ 'time' => 2, ], + /* + |-------------------------------------------------------------------------- + | Password Rehashing on Login + |-------------------------------------------------------------------------- + | + | When enabled, passwords will be automatically rehashed during + | authentication if the hashing algorithm's work factor has changed. + | This ensures passwords stay secure as hardware improves. + | + */ + + 'rehash_on_login' => true, + ]; diff --git a/database/migrations/2020_11_28_060758_create_bookings_table.php b/database/migrations/2020_11_28_060758_create_bookings_table.php index 115af43b..703c24ef 100644 --- a/database/migrations/2020_11_28_060758_create_bookings_table.php +++ b/database/migrations/2020_11_28_060758_create_bookings_table.php @@ -20,7 +20,7 @@ class CreateBookingsTable extends Migration $table->string('marking')->unique(); $table->foreignId('service_id')->unsigned(); $table->foreignId('bank_id')->unsigned(); - $table->float('fix_amount', 20, 5); + $table->decimal('fix_amount', 20, 5); $table->foreignId('fix_currency_id')->unsigned(); $table->foreignId('convertible_currency_id')->unsigned(); $table->foreignId('conversion_currency_id')->unsigned(); diff --git a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php index 29cacb80..e2937c59 100644 --- a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php +++ b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php @@ -24,7 +24,7 @@ class CreateStatementTransactionsTable extends Migration $table->string('transaction_description_4')->nullable(); $table->string('transaction_description_5')->nullable(); $table->string('transaction_ref')->nullable(); - $table->float('amount', 15, 2)->unsigned(false); + $table->decimal('amount', 15, 2)->unsigned(false); $table->string('teller_id')->nullable(); $table->string('branch_channel'); $table->string('transaction_code'); diff --git a/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php b/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php index d0b21f09..1f347ef6 100644 --- a/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php +++ b/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php @@ -13,11 +13,13 @@ class AddInvoiceStatusToBookingLogsTable extends Migration */ public function up() { - Schema::table('booking_logs', function (Blueprint $table) { - $table->boolean('invoice_status') - ->default(false) - ->after('status'); - }); + if (Schema::hasTable('booking_logs')) { + Schema::table('booking_logs', function (Blueprint $table) { + $table->boolean('invoice_status') + ->default(false) + ->after('status'); + }); + } } /** @@ -27,8 +29,10 @@ class AddInvoiceStatusToBookingLogsTable extends Migration */ public function down() { - Schema::table('booking_logs', function (Blueprint $table) { - $table->dropColumn('invoice_status'); - }); + if (Schema::hasTable('booking_logs')) { + Schema::table('booking_logs', function (Blueprint $table) { + $table->dropColumn('invoice_status'); + }); + } } } diff --git a/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php b/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php index e04b01d0..981971d9 100644 --- a/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php +++ b/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php @@ -13,11 +13,13 @@ class AddIsInvoiceGeneratedToBookingLogsTable extends Migration */ public function up() { - Schema::table('booking_logs', function (Blueprint $table) { - $table->boolean('is_invoice_generated') - ->default(false) - ->after('status'); - }); + if (Schema::hasTable('booking_logs')) { + Schema::table('booking_logs', function (Blueprint $table) { + $table->boolean('is_invoice_generated') + ->default(false) + ->after('status'); + }); + } } /** @@ -27,8 +29,10 @@ class AddIsInvoiceGeneratedToBookingLogsTable extends Migration */ public function down() { - Schema::table('booking_logs', function (Blueprint $table) { - $table->dropColumn('is_invoice_generated'); - }); + if (Schema::hasTable('booking_logs')) { + Schema::table('booking_logs', function (Blueprint $table) { + $table->dropColumn('is_invoice_generated'); + }); + } } } diff --git a/database/migrations/2026_01_31_220320_remove_is_invoice_generated_from_booking_logs_table.php b/database/migrations/2026_01_31_220320_remove_is_invoice_generated_from_booking_logs_table.php index 45c02fe6..f3d36e6f 100644 --- a/database/migrations/2026_01_31_220320_remove_is_invoice_generated_from_booking_logs_table.php +++ b/database/migrations/2026_01_31_220320_remove_is_invoice_generated_from_booking_logs_table.php @@ -13,9 +13,11 @@ class RemoveIsInvoiceGeneratedFromBookingLogsTable extends Migration */ public function up() { - Schema::table('booking_logs', function (Blueprint $table) { - $table->dropColumn('is_invoice_generated'); - }); + if (Schema::hasTable('booking_logs')) { + Schema::table('booking_logs', function (Blueprint $table) { + $table->dropColumn('is_invoice_generated'); + }); + } } /** @@ -25,10 +27,12 @@ class RemoveIsInvoiceGeneratedFromBookingLogsTable extends Migration */ public function down() { - Schema::table('booking_logs', function (Blueprint $table) { - $table->boolean('is_invoice_generated') - ->default(false) - ->after('status'); - }); + if (Schema::hasTable('booking_logs')) { + Schema::table('booking_logs', function (Blueprint $table) { + $table->boolean('is_invoice_generated') + ->default(false) + ->after('status'); + }); + } } } diff --git a/database/migrations/2026_03_13_093615_add_batch_uuid_and_event_to_activity_log_table.php b/database/migrations/2026_03_13_093615_add_batch_uuid_and_event_to_activity_log_table.php new file mode 100644 index 00000000..f6331674 --- /dev/null +++ b/database/migrations/2026_03_13_093615_add_batch_uuid_and_event_to_activity_log_table.php @@ -0,0 +1,30 @@ +uuid('batch_uuid')->nullable()->after('properties'); + $table->string('event')->nullable()->after('subject_type'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('activity_log', function (Blueprint $table) { + $table->dropColumn('batch_uuid'); + $table->dropColumn('event'); + }); + } +}; diff --git a/database/migrations/2026_03_28_015715_update_spatie_roles_and_permissions_guard_to_api.php b/database/migrations/2026_03_28_015715_update_spatie_roles_and_permissions_guard_to_api.php new file mode 100644 index 00000000..c5562c10 --- /dev/null +++ b/database/migrations/2026_03_28_015715_update_spatie_roles_and_permissions_guard_to_api.php @@ -0,0 +1,36 @@ +where('id', 1)->update(['guard_name' => 'api']); + DB::table('roles')->where('id', 2)->update(['guard_name' => 'api']); + DB::table('permissions')->where('id', '>', 0)->update(['guard_name' => 'api']); + + // Clear Spatie permission cache so changes take effect immediately + app()['cache']->forget('spatie.permission.cache'); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + DB::table('roles')->where('id', 1)->update(['guard_name' => 'web']); + DB::table('roles')->where('id', 2)->update(['guard_name' => 'web']); + DB::table('permissions')->where('id', '>', 0)->update(['guard_name' => 'web']); + + // Clear Spatie permission cache so rollback takes effect immediately + app()['cache']->forget('spatie.permission.cache'); + } +}; diff --git a/database/seeds/AdminUserPermissionsTableSeeder.php b/database/seeds/AdminUserPermissionsTableSeeder.php index ee86dc8a..477b1c23 100644 --- a/database/seeds/AdminUserPermissionsTableSeeder.php +++ b/database/seeds/AdminUserPermissionsTableSeeder.php @@ -20,61 +20,61 @@ class AdminUserPermissionsTableSeeder extends Seeder // admin permissions $permissions = [ - ['name' => 'view document', 'guard_name' => 'web'], - ['name' => 'add document', 'guard_name' => 'web'], - ['name' => 'edit document', 'guard_name' => 'web'], - ['name' => 'delete document', 'guard_name' => 'web'], + ['name' => 'view document', 'guard_name' => 'api'], + ['name' => 'add document', 'guard_name' => 'api'], + ['name' => 'edit document', 'guard_name' => 'api'], + ['name' => 'delete document', 'guard_name' => 'api'], - ['name' => 'view standard_segment', 'guard_name' => 'web'], - ['name' => 'add standard_segment', 'guard_name' => 'web'], - ['name' => 'edit standard_segment', 'guard_name' => 'web'], - ['name' => 'delete standard_segment', 'guard_name' => 'web'], + ['name' => 'view standard_segment', 'guard_name' => 'api'], + ['name' => 'add standard_segment', 'guard_name' => 'api'], + ['name' => 'edit standard_segment', 'guard_name' => 'api'], + ['name' => 'delete standard_segment', 'guard_name' => 'api'], - ['name' => 'view standard_segment_constant', 'guard_name' => 'web'], - ['name' => 'add standard_segment_constant', 'guard_name' => 'web'], - ['name' => 'edit standard_segment_constant', 'guard_name' => 'web'], - ['name' => 'delete standard_segment_constant', 'guard_name' => 'web'], + ['name' => 'view standard_segment_constant', 'guard_name' => 'api'], + ['name' => 'add standard_segment_constant', 'guard_name' => 'api'], + ['name' => 'edit standard_segment_constant', 'guard_name' => 'api'], + ['name' => 'delete standard_segment_constant', 'guard_name' => 'api'], - ['name' => 'view segment', 'guard_name' => 'web'], - ['name' => 'add segment', 'guard_name' => 'web'], - ['name' => 'edit segment', 'guard_name' => 'web'], - ['name' => 'delete segment', 'guard_name' => 'web'], + ['name' => 'view segment', 'guard_name' => 'api'], + ['name' => 'add segment', 'guard_name' => 'api'], + ['name' => 'edit segment', 'guard_name' => 'api'], + ['name' => 'delete segment', 'guard_name' => 'api'], - ['name' => 'view segment_constant', 'guard_name' => 'web'], - ['name' => 'add segment_constant', 'guard_name' => 'web'], - ['name' => 'edit segment_constant', 'guard_name' => 'web'], - ['name' => 'delete segment_constant', 'guard_name' => 'web'], + ['name' => 'view segment_constant', 'guard_name' => 'api'], + ['name' => 'add segment_constant', 'guard_name' => 'api'], + ['name' => 'edit segment_constant', 'guard_name' => 'api'], + ['name' => 'delete segment_constant', 'guard_name' => 'api'], - ['name' => 'view company_bank', 'guard_name' => 'web'], - ['name' => 'add company_bank', 'guard_name' => 'web'], - ['name' => 'edit company_bank', 'guard_name' => 'web'], - ['name' => 'delete company_bank', 'guard_name' => 'web'], + ['name' => 'view company_bank', 'guard_name' => 'api'], + ['name' => 'add company_bank', 'guard_name' => 'api'], + ['name' => 'edit company_bank', 'guard_name' => 'api'], + ['name' => 'delete company_bank', 'guard_name' => 'api'], - ['name' => 'view currency', 'guard_name' => 'web'], - ['name' => 'add currency', 'guard_name' => 'web'], - ['name' => 'edit currency', 'guard_name' => 'web'], - ['name' => 'delete currency', 'guard_name' => 'web'], + ['name' => 'view currency', 'guard_name' => 'api'], + ['name' => 'add currency', 'guard_name' => 'api'], + ['name' => 'edit currency', 'guard_name' => 'api'], + ['name' => 'delete currency', 'guard_name' => 'api'], - ['name' => 'view currency_rate', 'guard_name' => 'web'], - ['name' => 'add currency_rate', 'guard_name' => 'web'], - ['name' => 'edit currency_rate', 'guard_name' => 'web'], - ['name' => 'delete currency_rate', 'guard_name' => 'web'], + ['name' => 'view currency_rate', 'guard_name' => 'api'], + ['name' => 'add currency_rate', 'guard_name' => 'api'], + ['name' => 'edit currency_rate', 'guard_name' => 'api'], + ['name' => 'delete currency_rate', 'guard_name' => 'api'], - ['name' => 'view booking', 'guard_name' => 'web'], - ['name' => 'add booking', 'guard_name' => 'web'], - ['name' => 'edit booking', 'guard_name' => 'web'], - ['name' => 'delete booking', 'guard_name' => 'web'], + ['name' => 'view booking', 'guard_name' => 'api'], + ['name' => 'add booking', 'guard_name' => 'api'], + ['name' => 'edit booking', 'guard_name' => 'api'], + ['name' => 'delete booking', 'guard_name' => 'api'], - ['name' => 'add milestone', 'guard_name' => 'web'], - ['name' => 'add reward', 'guard_name' => 'web'], - ['name' => 'edit milestone', 'guard_name' => 'web'], - ['name' => 'delete milestone', 'guard_name' => 'web'], - ['name' => 'delete reward', 'guard_name' => 'web'], + ['name' => 'add milestone', 'guard_name' => 'api'], + ['name' => 'add reward', 'guard_name' => 'api'], + ['name' => 'edit milestone', 'guard_name' => 'api'], + ['name' => 'delete milestone', 'guard_name' => 'api'], + ['name' => 'delete reward', 'guard_name' => 'api'], - ['name' => 'add voucher', 'guard_name' => 'web'], - ['name' => 'list voucher campaigns', 'guard_name' => 'web'], + ['name' => 'add voucher', 'guard_name' => 'api'], + ['name' => 'list voucher campaigns', 'guard_name' => 'api'], - ['name' => 'update bank_metadata', 'guard_name' => 'web'], + ['name' => 'update bank_metadata', 'guard_name' => 'api'], ]; foreach ($permissions as $permission){ @@ -87,7 +87,7 @@ class AdminUserPermissionsTableSeeder extends Seeder ['name' => 'Shadow Admin'], [ 'name' => 'Shadow Admin', - 'guard_name' => 'web', + 'guard_name' => 'api', 'type' => 1, ] ); @@ -108,7 +108,7 @@ class AdminUserPermissionsTableSeeder extends Seeder ['name' => 'Ultimate Admin'], [ 'name' => 'Ultimate Admin', - 'guard_name' => 'web', + 'guard_name' => 'api', 'type' => 1, ] ); @@ -125,7 +125,7 @@ class AdminUserPermissionsTableSeeder extends Seeder ['name' => 'Admin'], [ 'name' => 'Admin', - 'guard_name' => 'web', + 'guard_name' => 'api', 'type' => 1, ] ); diff --git a/development.Dockerfile b/development.Dockerfile index 53dee762..40e0e69d 100644 --- a/development.Dockerfile +++ b/development.Dockerfile @@ -1,3 +1,3 @@ -FROM laravelphp/vapor:php74 +FROM laravelphp/vapor:php83 COPY . /var/task diff --git a/docker-setup/Dockerfile b/docker-setup/Dockerfile index 71255f30..8d61791c 100644 --- a/docker-setup/Dockerfile +++ b/docker-setup/Dockerfile @@ -1,12 +1,10 @@ -FROM php:7.4-fpm +FROM php:8.3-fpm WORKDIR /var/www/html -RUN pecl install xdebug-2.9.8 && docker-php-ext-enable xdebug - -RUN docker-php-ext-install pdo pdo_mysql - +# Install system dependencies RUN apt-get update && apt-get install -y \ + curl \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ @@ -15,25 +13,45 @@ RUN apt-get update && apt-get install -y \ cron \ supervisor \ nano \ - && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && rm -rf /var/lib/apt/lists/* + +# Install Xdebug (compatible with PHP 8.3) +RUN pecl install xdebug && docker-php-ext-enable xdebug + +# Install PHP extensions +RUN docker-php-ext-install pdo pdo_mysql + +RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ - && docker-php-ext-install zip \ - && docker-php-ext-install bcmath + && docker-php-ext-install zip \ + && docker-php-ext-install bcmath -COPY --from=composer:1.9.3 /usr/bin/composer /usr/bin/composer +# Install Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -#NODEJS & NPM -RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - -RUN apt-get -y install nodejs +#NODEJS & NPM (OLD Before upgrade) +# RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - +# RUN apt-get -y install nodejs -RUN chown -R www-data:www-data /var/www -RUN chmod 755 /var/www +#NODEJS & NPM (Node 14 for x86_64 (amd64)) +# RUN curl -fsSL https://nodejs.org/dist/v14.21.3/node-v14.21.3-linux-x64.tar.xz -o node.tar.xz \ +# && tar -xJf node.tar.xz -C /usr/local --strip-components=1 \ +# && rm node.tar.xz -# Configure xdebug -RUN echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini -RUN echo "xdebug.remote_autostart=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini -RUN echo "xdebug.remote_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini -RUN echo "xdebug.remote_port=9002" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +# NODEJS & NPM (Node 14 for ARM64) +RUN curl -fsSL https://nodejs.org/dist/v14.21.3/node-v14.21.3-linux-arm64.tar.xz -o node.tar.xz \ + && tar -xJf node.tar.xz -C /usr/local --strip-components=1 \ + && rm node.tar.xz + +# Set permissions +RUN chown -R www-data:www-data /var/www \ + && chmod 755 /var/www + +# Configure Xdebug +RUN echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +RUN echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +RUN echo "xdebug.client_port=9002" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini RUN echo "xdebug.idekey=VSCODE" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini # Moved to docker-setup folder diff --git a/docker-setup/docker-compose.yml b/docker-setup/docker-compose.yml index 4fd3ec64..6b4a4f36 100644 --- a/docker-setup/docker-compose.yml +++ b/docker-setup/docker-compose.yml @@ -1,13 +1,13 @@ version: '3' networks: - exchange-staging: + exchange-development: services: ################################################################# nginx: image: nginx:stable-alpine - container_name: exchange-ngnix + container_name: exchange-2-ngnix ports: - "8082:80" volumes: @@ -17,11 +17,11 @@ services: - php - mysql networks: - - exchange-staging + - exchange-development ################################################################# mysql: image: mysql:5.7.29 - container_name: exchange-mysql + container_name: exchange-2-mysql restart: unless-stopped tty: true ports: @@ -36,20 +36,20 @@ services: volumes: - mysql-data:/var/lib/mysql networks: - - exchange-staging + - exchange-development ################################################################# php: build: context: . dockerfile: Dockerfile - container_name: exchange-php + container_name: exchange-2-php volumes: - ../:/var/www/html - ./php/default.conf:/usr/local/etc/php-fpm.d/zz-docker.conf ports: - "9002:9000" networks: - - exchange-staging + - exchange-development ################################################################# volumes: diff --git a/phpunit.ci.xml b/phpunit.ci.xml new file mode 100644 index 00000000..7a3fd79c --- /dev/null +++ b/phpunit.ci.xml @@ -0,0 +1,39 @@ + + + + + ./tests/Unit + + + ./tests/Feature + + + + + ./app + + + + + + + + + + + + + + diff --git a/phpunit.xml b/phpunit.xml index 964ff0c5..89828114 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -12,17 +12,17 @@ ./tests/Feature - - + + ./app - - + + - - + diff --git a/production.Dockerfile b/production.Dockerfile index 53dee762..40e0e69d 100644 --- a/production.Dockerfile +++ b/production.Dockerfile @@ -1,3 +1,3 @@ -FROM laravelphp/vapor:php74 +FROM laravelphp/vapor:php83 COPY . /var/task diff --git a/resources/assets/vue/components/companies/elements/NewServiceAnnouncementComponent.vue b/resources/assets/vue/components/companies/elements/NewServiceAnnouncementComponent.vue index bd61392c..3cdaec4e 100644 --- a/resources/assets/vue/components/companies/elements/NewServiceAnnouncementComponent.vue +++ b/resources/assets/vue/components/companies/elements/NewServiceAnnouncementComponent.vue @@ -69,7 +69,7 @@ - +
diff --git a/resources/assets/vue/components/companies/forms/EditCustomerCompanyTypeFormComponent.vue b/resources/assets/vue/components/companies/forms/EditCustomerCompanyTypeFormComponent.vue index c15091b5..e801fc41 100644 --- a/resources/assets/vue/components/companies/forms/EditCustomerCompanyTypeFormComponent.vue +++ b/resources/assets/vue/components/companies/forms/EditCustomerCompanyTypeFormComponent.vue @@ -41,10 +41,12 @@ }, }, created() { - this.parameters = {}; - this.parameters.type = [0,1].includes(this.data.type) ? this.data.type: 0; - this.parameters.email = this.data.contact ? this.data.contact.email : ""; - this.parameters.phone = this.data.contact ? this.data.contact.phone : ""; + this.initParameters(); + }, + watch: { + 'data': function() { + this.initParameters(); + } }, data(){ return { @@ -59,8 +61,14 @@ } }, methods: { + initParameters() { + this.parameters = {}; + this.parameters.type = [0,1].includes(this.data.type) ? this.data.type: 0; + this.parameters.email = this.data.contact ? this.data.contact.email : ""; + this.parameters.phone = this.data.contact ? this.data.contact.phone : ""; + }, submitForm(){ - this.submit(route('api.company.profile.update', this.data.id), 'put', this.section, true, true); + this.submit(route('api.company.profile.update', this.data.id), 'put', this.section + 'EditCompanyType', true, true); }, successHandler(){ window.location.reload(); @@ -68,4 +76,4 @@ }, mixins: [modalFormHandler] } - \ No newline at end of file + diff --git a/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue b/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue index 3f1b0b37..fb6a9644 100644 --- a/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue +++ b/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue @@ -14,7 +14,7 @@
diff --git a/resources/assets/vue/general/mixins/guards.js b/resources/assets/vue/general/mixins/guards.js index f706135d..8f930159 100644 --- a/resources/assets/vue/general/mixins/guards.js +++ b/resources/assets/vue/general/mixins/guards.js @@ -26,7 +26,7 @@ export default { return !unprotectedPaths.includes(currentPath); }, isWithTokenRoute(){ - return window.location.href.includes(this.route('account.password.reset')); + return window.location.href.includes(this.route('account.password.reset')) || window.location.href.includes('/account/email/verification'); } } diff --git a/resources/views/emails/accounts/user_verification.blade.php b/resources/views/emails/accounts/user_verification.blade.php index 1f711740..c913e0b0 100644 --- a/resources/views/emails/accounts/user_verification.blade.php +++ b/resources/views/emails/accounts/user_verification.blade.php @@ -2,10 +2,10 @@ @section('content')

Hello, {{$user->name}}

-

verify your email to finish your account registration on {{route('login')}}

-

Please confirm that {{$user->email}} is your email address by clicking on the button below or use this link {{route('account.email.verification', $attempt->token)}} within 48 hours

+

Please verify your email to finish your account registration on {{route('login')}}

+

Please confirm that {{$user->email}} is your email address by clicking on the button below or use this link {{route('account.email.verification', $attempt->token)}} within 48 hours

If you didn't perform this request you can safely ignore this email.
-@endsection \ No newline at end of file +@endsection diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php index f096db8d..1a3059e9 100644 --- a/resources/views/errors/503.blade.php +++ b/resources/views/errors/503.blade.php @@ -19,6 +19,12 @@ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } + +
@@ -26,6 +32,8 @@ Maintenance

{{ config('maintenance.message') }}

— CIEF EXCHANGE

+ + Go Back Home
diff --git a/routes/account.php b/routes/account.php index 2afad1cd..1c8a7706 100644 --- a/routes/account.php +++ b/routes/account.php @@ -1,48 +1,64 @@ 'account', 'namespace' => 'Accounts', 'as' => 'account.'], function () { +Route::group(['prefix' => 'account', 'as' => 'account.'], function () { Route::group(['prefix' => 'authentication', 'as' => 'authentication.'], function () { Route::group(['middleware' => 'valid.token'], function () { - Route::get('/logout', 'UserAuthenticationLogoutController@logout')->name('logout'); - Route::get('/refresh', 'RefreshAuthenticationTokenController@refresh')->name('refresh'); + Route::get('/logout', [UserAuthenticationLogoutController::class, 'logout'])->name('logout'); + Route::get('/refresh', [RefreshAuthenticationTokenController::class, 'refresh'])->name('refresh'); }); Route::group(['prefix' => 'login', 'as' => 'authenticate.'], function () { - Route::post('/attempt', 'UserAuthenticationController@authenticate')->name('attempt'); - Route::post('/check_email', 'CheckEmailController@check')->name('email.check'); + Route::post('/attempt', [UserAuthenticationController::class, 'authenticate'])->name('attempt'); + Route::post('/check_email', [CheckEmailController::class, 'check'])->name('email.check'); }); Route::group(['prefix' => 'password', 'as' => 'password.'], function () { - Route::post('/forget', 'GeneratePasswordResetController@generate')->name('forget'); - Route::post('/reset', 'ResetPasswordController@reset')->name('reset'); + Route::post('/forget', [GeneratePasswordResetController::class, 'generate'])->name('forget'); + Route::post('/reset', [ResetPasswordController::class, 'reset'])->name('reset'); }); }); Route::group(['prefix' => 'registration', 'as' => 'registration.'], function () { - Route::post('/registration', 'CreateCustomerController@create')->name('register'); + Route::post('/registration', [CreateCustomerController::class, 'create'])->name('register'); }); Route::group(['prefix' => 'email', 'as' => 'email.'], function () { - Route::post('/verify', 'UserEmailVerificationController@verify')->name('verify'); - Route::post('/verification/resend', 'ResendEmailVerificationController@resend')->name('verification.resend'); + Route::post('/verify', [UserEmailVerificationController::class, 'verify'])->name('verify'); + Route::post('/verification/resend', [ResendEmailVerificationController::class, 'resend'])->name('verification.resend'); }); Route::group(['prefix' => 'user', 'as' => 'user.', 'middleware' => 'valid.token'], function () { - Route::get('email/{email}', 'FetchUserByEmailController@fetch')->name('company'); - Route::post('/show', 'FetchUserController@fetch')->name('show'); - Route::get('/list', 'ListUsersController@list')->name('list'); - Route::put('/update/{id}', 'UpdateUserController@update')->name('update'); + Route::get('email/{email}', [FetchUserByEmailController::class, 'fetch'])->name('company'); + Route::post('/show', [FetchUserController::class, 'fetch'])->name('show'); + Route::get('/list', [ListUsersController::class, 'list'])->name('list'); + Route::put('/update/{id}', [UpdateUserController::class, 'update'])->name('update'); - Route::post('/admin/create', 'CreateAdminUserController@create')->name('admin.create'); - Route::delete('/delete/{id}', 'DeleteUserController@delete')->name('delete'); - Route::put('/update/{id}/role', 'UpdateUserRoleController@update')->name('update.role'); + Route::post('/admin/create', [CreateAdminUserController::class, 'create'])->name('admin.create'); + Route::delete('/delete/{id}', [DeleteUserController::class, 'delete'])->name('delete'); + Route::put('/update/{id}/role', [UpdateUserRoleController::class, 'update'])->name('update.role'); Route::post('/system/create', [CreateSystemUserController::class, 'create'])->name('system.create'); }); diff --git a/routes/accounting.php b/routes/accounting.php index ddeecb21..469789af 100644 --- a/routes/accounting.php +++ b/routes/accounting.php @@ -1,22 +1,27 @@ 'accounting', 'as' => 'accounting.', 'namespace' => 'Accounting'], function () { - Route::post('/import', 'BankStatementController@import')->name('statement.import'); - Route::get('/bank_account', 'BankStatementController@transactions')->name('bank.transaction'); +Route::group(['prefix' => 'accounting', 'as' => 'accounting.'], function () { + Route::post('/import', [BankStatementController::class, 'import'])->name('statement.import'); + Route::get('/bank_account', [BankStatementController::class, 'transactions'])->name('bank.transaction'); Route::group(['prefix' => 'statements/{id}', 'as' => 'statement.'], function () { - Route::get('/details', 'BankStatementController@fetch')->name('details'); - Route::put('/details/update', 'BankStatementController@update')->name('details.update'); + Route::get('/details', [BankStatementController::class, 'fetch'])->name('details'); + Route::put('/details/update', [BankStatementController::class, 'update'])->name('details.update'); }); - Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject|pending_verification')->name('bankStatement.details.status.update'); + Route::post('bankStatement/{id}/details/{status}', [ApproveDuplicateBankStatementDetailsStatusController::class, 'update'])->where('status', 'approve|reject|pending_verification')->name('bankStatement.details.status.update'); Route::group(['prefix' => 'statement_transaction', 'as' => 'statement_transaction.'], function () { - Route::post('/owner/group-approve', 'GroupApproveStatementTransactionController@approve')->name('owner.groupApprove'); - Route::post('/{id}/owner/{status}', 'UpdateStatementTransactionStatusController@update')->where('status', 'approve|reject')->name('owner.status.update'); + Route::post('/owner/group-approve', [GroupApproveStatementTransactionController::class, 'approve'])->name('owner.groupApprove'); + Route::post('/{id}/owner/{status}', [UpdateStatementTransactionStatusController::class, 'update'])->where('status', 'approve|reject')->name('owner.status.update'); }); - Route::get('history/imported', 'HistoryImportedTransactionMappedController@getImported')->name('history.imported'); - + Route::get('history/imported', [HistoryImportedTransactionMappedController::class, 'getImported'])->name('history.imported'); + }); diff --git a/routes/affiliate.php b/routes/affiliate.php index 1badb6b7..fcb53cec 100644 --- a/routes/affiliate.php +++ b/routes/affiliate.php @@ -1,14 +1,20 @@ 'affiliate', 'as' => 'affiliate.'], function () { - Route::get('/settings', 'Affiliate\GetAffiliateSettingsController@get')->name('settings.get'); - Route::post('/settings', 'Affiliate\UpdateAffiliateSettingsController@update')->name('settings.update'); - - Route::get('/list', 'Affiliate\ListAffiliatesController@list')->name('list'); - Route::post('/create', 'Affiliate\CreateAffiliateController@create')->name('create'); - Route::put('/update/{id}', 'Affiliate\UpdateAffiliateController@update')->name('update'); - Route::delete('/delete/{id}', 'Affiliate\DeleteAffiliateController@delete')->name('delete'); + Route::get('/settings', [GetAffiliateSettingsController::class, 'get'])->name('settings.get'); + Route::post('/settings', [UpdateAffiliateSettingsController::class, 'update'])->name('settings.update'); + + Route::get('/list', [ListAffiliatesController::class, 'list'])->name('list'); + Route::post('/create', [CreateAffiliateController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateAffiliateController::class, 'update'])->name('update'); + Route::delete('/delete/{id}', [DeleteAffiliateController::class, 'delete'])->name('delete'); }); diff --git a/routes/announcement.php b/routes/announcement.php index b6016706..b6dbd1ac 100644 --- a/routes/announcement.php +++ b/routes/announcement.php @@ -1,15 +1,21 @@ 'announcement', 'as' => 'announcement.', 'namespace' => 'Announcements'], function () { - Route::get('/list', 'ListAnnouncementsController@list')->name('list'); - Route::post('/create', 'CreateAnnouncementController@create')->name('create'); - Route::put('/update/{id}', 'UpdateAnnouncementController@update')->name('update'); - Route::delete('/delete/{id}', 'DeleteAnnouncementController@delete')->name('delete'); - +Route::group(['prefix' => 'announcement', 'as' => 'announcement.'], function () { + Route::get('/list', [ListAnnouncementsController::class, 'list'])->name('list'); + Route::post('/create', [CreateAnnouncementController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateAnnouncementController::class, 'update'])->name('update'); + Route::delete('/delete/{id}', [DeleteAnnouncementController::class, 'delete'])->name('delete'); + Route::group(['prefix' => '{id}/segment', 'as' => 'segment.'], function () { - Route::post('/assign', 'AssignAnnouncementToSegmentController@assign')->name('assign'); - Route::delete('/detach/{segment_id}', 'RemoveSegmentFromAnnouncementController@detach')->name('detach'); + Route::post('/assign', [AssignAnnouncementToSegmentController::class, 'assign'])->name('assign'); + Route::delete('/detach/{segment_id}', [RemoveSegmentFromAnnouncementController::class, 'detach'])->name('detach'); }); }); \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index e8c8a651..d7edfd88 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,5 +1,14 @@ 'api', 'prefix' => 'v1', 'as' => 'api.'], function () { +Route::group(['prefix' => 'v1', 'as' => 'api.'], function () { require __DIR__ . '/account.php'; -// Route::get('/rate/calculate', 'RateCalculateCurrencyController@convert')->name('calculate'); +// Route::get('/rate/calculate', [RateCalculateCurrencyController::class, 'convert'])->name('calculate'); Route::group(['prefix' => 'service', 'as' => 'service.'], function () { - Route::get('countries/list', 'Services\CountriesListController@index')->name('list.countries'); + Route::get('countries/list', [CountriesListController::class, 'index'])->name('list.countries'); }); - Route::post('online_payment/callback', 'Billplz\CallbackBillplzController@callback')->name('online_payment.callback'); + Route::post('online_payment/callback', [CallbackBillplzController::class, 'callback'])->name('online_payment.callback'); Route::group(['middleware' => 'valid.token'], function () { Route::group(['middleware' => 'admin'], function () { //cief maintenance - Route::get('/storage/{fileName}/fetch', 'Documents\RenderDocumentController@fileStorageServe')->where(['fileName' => '.*'])->name('storage.document.file'); - Route::post('/import/update-debtor/f614e339d7058904a831aad742e24d55', 'Imports\ImportUpdateDebtorController@import')->name('debtor.import'); - Route::post('/import/upload-honey-trap', 'Imports\ImportHoneyTrapController@import')->name('honey_trap.upload'); - Route::post('/import/upload-import-invoices', 'Imports\ImportStatementInvoiceController@import')->name('import_invoices.upload'); - Route::post('/import/upload-import-receipt', 'Imports\ImportStatementReceiptsController@import')->name('import_receipts.upload'); - Route::post('/customers/invoices', 'Companies\BulkDownloadCustomerInvoicesController@download')->name('customers.invoices'); - Route::post('/supplier/white-form/bulk-download', 'Companies\BulkDownloadSupplierWhiteFormsController@download')->name('suppliers.white_forms'); + Route::get('/storage/{fileName}/fetch', [RenderDocumentController::class, 'fileStorageServe'])->where(['fileName' => '.*'])->name('storage.document.file'); + Route::post('/import/update-debtor/f614e339d7058904a831aad742e24d55', [ImportUpdateDebtorController::class, 'import'])->name('debtor.import'); + Route::post('/import/upload-honey-trap', [ImportHoneyTrapController::class, 'import'])->name('honey_trap.upload'); + Route::post('/import/upload-import-invoices', [ImportStatementInvoiceController::class, 'import'])->name('import_invoices.upload'); + Route::post('/import/upload-import-receipt', [ImportStatementReceiptsController::class, 'import'])->name('import_receipts.upload'); + Route::post('/customers/invoices', [BulkDownloadCustomerInvoicesController::class, 'download'])->name('customers.invoices'); + Route::post('/supplier/white-form/bulk-download', [BulkDownloadSupplierWhiteFormsController::class, 'download'])->name('suppliers.white_forms'); require __DIR__ . '/company.php'; diff --git a/routes/apipub.php b/routes/apipub.php index 6e2cdb19..a984368f 100644 --- a/routes/apipub.php +++ b/routes/apipub.php @@ -2,11 +2,12 @@ use App\Http\Controllers\Bookings\ListBookingsSalesInvoiceController; use App\Http\Controllers\Bookings\UpdateBookingSalesInvoiceController; +use App\Http\Controllers\Transactions\ListMappableTransactionsController; use Illuminate\Support\Facades\Route; -Route::group(['middleware' => 'apipub', 'prefix' => 'v1', 'as' => 'apipub.'], function () { +Route::group(['prefix' => 'v1', 'as' => 'apipub.'], function () { Route::group(['middleware' => 'token.check'], function () { - Route::get('transactions/mappable/query', 'Transactions\ListMappableTransactionsController@list')->name('transaction.mappable.list'); + Route::get('transactions/mappable/query', [ListMappableTransactionsController::class, 'list'])->name('transaction.mappable.list'); Route::group(['prefix' => 'booking', 'as' => 'booking.'], function () { Route::get('/sales-invoice/list', [ListBookingsSalesInvoiceController::class, 'list'])->name('booking.sales-invoice.list'); diff --git a/routes/bank.php b/routes/bank.php index b7c7e96e..8e9fc9a3 100644 --- a/routes/bank.php +++ b/routes/bank.php @@ -1,15 +1,22 @@ 'bank', 'as' => 'bank.', 'namespace' => 'Banks'], function () { - Route::get('/list', 'ListBanksController@list')->name('list'); - Route::post('/create', 'CreateBankController@create')->name('create'); - Route::put('/update/{id}', 'UpdateBankController@update')->name('update'); - Route::put('/{id}/default', 'SetBankToDefaultController@update')->name('default'); - Route::delete('/delete/{id}', 'DeleteBankController@delete')->name('delete'); +Route::group(['prefix' => 'bank', 'as' => 'bank.'], function () { + Route::get('/list', [ListBanksController::class, 'list'])->name('list'); + Route::post('/create', [CreateBankController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateBankController::class, 'update'])->name('update'); + Route::put('/{id}/default', [SetBankToDefaultController::class, 'update'])->name('default'); + Route::delete('/delete/{id}', [DeleteBankController::class, 'delete'])->name('delete'); - Route::put('/update/{id}/status', 'UpdateBankStatusController@update')->name('status.update'); + Route::put('/update/{id}/status', [UpdateBankStatusController::class, 'update'])->name('status.update'); - Route::post('/metadata/update/{id}', 'UpdateBankMetadataController@delete')->name('update.metadata'); + Route::post('/metadata/update/{id}', [UpdateBankMetadataController::class, 'delete'])->name('update.metadata'); }); diff --git a/routes/billplz.php b/routes/billplz.php index e1717a20..243b3376 100644 --- a/routes/billplz.php +++ b/routes/billplz.php @@ -1,9 +1,10 @@ 'billplz', 'as' => 'billplz.', 'namespace' => 'Billplz'], function () { +Route::group(['prefix' => 'billplz', 'as' => 'billplz.'], function () { Route::group(['prefix' => 'bill', 'as' => 'bill.'], function () { - Route::post('/create', 'CreateBillplzBillController@create')->name('create'); + Route::post('/create', [CreateBillplzBillController::class, 'create'])->name('create'); }); }); \ No newline at end of file diff --git a/routes/booking.php b/routes/booking.php index 7416a396..d188d9dc 100644 --- a/routes/booking.php +++ b/routes/booking.php @@ -1,53 +1,77 @@ 'booking', 'as' => 'booking.', 'namespace' => 'Bookings'], function () { - Route::get('/show/{marking}', 'FetchBookingController@fetch')->name('show'); - Route::get('/list', 'ListBookingsController@list')->name('list'); - Route::get('/list/job', 'ListBookingsJobController@list')->name('list.job'); - Route::post('/create', 'CreateBookingController@create')->name('create'); +Route::group(['prefix' => 'booking', 'as' => 'booking.'], function () { + Route::get('/show/{marking}', [FetchBookingController::class, 'fetch'])->name('show'); + Route::get('/list', [ListBookingsController::class, 'list'])->name('list'); + Route::get('/list/job', [ListBookingsJobController::class, 'list'])->name('list.job'); + Route::post('/create', [CreateBookingController::class, 'create'])->name('create'); Route::post('/create/lock', [CreateBookingLockController::class, 'create'])->name('create.lock'); Route::delete('/delete/lock/{id}', [DeleteBookingLockController::class, 'delete'])->name('delete.lock'); - Route::put('/update/{id}', 'UpdateBookingController@update')->name('update'); - Route::put('/recipient/update/{id}', 'UpdateBookingRecipientController@update')->name('update.recipient'); - Route::put('/cancel/{id}', 'CancelBookingController@cancel')->name('cancel'); - Route::put('/restore/{id}', 'RestoreBookingController@restore')->name('restore'); - Route::delete('/delete/{id}', 'DeleteBookingController@delete')->name('delete'); - Route::post('/regenerate/invoice/{id}', 'RegenerateInvoiceBookingController@regenerate')->name('regenerate.invoice'); + Route::put('/update/{id}', [UpdateBookingController::class, 'update'])->name('update'); + Route::put('/recipient/update/{id}', [UpdateBookingRecipientController::class, 'update'])->name('update.recipient'); + Route::put('/cancel/{id}', [CancelBookingController::class, 'cancel'])->name('cancel'); + Route::put('/restore/{id}', [RestoreBookingController::class, 'restore'])->name('restore'); + Route::delete('/delete/{id}', [DeleteBookingController::class, 'delete'])->name('delete'); + Route::post('/regenerate/invoice/{id}', [RegenerateInvoiceBookingController::class, 'regenerate'])->name('regenerate.invoice'); - Route::put('/owner/update/{id}', 'UpdateBookingOwnerController@update')->name('owner.update'); + Route::put('/owner/update/{id}', [UpdateBookingOwnerController::class, 'update'])->name('owner.update'); Route::group(['prefix' => '{id}/payment', 'as' => 'payment.'], function () { - Route::post('quotation', 'FetchBookingPaymentQuotationController@fetch')->name('quotation'); - Route::post('create', 'CreateBookingPaymentController@create')->name('create'); - Route::post('{payment_id}/verification/create', 'CreatePaymentVerificationController@create')->name('verification.create'); - Route::put('/{payment_id}/approval/{status}', 'ApprovePaymentVerificationController@approve')->where('status', 'approve|reject')->name('approval'); - Route::post('delete', 'ExpireBookingPaymentController@expire')->name('expire'); + Route::post('quotation', [FetchBookingPaymentQuotationController::class, 'fetch'])->name('quotation'); + Route::post('create', [CreateBookingPaymentController::class, 'create'])->name('create'); + Route::post('{payment_id}/verification/create', [CreatePaymentVerificationController::class, 'create'])->name('verification.create'); + Route::put('/{payment_id}/approval/{status}', [ApprovePaymentVerificationController::class, 'approve'])->where('status', 'approve|reject')->name('approval'); + Route::post('delete', [ExpireBookingPaymentController::class, 'expire'])->name('expire'); }); Route::group(['prefix' => '{id}/refund', 'as' => 'refund.'], function () { - Route::post('{payment_id}/create', 'CreateBookingRefundController@create')->name('create'); - Route::post('{payment_id}/credit_note/create', 'CreateBookingRefundCreditNoteController@create')->name('credit_note.create'); + Route::post('{payment_id}/create', [CreateBookingRefundController::class, 'create'])->name('create'); + Route::post('{payment_id}/credit_note/create', [CreateBookingRefundCreditNoteController::class, 'create'])->name('credit_note.create'); }); - Route::post('{id}/purchase_order/verification', 'ApprovePurchaseOrderController@approve')->name('po.approval'); - Route::post('{id}/purchase_order/pdf', 'UploadPurchaseOrderController@upload')->name('po.pdf'); - Route::delete('{id}/purchase_order/pdf', 'DeletePurchaseOrderPdfController@delete')->name('po.pdf.delete'); + Route::post('{id}/purchase_order/verification', [ApprovePurchaseOrderController::class, 'approve'])->name('po.approval'); + Route::post('{id}/purchase_order/pdf', [UploadPurchaseOrderController::class, 'upload'])->name('po.pdf'); + Route::delete('{id}/purchase_order/pdf', [DeletePurchaseOrderPdfController::class, 'delete'])->name('po.pdf.delete'); - Route::put('{id}/updateAmount', 'UpdateBookingAmountController@update')->name('booking_amount.update'); + Route::put('{id}/updateAmount', [UpdateBookingAmountController::class, 'update'])->name('booking_amount.update'); Route::put('{id}/updateAmountWithPO', [UpdateBookingAmountController::class, 'updateOnHold'])->name('amount.update'); - Route::put('{id}/updateOrderReferences', 'UpdateBookingOrderReferenceController@update')->name('booking_order_reference.update'); + Route::put('{id}/updateOrderReferences', [UpdateBookingOrderReferenceController::class, 'update'])->name('booking_order_reference.update'); - Route::post('/merge', 'MergeBookingController@merge')->name('merge'); + Route::post('/merge', [MergeBookingController::class, 'merge'])->name('merge'); - Route::post('{id}/proforma/create', 'CreateProformaInvoiceTransaction@create')->name('proforma.create'); + Route::post('{id}/proforma/create', [CreateProformaInvoiceTransaction::class, 'create'])->name('proforma.create'); Route::post('{id}/banking/create', [CreateBankingInvoiceTransactionController::class, 'create'])->name('banking.create'); diff --git a/routes/company.php b/routes/company.php index d844f51a..af1a75bd 100644 --- a/routes/company.php +++ b/routes/company.php @@ -1,42 +1,60 @@ 'company', 'as' => 'company.', 'namespace' => 'Companies'], function () { - Route::get('/{id}/show', 'FetchCompanyController@fetch')->name('show'); - Route::get('/list', 'ListCompaniesController@list')->name('list'); - Route::post('/create', 'CreateCompanyController@create')->name('create'); - Route::put('/update/{id}', 'UpdateCompanyController@update')->name('update'); - Route::put('/update/{id}/profile', 'UpdateCompanyProfileController@update')->name('profile.update'); - Route::put('update/{id}/status', 'UpdateCompanyStatusController@update')->name('status.update'); - // Route::delete('/delete/{id}', 'DeleteCompanyController@destroy')->name('delete'); - Route::delete('/delete/{id}', 'DeleteCompanyController@destroy')->name('destroy'); - Route::put('/name-and-debtor/update/{id}', 'UpdateCompanyNameAndDebtorController@update')->name('update.nameAndDebtor'); +Route::group(['prefix' => 'company', 'as' => 'company.'], function () { + Route::get('/{id}/show', [FetchCompanyController::class, 'fetch'])->name('show'); + Route::get('/list', [ListCompaniesController::class, 'list'])->name('list'); + Route::post('/create', [CreateCompanyController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateCompanyController::class, 'update'])->name('update'); + Route::put('/update/{id}/profile', [UpdateCompanyProfileController::class, 'update'])->name('profile.update'); + Route::put('update/{id}/status', [UpdateCompanyStatusController::class, 'update'])->name('status.update'); + // Route::delete('/delete/{id}', [DeleteCompanyController::class, 'destroy'])->name('delete'); + Route::delete('/delete/{id}', [DeleteCompanyController::class, 'destroy'])->name('destroy'); + Route::put('/name-and-debtor/update/{id}', [UpdateCompanyNameAndDebtorController::class, 'update'])->name('update.nameAndDebtor'); - Route::get('/business-type/list', 'ListBusinessTypesController@list')->name('business_type.list'); - Route::get('/company-type/list', 'ListCompanyTypesController@list')->name('company_type.list'); + Route::get('/business-type/list', [ListBusinessTypesController::class, 'list'])->name('business_type.list'); + Route::get('/company-type/list', [ListCompanyTypesController::class, 'list'])->name('company_type.list'); - Route::put('/update/debtor/{id}', 'UpdateCompanyDebtorController@update')->name('delete'); + Route::put('/update/debtor/{id}', [UpdateCompanyDebtorController::class, 'update'])->name('delete'); - Route::post('/team/create', 'AddNewMemberController@create')->name('team.create'); + Route::post('/team/create', [AddNewMemberController::class, 'create'])->name('team.create'); Route::group(['prefix' => '{id}/segment', 'as' => 'segment.'], function () { - Route::post('/assign', 'AssignCompanyToSegmentController@assign')->name('assign'); - Route::delete('/detach/{segment_id}', 'RemoveCompanyFromSegmentController@detach')->name('detach'); + Route::post('/assign', [AssignCompanyToSegmentController::class, 'assign'])->name('assign'); + Route::delete('/detach/{segment_id}', [RemoveCompanyFromSegmentController::class, 'detach'])->name('detach'); }); Route::group(['prefix' => '{id}/currency', 'as' => 'currency.'], function () { - Route::post('/convert', 'FetchCompanyBookingQuotationController@fetch')->name('convert'); + Route::post('/convert', [FetchCompanyBookingQuotationController::class, 'fetch'])->name('convert'); }); - Route::put('supplier/{id}/currencies/update', 'UpdateSupplierCurrenciesController@update')->name('supplier.currencies.update'); + Route::put('supplier/{id}/currencies/update', [UpdateSupplierCurrenciesController::class, 'update'])->name('supplier.currencies.update'); Route::group(['prefix' => '{id}/identification', 'as' => 'identification.'], function () { - Route::post('/create', 'CreateIdentificationDocumentController@create')->name('create'); - Route::put('/{document_id}/approval/{status}', 'ApproveIdentificationDocumentController@approve')->where('status', 'approve|reject')->name('approval'); + Route::post('/create', [CreateIdentificationDocumentController::class, 'create'])->name('create'); + Route::put('/{document_id}/approval/{status}', [ApproveIdentificationDocumentController::class, 'approve'])->where('status', 'approve|reject')->name('approval'); }); Route::put('/details/update/{id}', [UpdateCompanyDetailsController::class, 'update'])->name('update.details'); diff --git a/routes/crud.php b/routes/crud.php index b8db3c71..17ba50f9 100644 --- a/routes/crud.php +++ b/routes/crud.php @@ -1,38 +1,51 @@ 'address', 'as' => 'address.', 'namespace' => 'Addresses'], function () { +Route::group(['prefix' => 'address', 'as' => 'address.'], function () { - Route::get('/{id}/show', 'FetchAddressController@fetch')->name('show'); + Route::get('/{id}/show', [FetchAddressController::class, 'fetch'])->name('show'); - Route::get('/list', 'ListAddressesController@list')->name('list'); - Route::get('district/list', 'ListDistrictsController@list')->name('district.list'); + Route::get('/list', [ListAddressesController::class, 'list'])->name('list'); + Route::get('district/list', [ListDistrictsController::class, 'list'])->name('district.list'); Route::get('state/list', [ListStatesController::class, 'list'])->name('state.list'); - Route::post('/create', 'CreateAddressController@create')->name('create'); + Route::post('/create', [CreateAddressController::class, 'create'])->name('create'); - Route::put('/update/{id}', 'UpdateAddressController@update')->name('update'); + Route::put('/update/{id}', [UpdateAddressController::class, 'update'])->name('update'); - Route::put('/{id}/default', 'SetAddressToDefaultController@update')->name('default'); + Route::put('/{id}/default', [SetAddressToDefaultController::class, 'update'])->name('default'); - Route::delete('/delete/{id}', 'DeleteAddressController@destroy')->name('delete'); + Route::delete('/delete/{id}', [DeleteAddressController::class, 'destroy'])->name('delete'); }); -Route::group(['prefix' => 'service_type', 'as' => 'service_type.', 'namespace' => 'ServiceTypes'], function () { +Route::group(['prefix' => 'service_type', 'as' => 'service_type.'], function () { - Route::get('/{id}/show', 'FetchServiceTypeController@fetch')->name('show'); + Route::get('/{id}/show', [FetchServiceTypeController::class, 'fetch'])->name('show'); - Route::get('/list', 'ListServiceTypesController@list')->name('list'); + Route::get('/list', [ListServiceTypesController::class, 'list'])->name('list'); - Route::post('/create', 'CreateServiceTypeController@create')->name('create'); + Route::post('/create', [CreateServiceTypeController::class, 'create'])->name('create'); - Route::put('/update/{id}', 'UpdateServiceTypeController@update')->name('update'); + Route::put('/update/{id}', [UpdateServiceTypeController::class, 'update'])->name('update'); - Route::put('/status/{id}/{status}', 'UpdateServiceTypeStatusController@activate')->where('status', 'active|inactive')->name('status'); + Route::put('/status/{id}/{status}', [UpdateServiceTypeStatusController::class, 'activate'])->where('status', 'active|inactive')->name('status'); - Route::delete('/delete/{id}', 'DeleteServiceTypeController@destroy')->name('delete'); + Route::delete('/delete/{id}', [DeleteServiceTypeController::class, 'destroy'])->name('delete'); }); diff --git a/routes/currency.php b/routes/currency.php index ba55c9a2..2d2583b9 100644 --- a/routes/currency.php +++ b/routes/currency.php @@ -1,14 +1,19 @@ 'Currencies', 'as' => 'currency.', 'prefix' => 'currency'], function () { - Route::get('/primary/show', 'FetchSystemPrimaryCurrencyController@fetch')->name('primary.show'); - Route::get('/list', 'ListCurrencyController@list')->name('list'); - Route::post('/create', 'CreateCurrencyController@create')->name('create'); - Route::delete('/delete/{id}', 'DeleteCurrencyController@delete')->name('delete'); +Route::group(['as' => 'currency.', 'prefix' => 'currency'], function () { + Route::get('/primary/show', [FetchSystemPrimaryCurrencyController::class, 'fetch'])->name('primary.show'); + Route::get('/list', [ListCurrencyController::class, 'list'])->name('list'); + Route::post('/create', [CreateCurrencyController::class, 'create'])->name('create'); + Route::delete('/delete/{id}', [DeleteCurrencyController::class, 'delete'])->name('delete'); - Route::group(['prefix' => 'history', 'namespace' => 'History', 'as' => 'history.'], function () { - Route::get('/list', 'ListCurrencyRateHistory@list')->name('list'); + Route::group(['prefix' => 'history', 'as' => 'history.'], function () { + Route::get('/list', [ListCurrencyRateHistory::class, 'list'])->name('list'); }); }); diff --git a/routes/document.php b/routes/document.php index 07a7d18a..034af827 100644 --- a/routes/document.php +++ b/routes/document.php @@ -1,13 +1,19 @@ 'document', 'as' => 'document.', 'namespace' => 'Documents'], function () { - Route::get('/list', 'ListDocumentsController@list')->name('list'); - Route::get('/list/job', 'ListDocumentsJobController@list')->name('list.job'); - Route::delete('/{id}/delete', 'DeleteDocumentController@delete')->name('delete'); - Route::put('/{id}/approve', 'ApproveDocumentController@approve')->name('status.approve'); - Route::put('/{id}/reject', 'RejectDocumentController@reject')->name('status.reject'); +Route::group(['prefix' => 'document', 'as' => 'document.'], function () { + Route::get('/list', [ListDocumentsController::class, 'list'])->name('list'); + Route::get('/list/job', [ListDocumentsJobController::class, 'list'])->name('list.job'); + Route::delete('/{id}/delete', [DeleteDocumentController::class, 'delete'])->name('delete'); + Route::put('/{id}/approve', [ApproveDocumentController::class, 'approve'])->name('status.approve'); + Route::put('/{id}/reject', [RejectDocumentController::class, 'reject'])->name('status.reject'); - Route::put('/{id}/reference/update', 'UpdateDocumentReferenceController@update')->name('reference.update'); + Route::put('/{id}/reference/update', [UpdateDocumentReferenceController::class, 'update'])->name('reference.update'); }); diff --git a/routes/export.php b/routes/export.php index f91357a9..b8f50f8d 100644 --- a/routes/export.php +++ b/routes/export.php @@ -5,7 +5,7 @@ use App\Http\Controllers\Imports\ImportController; use Illuminate\Support\Facades\Route; -Route::group(['prefix' => 'export', 'as' => 'export.', 'namespace' => 'Exports'], function () { +Route::group(['prefix' => 'export', 'as' => 'export.'], function () { Route::group(['prefix' => 'bookings', 'as' => 'bookings.'], function () { Route::get('/sales-invoices', [ExportController::class, 'salesInvoices'])->name('sales_invoices'); Route::get('/sales-invoices-refund', [ExportController::class, 'salesInvoicesWithRefund'])->name('sales_invoices_w_refund'); @@ -24,7 +24,7 @@ Route::group(['prefix' => 'export', 'as' => 'export.', 'namespace' => 'Exports'] }); }); -Route::group(['prefix' => 'import', 'as' => 'import.', 'namespace' => 'Imports'], function () { +Route::group(['prefix' => 'import', 'as' => 'import.'], function () { Route::post('/import/sales-invoice', [ImportController::class, 'salesInvoices'])->name('sales_invoices'); Route::post('/import/offical-receipt', [ImportController::class, 'officialReceipt'])->name('official_receipt'); Route::post('/import/sales-deposit', [ImportController::class, 'salesDeposit'])->name('sales_deposit'); diff --git a/routes/job.php b/routes/job.php index 028e9468..39409b91 100644 --- a/routes/job.php +++ b/routes/job.php @@ -1,8 +1,9 @@ 'job', 'as' => 'job.', 'namespace' => 'Jobs'], function () { - Route::get('/fetch/{job_id}', 'FetchJobResultController@fetch')->name('fetch'); - Route::get('/fetch/{job_id}/{is_last}', 'FetchJobResultController@fetch')->name('fetch.last.attempt'); +Route::group(['prefix' => 'job', 'as' => 'job.'], function () { + Route::get('/fetch/{job_id}', [FetchJobResultController::class, 'fetch'])->name('fetch'); + Route::get('/fetch/{job_id}/{is_last}', [FetchJobResultController::class, 'fetch'])->name('fetch.last.attempt'); }); diff --git a/routes/key_value_pair.php b/routes/key_value_pair.php index 277f7b30..4adc893a 100644 --- a/routes/key_value_pair.php +++ b/routes/key_value_pair.php @@ -1,15 +1,15 @@ 'kvp', 'as' => 'kvp.', 'namespace' => 'KeyValuePairs'], function () { +Route::group(['prefix' => 'kvp', 'as' => 'kvp.'], function () { Route::get('/prompts/list', [ListAiPromptsKVPController::class, 'list'])->name('prompts.list'); Route::put('/chatgpt/prompt/update/{id}', [UpdateChatGPTPromptKVPController::class, 'update'])->name('chatgpt.prompt.update'); diff --git a/routes/milestone.php b/routes/milestone.php index 4777e8c8..1bf10e8a 100644 --- a/routes/milestone.php +++ b/routes/milestone.php @@ -1,11 +1,16 @@ 'milestone', 'as' => 'milestone.', 'namespace' => 'Milestones'], function () { - Route::post('/create', 'CreateMilestoneController@create')->name('create'); - Route::put('/update/{id}', 'UpdateMilestoneController@update')->name('update'); - Route::get('/list', 'ListMilestonesController@list')->name('list'); - Route::get('/user/{id}/progress/list', 'ListMilestoneProgressController@list')->name('progress.list'); - Route::delete('/delete/{id}', 'DeleteMilestoneController@delete')->name('delete'); +Route::group(['prefix' => 'milestone', 'as' => 'milestone.'], function () { + Route::post('/create', [CreateMilestoneController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateMilestoneController::class, 'update'])->name('update'); + Route::get('/list', [ListMilestonesController::class, 'list'])->name('list'); + Route::get('/user/{id}/progress/list', [ListMilestoneProgressController::class, 'list'])->name('progress.list'); + Route::delete('/delete/{id}', [DeleteMilestoneController::class, 'delete'])->name('delete'); }); diff --git a/routes/rate.php b/routes/rate.php index 78e4b479..e5ed988d 100644 --- a/routes/rate.php +++ b/routes/rate.php @@ -1,12 +1,18 @@ 'Rates', 'prefix' => 'currency-rate'], function () { - Route::get('/{id}/show', 'FetchRateController@fetch')->name('show'); - Route::get('/list', 'ListRatesController@list')->name('list'); - Route::get('/calculate', 'CalculateRateController@calculate')->name('calculate'); - Route::post('/create', 'CreateRateController@create')->name('create'); - Route::put('/update/{id}', 'UpdateRateController@update')->name('update'); - Route::delete('/delete/{id}', 'DeleteRateController@delete')->name('delete'); -}); \ No newline at end of file +Route::group(['prefix' => 'currency-rate'], function () { + Route::get('/{id}/show', [FetchRateController::class, 'fetch'])->name('show'); + Route::get('/list', [ListRatesController::class, 'list'])->name('list'); + Route::get('/calculate', [CalculateRateController::class, 'calculate'])->name('calculate'); + Route::post('/create', [CreateRateController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateRateController::class, 'update'])->name('update'); + Route::delete('/delete/{id}', [DeleteRateController::class, 'delete'])->name('delete'); +}); diff --git a/routes/receipt.php b/routes/receipt.php index aa532fe8..e331cee8 100644 --- a/routes/receipt.php +++ b/routes/receipt.php @@ -1,10 +1,11 @@ 'receipt', 'namespace' => 'Receipts', 'as' => 'receipt.'], function () { +Route::group(['prefix' => 'receipt', 'as' => 'receipt.'], function () { - Route::post('/create/{id}', 'CreateReceiptController@create')->name('create'); - //Route::post('/create-transaction/{id}', 'CreateWalletTransactionController@create')->name('create_transaction'); + Route::post('/create/{id}', [CreateReceiptController::class, 'create'])->name('create'); + //Route::post('/create-transaction/{id}', [CreateWalletTransactionController::class, 'create'])->name('create_transaction'); }); \ No newline at end of file diff --git a/routes/remark.php b/routes/remark.php index 90f781eb..e9155c26 100644 --- a/routes/remark.php +++ b/routes/remark.php @@ -1,14 +1,19 @@ 'Remarks', 'as' => 'remark.', 'prefix' => 'remark'], function () { - Route::get('/{id}/show', 'FetchRemarkController@fetch')->name('show'); - Route::get('/list', 'ListRemarksController@list')->name('list'); - Route::post('/{id}/create', 'CreateRemarkController@create')->name('create'); - Route::put('/update/{id}', 'UpdateRemarkController@update')->name('update'); - Route::delete('/delete/{id}', 'DeleteRemarkController@delete')->name('delete'); +Route::group(['as' => 'remark.', 'prefix' => 'remark'], function () { + Route::get('/{id}/show', [FetchRemarkController::class, 'fetch'])->name('show'); + Route::get('/list', [ListRemarksController::class, 'list'])->name('list'); + Route::post('/{id}/create', [CreateRemarkController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateRemarkController::class, 'update'])->name('update'); + Route::delete('/delete/{id}', [DeleteRemarkController::class, 'delete'])->name('delete'); Route::get('/list/refund-reasons', [ListRefundRemarksController::class, 'list'])->name('list.refund_reasons'); }); diff --git a/routes/reward.php b/routes/reward.php index c58b19f5..b839d2a4 100644 --- a/routes/reward.php +++ b/routes/reward.php @@ -1,11 +1,15 @@ 'reward', 'as' => 'reward.', 'namespace' => 'Rewards'], function () { - Route::post('/create', 'CreateRewardController@create')->name('create'); - Route::get('/list', 'ListRewardsController@list')->name('list'); - Route::get('/list/details', 'ListRewardsDetailsController@list')->name('list.details'); - Route::get('/list/details/{user_id}', 'ListRewardsDetailsController@list')->name('list.details.admin'); - Route::delete('/delete/{id}', 'DeleteRewardController@delete')->name('delete'); +Route::group(['prefix' => 'reward', 'as' => 'reward.'], function () { + Route::post('/create', [CreateRewardController::class, 'create'])->name('create'); + Route::get('/list', [ListRewardsController::class, 'list'])->name('list'); + Route::get('/list/details', [ListRewardsDetailsController::class, 'list'])->name('list.details'); + Route::get('/list/details/{user_id}', [ListRewardsDetailsController::class, 'list'])->name('list.details.admin'); + Route::delete('/delete/{id}', [DeleteRewardController::class, 'delete'])->name('delete'); }); diff --git a/routes/segment.php b/routes/segment.php index 685b3ee0..370f1bde 100644 --- a/routes/segment.php +++ b/routes/segment.php @@ -1,18 +1,26 @@ 'segment', 'as' => 'segment.', 'namespace' => 'Segments'], function () { - Route::get('/{id}/show', 'FetchSegmentController@fetch')->name('show'); - Route::post('/create', 'CreateSegmentController@create')->name('create'); - Route::put('/update/{id}', 'UpdateSegmentController@update')->name('update'); - Route::delete('/delete/{id}', 'DeleteSegmentController@delete')->name('delete'); - Route::get('/list', 'ListSegmentsController@list')->name('list'); +Route::group(['prefix' => 'segment', 'as' => 'segment.'], function () { + Route::get('/{id}/show', [FetchSegmentController::class, 'fetch'])->name('show'); + Route::post('/create', [CreateSegmentController::class, 'create'])->name('create'); + Route::put('/update/{id}', [UpdateSegmentController::class, 'update'])->name('update'); + Route::delete('/delete/{id}', [DeleteSegmentController::class, 'delete'])->name('delete'); + Route::get('/list', [ListSegmentsController::class, 'list'])->name('list'); Route::group(['prefix' => '{id}/constant', 'as' => 'constant.'], function () { - Route::put('/service/update', 'UpdateCustomServiceConstantController@update')->name('service.update'); - Route::put('/update', 'UpdateConstantController@update')->name('update'); - Route::get('/show/{reference}', 'FetchConstantController@fetch')->name('show'); + Route::put('/service/update', [UpdateCustomServiceConstantController::class, 'update'])->name('service.update'); + Route::put('/update', [UpdateConstantController::class, 'update'])->name('update'); + Route::get('/show/{reference}', [FetchConstantController::class, 'fetch'])->name('show'); }); }); diff --git a/routes/segment_constant.php b/routes/segment_constant.php index e393e3f3..e31d6df8 100644 --- a/routes/segment_constant.php +++ b/routes/segment_constant.php @@ -1,23 +1,24 @@ 'StandardSegmentConstants'], function () { // Route::group(['middleware' => 'valid.token'], function () { // Route::group(['prefix' => 'standard-segment-constant'], function () { -// Route::get('/list', 'ListStandardSegmentConstantsController@list')->name('standard_segment.update'); -// Route::put('/update/{id}', 'UpdateStandardSegmentConstantController@update')->name('standard_segment_constant.update'); +// Route::get('/list', [ListStandardSegmentConstantsController::class, 'list'])->name('standard_segment.update'); +// Route::put('/update/{id}', [UpdateStandardSegmentConstantController::class, 'update'])->name('standard_segment_constant.update'); // }); // }); // }); -Route::group(['namespace' => 'SegmentConstants'], function () { - Route::group(['middleware' => 'valid.token'], function () { - Route::group(['prefix' => 'segment-constant'], function () { - Route::get('/{id}/show', 'FetchSegmentConstantController@fetch')->name('segment_constant.show'); - Route::post('/create', 'CreateSegmentConstantController@create')->name('segment_constant.create'); - Route::put('/update/{id}', 'UpdateSegmentConstantController@update')->name('segment_constant.update'); - }); +Route::group(['middleware' => 'valid.token'], function () { + Route::group(['prefix' => 'segment-constant'], function () { + Route::get('/{id}/show', [FetchSegmentConstantController::class, 'fetch'])->name('segment_constant.show'); + Route::post('/create', [CreateSegmentConstantController::class, 'create'])->name('segment_constant.create'); + Route::put('/update/{id}', [UpdateSegmentConstantController::class, 'update'])->name('segment_constant.update'); }); }); \ No newline at end of file diff --git a/routes/transaction.php b/routes/transaction.php index 6c96d469..6e925123 100644 --- a/routes/transaction.php +++ b/routes/transaction.php @@ -1,55 +1,84 @@ 'transactions', 'namespace' => 'Transactions', 'as' => 'transaction.'], function () { +Route::group(['prefix' => 'transactions', 'as' => 'transaction.'], function () { - Route::get('/list', 'ListTransactionsController@list')->name('list'); - Route::get('/list/job', 'ListTransactionsJobController@list')->name('list.job'); - Route::get('/list/urgent', 'ListUrgentTransactionsController@list')->name('list.urgent'); - Route::delete('/suspend/{id}', 'SuspendTransactionController@suspend')->name('suspend'); + Route::get('/list', [ListTransactionsController::class, 'list'])->name('list'); + Route::get('/list/job', [ListTransactionsJobController::class, 'list'])->name('list.job'); + Route::get('/list/urgent', [ListUrgentTransactionsController::class, 'list'])->name('list.urgent'); + Route::delete('/suspend/{id}', [SuspendTransactionController::class, 'suspend'])->name('suspend'); - route::post('/supplier/{id}/bill/create', 'CreateSupplierTransactionController@create')->name('supplier.create'); - route::post('/supplier/{id}/bill/group/create', 'CreateSupplierBillGroupController@create')->name('supplier.bill_group.create'); - route::post('{id}/bill/verification', 'CreatePaymentProofDocumentController@verify')->name('bill.verification'); - route::post('{id}/bill/pay', 'CreatePaymentProofDocumentController@pay')->name('bill.pay'); - Route::put('/{id}/bill/{status}', 'UpdatePaymentTransactionStatusController@update')->where('status', 'pending|complete')->name('bill.status'); - Route::put('/{id}/refund/status/update/{status}', 'UpdateRefundTransactionStatusController@update')->name('refund.status.update'); + Route::post('/supplier/{id}/bill/create', [CreateSupplierTransactionController::class, 'create'])->name('supplier.create'); + Route::post('/supplier/{id}/bill/group/create', [CreateSupplierBillGroupController::class, 'create'])->name('supplier.bill_group.create'); + Route::post('{id}/bill/verification', [CreatePaymentProofDocumentController::class, 'verify'])->name('bill.verification'); + Route::post('{id}/bill/pay', [CreatePaymentProofDocumentController::class, 'pay'])->name('bill.pay'); + Route::put('/{id}/bill/{status}', [UpdatePaymentTransactionStatusController::class, 'update'])->where('status', 'pending|complete')->name('bill.status'); + Route::put('/{id}/refund/status/update/{status}', [UpdateRefundTransactionStatusController::class, 'update'])->name('refund.status.update'); - Route::delete('/refund/{id}/delete', 'DeleteRefundTransactionController@delete')->name('refund.delete'); + Route::delete('/refund/{id}/delete', [DeleteRefundTransactionController::class, 'delete'])->name('refund.delete'); - route::delete('{id}/bill/delete', 'DeletePaymentProofDocumentController@delete')->name('bill.delete'); + Route::delete('{id}/bill/delete', [DeletePaymentProofDocumentController::class, 'delete'])->name('bill.delete'); - Route::post('booking/{id}/details/update', 'CreatePurchaseOrderTransactionController@create')->name('po.create'); - Route::post('booking/{id}/details/import', 'ImportPurchaseOrderTransactionController@import')->name('po.import'); + Route::post('booking/{id}/details/update', [CreatePurchaseOrderTransactionController::class, 'create'])->name('po.create'); + Route::post('booking/{id}/details/import', [ImportPurchaseOrderTransactionController::class, 'import'])->name('po.import'); Route::post('booking/{id}/details/etl', [ETLPurchaseOrderTransactionController::class, 'etl'])->name('po.etl'); - Route::get('bulk/po/{issuer_id}/{start_date}/{end_date}', 'CreateBulkPurchaseOrderTransactionController@create')->name('po.bulk.create'); + Route::get('bulk/po/{issuer_id}/{start_date}/{end_date}', [CreateBulkPurchaseOrderTransactionController::class, 'create'])->name('po.bulk.create'); - Route::get('wallet/list', 'ListWalletTransactionsController@list')->name('wallet.list'); + Route::get('wallet/list', [ListWalletTransactionsController::class, 'list'])->name('wallet.list'); - Route::get('/company/{id}/account/balance', 'FetchCompanyAccountBalanceController@fetch')->name('company.account.balance'); - Route::get('/company/{id}/transaction/fetch', 'FetchCompanyTransactionStatementController@fetch')->name('company.transaction.fetch'); + Route::get('/company/{id}/account/balance', [FetchCompanyAccountBalanceController::class, 'fetch'])->name('company.account.balance'); + Route::get('/company/{id}/transaction/fetch', [FetchCompanyTransactionStatementController::class, 'fetch'])->name('company.transaction.fetch'); - Route::get('/bank/{id}/account/balance', 'FetchBankAccountBalanceController@fetch')->name('bank.account.balance'); + Route::get('/bank/{id}/account/balance', [FetchBankAccountBalanceController::class, 'fetch'])->name('bank.account.balance'); Route::group(['prefix' => 'groups', 'as' => 'group.'], function () { - Route::get('/list', 'ListGroupsController@list')->name('list'); - Route::delete('/{id}/delete', 'DeleteGroupController@delete')->name('delete'); - Route::put('/{id}/update', 'UpdateGroupController@update')->name('update'); - Route::put('/{id}/update/fee', 'UpdateGroupTransferFeeController@update')->name('fee.update'); - Route::post('/{id}/approve', 'CreateBulkPurchaseOrderDocumentController@aprove')->name('approve'); - Route::post('/bulk/po', 'CreateBulkPurchaseOrderDocumentController@create')->name('bulk.po'); + Route::get('/list', [ListGroupsController::class, 'list'])->name('list'); + Route::delete('/{id}/delete', [DeleteGroupController::class, 'delete'])->name('delete'); + Route::put('/{id}/update', [UpdateGroupController::class, 'update'])->name('update'); + Route::put('/{id}/update/fee', [UpdateGroupTransferFeeController::class, 'update'])->name('fee.update'); + Route::post('/{id}/approve', [CreateBulkPurchaseOrderDocumentController::class, 'aprove'])->name('approve'); + Route::post('/bulk/po', [CreateBulkPurchaseOrderDocumentController::class, 'create'])->name('bulk.po'); Route::group(['prefix' => 'bills', 'as' => 'bill.'], function () { - Route::get('/list', 'ListBillGroupsController@list')->name('list'); - Route::post('/transaction/{id}', 'CreateBillGroupPaymentProofDocumentController@create')->name('payment_proof.create'); - Route::post('/transaction/{id}/approval/{status}', 'ApproveBillGroupPaymentVerificationController@approve')->where('status', 'approve|reject')->name('payment_proof.approval'); - Route::delete('/{id}/delete', 'DeleteBillGroupController@delete')->name('delete'); - Route::put('/{id}/cancel', 'CancelBillGroupController@cancel')->name('cancel'); - Route::post('/{id}/pay', 'CreateBillGroupPaymentTransactionController@pay')->name('pay'); - // Route::post('/bulk/po', 'CreateBulkPurchaseOrderDocumentController@create')->name('bulk.po'); + Route::get('/list', [ListBillGroupsController::class, 'list'])->name('list'); + Route::post('/transaction/{id}', [CreateBillGroupPaymentProofDocumentController::class, 'create'])->name('payment_proof.create'); + Route::post('/transaction/{id}/approval/{status}', [ApproveBillGroupPaymentVerificationController::class, 'approve'])->where('status', 'approve|reject')->name('payment_proof.approval'); + Route::delete('/{id}/delete', [DeleteBillGroupController::class, 'delete'])->name('delete'); + Route::put('/{id}/cancel', [CancelBillGroupController::class, 'cancel'])->name('cancel'); + Route::post('/{id}/pay', [CreateBillGroupPaymentTransactionController::class, 'pay'])->name('pay'); + // Route::post('/bulk/po', [CreateBulkPurchaseOrderDocumentController::class, 'create'])->name('bulk.po'); }); }); }); diff --git a/routes/voucher.php b/routes/voucher.php index 2cf82d10..f6818910 100644 --- a/routes/voucher.php +++ b/routes/voucher.php @@ -1,11 +1,15 @@ 'voucher', 'as' => 'voucher.', 'namespace' => 'Vouchers'], function () { - Route::post('fetch', 'ValidateVoucherController@validate')->name('validate'); - Route::post('create', 'CreateVoucherController@create')->name('create'); - // Route::post('redeem', 'RedeemVoucherController@redeem')->name('redeem'); - Route::get('/user/list', 'ListUserVouchersController@list')->name('user.list'); - Route::get('/voucher/campaigns/list', 'ListVoucherCampaignsController@list')->name('campaigns.list'); +Route::group(['prefix' => 'voucher', 'as' => 'voucher.'], function () { + Route::post('fetch', [ValidateVoucherController::class, 'validate'])->name('validate'); + Route::post('create', [CreateVoucherController::class, 'create'])->name('create'); + // Route::post('redeem', [RedeemVoucherController::class, 'redeem'])->name('redeem'); + Route::get('/user/list', [ListUserVouchersController::class, 'list'])->name('user.list'); + Route::get('/voucher/campaigns/list', [ListVoucherCampaignsController::class, 'list'])->name('campaigns.list'); }); diff --git a/routes/wallet.php b/routes/wallet.php index f79708b3..e3aa91c3 100644 --- a/routes/wallet.php +++ b/routes/wallet.php @@ -1,15 +1,21 @@ 'wallets', 'namespace' => 'Wallets', 'as' => 'wallet.'], function () { - Route::get('/', 'ListWalletController@list')->name('list'); - Route::post('/create', 'CreateWalletController@create')->name('create'); +Route::group(['prefix' => 'wallets', 'as' => 'wallet.'], function () { + Route::get('/', [ListWalletController::class, 'list'])->name('list'); + Route::post('/create', [CreateWalletController::class, 'create'])->name('create'); - Route::post('/topup', 'TopUpWalletController@topUp')->name('topup'); // user - Route::post('/credit', 'CreditWalletController@credit')->name('credit'); // admin + + Route::post('/topup', [TopUpWalletController::class, 'topUp'])->name('topup'); // user + Route::post('/credit', [CreditWalletController::class, 'credit'])->name('credit'); // admin + - Route::put('/{transaction_id}/update-status/{status}', 'UpdateStatusWalletController@updateStatus')->where('status', 'approve|reject')->name('approval'); + Route::put('/{transaction_id}/update-status/{status}', [UpdateStatusWalletController::class, 'updateStatus'])->where('status', 'approve|reject')->name('approval'); - Route::get('/reports', 'WalletReportController@walletsReport')->name('reports'); + Route::get('/reports', [WalletReportController::class, 'walletsReport'])->name('reports'); }); diff --git a/routes/web.php b/routes/web.php index aa3d2c24..ec7fbe07 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,7 +1,17 @@ name('support'); //duplicate name -Route::get('/online_payment/redirect', 'Billplz\CallbackBillplzController@callback')->name('online_payment.redirect'); +Route::get('/online_payment/redirect', [CallbackBillplzController::class, 'callback'])->name('online_payment.redirect'); Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) { $exportFileName = 'products.csv'; @@ -315,7 +325,7 @@ Route::get('/wallet/{marking}/details', function ($marking) { return view('pages.wallet.index', ['id' => $id, 'wallet_id' => $wallet_id]); })->name('wallet.details'); -Route::get('/wallet/{marking}/{is_precise}/export', 'Exports\ExportCustomersWalletTransactionToExcelController@export')->name('wallet.details-export'); +Route::get('/wallet/{marking}/{is_precise}/export', [ExportCustomersWalletTransactionToExcelController::class, 'export'])->name('wallet.details-export'); Route::get('/wallets', function () { return view('pages.wallet.wallets'); @@ -325,31 +335,31 @@ Route::get('/bookings/billplz', function () { return view('pages.billplz_redirect'); })->name('bookings.billplz'); -Route::get('/document/download', 'Bookings\DownloadBookingDocumentController@download')->name('documents.download'); +Route::get('/document/download', [DownloadBookingDocumentController::class, 'download'])->name('documents.download'); Route::get('billplz/bills/{bill_no}', function($bill_no){ return redirect(env('BILLPLZ_BASE_URL').'/bills/'.$bill_no); })->name('billplz.bill'); -Route::get('/export/customers/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@export')->name('customers.export'); -Route::get('/export/transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@transactions')->name('transactions.export'); -Route::get('/export/transactions/v2/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@v2transactions')->name('transactions.v2.export'); -Route::get('/export/null-debtor/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@nullDebtor')->name('newDebtor.export'); -Route::get('/export/payment-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@paymentTransactions')->name('paymentTransactions.export'); -Route::get('/export/white-form-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@whiteFormTransactions')->name('whiteFormTransactions.export'); -Route::get('/export/wallet-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@walletTransactions')->name('walletTransactions.export'); -Route::get('/export/booking-transactions', 'Exports\ExportCustomersToExcelController@bookingTransactions')->name('export.transactions.booking'); -Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@invoiceTransactions')->name('invoiceTransactions.export'); -Route::get('/export/receipt-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@receiptTransactions')->name('receiptTransactions.export'); -Route::get('/export/imported-invoice-mapped', 'Exports\ExportCustomersToExcelController@importedInvoiceMapped')->name('importedInvoiceMapped.export'); -Route::get('/export/imported-receipt-mapped', 'Exports\ExportCustomersToExcelController@importedReceiptMapped')->name('importedReceiptMapped.export'); -Route::get('/export/analytic/booking', 'Exports\ExportAnalyticToExcelController@bookingData')->name('bookingData.export');; -Route::get('/export/analytic/bills', 'Exports\ExportAnalyticToExcelController@billingData')->name('billingData.export');; -Route::get('/export/customers/leads', 'Exports\ExportCustomersToExcelController@leadsData')->name('leads.export'); -route::get('/export/excel/{id}', 'Exports\ExportCustomersToExcelController@exportCurrencyVendorOrder')->name('group.excel'); -Route::get('/export/einv-debtor/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@eInvoiceDebtorSummary')->name('eInvoiceDebtorSummary.export'); -Route::get('/export/all-customers-info-for-lark-system', 'Exports\ExportCustomersToExcelController@exportAllCustomersInfoForLarkSystem')->name('exportAllCustomersInfoForLarkSystem.export'); +Route::get('/export/customers/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'export'])->name('customers.export'); +Route::get('/export/transactions/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'transactions'])->name('transactions.export'); +Route::get('/export/transactions/v2/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'v2transactions'])->name('transactions.v2.export'); +Route::get('/export/null-debtor/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'nullDebtor'])->name('newDebtor.export'); +Route::get('/export/payment-transactions/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'paymentTransactions'])->name('paymentTransactions.export'); +Route::get('/export/white-form-transactions/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'whiteFormTransactions'])->name('whiteFormTransactions.export'); +Route::get('/export/wallet-transactions/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'walletTransactions'])->name('walletTransactions.export'); +Route::get('/export/booking-transactions', [ExportCustomersToExcelController::class, 'bookingTransactions'])->name('export.transactions.booking'); +Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'invoiceTransactions'])->name('invoiceTransactions.export'); +Route::get('/export/receipt-transactions/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'receiptTransactions'])->name('receiptTransactions.export'); +Route::get('/export/imported-invoice-mapped', [ExportCustomersToExcelController::class, 'importedInvoiceMapped'])->name('importedInvoiceMapped.export'); +Route::get('/export/imported-receipt-mapped', [ExportCustomersToExcelController::class, 'importedReceiptMapped'])->name('importedReceiptMapped.export'); +Route::get('/export/analytic/booking', [ExportAnalyticToExcelController::class, 'bookingData'])->name('bookingData.export');; +Route::get('/export/analytic/bills', [ExportAnalyticToExcelController::class, 'billingData'])->name('billingData.export');; +Route::get('/export/customers/leads', [ExportCustomersToExcelController::class, 'leadsData'])->name('leads.export'); +Route::get('/export/excel/{id}', [ExportCustomersToExcelController::class, 'exportCurrencyVendorOrder'])->name('group.excel'); +Route::get('/export/einv-debtor/f614e339d7058904a831aad742e24d55', [ExportCustomersToExcelController::class, 'eInvoiceDebtorSummary'])->name('eInvoiceDebtorSummary.export'); +Route::get('/export/all-customers-info-for-lark-system', [ExportCustomersToExcelController::class, 'exportAllCustomersInfoForLarkSystem'])->name('exportAllCustomersInfoForLarkSystem.export'); Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) { $bookings = Booking::where(function($query){ @@ -370,7 +380,7 @@ Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsP } })->name('products.random.3'); -Route::get('/auto-purchase-order-fill', 'Bookings\AutoPurchaseOrderFillController@auto')->name('assign'); +Route::get('/auto-purchase-order-fill', [AutoPurchaseOrderFillController::class, 'auto'])->name('assign'); Route::get('purchase/sensitive/', function(Request $request){ $keywords = json_decode($request->input('keywords')); @@ -391,9 +401,9 @@ Route::get('purchase/sensitive/', function(Request $request){ } }); -Route::get('/transactions/supplier/{id}/mock_up', 'Transactions\DownloadMockUpWhiteFormPdfController@download')->name('whiteForm.mockUp'); +Route::get('/transactions/supplier/{id}/mock_up', [DownloadMockUpWhiteFormPdfController::class, 'download'])->name('whiteForm.mockUp'); -Route::get('/notifications/list', 'Notifications\ListNotificationsController@list')->name('notifications.list'); +Route::get('/notifications/list', [ListNotificationsController::class, 'list'])->name('notifications.list'); Route::get('/supplier/pi/export/{month}/{year}/{id?}', function($month, $year, $id = null){ @@ -943,7 +953,7 @@ Route::get('/statements/{account}/transactions', function ($account) { Route::get('/statements/{statement}', [BankStatementController::class, 'show'])->name('statements.show'); Route::get('/statements/mapping/rerun', [BankStatementController::class, 'rerun'])->name('statements.rerun'); // Route::get('/statements/{statement}/download', 'StatementController@download')->name('statements.download'); -Route::get('/bank-record', 'Imports\ImportBankRecordController@import'); +Route::get('/bank-record', [ImportBankRecordController::class, 'import']); Route::get('/po/outsource/check', function(){ $bookings = Booking::whereIn('marking', [34735, 43980, 35339, 28104, 40185, 46648, 34192, 21512, 84607, 31319, 23566, 48372, 59239, 72665, 81127, 46881, 41055, 67368, 41817, 60443, 28958, 46782, 98512, 43356, 78469, 88173, 52592, 77036, 76750, 77732, 31980, 57146, 38544, 78567, 98297, 90128, 43680, 86478, 80340, 41961, 26857, 33992, 79929, 53226, 88107, 31187, 68015, 43762, 34928, 55525, 44528, 57146, 31980, 27399, 63141, 74987, 85935, 37032, 95911, 59511, 47395, 97293, 43906, 74944, 53418, 61988, 81406, 83889, 83359, 66896, 21425, 61124, 23536, 56129, 21116, 64213, 72950, 20502, 20067, 64213, 59854, 44783, 35681, 74828, 28179, 32961, 46412, 99908, 49008, 77655, 45250, 65047, 37167, 90598, 26275, 58013, 38994, 63187, 33219, 52669, 79885, 74828, 91775, 29282, 46781, 96415, 36318, 84491, 32659, 23846, 38994, 65329, 25936, 68209, 72866, 63231, 32216, 82977, 24819, 32600, 38019, 80872, 65505, 37236, 82262, 30815, 59033, 46776, 87317, 89548, 36548, 54468, 35340, 98242, 29234, 47129, 67047, 64210, 36698, 39353, 86435, 65240, 37116, 71007, 40148, 88187, 76368, 91155, 57040, 95456, 29961, 66447, 43023, 29396, 30637, 60789, 84221, 35805, 44552, 35524, 43457, 22810, 83545, 92252, 83603, 59797, 40526, 32520, 71011, 95151, 90464, 78629, 61225, 74864, 73518, 53793, 26478, 57640, 43674, 23476, 76683, 23920, 22810, 44603, 56291, 23580, 94241, 51565, 83769, 63123, 58369, 99399, 41098, 60942, 69442, 80963, 48392, 73169, 59764, 66099, 21107, 33029, 38288, 32223, 55931, 43685, 24267, 83865, 52066, 61501, 83210, 20731, 55951, 82502, 66618, 62216, 22020, 42402, 99644, 35305, 49263, 37387, 73928, 92279, 26445, 83497, 96740, 38374, 29273, 94073, 99785, 21502, 51269, 31609, 97369, 73078, 28982, 64902, 41380, 87008, 59377, 39441, 81341, 62750, 29410, 85975, 37215, 43386, 80627, 79967, 81729, 81738, 58658, 40579, 56179, 37548, 72436, 77165, 32069, 97447, 84575, 49167, 45507, 96371, 90835, 27942, 87691, 30431, 47815, 82960, 43228, 87534, 93737, 98938, 69548, 82923, 48463, 24385, 96569, 53812, 32926, 54418, 34399, 53189, 49377, 27036, 68832, 72799, 76120, 78203, 87009, 86992, 97722, 96262, 95551, 77632, 54408, 33931, 62397, 58343, 52347, 59419, 50339, 54941, 31199, 92385, 90028, 90379, 43070, 25357, 24591, 60276, 91851, 96371, 81886, 24377, 21236, 66737, 93637, 85844, 23130, 75659, 27318, 43587, 46555, 28903, 44930, 52377, 20387, 40705, 79255, 29196, 30968, 76319, 54600, 29881, 37920, 43319, 35893, 65863, 33102, 71589, 45905, 49031, 97435, 70157, 78795, 47570, 71881, 92076, 45847, 35957, 58785, 84896, 65918, 25550, 49031, 50624, 83286, 63111, 21402, 56300, 77238, 21271, 21984, 30500, 76170, 95325, 22888, 84895, 26100, 84952, 49302, 41944, 43703, 84028, 53672, 49162, 28342, 47182, 70484, 59467, 85415, 20202, 97967, 58011, 85807, 79868, 81192, 86985, 43867, 47473, 28063, 68849, 61628, 96641, 37285, 58384, 86505, 51720, 63951, 91958, 28082, 46229, 57439, 55178, 96813, 34444, 28100, 75967, 33204, 75922, 68707, 71960, 34769, 29161, 49088, 79773, 91131, 53033, 77611, 81034, 72625, 36273, 78240, 34647, 21838, 73195, 83282, 60911, 29019, 98859, 44064, 82113, 51118, 54681, 59751, 64347, 21623, 47023, 62168, 23466, 62137, 85432, 85043, 41984, 30417, 40616, 97170, 69106, 81484, 68902, 78149, 62438, 67710, 57370, 99207, 64271, 33959, 60821, 51292, 44130, 28469, 77069, 91088, 47702, 89046, 84958, 41601, 99752, 72976, 26393, 85548, 32920, 86353, 97430, 71507, 36667, 57059, 71148, 44588, 35807, 80213, 89884, 76616, 35999, 79860, 37284, 72249, 32885, 70622, 47036, 97366, 60483, 89171, 37048, 34227, 76290, 46761, 31389, 73977, 54421, 87527, 75925, 68236, 31131, 43871, 54753, 90896, 41653, 82304, 87123, 80391, 42368, 35553, 60587, 30941, 31843, 25076]) @@ -1035,8 +1045,8 @@ Route::get('/customer/vouchers/{marking}', function ($marking) { } })->name('customer.reward'); -Route::get('transaction/{id}/credit_note/download', 'Transactions\GenerateCreditNotePdfController@downloadV2')->name('transaction.credit_note.download'); -Route::get('transaction/{id}/credit_note/download/v2', 'Transactions\GenerateCreditNotePdfController@downloadV2')->name('transaction.credit_note.download.v2'); +Route::get('transaction/{id}/credit_note/download', [GenerateCreditNotePdfController::class, 'downloadV2'])->name('transaction.credit_note.download'); +Route::get('transaction/{id}/credit_note/download/v2', [GenerateCreditNotePdfController::class, 'downloadV2'])->name('transaction.credit_note.download.v2'); Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking, $started_at, $ended_at) { @@ -1117,7 +1127,7 @@ Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking, ); })->name('invoice.fix.byCustomerMarking'); -route:: post('/transaction/{id}/create-remark',function ($transactionId) { +Route::post('/transaction/{id}/create-remark',function ($transactionId) { $transaction = Transaction::find($transactionId); $remark = new Remark(); diff --git a/staging.Dockerfile b/staging.Dockerfile index 53dee762..40e0e69d 100644 --- a/staging.Dockerfile +++ b/staging.Dockerfile @@ -1,3 +1,3 @@ -FROM laravelphp/vapor:php74 +FROM laravelphp/vapor:php83 COPY . /var/task diff --git a/test.Dockerfile b/test.Dockerfile new file mode 100644 index 00000000..40e0e69d --- /dev/null +++ b/test.Dockerfile @@ -0,0 +1,3 @@ +FROM laravelphp/vapor:php83 + +COPY . /var/task diff --git a/tests/Browser/DryRun/CreateBookingTest.php b/tests/Browser/DryRun/CreateBookingTest.php index 989dd565..13e8de83 100644 --- a/tests/Browser/DryRun/CreateBookingTest.php +++ b/tests/Browser/DryRun/CreateBookingTest.php @@ -69,7 +69,7 @@ class CreateBookingTest extends DuskTestCase $modal->click('#confirm-booking'); }) ->pause(10000); - //Assert if booking created successfully + //A S S E R T if booking created successfully }); } diff --git a/tests/Feature/Accounts/AuthenticationTest.php b/tests/Feature/Accounts/AuthenticationTest.php new file mode 100644 index 00000000..60202a9a --- /dev/null +++ b/tests/Feature/Accounts/AuthenticationTest.php @@ -0,0 +1,86 @@ +first(); + if (!$user) { + $user = new User(); + $user->email = $email; + } + $user->name = 'test_user_can_authenticate_with_valid_credentials'; + $user->password = Hash::make('password123'); + $user->type = \App\Classes\ValueObjects\Constants\RoleTypes::ADMIN; + $user->status = 1; + $user->save(); + + // A C T: Hit the login attempt API + $response = $this->postJson('/api/v1/account/authentication/login/attempt', [ + 'email' => $email, + 'password' => 'password123', + ]); + + // A S S E R T: Expect 200 OK and a JSON payload structure + $response->assertStatus(200) + ->assertJsonStructure([ + 'payload' => [ + 'access_token', + 'redirect_url' + ] + ]); + } + + /** + * Test user cannot authenticate with invalid password. + * + * @return void + */ + public function test_user_cannot_authenticate_with_invalid_credentials() + { + // A R R A N G E + $email = 'test_user_cannot_authenticate_with_invalid_credentials@example.com'; + $user = User::where('email', $email)->first(); + if (!$user) { + $user = new User(); + $user->email = $email; + } + $user->name = 'test_user_cannot_authenticate_with_invalid_credentials'; + $user->password = Hash::make('password123'); + $user->type = \App\Classes\ValueObjects\Constants\RoleTypes::ADMIN; + $user->status = 1; + $user->save(); + + // A C T + $response = $this->postJson('/api/v1/account/authentication/login/attempt', [ + 'email' => $email, + 'password' => 'wrongpassword', + ]); + + // A S S E R T + // Unprocessable Entity or Unauthorized depending on application logic + // 400/401/422 are common. Let's assert it just doesn't succeed (not 200) + $this->assertNotEquals(200, $response->getStatusCode()); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/CreateSegmentLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/CreateSegmentLogicTest.php new file mode 100644 index 00000000..e4453fa7 --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/CreateSegmentLogicTest.php @@ -0,0 +1,90 @@ +first(); + if (!$user) { + $user = new User(); + $user->name = 'test_create_segment_logic_execution'; + $user->email = $email; + $user->password = bcrypt('password'); + $user->save(); + } + + $this->actingAs($user); + + // Mock CanCreateSegment to pass + $canCreateSegment = Mockery::mock(CanCreateSegment::class); + $canCreateSegment->shouldReceive('passes')->once()->andReturn(true); + + // Mock CreatesSegment to return a Segment model + $segment = new Segment(); + $segment->id = 1; + $segment->name = 'test_create_segment_logic_execution'; + $segment->type = SegmentConstants::STANDARD_SEGMENT; + + $createsSegment = Mockery::mock(CreatesSegment::class); + $createsSegment->shouldReceive('execute') + ->once() + ->with(Mockery::type(SegmentObject::class)) + ->andReturn($segment); + + $logic = new CreateSegmentLogic($canCreateSegment, $createsSegment); + + $request = Request::create('/api/segments', 'POST', [ + 'name' => 'test_create_segment_logic_execution', + 'type' => SegmentConstants::STANDARD_SEGMENT + ]); + $request->headers->set('captcha-token', 'fake-token'); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + + $this->assertEquals('Created Segment Successful', $data['title']); + $this->assertEquals('test_create_segment_logic_execution', $data['payload']['data']['name']); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/DeleteSegmentLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/DeleteSegmentLogicTest.php new file mode 100644 index 00000000..21e64901 --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/DeleteSegmentLogicTest.php @@ -0,0 +1,94 @@ +first(); + if (!$user) { + $user = new User(); + $user->name = 'test_delete_segment_logic_execution'; + $user->email = $email; + $user->password = bcrypt('password'); + $user->save(); + } + $this->actingAs($user); + + $segment = new Segment(); + $segment->id = 1; + $segment->name = 'test_delete_segment_logic_execution'; + + // Mock FetchesSegment + $fetchesSegment = Mockery::mock(FetchesSegment::class); + $fetchesSegment->shouldReceive('execute') + ->once() + ->with(['id' => 1]) + ->andReturn($segment); + + // Mock CanDeleteSegment + $canDeleteSegment = Mockery::mock(CanDeleteSegment::class); + $canDeleteSegment->shouldReceive('passes')->once()->andReturn(true); + + // Mock DeletesSegment + $deletesSegment = Mockery::mock(DeletesSegment::class); + $deletesSegment->shouldReceive('execute') + ->once() + ->with($segment) + ->andReturn([]); + + $logic = new DeleteSegmentLogic($canDeleteSegment, $deletesSegment, $fetchesSegment); + + $request = Request::create('/api/segments/1', 'DELETE'); + $request->headers->set('captcha-token', 'fake-token'); + $request->setRouteResolver(function () { + $route = Mockery::mock(\Illuminate\Routing\Route::class); + $route->shouldReceive('parameter')->with('id', null)->andReturn(1); + return $route; + }); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Delete Segment Successful', $data['title']); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/FetchConstantLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/FetchConstantLogicTest.php new file mode 100644 index 00000000..3af669dc --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/FetchConstantLogicTest.php @@ -0,0 +1,85 @@ +first(); + if (!$user) { + $user = new User(); + $user->name = 'test_fetch_constant_logic_execution'; + $user->email = $email; + $user->password = bcrypt('password'); + $user->save(); + } + $this->actingAs($user); + + $constant = new SegmentConstant(); + $constant->id = 1; + $constant->name = 'test_fetch_constant_logic_execution'; + $constant->reference = 'test_fetch_constant_logic_execution'; + $constant->detail = (object) ['foo' => 'bar']; + + // Mock FetchesConstant + $fetchesConstant = Mockery::mock(FetchesConstant::class); + $fetchesConstant->shouldReceive('execute') + ->once() + ->with(['segment_id' => 1, 'reference' => 'test_fetch_constant_logic_execution']) + ->andReturn($constant); + + $logic = new FetchConstantLogic($fetchesConstant); + + $request = Request::create('/api/segments/1/constants/test_fetch_constant_logic_execution', 'GET'); + $request->headers->set('captcha-token', 'fake-token'); + $request->setRouteResolver(function () { + $route = Mockery::mock(\Illuminate\Routing\Route::class); + $route->shouldReceive('parameter')->with('id', null)->andReturn(1); + $route->shouldReceive('parameter')->with('reference', null)->andReturn('test_fetch_constant_logic_execution'); + return $route; + }); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Fetch Segment Constant Successful', $data['title']); + $this->assertEquals('test_fetch_constant_logic_execution', $data['payload']['data']['reference']); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/FetchSegmentLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/FetchSegmentLogicTest.php new file mode 100644 index 00000000..cdde2595 --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/FetchSegmentLogicTest.php @@ -0,0 +1,87 @@ +first(); + if (!$user) { + $user = new User(); + $user->name = 'test_fetch_segment_logic_execution'; + $user->email = $email; + $user->password = bcrypt('password'); + $user->save(); + } + $this->actingAs($user); + + $segment = new Segment(); + $segment->id = 1; + $segment->name = 'test_fetch_segment_logic_execution'; + + // Mock CanFetchSegment + $canFetchSegment = Mockery::mock(CanFetchSegment::class); + $canFetchSegment->shouldReceive('passes')->once()->andReturn(true); + + // Mock FetchesSegment + $fetchesSegment = Mockery::mock(FetchesSegment::class); + $fetchesSegment->shouldReceive('execute') + ->once() + ->with(['id' => 1]) + ->andReturn($segment); + + $logic = new FetchSegmentLogic($canFetchSegment, $fetchesSegment); + + $request = Request::create('/api/segments/1', 'GET'); + $request->headers->set('captcha-token', 'fake-token'); + $request->setRouteResolver(function () { + $route = Mockery::mock(\Illuminate\Routing\Route::class); + $route->shouldReceive('parameter')->with('id', null)->andReturn(1); + return $route; + }); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Retrieved Segment Successful', $data['title']); + $this->assertEquals('test_fetch_segment_logic_execution', $data['payload']['data']['name']); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/ListSegmentLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/ListSegmentLogicTest.php new file mode 100644 index 00000000..46735d2c --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/ListSegmentLogicTest.php @@ -0,0 +1,88 @@ +first(); + if (!$user) { + $user = new User(); + $user->name = 'test_list_segment_logic_execution'; + $user->email = $email; + $user->password = bcrypt('password'); + $user->save(); + } + $this->actingAs($user); + + $s1 = new Segment(); + $s1->id = 1; + $s1->name = 'test_list_segment_logic_execution_1'; + + $s2 = new Segment(); + $s2->id = 2; + $s2->name = 'test_list_segment_logic_execution_2'; + + $segments = new Collection([$s1, $s2]); + + // Mock ListsSegments + $listsSegments = Mockery::mock(ListsSegments::class); + $listsSegments->shouldReceive('deserializeFilters') + ->once() + ->with(null) + ->andReturn([]); + $listsSegments->shouldReceive('execute') + ->once() + ->with([]) + ->andReturn($segments); + + $logic = new ListSegmentLogic($listsSegments); + + $request = Request::create('/api/segments', 'GET'); + $request->headers->set('captcha-token', 'fake-token'); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Retrieved Segment Successful', $data['title']); + $this->assertCount(2, $data['payload']['data']); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogic2Test.php b/tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogic2Test.php new file mode 100644 index 00000000..459c8033 --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogic2Test.php @@ -0,0 +1,129 @@ +admin = User::where('email', $email)->first(); + if (!$this->admin) { + $this->admin = new User(); + $this->admin->email = $email; + $this->admin->name = 'Admin Update Constant Execution'; + $this->admin->password = Hash::make('password'); + $this->admin->type = RoleTypes::ADMIN; + $this->admin->status = 1; + $this->admin->save(); + } + + // Ensure user has necessary permissions + $permission = Permission::firstOrCreate(['name' => 'edit segment_constant', 'guard_name' => 'api']); + $this->admin->givePermissionTo($permission); + $permission = Permission::firstOrCreate(['name' => 'add segment_constant', 'guard_name' => 'api']); + $this->admin->givePermissionTo($permission); + + // Create a test segment + $this->segment = new Segment(); + $this->segment->name = 'Update Constant Execution Segment'; + $this->segment->save(); + } + + /** + * Test updating an existing segment constant without Mockery. + * + * @return void + */ + public function test_it_can_update_existing_constant() + { + // A R R A N G E + $reference = 'execution_test_ref'; + $detail = ['foo' => 'bar']; + + $constant = new SegmentConstant(); + $constant->segment_id = $this->segment->id; + $constant->name = 'Old Name'; + $constant->reference = $reference; + $constant->detail = (object) ['old' => 'data']; + $constant->save(); + + $payload = [ + 'name' => 'Updated Name', + 'reference' => $reference, + 'detail' => $detail + ]; + + // A C T + $response = $this->actingAs($this->admin, 'api') + ->putJson("/api/v1/segment/{$this->segment->id}/constant/update", $payload); + + // A S S E R T + $response->assertStatus(200); + $response->assertJsonPath('payload.data.name', 'Updated Name'); + $response->assertJsonPath('payload.data.reference', $reference); + + $this->assertDatabaseHas('segment_constants', [ + 'segment_id' => $this->segment->id, + 'reference' => $reference, + 'name' => 'Updated Name' + ]); + + $updatedConstant = SegmentConstant::where('reference', $reference)->first(); + $this->assertEquals((object) $detail, $updatedConstant->detail); + } + + /** + * Test creating a constant if it doesn't exist during update. + * + * @return void + */ + public function test_it_creates_constant_if_not_exists() + { + // A R R A N G E + $reference = 'new_execution_test_ref'; + $detail = ['new' => 'data']; + + $payload = [ + 'name' => 'New Constant', + 'reference' => $reference, + 'detail' => $detail + ]; + + // A C T + $response = $this->actingAs($this->admin, 'api') + ->putJson("/api/v1/segment/{$this->segment->id}/constant/update", $payload); + + // A S S E R T + $response->assertStatus(200); + + $this->assertDatabaseHas('segment_constants', [ + 'segment_id' => $this->segment->id, + 'reference' => $reference, + 'name' => 'New Constant' + ]); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogicTest.php new file mode 100644 index 00000000..365c6ea9 --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/UpdateConstantLogicTest.php @@ -0,0 +1,182 @@ +user = User::where('email', $email)->first(); + if (!$this->user) { + $this->user = new User(); + $this->user->name = 'UpdateConstantLogicTest'; + $this->user->email = $email; + $this->user->password = bcrypt('password'); + $this->user->save(); + } + $this->actingAs($this->user); + + $this->segment = new Segment(); + $this->segment->id = 1; + $this->segment->name = 'UpdateConstantLogicTest_Segment'; + } + + /** + * Test UpdateConstantLogic execution for updating existing constant. + * + * @return void + */ + public function test_update_constant_logic_updates_existing() + { + // A R R A N G E + Bus::fake([UserRiskAnalysis::class]); + + $constant = new SegmentConstant(); + $constant->id = 10; + $constant->segment_id = 1; + $constant->name = 'test_update_constant_logic_updates_existing'; + $constant->reference = 'test_update_constant_logic_updates_existing'; + $constant->detail = (object) ['foo' => 'bar']; + + $fetchesSegment = Mockery::mock(FetchesSegment::class); + $fetchesSegment->shouldReceive('execute')->with(['id' => 1])->andReturn($this->segment); + + $fetchesConstant = Mockery::mock(FetchesConstant::class); + $fetchesConstant->shouldReceive('execute')->with(['segment_id' => 1, 'reference' => 'test_update_constant_logic_updates_existing'])->andReturn($constant); + + $canUpdateConstant = Mockery::mock(CanUpdateConstant::class); + $canUpdateConstant->shouldReceive('passes')->once()->andReturn(true); + + $updatesConstant = Mockery::mock(UpdatesConstant::class); + $updatesConstant->shouldReceive('execute')->once()->andReturn($constant); + + $canCreateConstant = Mockery::mock(CanCreateConstant::class); + $createsConstant = Mockery::mock(CreatesConstant::class); + + $logic = new UpdateConstantLogic( + $canUpdateConstant, + $updatesConstant, + $fetchesSegment, + $fetchesConstant, + $canCreateConstant, + $createsConstant + ); + + $request = Request::create('/api/segments/1/constants', 'POST', [ + 'name' => 'test_update_constant_logic_updates_existing_NEW', + 'reference' => 'test_update_constant_logic_updates_existing', + 'detail' => ['new' => 'data'] + ]); + $request->headers->set('captcha-token', 'fake-token'); + $request->setRouteResolver(function () { + $route = Mockery::mock(\Illuminate\Routing\Route::class); + $route->shouldReceive('parameter')->with('id', null)->andReturn(1); + return $route; + }); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Updated Segment Constant Successful', $data['title']); + } + + /** + * Test UpdateConstantLogic execution for creating new constant if not found. + * + * @return void + */ + public function test_update_constant_logic_creates_new_if_not_found() + { + // A R R A N G E + Bus::fake([UserRiskAnalysis::class]); + + $fetchesSegment = Mockery::mock(FetchesSegment::class); + $fetchesSegment->shouldReceive('execute')->andReturn($this->segment); + + $fetchesConstant = Mockery::mock(FetchesConstant::class); + $fetchesConstant->shouldReceive('execute')->andThrow(new ResourceNotFoundException()); + + $canUpdateConstant = Mockery::mock(CanUpdateConstant::class); + $updatesConstant = Mockery::mock(UpdatesConstant::class); + + $canCreateConstant = Mockery::mock(CanCreateConstant::class); + $canCreateConstant->shouldReceive('passes')->once()->andReturn(true); + + $constant = new SegmentConstant(); + $constant->id = 11; + $constant->name = 'test_update_constant_logic_creates_new_if_not_found'; + + $createsConstant = Mockery::mock(CreatesConstant::class); + $createsConstant->shouldReceive('execute')->once()->andReturn($constant); + + $logic = new UpdateConstantLogic( + $canUpdateConstant, + $updatesConstant, + $fetchesSegment, + $fetchesConstant, + $canCreateConstant, + $createsConstant + ); + + $request = Request::create('/api/segments/1/constants', 'POST', [ + 'name' => 'test_update_constant_logic_creates_new_if_not_found', + 'reference' => 'test_update_constant_logic_creates_new_if_not_found', + 'detail' => [], + ]); + $request->headers->set('captcha-token', 'fake-token'); + $request->setRouteResolver(function () { + $route = Mockery::mock(\Illuminate\Routing\Route::class); + $route->shouldReceive('parameter')->with('id', null)->andReturn(1); + return $route; + }); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Updated Segment Constant Successful', $data['title']); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogic2Test.php b/tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogic2Test.php new file mode 100644 index 00000000..a77a2600 --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogic2Test.php @@ -0,0 +1,80 @@ +admin = User::where('email', $email)->first(); + if (!$this->admin) { + $this->admin = new User(); + $this->admin->email = $email; + $this->admin->name = 'Admin Update Segment Execution'; + $this->admin->password = Hash::make('password'); + $this->admin->type = RoleTypes::ADMIN; + $this->admin->status = 1; + $this->admin->save(); + } + + // Grant permission to resolve 403 Forbidden + $permission = Permission::firstOrCreate(['name' => 'edit segment', 'guard_name' => 'api']); + $this->admin->givePermissionTo($permission); + + // Create a test segment + $this->segment = new Segment(); + $this->segment->name = 'Update Segment Execution Segment'; + $this->segment->save(); + } + + /** + * Test updating a segment without Mockery. + * + * @return void + */ + public function test_it_can_update_segment() + { + // A R R A N G E + $newName = 'Updated Segment Name'; + + $payload = [ + 'name' => $newName + ]; + + // A C T + $response = $this->actingAs($this->admin, 'api') + ->putJson("/api/v1/segment/update/{$this->segment->id}", $payload); + + // A S S E R T + $response->assertStatus(200); + $response->assertJsonPath('payload.data.name', $newName); + + $this->assertDatabaseHas('segments', [ + 'id' => $this->segment->id, + 'name' => $newName + ]); + } +} diff --git a/tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogicTest.php b/tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogicTest.php new file mode 100644 index 00000000..33cff42e --- /dev/null +++ b/tests/Feature/Modules/Segments/ControllersLogic/UpdateSegmentLogicTest.php @@ -0,0 +1,96 @@ +first(); + if (!$user) { + $user = new User(); + $user->name = 'test_update_segment_logic_execution'; + $user->email = $email; + $user->type = 1; + $user->password = bcrypt('password'); + $user->save(); + } + $this->actingAs($user); + + $segment = new Segment(); + $segment->id = 1; + $segment->name = 'test_update_segment_logic_execution'; + + // Mock FetchesSegment + $fetchesSegment = Mockery::mock(FetchesSegment::class); + $fetchesSegment->shouldReceive('execute') + ->once() + ->with(['id' => 1]) + ->andReturn($segment); + + // Mock CanUpdateSegment + $canUpdateSegment = Mockery::mock(CanUpdateSegment::class); + $canUpdateSegment->shouldReceive('passes') + ->once() + ->with(Mockery::type(SegmentObject::class)) + ->andReturn(true); + + // Mock UpdatesSegment + $updatesSegment = Mockery::mock(UpdatesSegment::class); + $updatesSegment->shouldReceive('execute') + ->once() + ->with($segment, Mockery::type(SegmentObject::class)) + ->andReturn($segment); + + $logic = new UpdateSegmentLogic($canUpdateSegment, $updatesSegment, $fetchesSegment); + + $request = Request::create('/api/segments/1', 'PUT', [ + 'name' => 'test_update_segment_logic_execution_NEW' + ]); + $request->setRouteResolver(function () { + $route = Mockery::mock(\Illuminate\Routing\Route::class); + $route->shouldReceive('parameter')->with('id', null)->andReturn(1); + return $route; + }); + + // A C T + $response = $logic->execute($request); + + // A S S E R T + $this->assertEquals(200, $response->getStatusCode()); + $data = $response->getData(true); + $this->assertEquals('Updated Segment Successful', $data['title']); + } + + protected function tearDown(): void + { + parent::tearDown(); + Mockery::close(); + } +} diff --git a/tests/Unit/Modules/Segments/Services/ConvertsConstantDetailsToResourceTest.php b/tests/Unit/Modules/Segments/Services/ConvertsConstantDetailsToResourceTest.php new file mode 100644 index 00000000..13b662c7 --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/ConvertsConstantDetailsToResourceTest.php @@ -0,0 +1,105 @@ +reference = 'test_it_returns_detail_directly_if_not_supplier_currencies'; + $constant->detail = (object) ['foo' => 'bar']; + + // A C T + $result = $service->execute($constant); + + // A S S E R T + $this->assertEquals($constant->detail, $result); + } + + /** + * Test it returns CurrencyResource if reference is SUPPLIER_CURRENCIES. + * + * @return void + */ + public function test_it_returns_currency_resource_if_reference_is_supplier_currencies() + { + // A R R A N G E + $currencyId = 123; + $mockCurrency = new Currency(); + $mockCurrency->id = $currencyId; + $mockCurrency->name = 'test_it_returns_currency_resource_if_reference_is_supplier_currencies'; + + $mockFetchesCurrency = Mockery::mock(FetchesCurrency::class); + $mockFetchesCurrency->shouldReceive('execute') + ->with(['id' => $currencyId]) + ->once() + ->andReturn($mockCurrency); + + $service = new ConvertsConstantDetailsToResource($mockFetchesCurrency); + + $constant = new SegmentConstant(); + $constant->reference = SegmentConstants::SUPPLIER_CURRENCIES; + $constant->detail = (object) ['id' => $currencyId]; + + // A C T + $result = $service->execute($constant); + + // A S S E R T + $this->assertInstanceOf(CurrencyResource::class, $result); + $this->assertEquals($currencyId, $result->id); + } + + /** + * Test it returns empty string if SUPPLIER_CURRENCIES but no id in detail. + * + * @return void + */ + public function test_it_returns_empty_if_no_id_in_supplier_currencies() + { + // A R R A N G E + $mockFetchesCurrency = Mockery::mock(FetchesCurrency::class); + $service = new ConvertsConstantDetailsToResource($mockFetchesCurrency); + + $constant = new SegmentConstant(); + $constant->reference = SegmentConstants::SUPPLIER_CURRENCIES; + $constant->detail = (object) ['some' => 'other']; + + // A C T + $result = $service->execute($constant); + + // A S S E R T + $this->assertEquals('', $result); + } + + protected function tearDown(): void + { + Mockery::close(); + parent::tearDown(); + } +} diff --git a/tests/Unit/Modules/Segments/Services/CreatesConstantTest.php b/tests/Unit/Modules/Segments/Services/CreatesConstantTest.php new file mode 100644 index 00000000..277b09da --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/CreatesConstantTest.php @@ -0,0 +1,54 @@ +name = 'test_it_can_create_a_segment_constant_SEG'; + $segment->save(); + + $detail = ['key' => 'value']; + $object = new ConstantObject('test_it_can_create_a_segment_constant_CON', 'test_it_can_create_a_segment_constant_REF', $detail); + $service = new CreatesConstant(); + + // A C T + $result = $service->execute($segment, $object); + + // A S S E R T + $this->assertInstanceOf(SegmentConstant::class, $result); + $this->assertEquals('test_it_can_create_a_segment_constant_CON', $result->name); + $this->assertEquals('test_it_can_create_a_segment_constant_REF', $result->reference); + $this->assertEquals((object) $detail, $result->detail); + $this->assertEquals($segment->id, $result->segment_id); + + $this->assertDatabaseHas('segment_constants', [ + 'id' => $result->id, + 'name' => 'test_it_can_create_a_segment_constant_CON', + 'reference' => 'test_it_can_create_a_segment_constant_REF', + 'segment_id' => $segment->id, + ]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/CreatesSeasonalSegmentTest.php b/tests/Unit/Modules/Segments/Services/CreatesSeasonalSegmentTest.php new file mode 100644 index 00000000..741904ab --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/CreatesSeasonalSegmentTest.php @@ -0,0 +1,69 @@ +name = 'test_it_can_create_a_seasonal_segment_COMP'; + $company->reference = 'TEST-CSST'; + $company->business_type = 1; + $company->save(); + + $segment = new Segment(); + $segment->name = 'test_it_can_create_a_seasonal_segment_SEG'; + $segment->save(); + + $startingOn = Carbon::now()->addDay()->format('Y-m-d H:i:s'); + $endingOn = Carbon::now()->addMonth()->format('Y-m-d H:i:s'); + + $object = new SeasonalSegmentObject( + $company->id, + $segment->id, + $startingOn, + $endingOn + ); + + $service = new CreatesSeasonalSegment(); + + // A C T + $result = $service->execute($object); + + // A S S E R T + $this->assertInstanceOf(SeasonalSegment::class, $result); + $this->assertEquals($company->id, $result->company_id); + $this->assertEquals($segment->id, $result->segment_id); + $this->assertEquals($startingOn, $result->starting_on->format('Y-m-d H:i:s')); + $this->assertEquals($endingOn, $result->ending_on->format('Y-m-d H:i:s')); + + $this->assertDatabaseHas('seasonal_segment', [ + 'id' => $result->id, + 'company_id' => $company->id, + 'segment_id' => $segment->id, + ]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/CreatesSegmentTest.php b/tests/Unit/Modules/Segments/Services/CreatesSegmentTest.php new file mode 100644 index 00000000..446c8fec --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/CreatesSegmentTest.php @@ -0,0 +1,48 @@ +execute($object); + + // A S S E R T + $this->assertInstanceOf(Segment::class, $result); + $this->assertEquals($name, $result->name); + $this->assertEquals($type, $result->type); + + $this->assertDatabaseHas('segments', [ + 'id' => $result->id, + 'name' => $name, + 'type' => $type, + ]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/DeletesSegmentTest.php b/tests/Unit/Modules/Segments/Services/DeletesSegmentTest.php new file mode 100644 index 00000000..08aa1370 --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/DeletesSegmentTest.php @@ -0,0 +1,44 @@ +name = 'test_it_can_delete_a_segment'; + $segment->save(); + + $service = new DeletesSegment(); + + // A C T + $result = $service->execute($segment); + + // A S S E R T + $this->assertIsArray($result); + + // Since Segment uses SoftDeletes, check if it's still in DB but trashed + $this->assertSoftDeleted('segments', [ + 'id' => $segment->id, + ]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/FetchesConstantTest.php b/tests/Unit/Modules/Segments/Services/FetchesConstantTest.php new file mode 100644 index 00000000..213fe45e --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/FetchesConstantTest.php @@ -0,0 +1,94 @@ +name = 'test_it_can_fetch_a_segment_constant_by_id_SEG'; + $segment->save(); + + $constant = new SegmentConstant(); + $constant->segment_id = $segment->id; + $constant->name = 'test_it_can_fetch_a_segment_constant_by_id_CON'; + $constant->reference = 'test_it_can_fetch_a_segment_constant_by_id_REF'; + $constant->detail = (object) ['foo' => 'bar']; + $constant->save(); + + $service = new FetchesConstant(new SegmentConstant()); + + // A C T + $result = $service->execute(['id' => $constant->id]); + + // A S S E R T + $this->assertInstanceOf(SegmentConstant::class, $result); + $this->assertEquals($constant->id, $result->id); + } + + /** + * Test it can fetch a segment constant by reference. + * + * @return void + */ + public function test_it_can_fetch_a_segment_constant_by_reference() + { + // A R R A N G E + $segment = new Segment(); + $segment->name = 'test_it_can_fetch_a_segment_constant_by_reference_SEG'; + $segment->save(); + + $constant = new SegmentConstant(); + $constant->segment_id = $segment->id; + $constant->name = 'test_it_can_fetch_a_segment_constant_by_reference_CON'; + $constant->reference = 'test_it_can_fetch_a_segment_constant_by_reference_REF'; + $constant->detail = (object) ['foo' => 'bar']; + $constant->save(); + + $service = new FetchesConstant(new SegmentConstant()); + + // A C T + $result = $service->execute(['reference' => 'test_it_can_fetch_a_segment_constant_by_reference_REF']); + + // A S S E R T + $this->assertInstanceOf(SegmentConstant::class, $result); + $this->assertEquals($constant->id, $result->id); + } + + /** + * Test it throws exception if constant not found. + * + * @return void + */ + public function test_it_throws_exception_if_constant_not_found() + { + // A R R A N G E + $service = new FetchesConstant(new SegmentConstant()); + + // A S S E R T + $this->expectException(ResourceNotFoundException::class); + + // A C T + $service->execute(['id' => 99999]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/FetchesSegmentTest.php b/tests/Unit/Modules/Segments/Services/FetchesSegmentTest.php new file mode 100644 index 00000000..58ad574b --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/FetchesSegmentTest.php @@ -0,0 +1,80 @@ +name = 'test_it_can_fetch_a_segment_by_id'; + $segment->save(); + + $service = new FetchesSegment(new Segment()); + + // A C T + $result = $service->execute(['id' => $segment->id]); + + // A S S E R T + $this->assertInstanceOf(Segment::class, $result); + $this->assertEquals($segment->id, $result->id); + $this->assertEquals('test_it_can_fetch_a_segment_by_id', $result->name); + } + + /** + * Test it can fetch a segment by name. + * + * @return void + */ + public function test_it_can_fetch_a_segment_by_name() + { + // A R R A N G E + $segment = new Segment(); + $segment->name = 'test_it_can_fetch_a_segment_by_name'; + $segment->save(); + + $service = new FetchesSegment(new Segment()); + + // A C T + $result = $service->execute(['name' => 'test_it_can_fetch_a_segment_by_name']); + + // A S S E R T + $this->assertInstanceOf(Segment::class, $result); + $this->assertEquals($segment->id, $result->id); + } + + /** + * Test it throws exception if segment not found. + * + * @return void + */ + public function test_it_throws_exception_if_segment_not_found() + { + // A R R A N G E + $service = new FetchesSegment(new Segment()); + + // A S S E R T + $this->expectException(ResourceNotFoundException::class); + + // A C T + $service->execute(['id' => 99999]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/ListsConstantsTest.php b/tests/Unit/Modules/Segments/Services/ListsConstantsTest.php new file mode 100644 index 00000000..38a5e8b0 --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/ListsConstantsTest.php @@ -0,0 +1,102 @@ +delete(); // Clear existing + + $segment = new Segment(); + $segment->name = 'test_it_can_list_segment_constants_SEG'; + $segment->save(); + + $c1 = new SegmentConstant(); + $c1->segment_id = $segment->id; + $c1->name = 'test_it_can_list_segment_constants_A'; + $c1->reference = 'test_it_can_list_segment_constants_REF_A'; + $c1->detail = (object) ['foo' => 'bar']; + $c1->save(); + + $c2 = new SegmentConstant(); + $c2->segment_id = $segment->id; + $c2->name = 'test_it_can_list_segment_constants_B'; + $c2->reference = 'test_it_can_list_segment_constants_REF_B'; + $c2->detail = (object) ['foo' => 'bar']; + $c2->save(); + + $service = new ListsConstants(new SegmentConstant()); + + // A C T + $result = $service->execute(); + + // A S S E R T + $this->assertInstanceOf(Collection::class, $result); + $this->assertCount(2, $result); + $this->assertTrue($result->contains('name', 'test_it_can_list_segment_constants_A')); + $this->assertTrue($result->contains('name', 'test_it_can_list_segment_constants_B')); + } + + /** + * Test it can list segment constants with filters. + * + * @return void + */ + public function test_it_can_filter_segment_constants_by_segment_id() + { + // A R R A N G E + SegmentConstant::query()->delete(); + + $segment1 = new Segment(); + $segment1->name = 'test_it_can_filter_segment_constants_by_segment_id_SEG1'; + $segment1->save(); + + $segment2 = new Segment(); + $segment2->name = 'test_it_can_filter_segment_constants_by_segment_id_SEG2'; + $segment2->save(); + + $c1 = new SegmentConstant(); + $c1->segment_id = $segment1->id; + $c1->name = 'test_it_can_filter_segment_constants_by_segment_id_C1'; + $c1->reference = 'test_it_can_filter_segment_constants_by_segment_id_REF1'; + $c1->detail = (object) ['foo' => 'bar']; + $c1->save(); + + $c2 = new SegmentConstant(); + $c2->segment_id = $segment2->id; + $c2->name = 'test_it_can_filter_segment_constants_by_segment_id_C2'; + $c2->reference = 'test_it_can_filter_segment_constants_by_segment_id_REF2'; + $c2->detail = (object) ['foo' => 'bar']; + $c2->save(); + + $service = new ListsConstants(new SegmentConstant()); + + // A C T + $result = $service->execute(['segment_id' => $segment1->id]); + + // A S S E R T + $this->assertCount(1, $result); + $this->assertEquals('test_it_can_filter_segment_constants_by_segment_id_REF1', $result->first()->reference); + } +} diff --git a/tests/Unit/Modules/Segments/Services/ListsSegmentsTest.php b/tests/Unit/Modules/Segments/Services/ListsSegmentsTest.php new file mode 100644 index 00000000..59bf6b7d --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/ListsSegmentsTest.php @@ -0,0 +1,76 @@ +delete(); // Clear existing + + $segment1 = new Segment(); + $segment1->name = 'test_it_can_list_segments_1'; + $segment1->save(); + + $segment2 = new Segment(); + $segment2->name = 'test_it_can_list_segments_2'; + $segment2->save(); + + $service = new ListsSegments(new Segment()); + + // A C T + $result = $service->execute(); + + // A S S E R T + $this->assertInstanceOf(Collection::class, $result); + $this->assertCount(2, $result); + $this->assertTrue($result->contains('name', 'test_it_can_list_segments_1')); + $this->assertTrue($result->contains('name', 'test_it_can_list_segments_2')); + } + + /** + * Test it can list segments with pagination. + * + * @return void + */ + public function test_it_can_paginate_segments() + { + // A R R A N G E + Segment::query()->delete(); + + for ($i = 1; $i <= 5; $i++) { + $s = new Segment(); + $s->name = "test_it_can_paginate_segments_$i"; + $s->save(); + } + + $service = new ListsSegments(new Segment()); + + // A C T + $result = $service->execute(['per_page' => 2]); + + // A S S E R T + $this->assertInstanceOf(LengthAwarePaginator::class, $result); + $this->assertEquals(2, $result->perPage()); + $this->assertEquals(5, $result->total()); + } +} diff --git a/tests/Unit/Modules/Segments/Services/UpdatesConstantTest.php b/tests/Unit/Modules/Segments/Services/UpdatesConstantTest.php new file mode 100644 index 00000000..04cda524 --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/UpdatesConstantTest.php @@ -0,0 +1,60 @@ +name = 'test_it_can_update_a_segment_constant_SEG'; + $segment->save(); + + $constant = new SegmentConstant(); + $constant->segment_id = $segment->id; + $constant->name = 'test_it_can_update_a_segment_constant_OLD'; + $constant->reference = 'old-reference'; + $constant->detail = (object) ['old' => 'detail']; + $constant->save(); + + $newDetail = ['new' => 'detail']; + $object = new ConstantObject('test_it_can_update_a_segment_constant_NEW', 'test_it_can_update_a_segment_constant_REF', $newDetail); + $service = new UpdatesConstant(); + + // A C T + $result = $service->execute($constant, $object); + + // A S S E R T + $this->assertInstanceOf(SegmentConstant::class, $result); + $this->assertEquals('test_it_can_update_a_segment_constant_NEW', $result->name); + $this->assertEquals('test_it_can_update_a_segment_constant_REF', $result->reference); + $this->assertEquals((object) $newDetail, $result->detail); + $this->assertEquals($constant->id, $result->id); + + $this->assertDatabaseHas('segment_constants', [ + 'id' => $constant->id, + 'name' => 'test_it_can_update_a_segment_constant_NEW', + 'reference' => 'test_it_can_update_a_segment_constant_REF', + ]); + } +} diff --git a/tests/Unit/Modules/Segments/Services/UpdatesSegmentTest.php b/tests/Unit/Modules/Segments/Services/UpdatesSegmentTest.php new file mode 100644 index 00000000..d26a55fa --- /dev/null +++ b/tests/Unit/Modules/Segments/Services/UpdatesSegmentTest.php @@ -0,0 +1,49 @@ +name = 'test_it_can_update_a_segment_ORIGINAL'; + $segment->save(); + + $newName = 'test_it_can_update_a_segment_UPDATED'; + $object = new SegmentObject($newName); + $service = new UpdatesSegment(); + + // A C T + $result = $service->execute($segment, $object); + + // A S S E R T + $this->assertInstanceOf(Segment::class, $result); + $this->assertEquals($newName, $result->name); + $this->assertEquals($segment->id, $result->id); + + $this->assertDatabaseHas('segments', [ + 'id' => $segment->id, + 'name' => $newName, + ]); + } +} diff --git a/vapor.yml b/vapor.yml index 2ed0397a..570c2890 100644 --- a/vapor.yml +++ b/vapor.yml @@ -61,3 +61,21 @@ environments: - 'gulp build' deploy: - 'php artisan migrate --force' + test: + memory: 1024 + cli-memory: 512 + queues: + - exchange-default-test + - exchange-high_priority-test + database: cief-amazon-rds-mysql + storage: exchange-2.0-test + runtime: 'docker' + timeout: 180 + build: + - 'composer update' + - 'npm install' + - 'npm run dev' + - 'gulp build' + deploy: + - 'php artisan migrate --force' +