From 0ce88ab817ed69cf29e3f1b13ac79153b1e14698 Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski Date: Fri, 3 Apr 2026 15:37:22 +0200 Subject: [PATCH] Remove app/Space folder and extract model business logic into services Relocate all 14 files from the catch-all app/Space namespace into proper locations: data providers to Support/Formatters, installation utilities to Services/Installation, PDF utils to Services/Pdf, module/update classes to Services/Module and Services/Update, SiteApi trait to Traits, and helpers to Support. Extract ~1,400 lines of business logic from 8 fat models (Invoice, Payment, Estimate, RecurringInvoice, Company, Customer, Expense, User) into 9 new service classes with constructor injection. Controllers now depend on services instead of calling static model methods. Shared item/tax creation logic consolidated into DocumentItemService. --- .../Commands/CreateTemplateCommand.php | 2 +- app/Console/Commands/InstallModuleCommand.php | 2 +- app/Console/Commands/UpdateCommand.php | 2 +- .../V1/Admin/Company/CompaniesController.php | 9 +- .../V1/Admin/Customer/CustomersController.php | 15 +- .../Estimate/EstimateTemplatesController.php | 2 +- .../V1/Admin/Estimate/EstimatesController.php | 11 +- .../Admin/Estimate/SendEstimateController.php | 7 +- .../SendEstimatePreviewController.php | 7 +- .../V1/Admin/Expense/ExpensesController.php | 9 +- .../Admin/General/DateFormatsController.php | 2 +- .../Admin/General/TimeFormatsController.php | 2 +- .../V1/Admin/General/TimezonesController.php | 2 +- .../Invoice/InvoiceTemplatesController.php | 2 +- .../V1/Admin/Invoice/InvoicesController.php | 17 +- .../Admin/Invoice/SendInvoiceController.php | 7 +- .../Invoice/SendInvoicePreviewController.php | 7 +- .../V1/Admin/Modules/ApiTokenController.php | 2 +- .../CompleteModuleInstallationController.php | 2 +- .../V1/Admin/Modules/CopyModuleController.php | 2 +- .../Modules/DownloadModuleController.php | 2 +- .../V1/Admin/Modules/ModuleController.php | 2 +- .../V1/Admin/Modules/ModulesController.php | 2 +- .../Admin/Modules/UnzipModuleController.php | 2 +- .../Admin/Modules/UploadModuleController.php | 2 +- .../V1/Admin/Payment/PaymentsController.php | 11 +- .../Admin/Payment/SendPaymentController.php | 7 +- .../Payment/SendPaymentPreviewController.php | 7 +- .../RecurringInvoiceController.php | 11 +- .../Settings/MailConfigurationController.php | 2 +- .../Settings/PDFConfigurationController.php | 2 +- .../Admin/Update/CheckVersionController.php | 2 +- .../V1/Admin/Update/CopyFilesController.php | 2 +- .../V1/Admin/Update/DeleteFilesController.php | 2 +- .../Admin/Update/DownloadUpdateController.php | 2 +- .../Admin/Update/FinishUpdateController.php | 2 +- .../Admin/Update/MigrateUpdateController.php | 2 +- .../V1/Admin/Update/UnzipUpdateController.php | 2 +- .../V1/Admin/Update/UpdateController.php | 2 +- .../V1/Admin/Users/UsersController.php | 13 +- .../V1/Installation/AppDomainController.php | 2 +- .../DatabaseConfigurationController.php | 4 +- .../FilePermissionsController.php | 2 +- .../OnboardingWizardController.php | 2 +- .../Installation/RequirementsController.php | 2 +- .../V1/PDF/EstimatePdfController.php | 7 +- .../V1/PDF/InvoicePdfController.php | 7 +- app/Http/Middleware/ConfigMiddleware.php | 2 +- .../Middleware/InstallationMiddleware.php | 2 +- app/Http/Middleware/RedirectIfInstalled.php | 2 +- app/Jobs/CreateBackupJob.php | 2 +- app/Models/Company.php | 223 ------------- app/Models/Customer.php | 108 ------ app/Models/Estimate.php | 232 +------------ app/Models/Expense.php | 48 --- app/Models/Invoice.php | 309 +----------------- app/Models/Payment.php | 212 +----------- app/Models/RecurringInvoice.php | 224 ------------- app/Models/User.php | 81 ----- app/Providers/AppConfigProvider.php | 2 +- app/Providers/AppServiceProvider.php | 2 +- .../Backup}/BackupConfigurationFactory.php | 2 +- app/Services/CompanyService.php | 236 +++++++++++++ app/Services/CustomerService.php | 120 +++++++ app/Services/DocumentItemService.php | 69 ++++ app/Services/EstimateService.php | 202 ++++++++++++ app/Services/ExpenseService.php | 59 ++++ .../Installation}/EnvironmentManager.php | 2 +- .../Installation}/FilePermissionChecker.php | 2 +- .../Installation}/InstallUtils.php | 2 +- .../Installation}/RequirementsChecker.php | 2 +- app/Services/InvoiceService.php | 267 +++++++++++++++ .../Module}/ModuleInstaller.php | 3 +- app/Services/PaymentService.php | 222 +++++++++++++ app/{Space => Services/Pdf}/ImageUtils.php | 2 +- .../Pdf}/PdfTemplateUtils.php | 2 +- app/Services/RecurringInvoiceService.php | 237 ++++++++++++++ app/{Space => Services/Update}/Updater.php | 3 +- app/Services/UserService.php | 90 +++++ .../Formatters}/DateFormatter.php | 2 +- .../Formatters}/TimeFormatter.php | 2 +- .../Formatters}/TimeZones.php | 2 +- app/{Space => Support}/helpers.php | 2 +- app/{Space => Traits}/SiteApi.php | 2 +- composer.json | 2 +- database/seeders/DemoSeeder.php | 3 +- database/seeders/UsersTableSeeder.php | 5 +- .../app/pdf/estimate/estimate1.blade.php | 2 +- .../app/pdf/estimate/estimate2.blade.php | 2 +- .../app/pdf/estimate/estimate3.blade.php | 2 +- .../views/app/pdf/invoice/invoice1.blade.php | 2 +- .../views/app/pdf/invoice/invoice2.blade.php | 2 +- .../views/app/pdf/invoice/invoice3.blade.php | 2 +- .../views/app/pdf/payment/payment.blade.php | 2 +- routes/console.php | 5 +- tests/Feature/Admin/EstimateTest.php | 2 +- tests/Unit/EstimateTest.php | 19 +- tests/Unit/InvoiceTest.php | 19 +- 98 files changed, 1703 insertions(+), 1563 deletions(-) rename app/{Space => Services/Backup}/BackupConfigurationFactory.php (97%) create mode 100644 app/Services/CompanyService.php create mode 100644 app/Services/CustomerService.php create mode 100644 app/Services/DocumentItemService.php create mode 100644 app/Services/EstimateService.php create mode 100644 app/Services/ExpenseService.php rename app/{Space => Services/Installation}/EnvironmentManager.php (99%) rename app/{Space => Services/Installation}/FilePermissionChecker.php (97%) rename app/{Space => Services/Installation}/InstallUtils.php (96%) rename app/{Space => Services/Installation}/RequirementsChecker.php (99%) create mode 100644 app/Services/InvoiceService.php rename app/{Space => Services/Module}/ModuleInstaller.php (99%) create mode 100644 app/Services/PaymentService.php rename app/{Space => Services/Pdf}/ImageUtils.php (92%) rename app/{Space => Services/Pdf}/PdfTemplateUtils.php (99%) create mode 100644 app/Services/RecurringInvoiceService.php rename app/{Space => Services/Update}/Updater.php (98%) create mode 100644 app/Services/UserService.php rename app/{Space => Support/Formatters}/DateFormatter.php (97%) rename app/{Space => Support/Formatters}/TimeFormatter.php (95%) rename app/{Space => Support/Formatters}/TimeZones.php (99%) rename app/{Space => Support}/helpers.php (98%) rename app/{Space => Traits}/SiteApi.php (97%) diff --git a/app/Console/Commands/CreateTemplateCommand.php b/app/Console/Commands/CreateTemplateCommand.php index 18c2b5b0..487865a7 100644 --- a/app/Console/Commands/CreateTemplateCommand.php +++ b/app/Console/Commands/CreateTemplateCommand.php @@ -2,7 +2,7 @@ namespace App\Console\Commands; -use App\Space\PdfTemplateUtils; +use App\Services\Pdf\PdfTemplateUtils; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Storage; diff --git a/app/Console/Commands/InstallModuleCommand.php b/app/Console/Commands/InstallModuleCommand.php index a55e70cc..f66dd444 100644 --- a/app/Console/Commands/InstallModuleCommand.php +++ b/app/Console/Commands/InstallModuleCommand.php @@ -2,7 +2,7 @@ namespace App\Console\Commands; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Console\Command; class InstallModuleCommand extends Command diff --git a/app/Console/Commands/UpdateCommand.php b/app/Console/Commands/UpdateCommand.php index 7d6a57a5..15f24c1d 100644 --- a/app/Console/Commands/UpdateCommand.php +++ b/app/Console/Commands/UpdateCommand.php @@ -2,7 +2,7 @@ namespace App\Console\Commands; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; diff --git a/app/Http/Controllers/V1/Admin/Company/CompaniesController.php b/app/Http/Controllers/V1/Admin/Company/CompaniesController.php index 77964d5d..5873a9c3 100644 --- a/app/Http/Controllers/V1/Admin/Company/CompaniesController.php +++ b/app/Http/Controllers/V1/Admin/Company/CompaniesController.php @@ -8,11 +8,16 @@ use App\Http\Requests\CompaniesRequest; use App\Http\Resources\CompanyResource; use App\Models\Company; use App\Models\User; +use App\Services\CompanyService; use Illuminate\Http\Request; use Silber\Bouncer\BouncerFacade; class CompaniesController extends Controller { + public function __construct( + private readonly CompanyService $companyService, + ) {} + public function store(CompaniesRequest $request) { $this->authorize('create company'); @@ -22,7 +27,7 @@ class CompaniesController extends Controller $company = Company::create($request->getCompanyPayload()); $company->unique_hash = Hashids::connection(Company::class)->encode($company->id); $company->save(); - $company->setupDefaultData(); + $this->companyService->setupDefaults($company); $user->companies()->attach($company->id); $user->assign('super admin'); @@ -49,7 +54,7 @@ class CompaniesController extends Controller return respondJson('You_cannot_delete_all_companies', 'You cannot delete all companies'); } - $company->deleteCompany($user); + $this->companyService->delete($company, $user); return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/V1/Admin/Customer/CustomersController.php b/app/Http/Controllers/V1/Admin/Customer/CustomersController.php index 3dbe5846..1a3bb8a6 100644 --- a/app/Http/Controllers/V1/Admin/Customer/CustomersController.php +++ b/app/Http/Controllers/V1/Admin/Customer/CustomersController.php @@ -7,11 +7,16 @@ use App\Http\Requests; use App\Http\Requests\DeleteCustomersRequest; use App\Http\Resources\CustomerResource; use App\Models\Customer; +use App\Services\CustomerService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class CustomersController extends Controller { + public function __construct( + private readonly CustomerService $customerService, + ) {} + /** * Display a listing of the resource. * @@ -46,7 +51,7 @@ class CustomersController extends Controller { $this->authorize('create', Customer::class); - $customer = Customer::createCustomer($request); + $customer = $this->customerService->create($request); return new CustomerResource($customer); } @@ -73,11 +78,7 @@ class CustomersController extends Controller { $this->authorize('update', $customer); - $customer = Customer::updateCustomer($request, $customer); - - if (is_string($customer)) { - return respondJson('you_cannot_edit_currency', 'Cannot change currency once transactions created'); - } + $customer = $this->customerService->update($request, $customer); return new CustomerResource($customer); } @@ -96,7 +97,7 @@ class CustomersController extends Controller ->whereIn('id', $request->ids) ->pluck('id'); - Customer::deleteCustomers($ids); + $this->customerService->delete($ids); return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/V1/Admin/Estimate/EstimateTemplatesController.php b/app/Http/Controllers/V1/Admin/Estimate/EstimateTemplatesController.php index d76cedd4..230fcc43 100644 --- a/app/Http/Controllers/V1/Admin/Estimate/EstimateTemplatesController.php +++ b/app/Http/Controllers/V1/Admin/Estimate/EstimateTemplatesController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Estimate; use App\Http\Controllers\Controller; use App\Models\Estimate; -use App\Space\PdfTemplateUtils; +use App\Services\Pdf\PdfTemplateUtils; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php b/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php index fabd2a17..2a9cf6a5 100644 --- a/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php +++ b/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php @@ -8,10 +8,15 @@ use App\Http\Requests\EstimatesRequest; use App\Http\Resources\EstimateResource; use App\Jobs\GenerateEstimatePdfJob; use App\Models\Estimate; +use App\Services\EstimateService; use Illuminate\Http\Request; class EstimatesController extends Controller { + public function __construct( + private readonly EstimateService $estimateService, + ) {} + public function index(Request $request) { $this->authorize('viewAny', Estimate::class); @@ -35,10 +40,10 @@ class EstimatesController extends Controller { $this->authorize('create', Estimate::class); - $estimate = Estimate::createEstimate($request); + $estimate = $this->estimateService->create($request); if ($request->has('estimateSend')) { - $estimate->send($request->title, $request->body); + $this->estimateService->send($estimate, $request->only(['title', 'body'])); } GenerateEstimatePdfJob::dispatch($estimate); @@ -57,7 +62,7 @@ class EstimatesController extends Controller { $this->authorize('update', $estimate); - $estimate = $estimate->updateEstimate($request); + $estimate = $this->estimateService->update($estimate, $request); GenerateEstimatePdfJob::dispatch($estimate, true); diff --git a/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php b/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php index e0c04cac..69cb12bb 100644 --- a/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php +++ b/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php @@ -5,10 +5,15 @@ namespace App\Http\Controllers\V1\Admin\Estimate; use App\Http\Controllers\Controller; use App\Http\Requests\SendEstimatesRequest; use App\Models\Estimate; +use App\Services\EstimateService; use Illuminate\Http\JsonResponse; class SendEstimateController extends Controller { + public function __construct( + private readonly EstimateService $estimateService, + ) {} + /** * Handle the incoming request. * @@ -18,7 +23,7 @@ class SendEstimateController extends Controller { $this->authorize('send estimate', $estimate); - $response = $estimate->send($request->all()); + $response = $this->estimateService->send($estimate, $request->all()); return response()->json($response); } diff --git a/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php b/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php index 2b7b4ba2..b05327c9 100644 --- a/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php +++ b/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php @@ -5,11 +5,16 @@ namespace App\Http\Controllers\V1\Admin\Estimate; use App\Http\Controllers\Controller; use App\Http\Requests\SendEstimatesRequest; use App\Models\Estimate; +use App\Services\EstimateService; use Illuminate\Http\JsonResponse; use Illuminate\Mail\Markdown; class SendEstimatePreviewController extends Controller { + public function __construct( + private readonly EstimateService $estimateService, + ) {} + /** * Handle the incoming request. * @@ -21,7 +26,7 @@ class SendEstimatePreviewController extends Controller $markdown = new Markdown(view(), config('mail.markdown')); - $data = $estimate->sendEstimateData($request->all()); + $data = $this->estimateService->sendEstimateData($estimate, $request->all()); $data['url'] = $estimate->estimatePdfUrl; return $markdown->render('emails.send.estimate', ['data' => $data]); diff --git a/app/Http/Controllers/V1/Admin/Expense/ExpensesController.php b/app/Http/Controllers/V1/Admin/Expense/ExpensesController.php index c62e8c1d..6bad574e 100644 --- a/app/Http/Controllers/V1/Admin/Expense/ExpensesController.php +++ b/app/Http/Controllers/V1/Admin/Expense/ExpensesController.php @@ -7,11 +7,16 @@ use App\Http\Requests\DeleteExpensesRequest; use App\Http\Requests\ExpenseRequest; use App\Http\Resources\ExpenseResource; use App\Models\Expense; +use App\Services\ExpenseService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class ExpensesController extends Controller { + public function __construct( + private readonly ExpenseService $expenseService, + ) {} + /** * Display a listing of the resource. * @@ -46,7 +51,7 @@ class ExpensesController extends Controller { $this->authorize('create', Expense::class); - $expense = Expense::createExpense($request); + $expense = $this->expenseService->create($request); return new ExpenseResource($expense); } @@ -72,7 +77,7 @@ class ExpensesController extends Controller { $this->authorize('update', $expense); - $expense->updateExpense($request); + $this->expenseService->update($expense, $request); return new ExpenseResource($expense); } diff --git a/app/Http/Controllers/V1/Admin/General/DateFormatsController.php b/app/Http/Controllers/V1/Admin/General/DateFormatsController.php index 90d033c3..c0b27576 100644 --- a/app/Http/Controllers/V1/Admin/General/DateFormatsController.php +++ b/app/Http/Controllers/V1/Admin/General/DateFormatsController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\General; use App\Http\Controllers\Controller; -use App\Space\DateFormatter; +use App\Support\Formatters\DateFormatter; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/General/TimeFormatsController.php b/app/Http/Controllers/V1/Admin/General/TimeFormatsController.php index 27b838d2..3ec42627 100644 --- a/app/Http/Controllers/V1/Admin/General/TimeFormatsController.php +++ b/app/Http/Controllers/V1/Admin/General/TimeFormatsController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\General; use App\Http\Controllers\Controller; -use App\Space\TimeFormatter; +use App\Support\Formatters\TimeFormatter; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/General/TimezonesController.php b/app/Http/Controllers/V1/Admin/General/TimezonesController.php index a8513425..766dfe50 100644 --- a/app/Http/Controllers/V1/Admin/General/TimezonesController.php +++ b/app/Http/Controllers/V1/Admin/General/TimezonesController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\General; use App\Http\Controllers\Controller; -use App\Space\TimeZones; +use App\Support\Formatters\TimeZones; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Invoice/InvoiceTemplatesController.php b/app/Http/Controllers/V1/Admin/Invoice/InvoiceTemplatesController.php index c618d93d..6ed4b97b 100644 --- a/app/Http/Controllers/V1/Admin/Invoice/InvoiceTemplatesController.php +++ b/app/Http/Controllers/V1/Admin/Invoice/InvoiceTemplatesController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Invoice; use App\Http\Controllers\Controller; use App\Models\Invoice; -use App\Space\PdfTemplateUtils; +use App\Services\Pdf\PdfTemplateUtils; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php b/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php index 630d4736..e95078fb 100644 --- a/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php +++ b/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php @@ -8,11 +8,16 @@ use App\Http\Requests\DeleteInvoiceRequest; use App\Http\Resources\InvoiceResource; use App\Jobs\GenerateInvoicePdfJob; use App\Models\Invoice; +use App\Services\InvoiceService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class InvoicesController extends Controller { + public function __construct( + private readonly InvoiceService $invoiceService, + ) {} + /** * Display a listing of the resource. * @@ -46,10 +51,10 @@ class InvoicesController extends Controller { $this->authorize('create', Invoice::class); - $invoice = Invoice::createInvoice($request); + $invoice = $this->invoiceService->create($request); if ($request->has('invoiceSend')) { - $invoice->send($request->subject, $request->body); + $this->invoiceService->send($invoice, $request->only(['subject', 'body'])); } GenerateInvoicePdfJob::dispatch($invoice); @@ -79,11 +84,7 @@ class InvoicesController extends Controller { $this->authorize('update', $invoice); - $invoice = $invoice->updateInvoice($request); - - if (is_string($invoice)) { - return respondJson($invoice, $invoice); - } + $invoice = $this->invoiceService->update($invoice, $request); GenerateInvoicePdfJob::dispatch($invoice, true); @@ -104,7 +105,7 @@ class InvoicesController extends Controller ->whereIn('id', $request->ids) ->pluck('id'); - Invoice::deleteInvoices($ids); + $this->invoiceService->delete($ids); return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php b/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php index 36d952a7..a26d5e70 100644 --- a/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php +++ b/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php @@ -5,11 +5,16 @@ namespace App\Http\Controllers\V1\Admin\Invoice; use App\Http\Controllers\Controller; use App\Http\Requests\SendInvoiceRequest; use App\Models\Invoice; +use App\Services\InvoiceService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class SendInvoiceController extends Controller { + public function __construct( + private readonly InvoiceService $invoiceService, + ) {} + /** * Mail a specific invoice to the corresponding customer's email address. * @@ -20,7 +25,7 @@ class SendInvoiceController extends Controller { $this->authorize('send invoice', $invoice); - $invoice->send($request->all()); + $this->invoiceService->send($invoice, $request->all()); return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php b/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php index 8293b28b..e4eac342 100644 --- a/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php +++ b/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php @@ -5,12 +5,17 @@ namespace App\Http\Controllers\V1\Admin\Invoice; use App\Http\Controllers\Controller; use App\Http\Requests\SendInvoiceRequest; use App\Models\Invoice; +use App\Services\InvoiceService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Mail\Markdown; class SendInvoicePreviewController extends Controller { + public function __construct( + private readonly InvoiceService $invoiceService, + ) {} + /** * Mail a specific invoice to the corresponding customer's email address. * @@ -23,7 +28,7 @@ class SendInvoicePreviewController extends Controller $markdown = new Markdown(view(), config('mail.markdown')); - $data = $invoice->sendInvoiceData($request->all()); + $data = $this->invoiceService->sendInvoiceData($invoice, $request->all()); $data['url'] = $invoice->invoicePdfUrl; return $markdown->render('emails.send.invoice', ['data' => $data]); diff --git a/app/Http/Controllers/V1/Admin/Modules/ApiTokenController.php b/app/Http/Controllers/V1/Admin/Modules/ApiTokenController.php index 3512a1f0..003b8f73 100644 --- a/app/Http/Controllers/V1/Admin/Modules/ApiTokenController.php +++ b/app/Http/Controllers/V1/Admin/Modules/ApiTokenController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Modules/CompleteModuleInstallationController.php b/app/Http/Controllers/V1/Admin/Modules/CompleteModuleInstallationController.php index 38b6a379..16757917 100644 --- a/app/Http/Controllers/V1/Admin/Modules/CompleteModuleInstallationController.php +++ b/app/Http/Controllers/V1/Admin/Modules/CompleteModuleInstallationController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Modules/CopyModuleController.php b/app/Http/Controllers/V1/Admin/Modules/CopyModuleController.php index a4e0d5fa..2fefdf93 100644 --- a/app/Http/Controllers/V1/Admin/Modules/CopyModuleController.php +++ b/app/Http/Controllers/V1/Admin/Modules/CopyModuleController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Modules/DownloadModuleController.php b/app/Http/Controllers/V1/Admin/Modules/DownloadModuleController.php index 60f5c8c1..c7566810 100644 --- a/app/Http/Controllers/V1/Admin/Modules/DownloadModuleController.php +++ b/app/Http/Controllers/V1/Admin/Modules/DownloadModuleController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Modules/ModuleController.php b/app/Http/Controllers/V1/Admin/Modules/ModuleController.php index f9cc5015..777f2ff0 100644 --- a/app/Http/Controllers/V1/Admin/Modules/ModuleController.php +++ b/app/Http/Controllers/V1/Admin/Modules/ModuleController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; use App\Http\Resources\ModuleResource; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Modules/ModulesController.php b/app/Http/Controllers/V1/Admin/Modules/ModulesController.php index 984dbfdd..c6ab728c 100644 --- a/app/Http/Controllers/V1/Admin/Modules/ModulesController.php +++ b/app/Http/Controllers/V1/Admin/Modules/ModulesController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Modules/UnzipModuleController.php b/app/Http/Controllers/V1/Admin/Modules/UnzipModuleController.php index 2d4063c8..31de858f 100644 --- a/app/Http/Controllers/V1/Admin/Modules/UnzipModuleController.php +++ b/app/Http/Controllers/V1/Admin/Modules/UnzipModuleController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; use App\Http\Requests\UnzipUpdateRequest; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Response; class UnzipModuleController extends Controller diff --git a/app/Http/Controllers/V1/Admin/Modules/UploadModuleController.php b/app/Http/Controllers/V1/Admin/Modules/UploadModuleController.php index 6d143898..d47e6259 100644 --- a/app/Http/Controllers/V1/Admin/Modules/UploadModuleController.php +++ b/app/Http/Controllers/V1/Admin/Modules/UploadModuleController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Modules; use App\Http\Controllers\Controller; use App\Http\Requests\UploadModuleRequest; -use App\Space\ModuleInstaller; +use App\Services\Module\ModuleInstaller; use Illuminate\Http\Response; class UploadModuleController extends Controller diff --git a/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php b/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php index ee6d0ff7..5aaeb461 100644 --- a/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php +++ b/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php @@ -7,11 +7,16 @@ use App\Http\Requests\DeletePaymentsRequest; use App\Http\Requests\PaymentRequest; use App\Http\Resources\PaymentResource; use App\Models\Payment; +use App\Services\PaymentService; use Illuminate\Http\Request; use Illuminate\Http\Response; class PaymentsController extends Controller { + public function __construct( + private readonly PaymentService $paymentService, + ) {} + /** * Display a listing of the resource. * @@ -48,7 +53,7 @@ class PaymentsController extends Controller { $this->authorize('create', Payment::class); - $payment = Payment::createPayment($request); + $payment = $this->paymentService->create($request); return new PaymentResource($payment); } @@ -64,7 +69,7 @@ class PaymentsController extends Controller { $this->authorize('update', $payment); - $payment = $payment->updatePayment($request); + $payment = $this->paymentService->update($payment, $request); return new PaymentResource($payment); } @@ -77,7 +82,7 @@ class PaymentsController extends Controller ->whereIn('id', $request->ids) ->pluck('id'); - Payment::deletePayments($ids); + $this->paymentService->delete($ids); return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php b/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php index 095cdc7a..e9db7617 100644 --- a/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php +++ b/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php @@ -5,11 +5,16 @@ namespace App\Http\Controllers\V1\Admin\Payment; use App\Http\Controllers\Controller; use App\Http\Requests\SendPaymentRequest; use App\Models\Payment; +use App\Services\PaymentService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class SendPaymentController extends Controller { + public function __construct( + private readonly PaymentService $paymentService, + ) {} + /** * Handle the incoming request. * @@ -20,7 +25,7 @@ class SendPaymentController extends Controller { $this->authorize('send payment', $payment); - $response = $payment->send($request->all()); + $response = $this->paymentService->send($payment, $request->all()); return response()->json($response); } diff --git a/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php b/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php index a4585d4e..6fcd3832 100644 --- a/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php +++ b/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php @@ -4,12 +4,17 @@ namespace App\Http\Controllers\V1\Admin\Payment; use App\Http\Controllers\Controller; use App\Models\Payment; +use App\Services\PaymentService; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Mail\Markdown; class SendPaymentPreviewController extends Controller { + public function __construct( + private readonly PaymentService $paymentService, + ) {} + /** * Handle the incoming request. * @@ -21,7 +26,7 @@ class SendPaymentPreviewController extends Controller $markdown = new Markdown(view(), config('mail.markdown')); - $data = $payment->sendPaymentData($request->all()); + $data = $this->paymentService->sendPaymentData($payment, $request->all()); $data['url'] = $payment->paymentPdfUrl; return $markdown->render('emails.send.payment', ['data' => $data]); diff --git a/app/Http/Controllers/V1/Admin/RecurringInvoice/RecurringInvoiceController.php b/app/Http/Controllers/V1/Admin/RecurringInvoice/RecurringInvoiceController.php index e3becd7b..7a7f18ca 100644 --- a/app/Http/Controllers/V1/Admin/RecurringInvoice/RecurringInvoiceController.php +++ b/app/Http/Controllers/V1/Admin/RecurringInvoice/RecurringInvoiceController.php @@ -6,11 +6,16 @@ use App\Http\Controllers\Controller; use App\Http\Requests\RecurringInvoiceRequest; use App\Http\Resources\RecurringInvoiceResource; use App\Models\RecurringInvoice; +use App\Services\RecurringInvoiceService; use Illuminate\Http\Request; use Illuminate\Http\Response; class RecurringInvoiceController extends Controller { + public function __construct( + private readonly RecurringInvoiceService $recurringInvoiceService, + ) {} + /** * Display a listing of the resource. * @@ -42,7 +47,7 @@ class RecurringInvoiceController extends Controller { $this->authorize('create', RecurringInvoice::class); - $recurringInvoice = RecurringInvoice::createFromRequest($request); + $recurringInvoice = $this->recurringInvoiceService->create($request); return new RecurringInvoiceResource($recurringInvoice); } @@ -69,7 +74,7 @@ class RecurringInvoiceController extends Controller { $this->authorize('update', $recurringInvoice); - $recurringInvoice->updateFromRequest($request); + $this->recurringInvoiceService->update($recurringInvoice, $request); return new RecurringInvoiceResource($recurringInvoice); } @@ -88,7 +93,7 @@ class RecurringInvoiceController extends Controller ->whereIn('id', $request->ids) ->pluck('id'); - RecurringInvoice::deleteRecurringInvoice($ids); + $this->recurringInvoiceService->delete($ids); return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/V1/Admin/Settings/MailConfigurationController.php b/app/Http/Controllers/V1/Admin/Settings/MailConfigurationController.php index 0be5349e..80e0528b 100755 --- a/app/Http/Controllers/V1/Admin/Settings/MailConfigurationController.php +++ b/app/Http/Controllers/V1/Admin/Settings/MailConfigurationController.php @@ -6,7 +6,7 @@ use App\Http\Controllers\Controller; use App\Http\Requests\MailEnvironmentRequest; use App\Mail\TestMail; use App\Models\Setting; -use App\Space\EnvironmentManager; +use App\Services\Installation\EnvironmentManager; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/V1/Admin/Settings/PDFConfigurationController.php b/app/Http/Controllers/V1/Admin/Settings/PDFConfigurationController.php index cf520cb9..9e713684 100644 --- a/app/Http/Controllers/V1/Admin/Settings/PDFConfigurationController.php +++ b/app/Http/Controllers/V1/Admin/Settings/PDFConfigurationController.php @@ -5,7 +5,7 @@ namespace App\Http\Controllers\V1\Admin\Settings; use App\Http\Controllers\Controller; use App\Http\Requests\PDFConfigurationRequest; use App\Models\Setting; -use App\Space\EnvironmentManager; +use App\Services\Installation\EnvironmentManager; class PDFConfigurationController extends Controller { diff --git a/app/Http/Controllers/V1/Admin/Update/CheckVersionController.php b/app/Http/Controllers/V1/Admin/Update/CheckVersionController.php index d39ceefd..851fbf9a 100644 --- a/app/Http/Controllers/V1/Admin/Update/CheckVersionController.php +++ b/app/Http/Controllers/V1/Admin/Update/CheckVersionController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\File; diff --git a/app/Http/Controllers/V1/Admin/Update/CopyFilesController.php b/app/Http/Controllers/V1/Admin/Update/CopyFilesController.php index ec107d11..cde80d4e 100644 --- a/app/Http/Controllers/V1/Admin/Update/CopyFilesController.php +++ b/app/Http/Controllers/V1/Admin/Update/CopyFilesController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Update/DeleteFilesController.php b/app/Http/Controllers/V1/Admin/Update/DeleteFilesController.php index bddd76c1..e48da5d9 100644 --- a/app/Http/Controllers/V1/Admin/Update/DeleteFilesController.php +++ b/app/Http/Controllers/V1/Admin/Update/DeleteFilesController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Update/DownloadUpdateController.php b/app/Http/Controllers/V1/Admin/Update/DownloadUpdateController.php index d24c13cc..6b99f20d 100644 --- a/app/Http/Controllers/V1/Admin/Update/DownloadUpdateController.php +++ b/app/Http/Controllers/V1/Admin/Update/DownloadUpdateController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Update/FinishUpdateController.php b/app/Http/Controllers/V1/Admin/Update/FinishUpdateController.php index f952b793..e59efeb7 100644 --- a/app/Http/Controllers/V1/Admin/Update/FinishUpdateController.php +++ b/app/Http/Controllers/V1/Admin/Update/FinishUpdateController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Update/MigrateUpdateController.php b/app/Http/Controllers/V1/Admin/Update/MigrateUpdateController.php index 69d0998f..cfc7de8f 100644 --- a/app/Http/Controllers/V1/Admin/Update/MigrateUpdateController.php +++ b/app/Http/Controllers/V1/Admin/Update/MigrateUpdateController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Update/UnzipUpdateController.php b/app/Http/Controllers/V1/Admin/Update/UnzipUpdateController.php index a33bd2fb..afa6e059 100644 --- a/app/Http/Controllers/V1/Admin/Update/UnzipUpdateController.php +++ b/app/Http/Controllers/V1/Admin/Update/UnzipUpdateController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; use Illuminate\Http\Response; diff --git a/app/Http/Controllers/V1/Admin/Update/UpdateController.php b/app/Http/Controllers/V1/Admin/Update/UpdateController.php index 8a809252..1a35e004 100644 --- a/app/Http/Controllers/V1/Admin/Update/UpdateController.php +++ b/app/Http/Controllers/V1/Admin/Update/UpdateController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Update; use App\Http\Controllers\Controller; use App\Models\Setting; -use App\Space\Updater; +use App\Services\Update\Updater; use Illuminate\Http\Request; class UpdateController extends Controller diff --git a/app/Http/Controllers/V1/Admin/Users/UsersController.php b/app/Http/Controllers/V1/Admin/Users/UsersController.php index 03eb3628..94f814d2 100644 --- a/app/Http/Controllers/V1/Admin/Users/UsersController.php +++ b/app/Http/Controllers/V1/Admin/Users/UsersController.php @@ -7,11 +7,16 @@ use App\Http\Requests\DeleteUserRequest; use App\Http\Requests\UserRequest; use App\Http\Resources\UserResource; use App\Models\User; +use App\Services\UserService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class UsersController extends Controller { + public function __construct( + private readonly UserService $userService, + ) {} + /** * Display a listing of the resource. * @@ -40,14 +45,13 @@ class UsersController extends Controller /** * Store a newly created resource in storage. * - * @param \Illuminate\Http\UserRequest $request * @return JsonResponse */ public function store(UserRequest $request) { $this->authorize('create', User::class); - $user = User::createFromRequest($request); + $user = $this->userService->create($request); return new UserResource($user); } @@ -67,14 +71,13 @@ class UsersController extends Controller /** * Update the specified resource in storage. * - * @param \Illuminate\Http\UserRequest $request * @return JsonResponse */ public function update(UserRequest $request, User $user) { $this->authorize('update', $user); - $user->updateFromRequest($request); + $this->userService->update($user, $request); return new UserResource($user); } @@ -90,7 +93,7 @@ class UsersController extends Controller $this->authorize('delete multiple users', User::class); if ($request->users) { - User::deleteUsers($request->users); + $this->userService->delete($request->users); } return response()->json([ diff --git a/app/Http/Controllers/V1/Installation/AppDomainController.php b/app/Http/Controllers/V1/Installation/AppDomainController.php index 28ddb696..45265c55 100644 --- a/app/Http/Controllers/V1/Installation/AppDomainController.php +++ b/app/Http/Controllers/V1/Installation/AppDomainController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Installation; use App\Http\Controllers\Controller; use App\Http\Requests\DomainEnvironmentRequest; -use App\Space\EnvironmentManager; +use App\Services\Installation\EnvironmentManager; use Illuminate\Support\Facades\Artisan; class AppDomainController extends Controller diff --git a/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php b/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php index 446a1e31..48906eb2 100644 --- a/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php +++ b/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php @@ -4,8 +4,8 @@ namespace App\Http\Controllers\V1\Installation; use App\Http\Controllers\Controller; use App\Http\Requests\DatabaseEnvironmentRequest; -use App\Space\EnvironmentManager; -use App\Space\InstallUtils; +use App\Services\Installation\EnvironmentManager; +use App\Services\Installation\InstallUtils; use Illuminate\Http\Request; use Illuminate\Support\Facades\Artisan; diff --git a/app/Http/Controllers/V1/Installation/FilePermissionsController.php b/app/Http/Controllers/V1/Installation/FilePermissionsController.php index 05ac6777..a6e3641e 100644 --- a/app/Http/Controllers/V1/Installation/FilePermissionsController.php +++ b/app/Http/Controllers/V1/Installation/FilePermissionsController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Installation; use App\Http\Controllers\Controller; -use App\Space\FilePermissionChecker; +use App\Services\Installation\FilePermissionChecker; use Illuminate\Http\JsonResponse; class FilePermissionsController extends Controller diff --git a/app/Http/Controllers/V1/Installation/OnboardingWizardController.php b/app/Http/Controllers/V1/Installation/OnboardingWizardController.php index 7630420c..b276ad6d 100644 --- a/app/Http/Controllers/V1/Installation/OnboardingWizardController.php +++ b/app/Http/Controllers/V1/Installation/OnboardingWizardController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\V1\Installation; use App\Http\Controllers\Controller; use App\Models\Setting; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/V1/Installation/RequirementsController.php b/app/Http/Controllers/V1/Installation/RequirementsController.php index 160af02e..dd6cea64 100755 --- a/app/Http/Controllers/V1/Installation/RequirementsController.php +++ b/app/Http/Controllers/V1/Installation/RequirementsController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\V1\Installation; use App\Http\Controllers\Controller; -use App\Space\RequirementsChecker; +use App\Services\Installation\RequirementsChecker; use Illuminate\Http\JsonResponse; class RequirementsController extends Controller diff --git a/app/Http/Controllers/V1/PDF/EstimatePdfController.php b/app/Http/Controllers/V1/PDF/EstimatePdfController.php index 1bbced69..3a08e25b 100644 --- a/app/Http/Controllers/V1/PDF/EstimatePdfController.php +++ b/app/Http/Controllers/V1/PDF/EstimatePdfController.php @@ -4,11 +4,16 @@ namespace App\Http\Controllers\V1\PDF; use App\Http\Controllers\Controller; use App\Models\Estimate; +use App\Services\EstimateService; use Illuminate\Http\Request; use Illuminate\Http\Response; class EstimatePdfController extends Controller { + public function __construct( + private readonly EstimateService $estimateService, + ) {} + /** * Handle the incoming request. * @@ -17,7 +22,7 @@ class EstimatePdfController extends Controller public function __invoke(Request $request, Estimate $estimate) { if ($request->has('preview')) { - return $estimate->getPDFData(); + return $this->estimateService->getPdfData($estimate); } return $estimate->getGeneratedPDFOrStream('estimate'); diff --git a/app/Http/Controllers/V1/PDF/InvoicePdfController.php b/app/Http/Controllers/V1/PDF/InvoicePdfController.php index 6684d8e3..f7cbfa1e 100644 --- a/app/Http/Controllers/V1/PDF/InvoicePdfController.php +++ b/app/Http/Controllers/V1/PDF/InvoicePdfController.php @@ -4,11 +4,16 @@ namespace App\Http\Controllers\V1\PDF; use App\Http\Controllers\Controller; use App\Models\Invoice; +use App\Services\InvoiceService; use Illuminate\Http\Request; use Illuminate\Http\Response; class InvoicePdfController extends Controller { + public function __construct( + private readonly InvoiceService $invoiceService, + ) {} + /** * Handle the incoming request. * @@ -17,7 +22,7 @@ class InvoicePdfController extends Controller public function __invoke(Request $request, Invoice $invoice) { if ($request->has('preview')) { - return $invoice->getPDFData(); + return $this->invoiceService->getPdfData($invoice); } return $invoice->getGeneratedPDFOrStream('invoice'); diff --git a/app/Http/Middleware/ConfigMiddleware.php b/app/Http/Middleware/ConfigMiddleware.php index bdff4b8e..4e3589ff 100644 --- a/app/Http/Middleware/ConfigMiddleware.php +++ b/app/Http/Middleware/ConfigMiddleware.php @@ -3,7 +3,7 @@ namespace App\Http\Middleware; use App\Models\FileDisk; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/app/Http/Middleware/InstallationMiddleware.php b/app/Http/Middleware/InstallationMiddleware.php index d8900199..5349b98f 100644 --- a/app/Http/Middleware/InstallationMiddleware.php +++ b/app/Http/Middleware/InstallationMiddleware.php @@ -3,7 +3,7 @@ namespace App\Http\Middleware; use App\Models\Setting; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/app/Http/Middleware/RedirectIfInstalled.php b/app/Http/Middleware/RedirectIfInstalled.php index 23cad525..a5b52a24 100644 --- a/app/Http/Middleware/RedirectIfInstalled.php +++ b/app/Http/Middleware/RedirectIfInstalled.php @@ -3,7 +3,7 @@ namespace App\Http\Middleware; use App\Models\Setting; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/app/Jobs/CreateBackupJob.php b/app/Jobs/CreateBackupJob.php index c3a24e9a..131bbe5f 100644 --- a/app/Jobs/CreateBackupJob.php +++ b/app/Jobs/CreateBackupJob.php @@ -2,7 +2,7 @@ namespace App\Jobs; -use App\Space\BackupConfigurationFactory; +use App\Services\Backup\BackupConfigurationFactory; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; diff --git a/app/Models/Company.php b/app/Models/Company.php index be3541bc..dbc324dc 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; -use Silber\Bouncer\BouncerFacade; use Silber\Bouncer\Database\Role; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; @@ -157,228 +156,6 @@ class Company extends Model implements HasMedia return $this->belongsToMany(User::class, 'user_company', 'company_id', 'user_id'); } - public function setupRoles() - { - BouncerFacade::scope()->to($this->id); - - $super_admin = BouncerFacade::role()->firstOrCreate([ - 'name' => 'super admin', - 'title' => 'Super Admin', - 'scope' => $this->id, - ]); - - foreach (config('abilities.abilities') as $ability) { - BouncerFacade::allow($super_admin)->to($ability['ability'], $ability['model']); - } - } - - public function setupDefaultPaymentMethods() - { - PaymentMethod::create(['name' => 'Cash', 'company_id' => $this->id]); - PaymentMethod::create(['name' => 'Check', 'company_id' => $this->id]); - PaymentMethod::create(['name' => 'Credit Card', 'company_id' => $this->id]); - PaymentMethod::create(['name' => 'Bank Transfer', 'company_id' => $this->id]); - } - - public function setupDefaultUnits() - { - Unit::create(['name' => 'box', 'company_id' => $this->id]); - Unit::create(['name' => 'cm', 'company_id' => $this->id]); - Unit::create(['name' => 'dz', 'company_id' => $this->id]); - Unit::create(['name' => 'ft', 'company_id' => $this->id]); - Unit::create(['name' => 'g', 'company_id' => $this->id]); - Unit::create(['name' => 'in', 'company_id' => $this->id]); - Unit::create(['name' => 'kg', 'company_id' => $this->id]); - Unit::create(['name' => 'km', 'company_id' => $this->id]); - Unit::create(['name' => 'lb', 'company_id' => $this->id]); - Unit::create(['name' => 'mg', 'company_id' => $this->id]); - Unit::create(['name' => 'pc', 'company_id' => $this->id]); - } - - public function setupDefaultSettings() - { - $defaultInvoiceEmailBody = 'You have received a new invoice from {COMPANY_NAME}.
Please download using the button below:'; - $defaultEstimateEmailBody = 'You have received a new estimate from {COMPANY_NAME}.
Please download using the button below:'; - $defaultPaymentEmailBody = 'Thank you for the payment.
Please download your payment receipt using the button below:'; - $billingAddressFormat = '

{BILLING_ADDRESS_NAME}

{BILLING_ADDRESS_STREET_1}

{BILLING_ADDRESS_STREET_2}

{BILLING_CITY} {BILLING_STATE}

{BILLING_COUNTRY} {BILLING_ZIP_CODE}

{BILLING_PHONE}

'; - $shippingAddressFormat = '

{SHIPPING_ADDRESS_NAME}

{SHIPPING_ADDRESS_STREET_1}

{SHIPPING_ADDRESS_STREET_2}

{SHIPPING_CITY} {SHIPPING_STATE}

{SHIPPING_COUNTRY} {SHIPPING_ZIP_CODE}

{SHIPPING_PHONE}

'; - $companyAddressFormat = '

{COMPANY_NAME}

{COMPANY_ADDRESS_STREET_1}

{COMPANY_ADDRESS_STREET_2}

{COMPANY_CITY} {COMPANY_STATE}

{COMPANY_COUNTRY} {COMPANY_ZIP_CODE}

{COMPANY_PHONE}

'; - $paymentFromCustomerAddress = '

{BILLING_ADDRESS_NAME}

{BILLING_ADDRESS_STREET_1}

{BILLING_ADDRESS_STREET_2}

{BILLING_CITY} {BILLING_STATE} {BILLING_ZIP_CODE}

{BILLING_COUNTRY}

{BILLING_PHONE}

'; - - $settings = [ - 'invoice_mail_body' => $defaultInvoiceEmailBody, - 'estimate_mail_body' => $defaultEstimateEmailBody, - 'payment_mail_body' => $defaultPaymentEmailBody, - 'invoice_company_address_format' => $companyAddressFormat, - 'invoice_shipping_address_format' => $shippingAddressFormat, - 'invoice_billing_address_format' => $billingAddressFormat, - 'estimate_company_address_format' => $companyAddressFormat, - 'estimate_shipping_address_format' => $shippingAddressFormat, - 'estimate_billing_address_format' => $billingAddressFormat, - 'payment_company_address_format' => $companyAddressFormat, - 'payment_from_customer_address_format' => $paymentFromCustomerAddress, - 'currency' => request()->currency ?? 13, - 'time_zone' => 'Asia/Kolkata', - 'language' => 'en', - 'fiscal_year' => '1-12', - 'carbon_date_format' => 'Y/m/d', - 'moment_date_format' => 'YYYY/MM/DD', - 'carbon_time_format' => 'H:i', - 'moment_time_format' => 'HH:mm', - 'invoice_use_time' => 'NO', - 'notification_email' => 'noreply@invoiceshelf.com', - 'notify_invoice_viewed' => 'NO', - 'notify_estimate_viewed' => 'NO', - 'tax_per_item' => 'NO', - 'discount_per_item' => 'NO', - 'invoice_email_attachment' => 'NO', - 'estimate_email_attachment' => 'NO', - 'payment_email_attachment' => 'NO', - 'retrospective_edits' => 'allow', - 'invoice_number_format' => '{{SERIES:INV}}{{DELIMITER:-}}{{SEQUENCE:6}}', - 'estimate_number_format' => '{{SERIES:EST}}{{DELIMITER:-}}{{SEQUENCE:6}}', - 'payment_number_format' => '{{SERIES:PAY}}{{DELIMITER:-}}{{SEQUENCE:6}}', - 'estimate_set_expiry_date_automatically' => 'YES', - 'estimate_expiry_date_days' => 7, - 'invoice_set_due_date_automatically' => 'YES', - 'invoice_due_date_days' => 7, - 'bulk_exchange_rate_configured' => 'YES', - 'estimate_convert_action' => 'no_action', - 'automatically_expire_public_links' => 'YES', - 'link_expiry_days' => 7, - ]; - - CompanySetting::setSettings($settings, $this->id); - } - - public function setupDefaultData() - { - $this->setupRoles(); - $this->setupDefaultPaymentMethods(); - $this->setupDefaultUnits(); - $this->setupDefaultSettings(); - - return true; - } - - public function deleteCompany($user) - { - if ($this->exchangeRateLogs()->exists()) { - $this->exchangeRateLogs()->delete(); - } - - if ($this->exchangeRateProviders()->exists()) { - $this->exchangeRateProviders()->delete(); - } - - if ($this->expenses()->exists()) { - $this->expenses()->delete(); - } - - if ($this->expenseCategories()->exists()) { - $this->expenseCategories()->delete(); - } - - if ($this->payments()->exists()) { - $this->payments()->delete(); - } - - if ($this->paymentMethods()->exists()) { - $this->paymentMethods()->delete(); - } - - if ($this->customFieldValues()->exists()) { - $this->customFieldValues()->delete(); - } - - if ($this->customFields()->exists()) { - $this->customFields()->delete(); - } - - if ($this->invoices()->exists()) { - $this->invoices->map(function ($invoice) { - $this->checkModelData($invoice); - - if ($invoice->transactions()->exists()) { - $invoice->transactions()->delete(); - } - }); - - $this->invoices()->delete(); - } - - if ($this->recurringInvoices()->exists()) { - $this->recurringInvoices->map(function ($recurringInvoice) { - $this->checkModelData($recurringInvoice); - }); - - $this->recurringInvoices()->delete(); - } - - if ($this->estimates()->exists()) { - $this->estimates->map(function ($estimate) { - $this->checkModelData($estimate); - }); - - $this->estimates()->delete(); - } - - if ($this->items()->exists()) { - $this->items()->delete(); - } - - if ($this->taxTypes()->exists()) { - $this->taxTypes()->delete(); - } - - if ($this->customers()->exists()) { - $this->customers->map(function ($customer) { - if ($customer->addresses()->exists()) { - $customer->addresses()->delete(); - } - - $customer->delete(); - }); - } - - $roles = Role::when($this->id, function ($query) { - return $query->where('scope', $this->id); - })->get(); - - if ($roles) { - $roles->map(function ($role) { - $role->delete(); - }); - } - - if ($this->users()->exists()) { - $user->companies()->detach($this->id); - } - - $this->settings()->delete(); - - $this->address()->delete(); - - $this->delete(); - - return true; - } - - public function checkModelData($model) - { - $model->items->map(function ($item) { - if ($item->taxes()->exists()) { - $item->taxes()->delete(); - } - - $item->delete(); - }); - - if ($model->taxes()->exists()) { - $model->taxes()->delete(); - } - } - public function hasTransactions() { if ( diff --git a/app/Models/Customer.php b/app/Models/Customer.php index 47eb2d65..50df2a05 100644 --- a/app/Models/Customer.php +++ b/app/Models/Customer.php @@ -135,114 +135,6 @@ class Customer extends Authenticatable implements HasMedia return 0; } - public static function deleteCustomers($ids) - { - foreach ($ids as $id) { - $customer = self::find($id); - - if ($customer->estimates()->exists()) { - $customer->estimates()->delete(); - } - - if ($customer->invoices()->exists()) { - $customer->invoices->map(function ($invoice) { - if ($invoice->transactions()->exists()) { - $invoice->transactions()->delete(); - } - $invoice->delete(); - }); - } - - if ($customer->payments()->exists()) { - $customer->payments()->delete(); - } - - if ($customer->addresses()->exists()) { - $customer->addresses()->delete(); - } - - if ($customer->expenses()->exists()) { - $customer->expenses()->delete(); - } - - if ($customer->recurringInvoices()->exists()) { - foreach ($customer->recurringInvoices as $recurringInvoice) { - if ($recurringInvoice->items()->exists()) { - $recurringInvoice->items()->delete(); - } - - $recurringInvoice->delete(); - } - } - - $customer->delete(); - } - - return true; - } - - public static function createCustomer($request) - { - $customer = Customer::create($request->getCustomerPayload()); - - if ($request->shipping) { - if ($request->hasAddress($request->shipping)) { - $customer->addresses()->create($request->getShippingAddress()); - } - } - - if ($request->billing) { - if ($request->hasAddress($request->billing)) { - $customer->addresses()->create($request->getBillingAddress()); - } - } - - $customFields = $request->customFields; - - if ($customFields) { - $customer->addCustomFields($customFields); - } - - $customer = Customer::with('billingAddress', 'shippingAddress', 'fields')->find($customer->id); - - return $customer; - } - - public static function updateCustomer($request, $customer) - { - $condition = $customer->estimates()->exists() || $customer->invoices()->exists() || $customer->payments()->exists() || $customer->recurringInvoices()->exists(); - - if (($customer->currency_id !== $request->currency_id) && $condition) { - return 'you_cannot_edit_currency'; - } - - $customer->update($request->getCustomerPayload()); - - $customer->addresses()->delete(); - - if ($request->shipping) { - if ($request->hasAddress($request->shipping)) { - $customer->addresses()->create($request->getShippingAddress()); - } - } - - if ($request->billing) { - if ($request->hasAddress($request->billing)) { - $customer->addresses()->create($request->getBillingAddress()); - } - } - - $customFields = $request->customFields; - - if ($customFields) { - $customer->updateCustomFields($customFields); - } - - $customer = Customer::with('billingAddress', 'shippingAddress', 'fields')->find($customer->id); - - return $customer; - } - public function scopePaginateData($query, $limit) { if ($limit == 'all') { diff --git a/app/Models/Estimate.php b/app/Models/Estimate.php index 847063bf..a0a78965 100644 --- a/app/Models/Estimate.php +++ b/app/Models/Estimate.php @@ -2,13 +2,8 @@ namespace App\Models; -use App; -use App\Facades\Hashids; -use App\Facades\PDF; -use App\Mail\SendEstimateMail; -use App\Services\CompanyMailConfigService; -use App\Services\SerialNumberFormatter; -use App\Space\PdfTemplateUtils; +use App\Services\EstimateService; +use App\Services\Pdf\PdfTemplateUtils; use App\Support\PdfHtmlSanitizer; use App\Traits\GeneratesPdfTrait; use App\Traits\HasCustomFieldsTrait; @@ -218,230 +213,9 @@ class Estimate extends Model implements HasMedia return $query->paginate($limit); } - public static function createEstimate($request) - { - $data = $request->getEstimatePayload(); - - if ($request->has('estimateSend')) { - $data['status'] = self::STATUS_SENT; - } - - $estimate = self::create($data); - $estimate->unique_hash = Hashids::connection(Estimate::class)->encode($estimate->id); - $serial = (new SerialNumberFormatter) - ->setModel($estimate) - ->setCompany($estimate->company_id) - ->setCustomer($estimate->customer_id) - ->setNextNumbers(); - - $estimate->sequence_number = $serial->nextSequenceNumber; - $estimate->customer_sequence_number = $serial->nextCustomerSequenceNumber; - $estimate->save(); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($estimate); - } - - self::createItems($estimate, $request, $estimate->exchange_rate); - - if ($request->has('taxes') && (! empty($request->taxes))) { - self::createTaxes($estimate, $request, $estimate->exchange_rate); - } - - $customFields = $request->customFields; - - if ($customFields) { - $estimate->addCustomFields($customFields); - } - - return $estimate; - } - - public function updateEstimate($request) - { - $data = $request->getEstimatePayload(); - - $serial = (new SerialNumberFormatter) - ->setModel($this) - ->setCompany($this->company_id) - ->setCustomer($request->customer_id) - ->setModelObject($this->id) - ->setNextNumbers(); - - $data['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; - - $this->update($data); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($this); - } - - $this->items->map(function ($item) { - $fields = $item->fields()->get(); - - $fields->map(function ($field) { - $field->delete(); - }); - }); - - $this->items()->delete(); - $this->taxes()->delete(); - - self::createItems($this, $request, $this->exchange_rate); - - if ($request->has('taxes') && (! empty($request->taxes))) { - self::createTaxes($this, $request, $this->exchange_rate); - } - - if ($request->customFields) { - $this->updateCustomFields($request->customFields); - } - - return Estimate::with([ - 'items.taxes', - 'items.fields', - 'items.fields.customField', - 'customer', - 'taxes', - ]) - ->find($this->id); - } - - public static function createItems($estimate, $request, $exchange_rate) - { - $estimateItems = $request->items; - - foreach ($estimateItems as $estimateItem) { - $estimateItem['company_id'] = $request->header('company'); - $estimateItem['exchange_rate'] = $exchange_rate; - $estimateItem['base_price'] = $estimateItem['price'] * $exchange_rate; - $estimateItem['base_discount_val'] = $estimateItem['discount_val'] * $exchange_rate; - $estimateItem['base_tax'] = $estimate['tax'] * $exchange_rate; - $estimateItem['base_total'] = $estimateItem['total'] * $exchange_rate; - - $item = $estimate->items()->create($estimateItem); - - if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { - foreach ($estimateItem['taxes'] as $tax) { - if (gettype($tax['amount']) !== 'NULL') { - $tax['company_id'] = $request->header('company'); - $item->taxes()->create($tax); - } - } - } - - if (array_key_exists('custom_fields', $estimateItem) && $estimateItem['custom_fields']) { - $item->addCustomFields($estimateItem['custom_fields']); - } - } - } - - public static function createTaxes($estimate, $request, $exchange_rate) - { - $estimateTaxes = $request->taxes; - - foreach ($estimateTaxes as $tax) { - if (gettype($tax['amount']) !== 'NULL') { - $tax['company_id'] = $request->header('company'); - $tax['exchange_rate'] = $exchange_rate; - $tax['base_amount'] = $tax['amount'] * $exchange_rate; - $tax['currency_id'] = $estimate->currency_id; - - $estimate->taxes()->create($tax); - } - } - } - - public function sendEstimateData($data) - { - $data['estimate'] = $this->toArray(); - $data['user'] = $this->customer->toArray(); - $data['company'] = $this->company->toArray(); - $data['body'] = $this->getEmailBody($data['body']); - $data['attach']['data'] = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null; - - return $data; - } - - public function send($data) - { - $data = $this->sendEstimateData($data); - - CompanyMailConfigService::apply($this->company_id); - - if ($this->status == Estimate::STATUS_DRAFT) { - $this->status = Estimate::STATUS_SENT; - $this->save(); - } - - $mail = \Mail::to($data['to']); - if (! empty($data['cc'])) { - $mail->cc($data['cc']); - } - if (! empty($data['bcc'])) { - $mail->bcc($data['bcc']); - } - $mail->send(new SendEstimateMail($data)); - - return [ - 'success' => true, - 'type' => 'send', - ]; - } - public function getPDFData() { - $taxes = collect(); - - if ($this->tax_per_item === 'YES') { - foreach ($this->items as $item) { - foreach ($item->taxes as $tax) { - $found = $taxes->filter(function ($item) use ($tax) { - return $item->tax_type_id == $tax->tax_type_id; - })->first(); - - if ($found) { - $found->amount += $tax->amount; - } else { - $taxes->push($tax); - } - } - } - } - - $estimateTemplate = self::find($this->id)->template_name; - - $company = Company::find($this->company_id); - $locale = CompanySetting::getSetting('language', $company->id); - $customFields = CustomField::where('model_type', 'Item')->get(); - - App::setLocale($locale); - - $logo = $company->logo_path; - - view()->share([ - 'estimate' => $this, - 'customFields' => $customFields, - 'logo' => $logo ?? null, - 'company_address' => $this->getCompanyAddress(), - 'shipping_address' => $this->getCustomerShippingAddress(), - 'billing_address' => $this->getCustomerBillingAddress(), - 'notes' => $this->getNotes(), - 'taxes' => $taxes, - ]); - - $template = PdfTemplateUtils::findFormattedTemplate('estimate', $estimateTemplate, ''); - $templatePath = $template['custom'] ? sprintf('pdf_templates::estimate.%s', $estimateTemplate) : sprintf('app.pdf.estimate.%s', $estimateTemplate); - - if (request()->has('preview')) { - return view($templatePath); - } - - return PDF::loadView($templatePath); + return app(EstimateService::class)->getPdfData($this); } public function getCompanyAddress() diff --git a/app/Models/Expense.php b/app/Models/Expense.php index dfaa0da8..54514b1b 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -232,52 +232,4 @@ class Expense extends Model implements HasMedia ) ->groupBy('expense_category_id'); } - - public static function createExpense($request) - { - $expense = self::create($request->getExpensePayload()); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $expense['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($expense); - } - - if ($request->hasFile('attachment_receipt')) { - $expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts'); - } - - if ($request->customFields) { - $expense->addCustomFields(json_decode($request->customFields)); - } - - return $expense; - } - - public function updateExpense($request) - { - $data = $request->getExpensePayload(); - - $this->update($data); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($this); - } - - if (isset($request->is_attachment_receipt_removed) && (bool) $request->is_attachment_receipt_removed) { - $this->clearMediaCollection('receipts'); - } - if ($request->hasFile('attachment_receipt')) { - $this->clearMediaCollection('receipts'); - $this->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts'); - } - - if ($request->customFields) { - $this->updateCustomFields(json_decode($request->customFields)); - } - - return true; - } } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index b8fa632f..9c35a0c5 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -2,13 +2,7 @@ namespace App\Models; -use App; -use App\Facades\Hashids; -use App\Facades\PDF; -use App\Mail\SendInvoiceMail; -use App\Services\CompanyMailConfigService; -use App\Services\SerialNumberFormatter; -use App\Space\PdfTemplateUtils; +use App\Services\InvoiceService; use App\Support\PdfHtmlSanitizer; use App\Traits\GeneratesPdfTrait; use App\Traits\HasCustomFieldsTrait; @@ -325,293 +319,9 @@ class Invoice extends Model implements HasMedia return $query->paginate($limit); } - public static function createInvoice($request) - { - $data = $request->getInvoicePayload(); - - if ($request->has('invoiceSend')) { - $data['status'] = Invoice::STATUS_SENT; - } - - $invoice = Invoice::create($data); - - $serial = (new SerialNumberFormatter) - ->setModel($invoice) - ->setCompany($invoice->company_id) - ->setCustomer($invoice->customer_id) - ->setNextNumbers(); - - $invoice->sequence_number = $serial->nextSequenceNumber; - $invoice->customer_sequence_number = $serial->nextCustomerSequenceNumber; - $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); - $invoice->save(); - - self::createItems($invoice, $request->items); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($invoice); - } - - if ($request->has('taxes') && (! empty($request->taxes))) { - self::createTaxes($invoice, $request->taxes); - } - - if ($request->customFields) { - $invoice->addCustomFields($request->customFields); - } - - $invoice = Invoice::with([ - 'items', - 'items.fields', - 'items.fields.customField', - 'customer', - 'taxes', - ]) - ->find($invoice->id); - - return $invoice; - } - - public function updateInvoice($request) - { - $serial = (new SerialNumberFormatter) - ->setModel($this) - ->setCompany($this->company_id) - ->setCustomer($request->customer_id) - ->setModelObject($this->id) - ->setNextNumbers(); - - $data = $request->getInvoicePayload(); - $oldTotal = $this->total; - - $total_paid_amount = $this->total - $this->due_amount; - - if ($total_paid_amount > 0 && $this->customer_id !== $request->customer_id) { - return 'customer_cannot_be_changed_after_payment_is_added'; - } - - if ($request->total >= 0 && $request->total < $total_paid_amount) { - return 'total_invoice_amount_must_be_more_than_paid_amount'; - } - - if ($oldTotal != $request->total) { - $oldTotal = (int) round($request->total) - (int) $oldTotal; - } else { - $oldTotal = 0; - } - - $data['due_amount'] = ($this->due_amount + $oldTotal); - $data['base_due_amount'] = $data['due_amount'] * $data['exchange_rate']; - $data['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; - - $this->update($data); - - $statusData = $this->getInvoiceStatusByAmount($data['due_amount']); - if (! empty($statusData)) { - $this->update($statusData); - } - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($this); - } - - $this->items->map(function ($item) { - $fields = $item->fields()->get(); - - $fields->map(function ($field) { - $field->delete(); - }); - }); - - $this->items()->delete(); - $this->taxes()->delete(); - - self::createItems($this, $request->items); - - if ($request->has('taxes') && (! empty($request->taxes))) { - self::createTaxes($this, $request->taxes); - } - - if ($request->customFields) { - $this->updateCustomFields($request->customFields); - } - - $invoice = Invoice::with([ - 'items', - 'items.fields', - 'items.fields.customField', - 'customer', - 'taxes', - ]) - ->find($this->id); - - return $invoice; - } - - public function sendInvoiceData($data) - { - $data['invoice'] = $this->toArray(); - $data['customer'] = $this->customer->toArray(); - $data['company'] = Company::find($this->company_id); - $data['subject'] = $this->getEmailString($data['subject']); - $data['body'] = $this->getEmailString($data['body']); - $data['attach']['data'] = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null; - - return $data; - } - - public function preview($data) - { - $data = $this->sendInvoiceData($data); - - return [ - 'type' => 'preview', - 'view' => new SendInvoiceMail($data), - ]; - } - - public function send($data) - { - $data = $this->sendInvoiceData($data); - - CompanyMailConfigService::apply($this->company_id); - - $mail = \Mail::to($data['to']); - if (! empty($data['cc'])) { - $mail->cc($data['cc']); - } - if (! empty($data['bcc'])) { - $mail->bcc($data['bcc']); - } - $mail->send(new SendInvoiceMail($data)); - - if ($this->status == Invoice::STATUS_DRAFT) { - $this->status = Invoice::STATUS_SENT; - $this->sent = true; - $this->save(); - } - - return [ - 'success' => true, - 'type' => 'send', - ]; - } - - public static function createItems($invoice, $invoiceItems) - { - $exchange_rate = $invoice->exchange_rate; - - foreach ($invoiceItems as $invoiceItem) { - $invoiceItem['company_id'] = $invoice->company_id; - $invoiceItem['exchange_rate'] = $exchange_rate; - $invoiceItem['base_price'] = $invoiceItem['price'] * $exchange_rate; - $invoiceItem['base_discount_val'] = $invoiceItem['discount_val'] * $exchange_rate; - $invoiceItem['base_tax'] = $invoiceItem['tax'] * $exchange_rate; - $invoiceItem['base_total'] = $invoiceItem['total'] * $exchange_rate; - - if (array_key_exists('recurring_invoice_id', $invoiceItem)) { - unset($invoiceItem['recurring_invoice_id']); - } - - $item = $invoice->items()->create($invoiceItem); - - if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { - foreach ($invoiceItem['taxes'] as $tax) { - $tax['company_id'] = $invoice->company_id; - $tax['exchange_rate'] = $invoice->exchange_rate; - $tax['base_amount'] = $tax['amount'] * $exchange_rate; - $tax['currency_id'] = $invoice->currency_id; - - if (gettype($tax['amount']) !== 'NULL') { - if (array_key_exists('recurring_invoice_id', $invoiceItem)) { - unset($invoiceItem['recurring_invoice_id']); - } - - $item->taxes()->create($tax); - } - } - } - - if (array_key_exists('custom_fields', $invoiceItem) && $invoiceItem['custom_fields']) { - $item->addCustomFields($invoiceItem['custom_fields']); - } - } - } - - public static function createTaxes($invoice, $taxes) - { - - $exchange_rate = $invoice->exchange_rate; - - foreach ($taxes as $tax) { - $tax['company_id'] = $invoice->company_id; - $tax['exchange_rate'] = $invoice->exchange_rate; - $tax['base_amount'] = $tax['amount'] * $exchange_rate; - $tax['currency_id'] = $invoice->currency_id; - - if (gettype($tax['amount']) !== 'NULL') { - if (array_key_exists('recurring_invoice_id', $tax)) { - unset($tax['recurring_invoice_id']); - } - - $invoice->taxes()->create($tax); - } - } - } - public function getPDFData() { - $taxes = collect(); - - if ($this->tax_per_item === 'YES') { - foreach ($this->items as $item) { - foreach ($item->taxes as $tax) { - $found = $taxes->filter(function ($item) use ($tax) { - return $item->tax_type_id == $tax->tax_type_id; - })->first(); - - if ($found) { - $found->amount += $tax->amount; - } else { - $taxes->push($tax); - } - } - } - } - - $invoiceTemplate = self::find($this->id)->template_name; - - $company = Company::find($this->company_id); - $locale = CompanySetting::getSetting('language', $company->id); - $customFields = CustomField::where('model_type', 'Item')->get(); - - App::setLocale($locale); - - $logo = $company->logo_path; - - view()->share([ - 'invoice' => $this, - 'customFields' => $customFields, - 'company_address' => $this->getCompanyAddress(), - 'shipping_address' => $this->getCustomerShippingAddress(), - 'billing_address' => $this->getCustomerBillingAddress(), - 'notes' => $this->getNotes(), - 'logo' => $logo ?? null, - 'taxes' => $taxes, - ]); - - $template = PdfTemplateUtils::findFormattedTemplate('invoice', $invoiceTemplate, ''); - $templatePath = $template['custom'] ? sprintf('pdf_templates::invoice.%s', $invoiceTemplate) : sprintf('app.pdf.invoice.%s', $invoiceTemplate); - - if (request()->has('preview')) { - return view($templatePath); - } - - return PDF::loadView($templatePath); + return app(InvoiceService::class)->getPdfData($this); } public function getEmailAttachmentSetting() @@ -745,19 +455,4 @@ class Invoice extends Model implements HasMedia $this->save(); } } - - public static function deleteInvoices($ids) - { - foreach ($ids as $id) { - $invoice = self::find($id); - - if ($invoice->transactions()->exists()) { - $invoice->transactions()->delete(); - } - - $invoice->delete(); - } - - return true; - } } diff --git a/app/Models/Payment.php b/app/Models/Payment.php index 8b0f06a9..c478b074 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -2,15 +2,11 @@ namespace App\Models; -use App\Facades\Hashids; use App\Jobs\GeneratePaymentPdfJob; -use App\Mail\SendPaymentMail; -use App\Services\CompanyMailConfigService; -use App\Services\SerialNumberFormatter; +use App\Services\PaymentService; use App\Support\PdfHtmlSanitizer; use App\Traits\GeneratesPdfTrait; use App\Traits\HasCustomFieldsTrait; -use Barryvdh\DomPDF\Facade\Pdf as PDF; use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -131,158 +127,6 @@ class Payment extends Model implements HasMedia return $this->belongsTo(PaymentMethod::class); } - public function sendPaymentData($data) - { - $data['payment'] = $this->toArray(); - $data['user'] = $this->customer->toArray(); - $data['company'] = Company::find($this->company_id); - $data['body'] = $this->getEmailBody($data['body']); - $data['attach']['data'] = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null; - - return $data; - } - - public function send($data) - { - $data = $this->sendPaymentData($data); - - CompanyMailConfigService::apply($this->company_id); - - $mail = \Mail::to($data['to']); - if (! empty($data['cc'])) { - $mail->cc($data['cc']); - } - if (! empty($data['bcc'])) { - $mail->bcc($data['bcc']); - } - $mail->send(new SendPaymentMail($data)); - - return [ - 'success' => true, - ]; - } - - public static function createPayment($request) - { - $data = $request->getPaymentPayload(); - - if ($request->invoice_id) { - $invoice = Invoice::find($request->invoice_id); - $invoice->subtractInvoicePayment($request->amount); - } - - $payment = Payment::create($data); - $payment->unique_hash = Hashids::connection(Payment::class)->encode($payment->id); - - $serial = (new SerialNumberFormatter) - ->setModel($payment) - ->setCompany($payment->company_id) - ->setCustomer($payment->customer_id) - ->setNextNumbers(); - - $payment->sequence_number = $serial->nextSequenceNumber; - $payment->customer_sequence_number = $serial->nextCustomerSequenceNumber; - $payment->save(); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $payment['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($payment); - } - - $customFields = $request->customFields; - - if ($customFields) { - $payment->addCustomFields($customFields); - } - - $payment = Payment::with([ - 'customer', - 'invoice', - 'paymentMethod', - 'fields', - ])->find($payment->id); - - return $payment; - } - - public function updatePayment($request) - { - $data = $request->getPaymentPayload(); - - if ($request->invoice_id && (! $this->invoice_id || $this->invoice_id !== $request->invoice_id)) { - $invoice = Invoice::find($request->invoice_id); - $invoice->subtractInvoicePayment($request->amount); - } - - if ($this->invoice_id && (! $request->invoice_id || $this->invoice_id !== $request->invoice_id)) { - $invoice = Invoice::find($this->invoice_id); - $invoice->addInvoicePayment($this->amount); - } - - if ($this->invoice_id && $this->invoice_id === $request->invoice_id && $request->amount !== $this->amount) { - $invoice = Invoice::find($this->invoice_id); - $invoice->addInvoicePayment($this->amount); - $invoice->subtractInvoicePayment($request->amount); - } - - $serial = (new SerialNumberFormatter) - ->setModel($this) - ->setCompany($this->company_id) - ->setCustomer($request->customer_id) - ->setModelObject($this->id) - ->setNextNumbers(); - - $data['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; - $this->update($data); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($this); - } - - $customFields = $request->customFields; - - if ($customFields) { - $this->updateCustomFields($customFields); - } - - $payment = Payment::with([ - 'customer', - 'invoice', - 'paymentMethod', - ]) - ->find($this->id); - - return $payment; - } - - public static function deletePayments($ids) - { - foreach ($ids as $id) { - $payment = Payment::find($id); - - if ($payment->invoice_id != null) { - $invoice = Invoice::find($payment->invoice_id); - $invoice->due_amount = ((int) $invoice->due_amount + (int) $payment->amount); - - if ($invoice->due_amount == $invoice->total) { - $invoice->paid_status = Invoice::STATUS_UNPAID; - } else { - $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; - } - - $invoice->status = $invoice->getPreviousStatus(); - $invoice->save(); - } - - $payment->delete(); - } - - return true; - } - public function scopeWhereSearch($query, $search) { foreach (explode(' ', $search) as $term) { @@ -380,26 +224,7 @@ class Payment extends Model implements HasMedia public function getPDFData() { - $company = Company::find($this->company_id); - $locale = CompanySetting::getSetting('language', $company->id); - - \App::setLocale($locale); - - $logo = $company->logo_path; - - view()->share([ - 'payment' => $this, - 'company_address' => $this->getCompanyAddress(), - 'billing_address' => $this->getCustomerBillingAddress(), - 'notes' => $this->getNotes(), - 'logo' => $logo ?? null, - ]); - - if (request()->has('preview')) { - return view('app.pdf.payment.payment'); - } - - return PDF::loadView('app.pdf.payment.payment'); + return app(PaymentService::class)->getPdfData($this); } public function getCompanyAddress() @@ -458,37 +283,4 @@ class Payment extends Model implements HasMedia '{PAYMENT_AMOUNT}' => format_money_pdf($this->amount, $this->customer->currency), ]; } - - public static function generatePayment($transaction) - { - $invoice = Invoice::find($transaction->invoice_id); - - $serial = (new SerialNumberFormatter) - ->setModel(new Payment) - ->setCompany($invoice->company_id) - ->setCustomer($invoice->customer_id) - ->setNextNumbers(); - - $data['payment_number'] = $serial->getNextNumber(); - $data['payment_date'] = Carbon::now(); - $data['amount'] = $invoice->total; - $data['invoice_id'] = $invoice->id; - $data['payment_method_id'] = request()->payment_method_id; - $data['customer_id'] = $invoice->customer_id; - $data['exchange_rate'] = $invoice->exchange_rate; - $data['base_amount'] = $data['amount'] * $data['exchange_rate']; - $data['currency_id'] = $invoice->currency_id; - $data['company_id'] = $invoice->company_id; - $data['transaction_id'] = $transaction->id; - - $payment = Payment::create($data); - $payment->unique_hash = Hashids::connection(Payment::class)->encode($payment->id); - $payment->sequence_number = $serial->nextSequenceNumber; - $payment->customer_sequence_number = $serial->nextCustomerSequenceNumber; - $payment->save(); - - $invoice->subtractInvoicePayment($invoice->total); - - return $payment; - } } diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 5d910425..1affb3a5 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -2,9 +2,6 @@ namespace App\Models; -use App\Facades\Hashids; -use App\Http\Requests\RecurringInvoiceRequest; -use App\Services\SerialNumberFormatter; use App\Traits\HasCustomFieldsTrait; use Carbon\Carbon; use Cron; @@ -193,204 +190,6 @@ class RecurringInvoice extends Model } } - public static function createFromRequest(RecurringInvoiceRequest $request) - { - $recurringInvoice = self::create($request->getRecurringInvoicePayload()); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $recurringInvoice['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($recurringInvoice); - } - - self::createItems($recurringInvoice, $request->items); - - if ($request->has('taxes') && (! empty($request->taxes))) { - self::createTaxes($recurringInvoice, $request->taxes); - } - - if ($request->customFields) { - $recurringInvoice->addCustomFields($request->customFields); - } - - return $recurringInvoice; - } - - public function updateFromRequest(RecurringInvoiceRequest $request) - { - $data = $request->getRecurringInvoicePayload(); - - $this->update($data); - - $company_currency = CompanySetting::getSetting('currency', $request->header('company')); - - if ((string) $data['currency_id'] !== $company_currency) { - ExchangeRateLog::addExchangeRateLog($this); - } - - $this->items()->delete(); - self::createItems($this, $request->items); - - $this->taxes()->delete(); - if ($request->has('taxes') && (! empty($request->taxes))) { - self::createTaxes($this, $request->taxes); - } - - if ($request->customFields) { - $this->updateCustomFields($request->customFields); - } - - return $this; - } - - public static function createItems($recurringInvoice, $invoiceItems) - { - foreach ($invoiceItems as $invoiceItem) { - $invoiceItem['company_id'] = $recurringInvoice->company_id; - $item = $recurringInvoice->items()->create($invoiceItem); - if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { - foreach ($invoiceItem['taxes'] as $tax) { - $tax['company_id'] = $recurringInvoice->company_id; - if (gettype($tax['amount']) !== 'NULL') { - $item->taxes()->create($tax); - } - } - } - } - } - - public static function createTaxes($recurringInvoice, $taxes) - { - foreach ($taxes as $tax) { - $tax['company_id'] = $recurringInvoice->company_id; - - if (gettype($tax['amount']) !== 'NULL') { - $recurringInvoice->taxes()->create($tax); - } - } - } - - public function generateInvoice() - { - if (Carbon::now()->lessThan($this->starts_at)) { - return; - } - - if ($this->limit_by == 'DATE') { - $startDate = Carbon::today()->format('Y-m-d'); - - $endDate = $this->limit_date; - - if ($endDate >= $startDate) { - $this->createInvoice(); - - $this->updateNextInvoiceDate(); - } else { - $this->markStatusAsCompleted(); - } - } elseif ($this->limit_by == 'COUNT') { - $invoiceCount = Invoice::where('recurring_invoice_id', $this->id)->count(); - - if ($invoiceCount < $this->limit_count) { - $this->createInvoice(); - - $this->updateNextInvoiceDate(); - } else { - $this->markStatusAsCompleted(); - } - } else { - $this->createInvoice(); - - $this->updateNextInvoiceDate(); - } - } - - public function createInvoice() - { - // get invoice_number - $serial = (new SerialNumberFormatter) - ->setModel(new Invoice) - ->setCompany($this->company_id) - ->setCustomer($this->customer_id) - ->setNextNumbers(); - - $days = intval(CompanySetting::getSetting('invoice_due_date_days', $this->company_id)); - - if (! $days || $days == 'null') { - $days = 7; - } - - $newInvoice['creator_id'] = $this->creator_id; - $newInvoice['invoice_date'] = Carbon::today()->format('Y-m-d'); - $newInvoice['due_date'] = Carbon::today()->addDays($days)->format('Y-m-d'); - $newInvoice['status'] = Invoice::STATUS_DRAFT; - $newInvoice['company_id'] = $this->company_id; - $newInvoice['paid_status'] = Invoice::STATUS_UNPAID; - $newInvoice['sub_total'] = $this->sub_total; - $newInvoice['tax_per_item'] = $this->tax_per_item; - $newInvoice['discount_per_item'] = $this->discount_per_item; - $newInvoice['tax'] = $this->tax; - $newInvoice['total'] = $this->total; - $newInvoice['customer_id'] = $this->customer_id; - $newInvoice['currency_id'] = Customer::find($this->customer_id)->currency_id; - $newInvoice['template_name'] = $this->template_name; - $newInvoice['due_amount'] = $this->total; - $newInvoice['recurring_invoice_id'] = $this->id; - $newInvoice['discount_val'] = $this->discount_val; - $newInvoice['discount'] = $this->discount; - $newInvoice['discount_type'] = $this->discount_type; - $newInvoice['notes'] = $this->notes; - $newInvoice['exchange_rate'] = $this->exchange_rate; - $newInvoice['sales_tax_type'] = $this->sales_tax_type; - $newInvoice['sales_tax_address_type'] = $this->sales_tax_address_type; - $newInvoice['invoice_number'] = $serial->getNextNumber(); - $newInvoice['sequence_number'] = $serial->nextSequenceNumber; - $newInvoice['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; - $newInvoice['base_due_amount'] = $this->exchange_rate * $this->due_amount; - $newInvoice['base_discount_val'] = $this->exchange_rate * $this->discount_val; - $newInvoice['base_sub_total'] = $this->exchange_rate * $this->sub_total; - $newInvoice['base_tax'] = $this->exchange_rate * $this->tax; - $newInvoice['base_total'] = $this->exchange_rate * $this->total; - $invoice = Invoice::create($newInvoice); - $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); - $invoice->save(); - - $this->load('items.taxes'); - Invoice::createItems($invoice, $this->items->toArray()); - - if ($this->taxes()->exists()) { - Invoice::createTaxes($invoice, $this->taxes->toArray()); - } - - if ($this->fields()->exists()) { - $customField = []; - - foreach ($this->fields as $data) { - $customField[] = [ - 'id' => $data->custom_field_id, - 'value' => $data->defaultAnswer, - ]; - } - - $invoice->addCustomFields($customField); - } - - // send automatically - if ($this->send_automatically == true) { - $data = [ - 'body' => CompanySetting::getSetting('invoice_mail_body', $this->company_id), - 'from' => config('mail.from.address'), - 'to' => $this->customer->email, - 'subject' => trans('invoices')['new_invoice'], - 'invoice' => $invoice->toArray(), - 'customer' => $invoice->customer->toArray(), - 'company' => Company::find($invoice->company_id), - ]; - - $invoice->send($data); - } - } - public function markStatusAsCompleted() { if ($this->status == $this->status) { @@ -413,27 +212,4 @@ class RecurringInvoice extends Model $this->next_invoice_at = $nextInvoiceAt; $this->save(); } - - public static function deleteRecurringInvoice($ids) - { - foreach ($ids as $id) { - $recurringInvoice = self::find($id); - - if ($recurringInvoice->invoices()->exists()) { - $recurringInvoice->invoices()->update(['recurring_invoice_id' => null]); - } - - if ($recurringInvoice->items()->exists()) { - $recurringInvoice->items()->delete(); - } - - if ($recurringInvoice->taxes()->exists()) { - $recurringInvoice->taxes()->delete(); - } - - $recurringInvoice->delete(); - } - - return true; - } } diff --git a/app/Models/User.php b/app/Models/User.php index 7367cb4d..a6d9384a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,7 +2,6 @@ namespace App\Models; -use App\Http\Requests\UserRequest; use App\Notifications\MailResetPasswordNotification; use App\Traits\HasCustomFieldsTrait; use Carbon\Carbon; @@ -15,7 +14,6 @@ use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Schema; use Laravel\Sanctum\HasApiTokens; -use Silber\Bouncer\BouncerFacade; use Silber\Bouncer\Database\HasRolesAndAbilities; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; @@ -349,42 +347,6 @@ class User extends Authenticatable implements HasMedia return false; } - public static function createFromRequest(UserRequest $request) - { - $user = self::create($request->getUserPayload()); - - $user->setSettings([ - 'language' => CompanySetting::getSetting('language', $request->header('company')), - ]); - - $companies = collect($request->companies); - $user->companies()->sync($companies->pluck('id')); - - foreach ($companies as $company) { - BouncerFacade::scope()->to($company['id']); - - BouncerFacade::sync($user)->roles([$company['role']]); - } - - return $user; - } - - public function updateFromRequest(UserRequest $request) - { - $this->update($request->getUserPayload()); - - $companies = collect($request->companies); - $this->companies()->sync($companies->pluck('id')); - - foreach ($companies as $company) { - BouncerFacade::scope()->to($company['id']); - - BouncerFacade::sync($this)->roles([$company['role']]); - } - - return $this; - } - public function checkAccess($data) { if (! empty($data->data['super_admin_only']) && $data->data['super_admin_only']) { @@ -409,47 +371,4 @@ class User extends Authenticatable implements HasMedia return false; } - - public static function deleteUsers($ids) - { - foreach ($ids as $id) { - $user = self::find($id); - - if ($user->invoices()->exists()) { - $user->invoices()->update(['creator_id' => null]); - } - - if ($user->estimates()->exists()) { - $user->estimates()->update(['creator_id' => null]); - } - - if ($user->customers()->exists()) { - $user->customers()->update(['creator_id' => null]); - } - - if ($user->recurringInvoices()->exists()) { - $user->recurringInvoices()->update(['creator_id' => null]); - } - - if ($user->expenses()->exists()) { - $user->expenses()->update(['creator_id' => null]); - } - - if ($user->payments()->exists()) { - $user->payments()->update(['creator_id' => null]); - } - - if ($user->items()->exists()) { - $user->items()->update(['creator_id' => null]); - } - - if ($user->settings()->exists()) { - $user->settings()->delete(); - } - - $user->delete(); - } - - return true; - } } diff --git a/app/Providers/AppConfigProvider.php b/app/Providers/AppConfigProvider.php index 3f3279ca..3ab98bb0 100644 --- a/app/Providers/AppConfigProvider.php +++ b/app/Providers/AppConfigProvider.php @@ -4,7 +4,7 @@ namespace App\Providers; use App\Models\FileDisk; use App\Models\Setting; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; use Illuminate\Support\Facades\Config; use Illuminate\Support\ServiceProvider; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 487de0c3..8d3c2173 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -19,7 +19,7 @@ use App\Policies\ReportPolicy; use App\Policies\RolePolicy; use App\Policies\SettingsPolicy; use App\Policies\UserPolicy; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; use Gate; use Illuminate\Support\Facades\Broadcast; use Illuminate\Support\Facades\Mail; diff --git a/app/Space/BackupConfigurationFactory.php b/app/Services/Backup/BackupConfigurationFactory.php similarity index 97% rename from app/Space/BackupConfigurationFactory.php rename to app/Services/Backup/BackupConfigurationFactory.php index 934a2127..cb5f258a 100644 --- a/app/Space/BackupConfigurationFactory.php +++ b/app/Services/Backup/BackupConfigurationFactory.php @@ -1,6 +1,6 @@ setupRoles($company); + $this->setupDefaultPaymentMethods($company); + $this->setupDefaultUnits($company); + $this->setupDefaultSettings($company); + + return true; + } + + public function setupRoles(Company $company): void + { + BouncerFacade::scope()->to($company->id); + + $superAdmin = BouncerFacade::role()->firstOrCreate([ + 'name' => 'super admin', + 'title' => 'Super Admin', + 'scope' => $company->id, + ]); + + foreach (config('abilities.abilities') as $ability) { + BouncerFacade::allow($superAdmin)->to($ability['ability'], $ability['model']); + } + } + + public function delete(Company $company, User $user): bool + { + if ($company->exchangeRateLogs()->exists()) { + $company->exchangeRateLogs()->delete(); + } + + if ($company->exchangeRateProviders()->exists()) { + $company->exchangeRateProviders()->delete(); + } + + if ($company->expenses()->exists()) { + $company->expenses()->delete(); + } + + if ($company->expenseCategories()->exists()) { + $company->expenseCategories()->delete(); + } + + if ($company->payments()->exists()) { + $company->payments()->delete(); + } + + if ($company->paymentMethods()->exists()) { + $company->paymentMethods()->delete(); + } + + if ($company->customFieldValues()->exists()) { + $company->customFieldValues()->delete(); + } + + if ($company->customFields()->exists()) { + $company->customFields()->delete(); + } + + if ($company->invoices()->exists()) { + $company->invoices->map(function ($invoice) { + $this->checkModelData($invoice); + + if ($invoice->transactions()->exists()) { + $invoice->transactions()->delete(); + } + }); + + $company->invoices()->delete(); + } + + if ($company->recurringInvoices()->exists()) { + $company->recurringInvoices->map(function ($recurringInvoice) { + $this->checkModelData($recurringInvoice); + }); + + $company->recurringInvoices()->delete(); + } + + if ($company->estimates()->exists()) { + $company->estimates->map(function ($estimate) { + $this->checkModelData($estimate); + }); + + $company->estimates()->delete(); + } + + if ($company->items()->exists()) { + $company->items()->delete(); + } + + if ($company->taxTypes()->exists()) { + $company->taxTypes()->delete(); + } + + if ($company->customers()->exists()) { + $company->customers->map(function ($customer) { + if ($customer->addresses()->exists()) { + $customer->addresses()->delete(); + } + + $customer->delete(); + }); + } + + $roles = Role::when($company->id, function ($query) use ($company) { + return $query->where('scope', $company->id); + })->get(); + + if ($roles) { + $roles->map(function ($role) { + $role->delete(); + }); + } + + if ($company->users()->exists()) { + $user->companies()->detach($company->id); + } + + $company->settings()->delete(); + + $company->address()->delete(); + + $company->delete(); + + return true; + } + + private function setupDefaultPaymentMethods(Company $company): void + { + PaymentMethod::create(['name' => 'Cash', 'company_id' => $company->id]); + PaymentMethod::create(['name' => 'Check', 'company_id' => $company->id]); + PaymentMethod::create(['name' => 'Credit Card', 'company_id' => $company->id]); + PaymentMethod::create(['name' => 'Bank Transfer', 'company_id' => $company->id]); + } + + private function setupDefaultUnits(Company $company): void + { + Unit::create(['name' => 'box', 'company_id' => $company->id]); + Unit::create(['name' => 'cm', 'company_id' => $company->id]); + Unit::create(['name' => 'dz', 'company_id' => $company->id]); + Unit::create(['name' => 'ft', 'company_id' => $company->id]); + Unit::create(['name' => 'g', 'company_id' => $company->id]); + Unit::create(['name' => 'in', 'company_id' => $company->id]); + Unit::create(['name' => 'kg', 'company_id' => $company->id]); + Unit::create(['name' => 'km', 'company_id' => $company->id]); + Unit::create(['name' => 'lb', 'company_id' => $company->id]); + Unit::create(['name' => 'mg', 'company_id' => $company->id]); + Unit::create(['name' => 'pc', 'company_id' => $company->id]); + } + + private function setupDefaultSettings(Company $company): void + { + $defaultInvoiceEmailBody = 'You have received a new invoice from {COMPANY_NAME}.
Please download using the button below:'; + $defaultEstimateEmailBody = 'You have received a new estimate from {COMPANY_NAME}.
Please download using the button below:'; + $defaultPaymentEmailBody = 'Thank you for the payment.
Please download your payment receipt using the button below:'; + $billingAddressFormat = '

{BILLING_ADDRESS_NAME}

{BILLING_ADDRESS_STREET_1}

{BILLING_ADDRESS_STREET_2}

{BILLING_CITY} {BILLING_STATE}

{BILLING_COUNTRY} {BILLING_ZIP_CODE}

{BILLING_PHONE}

'; + $shippingAddressFormat = '

{SHIPPING_ADDRESS_NAME}

{SHIPPING_ADDRESS_STREET_1}

{SHIPPING_ADDRESS_STREET_2}

{SHIPPING_CITY} {SHIPPING_STATE}

{SHIPPING_COUNTRY} {SHIPPING_ZIP_CODE}

{SHIPPING_PHONE}

'; + $companyAddressFormat = '

{COMPANY_NAME}

{COMPANY_ADDRESS_STREET_1}

{COMPANY_ADDRESS_STREET_2}

{COMPANY_CITY} {COMPANY_STATE}

{COMPANY_COUNTRY} {COMPANY_ZIP_CODE}

{COMPANY_PHONE}

'; + $paymentFromCustomerAddress = '

{BILLING_ADDRESS_NAME}

{BILLING_ADDRESS_STREET_1}

{BILLING_ADDRESS_STREET_2}

{BILLING_CITY} {BILLING_STATE} {BILLING_ZIP_CODE}

{BILLING_COUNTRY}

{BILLING_PHONE}

'; + + $settings = [ + 'invoice_mail_body' => $defaultInvoiceEmailBody, + 'estimate_mail_body' => $defaultEstimateEmailBody, + 'payment_mail_body' => $defaultPaymentEmailBody, + 'invoice_company_address_format' => $companyAddressFormat, + 'invoice_shipping_address_format' => $shippingAddressFormat, + 'invoice_billing_address_format' => $billingAddressFormat, + 'estimate_company_address_format' => $companyAddressFormat, + 'estimate_shipping_address_format' => $shippingAddressFormat, + 'estimate_billing_address_format' => $billingAddressFormat, + 'payment_company_address_format' => $companyAddressFormat, + 'payment_from_customer_address_format' => $paymentFromCustomerAddress, + 'currency' => request()->currency ?? 13, + 'time_zone' => 'Asia/Kolkata', + 'language' => 'en', + 'fiscal_year' => '1-12', + 'carbon_date_format' => 'Y/m/d', + 'moment_date_format' => 'YYYY/MM/DD', + 'carbon_time_format' => 'H:i', + 'moment_time_format' => 'HH:mm', + 'invoice_use_time' => 'NO', + 'notification_email' => 'noreply@invoiceshelf.com', + 'notify_invoice_viewed' => 'NO', + 'notify_estimate_viewed' => 'NO', + 'tax_per_item' => 'NO', + 'discount_per_item' => 'NO', + 'invoice_email_attachment' => 'NO', + 'estimate_email_attachment' => 'NO', + 'payment_email_attachment' => 'NO', + 'retrospective_edits' => 'allow', + 'invoice_number_format' => '{{SERIES:INV}}{{DELIMITER:-}}{{SEQUENCE:6}}', + 'estimate_number_format' => '{{SERIES:EST}}{{DELIMITER:-}}{{SEQUENCE:6}}', + 'payment_number_format' => '{{SERIES:PAY}}{{DELIMITER:-}}{{SEQUENCE:6}}', + 'estimate_set_expiry_date_automatically' => 'YES', + 'estimate_expiry_date_days' => 7, + 'invoice_set_due_date_automatically' => 'YES', + 'invoice_due_date_days' => 7, + 'bulk_exchange_rate_configured' => 'YES', + 'estimate_convert_action' => 'no_action', + 'automatically_expire_public_links' => 'YES', + 'link_expiry_days' => 7, + ]; + + CompanySetting::setSettings($settings, $company->id); + } + + private function checkModelData($model): void + { + $model->items->map(function ($item) { + if ($item->taxes()->exists()) { + $item->taxes()->delete(); + } + + $item->delete(); + }); + + if ($model->taxes()->exists()) { + $model->taxes()->delete(); + } + } +} diff --git a/app/Services/CustomerService.php b/app/Services/CustomerService.php new file mode 100644 index 00000000..a811e86d --- /dev/null +++ b/app/Services/CustomerService.php @@ -0,0 +1,120 @@ +getCustomerPayload()); + + if ($request->shipping) { + if ($request->hasAddress($request->shipping)) { + $customer->addresses()->create($request->getShippingAddress()); + } + } + + if ($request->billing) { + if ($request->hasAddress($request->billing)) { + $customer->addresses()->create($request->getBillingAddress()); + } + } + + $customFields = $request->customFields; + + if ($customFields) { + $customer->addCustomFields($customFields); + } + + return Customer::with('billingAddress', 'shippingAddress', 'fields')->find($customer->id); + } + + /** + * @throws ValidationException + */ + public function update(Request $request, Customer $customer): Customer + { + $condition = $customer->estimates()->exists() || $customer->invoices()->exists() || $customer->payments()->exists() || $customer->recurringInvoices()->exists(); + + if (($customer->currency_id !== $request->currency_id) && $condition) { + throw ValidationException::withMessages([ + 'currency_id' => ['you_cannot_edit_currency'], + ]); + } + + $customer->update($request->getCustomerPayload()); + + $customer->addresses()->delete(); + + if ($request->shipping) { + if ($request->hasAddress($request->shipping)) { + $customer->addresses()->create($request->getShippingAddress()); + } + } + + if ($request->billing) { + if ($request->hasAddress($request->billing)) { + $customer->addresses()->create($request->getBillingAddress()); + } + } + + $customFields = $request->customFields; + + if ($customFields) { + $customer->updateCustomFields($customFields); + } + + return Customer::with('billingAddress', 'shippingAddress', 'fields')->find($customer->id); + } + + public function delete(Collection $ids): bool + { + foreach ($ids as $id) { + $customer = Customer::find($id); + + if ($customer->estimates()->exists()) { + $customer->estimates()->delete(); + } + + if ($customer->invoices()->exists()) { + $customer->invoices->map(function ($invoice) { + if ($invoice->transactions()->exists()) { + $invoice->transactions()->delete(); + } + $invoice->delete(); + }); + } + + if ($customer->payments()->exists()) { + $customer->payments()->delete(); + } + + if ($customer->addresses()->exists()) { + $customer->addresses()->delete(); + } + + if ($customer->expenses()->exists()) { + $customer->expenses()->delete(); + } + + if ($customer->recurringInvoices()->exists()) { + foreach ($customer->recurringInvoices as $recurringInvoice) { + if ($recurringInvoice->items()->exists()) { + $recurringInvoice->items()->delete(); + } + + $recurringInvoice->delete(); + } + } + + $customer->delete(); + } + + return true; + } +} diff --git a/app/Services/DocumentItemService.php b/app/Services/DocumentItemService.php new file mode 100644 index 00000000..4e6703d9 --- /dev/null +++ b/app/Services/DocumentItemService.php @@ -0,0 +1,69 @@ +exchange_rate; + + foreach ($items as $item) { + $item['company_id'] = $document->company_id; + $item['exchange_rate'] = $exchangeRate; + $item['base_price'] = $item['price'] * $exchangeRate; + $item['base_discount_val'] = $item['discount_val'] * $exchangeRate; + $item['base_tax'] = $item['tax'] * $exchangeRate; + $item['base_total'] = $item['total'] * $exchangeRate; + + if (array_key_exists('recurring_invoice_id', $item)) { + unset($item['recurring_invoice_id']); + } + + $createdItem = $document->items()->create($item); + + if (array_key_exists('taxes', $item) && $item['taxes']) { + foreach ($item['taxes'] as $tax) { + $tax['company_id'] = $document->company_id; + $tax['exchange_rate'] = $document->exchange_rate; + $tax['base_amount'] = $tax['amount'] * $exchangeRate; + $tax['currency_id'] = $document->currency_id; + + if (gettype($tax['amount']) !== 'NULL') { + if (array_key_exists('recurring_invoice_id', $tax)) { + unset($tax['recurring_invoice_id']); + } + + $createdItem->taxes()->create($tax); + } + } + } + + if (array_key_exists('custom_fields', $item) && $item['custom_fields']) { + $createdItem->addCustomFields($item['custom_fields']); + } + } + } + + public function createTaxes(Model $document, array $taxes): void + { + $exchangeRate = $document->exchange_rate; + + foreach ($taxes as $tax) { + $tax['company_id'] = $document->company_id; + $tax['exchange_rate'] = $document->exchange_rate; + $tax['base_amount'] = $tax['amount'] * $exchangeRate; + $tax['currency_id'] = $document->currency_id; + + if (gettype($tax['amount']) !== 'NULL') { + if (array_key_exists('recurring_invoice_id', $tax)) { + unset($tax['recurring_invoice_id']); + } + + $document->taxes()->create($tax); + } + } + } +} diff --git a/app/Services/EstimateService.php b/app/Services/EstimateService.php new file mode 100644 index 00000000..5027e1e2 --- /dev/null +++ b/app/Services/EstimateService.php @@ -0,0 +1,202 @@ +getEstimatePayload(); + + if ($request->has('estimateSend')) { + $data['status'] = Estimate::STATUS_SENT; + } + + $estimate = Estimate::create($data); + $estimate->unique_hash = Hashids::connection(Estimate::class)->encode($estimate->id); + $serial = (new SerialNumberFormatter) + ->setModel($estimate) + ->setCompany($estimate->company_id) + ->setCustomer($estimate->customer_id) + ->setNextNumbers(); + + $estimate->sequence_number = $serial->nextSequenceNumber; + $estimate->customer_sequence_number = $serial->nextCustomerSequenceNumber; + $estimate->save(); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($estimate); + } + + $this->documentItemService->createItems($estimate, $request->items); + + if ($request->has('taxes') && (! empty($request->taxes))) { + $this->documentItemService->createTaxes($estimate, $request->taxes); + } + + $customFields = $request->customFields; + + if ($customFields) { + $estimate->addCustomFields($customFields); + } + + return $estimate; + } + + public function update(Estimate $estimate, Request $request): Estimate + { + $data = $request->getEstimatePayload(); + + $serial = (new SerialNumberFormatter) + ->setModel($estimate) + ->setCompany($estimate->company_id) + ->setCustomer($request->customer_id) + ->setModelObject($estimate->id) + ->setNextNumbers(); + + $data['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; + + $estimate->update($data); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($estimate); + } + + $estimate->items->map(function ($item) { + $fields = $item->fields()->get(); + + $fields->map(function ($field) { + $field->delete(); + }); + }); + + $estimate->items()->delete(); + $estimate->taxes()->delete(); + + $this->documentItemService->createItems($estimate, $request->items); + + if ($request->has('taxes') && (! empty($request->taxes))) { + $this->documentItemService->createTaxes($estimate, $request->taxes); + } + + if ($request->customFields) { + $estimate->updateCustomFields($request->customFields); + } + + return Estimate::with([ + 'items.taxes', + 'items.fields', + 'items.fields.customField', + 'customer', + 'taxes', + ])->find($estimate->id); + } + + public function sendEstimateData(Estimate $estimate, array $data): array + { + $data['estimate'] = $estimate->toArray(); + $data['user'] = $estimate->customer->toArray(); + $data['company'] = $estimate->company->toArray(); + $data['body'] = $estimate->getEmailBody($data['body']); + $data['attach']['data'] = ($estimate->getEmailAttachmentSetting()) ? $this->getPdfData($estimate) : null; + + return $data; + } + + public function send(Estimate $estimate, array $data): array + { + $data = $this->sendEstimateData($estimate, $data); + + CompanyMailConfigService::apply($estimate->company_id); + + if ($estimate->status == Estimate::STATUS_DRAFT) { + $estimate->status = Estimate::STATUS_SENT; + $estimate->save(); + } + + $mail = \Mail::to($data['to']); + if (! empty($data['cc'])) { + $mail->cc($data['cc']); + } + if (! empty($data['bcc'])) { + $mail->bcc($data['bcc']); + } + $mail->send(new SendEstimateMail($data)); + + return [ + 'success' => true, + 'type' => 'send', + ]; + } + + public function getPdfData(Estimate $estimate) + { + $taxes = collect(); + + if ($estimate->tax_per_item === 'YES') { + foreach ($estimate->items as $item) { + foreach ($item->taxes as $tax) { + $found = $taxes->filter(function ($item) use ($tax) { + return $item->tax_type_id == $tax->tax_type_id; + })->first(); + + if ($found) { + $found->amount += $tax->amount; + } else { + $taxes->push($tax); + } + } + } + } + + $estimateTemplate = Estimate::find($estimate->id)->template_name; + + $company = Company::find($estimate->company_id); + $locale = CompanySetting::getSetting('language', $company->id); + $customFields = CustomField::where('model_type', 'Item')->get(); + + App::setLocale($locale); + + $logo = $company->logo_path; + + view()->share([ + 'estimate' => $estimate, + 'customFields' => $customFields, + 'logo' => $logo ?? null, + 'company_address' => $estimate->getCompanyAddress(), + 'shipping_address' => $estimate->getCustomerShippingAddress(), + 'billing_address' => $estimate->getCustomerBillingAddress(), + 'notes' => $estimate->getNotes(), + 'taxes' => $taxes, + ]); + + $template = PdfTemplateUtils::findFormattedTemplate('estimate', $estimateTemplate, ''); + $templatePath = $template['custom'] ? sprintf('pdf_templates::estimate.%s', $estimateTemplate) : sprintf('app.pdf.estimate.%s', $estimateTemplate); + + if (request()->has('preview')) { + return view($templatePath); + } + + return PDF::loadView($templatePath); + } +} diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php new file mode 100644 index 00000000..603df4ff --- /dev/null +++ b/app/Services/ExpenseService.php @@ -0,0 +1,59 @@ +getExpensePayload()); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $expense['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($expense); + } + + if ($request->hasFile('attachment_receipt')) { + $expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts'); + } + + if ($request->customFields) { + $expense->addCustomFields(json_decode($request->customFields)); + } + + return $expense; + } + + public function update(Expense $expense, Request $request): bool + { + $data = $request->getExpensePayload(); + + $expense->update($data); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($expense); + } + + if (isset($request->is_attachment_receipt_removed) && (bool) $request->is_attachment_receipt_removed) { + $expense->clearMediaCollection('receipts'); + } + if ($request->hasFile('attachment_receipt')) { + $expense->clearMediaCollection('receipts'); + $expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts'); + } + + if ($request->customFields) { + $expense->updateCustomFields(json_decode($request->customFields)); + } + + return true; + } +} diff --git a/app/Space/EnvironmentManager.php b/app/Services/Installation/EnvironmentManager.php similarity index 99% rename from app/Space/EnvironmentManager.php rename to app/Services/Installation/EnvironmentManager.php index 62df5bfe..c00b04f2 100755 --- a/app/Space/EnvironmentManager.php +++ b/app/Services/Installation/EnvironmentManager.php @@ -1,6 +1,6 @@ getInvoicePayload(); + + if ($request->has('invoiceSend')) { + $data['status'] = Invoice::STATUS_SENT; + } + + $invoice = Invoice::create($data); + + $serial = (new SerialNumberFormatter) + ->setModel($invoice) + ->setCompany($invoice->company_id) + ->setCustomer($invoice->customer_id) + ->setNextNumbers(); + + $invoice->sequence_number = $serial->nextSequenceNumber; + $invoice->customer_sequence_number = $serial->nextCustomerSequenceNumber; + $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); + $invoice->save(); + + $this->documentItemService->createItems($invoice, $request->items); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($invoice); + } + + if ($request->has('taxes') && (! empty($request->taxes))) { + $this->documentItemService->createTaxes($invoice, $request->taxes); + } + + if ($request->customFields) { + $invoice->addCustomFields($request->customFields); + } + + return Invoice::with([ + 'items', + 'items.fields', + 'items.fields.customField', + 'customer', + 'taxes', + ])->find($invoice->id); + } + + /** + * @throws ValidationException + */ + public function update(Invoice $invoice, Request $request): Invoice + { + $serial = (new SerialNumberFormatter) + ->setModel($invoice) + ->setCompany($invoice->company_id) + ->setCustomer($request->customer_id) + ->setModelObject($invoice->id) + ->setNextNumbers(); + + $data = $request->getInvoicePayload(); + $oldTotal = $invoice->total; + + $totalPaidAmount = $invoice->total - $invoice->due_amount; + + if ($totalPaidAmount > 0 && $invoice->customer_id !== $request->customer_id) { + throw ValidationException::withMessages([ + 'customer_id' => ['customer_cannot_be_changed_after_payment_is_added'], + ]); + } + + if ($request->total >= 0 && $request->total < $totalPaidAmount) { + throw ValidationException::withMessages([ + 'total' => ['total_invoice_amount_must_be_more_than_paid_amount'], + ]); + } + + if ($oldTotal != $request->total) { + $oldTotal = (int) round($request->total) - (int) $oldTotal; + } else { + $oldTotal = 0; + } + + $data['due_amount'] = ($invoice->due_amount + $oldTotal); + $data['base_due_amount'] = $data['due_amount'] * $data['exchange_rate']; + $data['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; + + $invoice->update($data); + + $statusData = $invoice->getInvoiceStatusByAmount($data['due_amount']); + if (! empty($statusData)) { + $invoice->update($statusData); + } + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($invoice); + } + + $invoice->items->map(function ($item) { + $fields = $item->fields()->get(); + + $fields->map(function ($field) { + $field->delete(); + }); + }); + + $invoice->items()->delete(); + $invoice->taxes()->delete(); + + $this->documentItemService->createItems($invoice, $request->items); + + if ($request->has('taxes') && (! empty($request->taxes))) { + $this->documentItemService->createTaxes($invoice, $request->taxes); + } + + if ($request->customFields) { + $invoice->updateCustomFields($request->customFields); + } + + return Invoice::with([ + 'items', + 'items.fields', + 'items.fields.customField', + 'customer', + 'taxes', + ])->find($invoice->id); + } + + public function delete(Collection $ids): bool + { + foreach ($ids as $id) { + $invoice = Invoice::find($id); + + if ($invoice->transactions()->exists()) { + $invoice->transactions()->delete(); + } + + $invoice->delete(); + } + + return true; + } + + public function sendInvoiceData(Invoice $invoice, array $data): array + { + $data['invoice'] = $invoice->toArray(); + $data['customer'] = $invoice->customer->toArray(); + $data['company'] = Company::find($invoice->company_id); + $data['subject'] = $invoice->getEmailString($data['subject']); + $data['body'] = $invoice->getEmailString($data['body']); + $data['attach']['data'] = ($invoice->getEmailAttachmentSetting()) ? $this->getPdfData($invoice) : null; + + return $data; + } + + public function preview(Invoice $invoice, array $data): array + { + $data = $this->sendInvoiceData($invoice, $data); + + return [ + 'type' => 'preview', + 'view' => new SendInvoiceMail($data), + ]; + } + + public function send(Invoice $invoice, array $data): array + { + $data = $this->sendInvoiceData($invoice, $data); + + CompanyMailConfigService::apply($invoice->company_id); + + $mail = \Mail::to($data['to']); + if (! empty($data['cc'])) { + $mail->cc($data['cc']); + } + if (! empty($data['bcc'])) { + $mail->bcc($data['bcc']); + } + $mail->send(new SendInvoiceMail($data)); + + if ($invoice->status == Invoice::STATUS_DRAFT) { + $invoice->status = Invoice::STATUS_SENT; + $invoice->sent = true; + $invoice->save(); + } + + return [ + 'success' => true, + 'type' => 'send', + ]; + } + + public function getPdfData(Invoice $invoice) + { + $taxes = collect(); + + if ($invoice->tax_per_item === 'YES') { + foreach ($invoice->items as $item) { + foreach ($item->taxes as $tax) { + $found = $taxes->filter(function ($item) use ($tax) { + return $item->tax_type_id == $tax->tax_type_id; + })->first(); + + if ($found) { + $found->amount += $tax->amount; + } else { + $taxes->push($tax); + } + } + } + } + + $invoiceTemplate = Invoice::find($invoice->id)->template_name; + + $company = Company::find($invoice->company_id); + $locale = CompanySetting::getSetting('language', $company->id); + $customFields = CustomField::where('model_type', 'Item')->get(); + + App::setLocale($locale); + + $logo = $company->logo_path; + + view()->share([ + 'invoice' => $invoice, + 'customFields' => $customFields, + 'company_address' => $invoice->getCompanyAddress(), + 'shipping_address' => $invoice->getCustomerShippingAddress(), + 'billing_address' => $invoice->getCustomerBillingAddress(), + 'notes' => $invoice->getNotes(), + 'logo' => $logo ?? null, + 'taxes' => $taxes, + ]); + + $template = PdfTemplateUtils::findFormattedTemplate('invoice', $invoiceTemplate, ''); + $templatePath = $template['custom'] ? sprintf('pdf_templates::invoice.%s', $invoiceTemplate) : sprintf('app.pdf.invoice.%s', $invoiceTemplate); + + if (request()->has('preview')) { + return view($templatePath); + } + + return PDF::loadView($templatePath); + } +} diff --git a/app/Space/ModuleInstaller.php b/app/Services/Module/ModuleInstaller.php similarity index 99% rename from app/Space/ModuleInstaller.php rename to app/Services/Module/ModuleInstaller.php index 57a6943c..52e3964c 100644 --- a/app/Space/ModuleInstaller.php +++ b/app/Services/Module/ModuleInstaller.php @@ -1,12 +1,13 @@ getPaymentPayload(); + + if ($request->invoice_id) { + $invoice = Invoice::find($request->invoice_id); + $invoice->subtractInvoicePayment($request->amount); + } + + $payment = Payment::create($data); + $payment->unique_hash = Hashids::connection(Payment::class)->encode($payment->id); + + $serial = (new SerialNumberFormatter) + ->setModel($payment) + ->setCompany($payment->company_id) + ->setCustomer($payment->customer_id) + ->setNextNumbers(); + + $payment->sequence_number = $serial->nextSequenceNumber; + $payment->customer_sequence_number = $serial->nextCustomerSequenceNumber; + $payment->save(); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $payment['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($payment); + } + + $customFields = $request->customFields; + + if ($customFields) { + $payment->addCustomFields($customFields); + } + + return Payment::with([ + 'customer', + 'invoice', + 'paymentMethod', + 'fields', + ])->find($payment->id); + } + + public function update(Payment $payment, Request $request): Payment + { + $data = $request->getPaymentPayload(); + + if ($request->invoice_id && (! $payment->invoice_id || $payment->invoice_id !== $request->invoice_id)) { + $invoice = Invoice::find($request->invoice_id); + $invoice->subtractInvoicePayment($request->amount); + } + + if ($payment->invoice_id && (! $request->invoice_id || $payment->invoice_id !== $request->invoice_id)) { + $invoice = Invoice::find($payment->invoice_id); + $invoice->addInvoicePayment($payment->amount); + } + + if ($payment->invoice_id && $payment->invoice_id === $request->invoice_id && $request->amount !== $payment->amount) { + $invoice = Invoice::find($payment->invoice_id); + $invoice->addInvoicePayment($payment->amount); + $invoice->subtractInvoicePayment($request->amount); + } + + $serial = (new SerialNumberFormatter) + ->setModel($payment) + ->setCompany($payment->company_id) + ->setCustomer($request->customer_id) + ->setModelObject($payment->id) + ->setNextNumbers(); + + $data['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; + $payment->update($data); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($payment); + } + + $customFields = $request->customFields; + + if ($customFields) { + $payment->updateCustomFields($customFields); + } + + return Payment::with([ + 'customer', + 'invoice', + 'paymentMethod', + ])->find($payment->id); + } + + public function delete(Collection $ids): bool + { + foreach ($ids as $id) { + $payment = Payment::find($id); + + if ($payment->invoice_id != null) { + $invoice = Invoice::find($payment->invoice_id); + $invoice->due_amount = ((int) $invoice->due_amount + (int) $payment->amount); + + if ($invoice->due_amount == $invoice->total) { + $invoice->paid_status = Invoice::STATUS_UNPAID; + } else { + $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; + } + + $invoice->status = $invoice->getPreviousStatus(); + $invoice->save(); + } + + $payment->delete(); + } + + return true; + } + + public function sendPaymentData(Payment $payment, array $data): array + { + $data['payment'] = $payment->toArray(); + $data['user'] = $payment->customer->toArray(); + $data['company'] = Company::find($payment->company_id); + $data['body'] = $payment->getEmailBody($data['body']); + $data['attach']['data'] = ($payment->getEmailAttachmentSetting()) ? $this->getPdfData($payment) : null; + + return $data; + } + + public function send(Payment $payment, array $data): array + { + $data = $this->sendPaymentData($payment, $data); + + CompanyMailConfigService::apply($payment->company_id); + + $mail = \Mail::to($data['to']); + if (! empty($data['cc'])) { + $mail->cc($data['cc']); + } + if (! empty($data['bcc'])) { + $mail->bcc($data['bcc']); + } + $mail->send(new SendPaymentMail($data)); + + return [ + 'success' => true, + ]; + } + + public function getPdfData(Payment $payment) + { + $company = Company::find($payment->company_id); + $locale = CompanySetting::getSetting('language', $company->id); + + \App::setLocale($locale); + + $logo = $company->logo_path; + + view()->share([ + 'payment' => $payment, + 'company_address' => $payment->getCompanyAddress(), + 'billing_address' => $payment->getCustomerBillingAddress(), + 'notes' => $payment->getNotes(), + 'logo' => $logo ?? null, + ]); + + if (request()->has('preview')) { + return view('app.pdf.payment.payment'); + } + + return PDF::loadView('app.pdf.payment.payment'); + } + + public function generateFromTransaction($transaction): Payment + { + $invoice = Invoice::find($transaction->invoice_id); + + $serial = (new SerialNumberFormatter) + ->setModel(new Payment) + ->setCompany($invoice->company_id) + ->setCustomer($invoice->customer_id) + ->setNextNumbers(); + + $data['payment_number'] = $serial->getNextNumber(); + $data['payment_date'] = Carbon::now(); + $data['amount'] = $invoice->total; + $data['invoice_id'] = $invoice->id; + $data['payment_method_id'] = request()->payment_method_id; + $data['customer_id'] = $invoice->customer_id; + $data['exchange_rate'] = $invoice->exchange_rate; + $data['base_amount'] = $data['amount'] * $data['exchange_rate']; + $data['currency_id'] = $invoice->currency_id; + $data['company_id'] = $invoice->company_id; + $data['transaction_id'] = $transaction->id; + + $payment = Payment::create($data); + $payment->unique_hash = Hashids::connection(Payment::class)->encode($payment->id); + $payment->sequence_number = $serial->nextSequenceNumber; + $payment->customer_sequence_number = $serial->nextCustomerSequenceNumber; + $payment->save(); + + $invoice->subtractInvoicePayment($invoice->total); + + return $payment; + } +} diff --git a/app/Space/ImageUtils.php b/app/Services/Pdf/ImageUtils.php similarity index 92% rename from app/Space/ImageUtils.php rename to app/Services/Pdf/ImageUtils.php index eecfb9ee..3fe99cfb 100644 --- a/app/Space/ImageUtils.php +++ b/app/Services/Pdf/ImageUtils.php @@ -1,6 +1,6 @@ getRecurringInvoicePayload()); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $recurringInvoice['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($recurringInvoice); + } + + $this->createItems($recurringInvoice, $request->items); + + if ($request->has('taxes') && (! empty($request->taxes))) { + $this->createTaxes($recurringInvoice, $request->taxes); + } + + if ($request->customFields) { + $recurringInvoice->addCustomFields($request->customFields); + } + + return $recurringInvoice; + } + + public function update(RecurringInvoice $recurringInvoice, RecurringInvoiceRequest $request): RecurringInvoice + { + $data = $request->getRecurringInvoicePayload(); + + $recurringInvoice->update($data); + + $companyCurrency = CompanySetting::getSetting('currency', $request->header('company')); + + if ((string) $data['currency_id'] !== $companyCurrency) { + ExchangeRateLog::addExchangeRateLog($recurringInvoice); + } + + $recurringInvoice->items()->delete(); + $this->createItems($recurringInvoice, $request->items); + + $recurringInvoice->taxes()->delete(); + if ($request->has('taxes') && (! empty($request->taxes))) { + $this->createTaxes($recurringInvoice, $request->taxes); + } + + if ($request->customFields) { + $recurringInvoice->updateCustomFields($request->customFields); + } + + return $recurringInvoice; + } + + public function delete(Collection $ids): bool + { + foreach ($ids as $id) { + $recurringInvoice = RecurringInvoice::find($id); + + if ($recurringInvoice->invoices()->exists()) { + $recurringInvoice->invoices()->update(['recurring_invoice_id' => null]); + } + + if ($recurringInvoice->items()->exists()) { + $recurringInvoice->items()->delete(); + } + + if ($recurringInvoice->taxes()->exists()) { + $recurringInvoice->taxes()->delete(); + } + + $recurringInvoice->delete(); + } + + return true; + } + + public function generateInvoice(RecurringInvoice $recurringInvoice): void + { + if (Carbon::now()->lessThan($recurringInvoice->starts_at)) { + return; + } + + if ($recurringInvoice->limit_by == 'DATE') { + $startDate = Carbon::today()->format('Y-m-d'); + $endDate = $recurringInvoice->limit_date; + + if ($endDate >= $startDate) { + $this->createInvoiceFromRecurring($recurringInvoice); + $recurringInvoice->updateNextInvoiceDate(); + } else { + $recurringInvoice->markStatusAsCompleted(); + } + } elseif ($recurringInvoice->limit_by == 'COUNT') { + $invoiceCount = Invoice::where('recurring_invoice_id', $recurringInvoice->id)->count(); + + if ($invoiceCount < $recurringInvoice->limit_count) { + $this->createInvoiceFromRecurring($recurringInvoice); + $recurringInvoice->updateNextInvoiceDate(); + } else { + $recurringInvoice->markStatusAsCompleted(); + } + } else { + $this->createInvoiceFromRecurring($recurringInvoice); + $recurringInvoice->updateNextInvoiceDate(); + } + } + + private function createInvoiceFromRecurring(RecurringInvoice $recurringInvoice): void + { + $serial = (new SerialNumberFormatter) + ->setModel(new Invoice) + ->setCompany($recurringInvoice->company_id) + ->setCustomer($recurringInvoice->customer_id) + ->setNextNumbers(); + + $days = intval(CompanySetting::getSetting('invoice_due_date_days', $recurringInvoice->company_id)); + + if (! $days || $days == 'null') { + $days = 7; + } + + $newInvoice['creator_id'] = $recurringInvoice->creator_id; + $newInvoice['invoice_date'] = Carbon::today()->format('Y-m-d'); + $newInvoice['due_date'] = Carbon::today()->addDays($days)->format('Y-m-d'); + $newInvoice['status'] = Invoice::STATUS_DRAFT; + $newInvoice['company_id'] = $recurringInvoice->company_id; + $newInvoice['paid_status'] = Invoice::STATUS_UNPAID; + $newInvoice['sub_total'] = $recurringInvoice->sub_total; + $newInvoice['tax_per_item'] = $recurringInvoice->tax_per_item; + $newInvoice['discount_per_item'] = $recurringInvoice->discount_per_item; + $newInvoice['tax'] = $recurringInvoice->tax; + $newInvoice['total'] = $recurringInvoice->total; + $newInvoice['customer_id'] = $recurringInvoice->customer_id; + $newInvoice['currency_id'] = Customer::find($recurringInvoice->customer_id)->currency_id; + $newInvoice['template_name'] = $recurringInvoice->template_name; + $newInvoice['due_amount'] = $recurringInvoice->total; + $newInvoice['recurring_invoice_id'] = $recurringInvoice->id; + $newInvoice['discount_val'] = $recurringInvoice->discount_val; + $newInvoice['discount'] = $recurringInvoice->discount; + $newInvoice['discount_type'] = $recurringInvoice->discount_type; + $newInvoice['notes'] = $recurringInvoice->notes; + $newInvoice['exchange_rate'] = $recurringInvoice->exchange_rate; + $newInvoice['sales_tax_type'] = $recurringInvoice->sales_tax_type; + $newInvoice['sales_tax_address_type'] = $recurringInvoice->sales_tax_address_type; + $newInvoice['invoice_number'] = $serial->getNextNumber(); + $newInvoice['sequence_number'] = $serial->nextSequenceNumber; + $newInvoice['customer_sequence_number'] = $serial->nextCustomerSequenceNumber; + $newInvoice['base_due_amount'] = $recurringInvoice->exchange_rate * $recurringInvoice->due_amount; + $newInvoice['base_discount_val'] = $recurringInvoice->exchange_rate * $recurringInvoice->discount_val; + $newInvoice['base_sub_total'] = $recurringInvoice->exchange_rate * $recurringInvoice->sub_total; + $newInvoice['base_tax'] = $recurringInvoice->exchange_rate * $recurringInvoice->tax; + $newInvoice['base_total'] = $recurringInvoice->exchange_rate * $recurringInvoice->total; + $invoice = Invoice::create($newInvoice); + $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); + $invoice->save(); + + $recurringInvoice->load('items.taxes'); + $this->documentItemService->createItems($invoice, $recurringInvoice->items->toArray()); + + if ($recurringInvoice->taxes()->exists()) { + $this->documentItemService->createTaxes($invoice, $recurringInvoice->taxes->toArray()); + } + + if ($recurringInvoice->fields()->exists()) { + $customField = []; + + foreach ($recurringInvoice->fields as $data) { + $customField[] = [ + 'id' => $data->custom_field_id, + 'value' => $data->defaultAnswer, + ]; + } + + $invoice->addCustomFields($customField); + } + + if ($recurringInvoice->send_automatically == true) { + $data = [ + 'body' => CompanySetting::getSetting('invoice_mail_body', $recurringInvoice->company_id), + 'from' => config('mail.from.address'), + 'to' => $recurringInvoice->customer->email, + 'subject' => trans('invoices')['new_invoice'], + 'invoice' => $invoice->toArray(), + 'customer' => $invoice->customer->toArray(), + 'company' => Company::find($invoice->company_id), + ]; + + $this->invoiceService->send($invoice, $data); + } + } + + private function createItems(RecurringInvoice $recurringInvoice, array $items): void + { + foreach ($items as $item) { + $item['company_id'] = $recurringInvoice->company_id; + $createdItem = $recurringInvoice->items()->create($item); + if (array_key_exists('taxes', $item) && $item['taxes']) { + foreach ($item['taxes'] as $tax) { + $tax['company_id'] = $recurringInvoice->company_id; + if (gettype($tax['amount']) !== 'NULL') { + $createdItem->taxes()->create($tax); + } + } + } + } + } + + private function createTaxes(RecurringInvoice $recurringInvoice, array $taxes): void + { + foreach ($taxes as $tax) { + $tax['company_id'] = $recurringInvoice->company_id; + + if (gettype($tax['amount']) !== 'NULL') { + $recurringInvoice->taxes()->create($tax); + } + } + } +} diff --git a/app/Space/Updater.php b/app/Services/Update/Updater.php similarity index 98% rename from app/Space/Updater.php rename to app/Services/Update/Updater.php index 28f5774b..caa7d999 100644 --- a/app/Space/Updater.php +++ b/app/Services/Update/Updater.php @@ -1,9 +1,10 @@ getUserPayload()); + + $user->setSettings([ + 'language' => CompanySetting::getSetting('language', $request->header('company')), + ]); + + $companies = collect($request->companies); + $user->companies()->sync($companies->pluck('id')); + + foreach ($companies as $company) { + BouncerFacade::scope()->to($company['id']); + + BouncerFacade::sync($user)->roles([$company['role']]); + } + + return $user; + } + + public function update(User $user, UserRequest $request): User + { + $user->update($request->getUserPayload()); + + $companies = collect($request->companies); + $user->companies()->sync($companies->pluck('id')); + + foreach ($companies as $company) { + BouncerFacade::scope()->to($company['id']); + + BouncerFacade::sync($user)->roles([$company['role']]); + } + + return $user; + } + + public function delete(array $ids): bool + { + foreach ($ids as $id) { + $user = User::find($id); + + if ($user->invoices()->exists()) { + $user->invoices()->update(['creator_id' => null]); + } + + if ($user->estimates()->exists()) { + $user->estimates()->update(['creator_id' => null]); + } + + if ($user->customers()->exists()) { + $user->customers()->update(['creator_id' => null]); + } + + if ($user->recurringInvoices()->exists()) { + $user->recurringInvoices()->update(['creator_id' => null]); + } + + if ($user->expenses()->exists()) { + $user->expenses()->update(['creator_id' => null]); + } + + if ($user->payments()->exists()) { + $user->payments()->update(['creator_id' => null]); + } + + if ($user->items()->exists()) { + $user->items()->update(['creator_id' => null]); + } + + if ($user->settings()->exists()) { + $user->settings()->delete(); + } + + $user->delete(); + } + + return true; + } +} diff --git a/app/Space/DateFormatter.php b/app/Support/Formatters/DateFormatter.php similarity index 97% rename from app/Space/DateFormatter.php rename to app/Support/Formatters/DateFormatter.php index 7510b83d..9e11f278 100644 --- a/app/Space/DateFormatter.php +++ b/app/Support/Formatters/DateFormatter.php @@ -1,6 +1,6 @@ unique_hash = Hashids::connection(Company::class)->encode($company->id); $company->save(); - $company->setupDefaultData(); + app(CompanyService::class)->setupDefaults($company); $user->companies()->attach($company->id); BouncerFacade::scope()->to($company->id); diff --git a/database/seeders/UsersTableSeeder.php b/database/seeders/UsersTableSeeder.php index 17be3741..17c0c58a 100644 --- a/database/seeders/UsersTableSeeder.php +++ b/database/seeders/UsersTableSeeder.php @@ -6,7 +6,8 @@ use App\Facades\Hashids; use App\Models\Company; use App\Models\Setting; use App\Models\User; -use App\Space\InstallUtils; +use App\Services\CompanyService; +use App\Services\Installation\InstallUtils; use Illuminate\Database\Seeder; use Silber\Bouncer\BouncerFacade; @@ -32,7 +33,7 @@ class UsersTableSeeder extends Seeder $company->unique_hash = Hashids::connection(Company::class)->encode($company->id); $company->save(); - $company->setupDefaultData(); + app(CompanyService::class)->setupDefaults($company); $user->companies()->attach($company->id); BouncerFacade::scope()->to($company->id); diff --git a/resources/views/app/pdf/estimate/estimate1.blade.php b/resources/views/app/pdf/estimate/estimate1.blade.php index 820606ba..80da043d 100644 --- a/resources/views/app/pdf/estimate/estimate1.blade.php +++ b/resources/views/app/pdf/estimate/estimate1.blade.php @@ -398,7 +398,7 @@ @if ($logo) - + @else @if ($estimate->customer->company) diff --git a/resources/views/app/pdf/estimate/estimate2.blade.php b/resources/views/app/pdf/estimate/estimate2.blade.php index eb35ab83..55edf048 100644 --- a/resources/views/app/pdf/estimate/estimate2.blade.php +++ b/resources/views/app/pdf/estimate/estimate2.blade.php @@ -420,7 +420,7 @@ @if ($logo) - + @else diff --git a/resources/views/app/pdf/estimate/estimate3.blade.php b/resources/views/app/pdf/estimate/estimate3.blade.php index 1cb18b08..5558d287 100644 --- a/resources/views/app/pdf/estimate/estimate3.blade.php +++ b/resources/views/app/pdf/estimate/estimate3.blade.php @@ -358,7 +358,7 @@ @if ($logo) - + @else

{{ $estimate->customer->company->name }}

@endif diff --git a/resources/views/app/pdf/invoice/invoice1.blade.php b/resources/views/app/pdf/invoice/invoice1.blade.php index 8573705e..ca57f6b9 100644 --- a/resources/views/app/pdf/invoice/invoice1.blade.php +++ b/resources/views/app/pdf/invoice/invoice1.blade.php @@ -337,7 +337,7 @@ @if ($logo) - + @else @if ($invoice->customer->company) diff --git a/resources/views/app/pdf/invoice/invoice2.blade.php b/resources/views/app/pdf/invoice/invoice2.blade.php index f20296bd..7e85ccd3 100644 --- a/resources/views/app/pdf/invoice/invoice2.blade.php +++ b/resources/views/app/pdf/invoice/invoice2.blade.php @@ -390,7 +390,7 @@ @if ($logo) - + @elseif ($invoice->customer->company)

{{ $invoice->customer->company->name }} diff --git a/resources/views/app/pdf/invoice/invoice3.blade.php b/resources/views/app/pdf/invoice/invoice3.blade.php index 05893608..2f5616dc 100644 --- a/resources/views/app/pdf/invoice/invoice3.blade.php +++ b/resources/views/app/pdf/invoice/invoice3.blade.php @@ -319,7 +319,7 @@ @if ($logo) - + @else

{{ $invoice->customer->company->name }}

@endif diff --git a/resources/views/app/pdf/payment/payment.blade.php b/resources/views/app/pdf/payment/payment.blade.php index 52dd5afd..394be0ef 100644 --- a/resources/views/app/pdf/payment/payment.blade.php +++ b/resources/views/app/pdf/payment/payment.blade.php @@ -288,7 +288,7 @@ @if ($logo) - + @else @if ($payment->customer) diff --git a/routes/console.php b/routes/console.php index 1acb6745..3b22769c 100644 --- a/routes/console.php +++ b/routes/console.php @@ -2,7 +2,8 @@ use App\Models\CompanySetting; use App\Models\RecurringInvoice; -use App\Space\InstallUtils; +use App\Services\Installation\InstallUtils; +use App\Services\RecurringInvoiceService; use Illuminate\Support\Facades\Schedule; // Only run in demo environment @@ -25,7 +26,7 @@ if (InstallUtils::isDbCreated()) { $timeZone = CompanySetting::getSetting('time_zone', $recurringInvoice->company_id); Schedule::call(function () use ($recurringInvoice) { - $recurringInvoice->generateInvoice(); + app(RecurringInvoiceService::class)->generateInvoice($recurringInvoice); })->cron($recurringInvoice->frequency)->timezone($timeZone); } } diff --git a/tests/Feature/Admin/EstimateTest.php b/tests/Feature/Admin/EstimateTest.php index 96bee25d..d8efc183 100644 --- a/tests/Feature/Admin/EstimateTest.php +++ b/tests/Feature/Admin/EstimateTest.php @@ -427,7 +427,7 @@ test('update estimate with EUR currency', function () { 'exchange_rate' => 86.403538, 'base_discount_val' => 0, 'base_price' => 17280.7076, - 'base_tax' => 777.631842, + 'base_tax' => 0, 'base_total' => 17280.7076, ])], ]); diff --git a/tests/Unit/EstimateTest.php b/tests/Unit/EstimateTest.php index 316d9a8b..b337df84 100644 --- a/tests/Unit/EstimateTest.php +++ b/tests/Unit/EstimateTest.php @@ -4,7 +4,8 @@ use App\Http\Requests\EstimatesRequest; use App\Models\Estimate; use App\Models\EstimateItem; use App\Models\Tax; -use Illuminate\Http\Request; +use App\Services\DocumentItemService; +use App\Services\EstimateService; use Illuminate\Support\Facades\Artisan; beforeEach(function () { @@ -51,7 +52,7 @@ test('create estimate', function () { $request->replace($estimate); - $response = Estimate::createEstimate($request); + $response = app(EstimateService::class)->create($request); $this->assertDatabaseHas('estimate_items', [ 'estimate_id' => $response->id, @@ -99,7 +100,7 @@ test('update estimate', function () { $number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1])); - $estimate->updateEstimate($request); + app(EstimateService::class)->update($estimate, $request); $this->assertDatabaseHas('estimate_items', [ 'estimate_id' => $estimate->id, @@ -135,11 +136,7 @@ test('create items', function () { array_push($items, $item); - $request = new Request; - - $request->replace(['items' => $items]); - - Estimate::createItems($estimate, $request, $estimate->exchange_rate); + app(DocumentItemService::class)->createItems($estimate, $items); $this->assertDatabaseHas('estimate_items', [ 'estimate_id' => $estimate->id, @@ -168,11 +165,7 @@ test('create taxes', function () { array_push($taxes, $tax1); array_push($taxes, $tax2); - $request = new Request; - - $request->replace(['taxes' => $taxes]); - - Estimate::createTaxes($estimate, $request, $estimate->exchange_rate); + app(DocumentItemService::class)->createTaxes($estimate, $taxes); $this->assertCount(2, $estimate->taxes); diff --git a/tests/Unit/InvoiceTest.php b/tests/Unit/InvoiceTest.php index e5ecb92e..32967f84 100644 --- a/tests/Unit/InvoiceTest.php +++ b/tests/Unit/InvoiceTest.php @@ -4,7 +4,8 @@ use App\Http\Requests\InvoicesRequest; use App\Models\Invoice; use App\Models\InvoiceItem; use App\Models\Tax; -use Illuminate\Http\Request; +use App\Services\DocumentItemService; +use App\Services\InvoiceService; use Illuminate\Support\Facades\Artisan; beforeEach(function () { @@ -68,7 +69,7 @@ test('create invoice', function () { $invoice_number = explode('-', $invoice['invoice_number']); $number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1])); - $response = Invoice::createInvoice($request); + $response = app(InvoiceService::class)->create($request); $this->assertDatabaseHas('invoice_items', [ 'invoice_id' => $response->id, @@ -119,7 +120,7 @@ test('update invoice', function () { $number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1])); - $response = $invoice->updateInvoice($request); + $response = app(InvoiceService::class)->update($invoice, $request); $this->assertDatabaseHas('invoice_items', [ 'invoice_id' => $response->id, @@ -154,11 +155,7 @@ test('create items', function () { array_push($items, $item); - $request = new InvoicesRequest; - - $request->replace(['items' => $items]); - - Invoice::createItems($invoice, $request->items); + app(DocumentItemService::class)->createItems($invoice, $items); $this->assertDatabaseHas('invoice_items', [ 'invoice_id' => $invoice->id, @@ -181,11 +178,7 @@ test('create taxes', function () { array_push($taxes, $tax); - $request = new Request; - - $request->replace(['taxes' => $taxes]); - - Invoice::createTaxes($invoice, $request->taxes); + app(DocumentItemService::class)->createTaxes($invoice, $taxes); $this->assertDatabaseHas('taxes', [ 'invoice_id' => $invoice->id,