diff --git a/app/Abstracts/Commands/Module.php b/app/Abstracts/Commands/Module.php index 35f4d49b7..b41e7b79a 100644 --- a/app/Abstracts/Commands/Module.php +++ b/app/Abstracts/Commands/Module.php @@ -21,9 +21,9 @@ abstract class Module extends Command protected function changeRuntime() { - $this->old_company_id = session('company_id'); + $this->old_company_id = company_id(); - session(['company_id' => $this->company_id]); + company($this->company_id)->makeCurrent(); app()->setLocale($this->locale); @@ -36,7 +36,7 @@ abstract class Module extends Command session()->forget('company_id'); if (!empty($this->old_company_id)) { - session(['company_id' => $this->old_company_id]); + company($this->old_company_id)->makeCurrent(); } } diff --git a/app/Abstracts/Export.php b/app/Abstracts/Export.php index 1b4a3ec26..5508ebc87 100644 --- a/app/Abstracts/Export.php +++ b/app/Abstracts/Export.php @@ -4,8 +4,12 @@ namespace App\Abstracts; use App\Events\Export\HeadingsPreparing; use App\Events\Export\RowsPreparing; +use App\Notifications\Common\ExportFailed; use App\Utilities\Date; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Support\Str; +use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\ShouldAutoSize; use Maatwebsite\Excel\Concerns\WithHeadings; @@ -13,16 +17,21 @@ use Maatwebsite\Excel\Concerns\WithMapping; use Maatwebsite\Excel\Concerns\WithTitle; use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate; -abstract class Export implements FromCollection, ShouldAutoSize, WithHeadings, WithMapping, WithTitle +abstract class Export implements FromCollection, HasLocalePreference, ShouldAutoSize, ShouldQueue, WithHeadings, WithMapping, WithTitle { + use Exportable; + public $ids; public $fields; + public $user; + public function __construct($ids = null) { $this->ids = $ids; $this->fields = $this->fields(); + $this->user = user(); } public function title(): string @@ -74,4 +83,14 @@ abstract class Export implements FromCollection, ShouldAutoSize, WithHeadings, W return $rows; } + + public function preferredLocale() + { + return $this->user->locale; + } + + public function failed(\Throwable $exception): void + { + $this->user->notify(new ExportFailed($exception)); + } } diff --git a/app/Abstracts/Factory.php b/app/Abstracts/Factory.php index 4cef11fe8..0c61d7d41 100644 --- a/app/Abstracts/Factory.php +++ b/app/Abstracts/Factory.php @@ -29,8 +29,7 @@ abstract class Factory extends BaseFactory $this->user = User::first(); $this->company = $this->user->companies()->first(); - session(['company_id' => $this->company->id]); - setting()->setExtraColumns(['company_id' => $this->company->id]); + company($this->company->id)->makeCurrent(); } public function getCompanyUsers() diff --git a/app/Abstracts/Http/Controller.php b/app/Abstracts/Http/Controller.php index 371a635fa..2bfe8931b 100644 --- a/app/Abstracts/Http/Controller.php +++ b/app/Abstracts/Http/Controller.php @@ -3,11 +3,12 @@ namespace App\Abstracts\Http; use App\Abstracts\Http\Response; +use App\Jobs\Auth\NotifyUser; +use App\Jobs\Common\CreateMediableForExport; +use App\Notifications\Common\ImportCompleted; use App\Traits\Jobs; use App\Traits\Permissions; use App\Traits\Relationships; -use Exception; -use ErrorException; use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Validation\ValidatesRequests; @@ -15,9 +16,6 @@ use Illuminate\Pagination\Paginator; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Routing\Controller as BaseController; use Illuminate\Support\Str; -use Maatwebsite\Excel\Exceptions\SheetNotFoundException; -use Maatwebsite\Excel\Facades\Excel; -use Throwable; abstract class Controller extends BaseController { @@ -78,23 +76,49 @@ abstract class Controller extends BaseController * * @param $class * @param $request - * @param $url + * @param $translation * * @return mixed */ - public function importExcel($class, $request) + public function importExcel($class, $request, $translation) { try { - Excel::import($class, $request->file('import')); + $file = $request->file('import'); + + if (should_queue()) { + $class->queue($file)->onQueue('imports')->chain([ + new NotifyUser(user(), new ImportCompleted), + ]); + + $message = trans('messages.success.import_queued', ['type' => $translation]); + } else { + $class->import($file); + + $message = trans('messages.success.imported', ['type' => $translation]); + } $response = [ 'success' => true, 'error' => false, 'data' => null, - 'message' => '', + 'message' => $message, ]; - } catch (SheetNotFoundException | ErrorException | Exception | Throwable $e) { - $message = $e->getMessage(); + } catch (\Throwable $e) { + if ($e instanceof \Maatwebsite\Excel\Validators\ValidationException) { + foreach ($e->failures() as $failure) { + $message = trans('messages.error.import_column', [ + 'message' => collect($failure->errors())->first(), + 'column' => $failure->attribute(), + 'line' => $failure->row(), + ]); + + flash($message)->error()->important(); + } + + $message = ''; + } else { + $message = $e->getMessage(); + } $response = [ 'success' => false, @@ -111,15 +135,30 @@ abstract class Controller extends BaseController * Export the excel file or catch errors * * @param $class - * @param $file_name + * @param $translation + * @param $extension * * @return mixed */ - public function exportExcel($class, $file_name, $extension = 'xlsx') + public function exportExcel($class, $translation, $extension = 'xlsx') { try { - return Excel::download($class, Str::filename($file_name) . '.' . $extension); - } catch (ErrorException | Exception | Throwable $e) { + $file_name = Str::filename($translation) . '.' . $extension; + + if (should_queue()) { + $class->queue($file_name)->onQueue('exports')->chain([ + new CreateMediableForExport(user(), $file_name), + ]); + + $message = trans('messages.success.export_queued', ['type' => $translation]); + + flash($message)->success(); + + return back(); + } else { + return $class->download($file_name); + } + } catch (\Throwable $e) { flash($e->getMessage())->error()->important(); return back(); diff --git a/app/Abstracts/Http/FormRequest.php b/app/Abstracts/Http/FormRequest.php index 1628789b1..2097492f5 100644 --- a/app/Abstracts/Http/FormRequest.php +++ b/app/Abstracts/Http/FormRequest.php @@ -15,7 +15,7 @@ abstract class FormRequest extends BaseFormRequest protected function prepareForValidation() { $this->merge([ - 'company_id' => session('company_id'), + 'company_id' => company_id(), ]); } diff --git a/app/Abstracts/Http/PaymentController.php b/app/Abstracts/Http/PaymentController.php index 5d4ce543b..c22045b39 100644 --- a/app/Abstracts/Http/PaymentController.php +++ b/app/Abstracts/Http/PaymentController.php @@ -139,14 +139,14 @@ abstract class PaymentController extends BaseController public function getNotifyUrl($invoice) { - return route('portal.invoices.' . $this->alias . '.notify', $invoice->id); + return route('portal.' . $this->alias . '.invoices.notify', $invoice->id); } public function getModuleUrl($invoice, $suffix) { return $this->user - ? route('portal.invoices.' . $this->alias . '.' . $suffix, $invoice->id) - : URL::signedRoute('signed.invoices.' . $this->alias . '.' . $suffix, [$invoice->id, 'company_id' => $invoice->company_id]); + ? route('portal.' . $this->alias . '.invoices.' . $suffix, $invoice->id) + : URL::signedRoute('signed.' . $this->alias . '.invoices.' . $suffix, [$invoice->id]); } public function getLogger() diff --git a/app/Abstracts/Import.php b/app/Abstracts/Import.php index 3cdd14e97..1bf5e3c74 100644 --- a/app/Abstracts/Import.php +++ b/app/Abstracts/Import.php @@ -5,30 +5,34 @@ namespace App\Abstracts; use App\Traits\Import as ImportHelper; use App\Utilities\Date; use Carbon\Exceptions\InvalidFormatException; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Validator; -use Illuminate\Support\Str; use Maatwebsite\Excel\Concerns\Importable; -use Maatwebsite\Excel\Concerns\SkipsOnError; -use Maatwebsite\Excel\Concerns\SkipsOnFailure; +use Maatwebsite\Excel\Concerns\SkipsEmptyRows; use Maatwebsite\Excel\Concerns\ToModel; use Maatwebsite\Excel\Concerns\WithChunkReading; use Maatwebsite\Excel\Concerns\WithHeadingRow; use Maatwebsite\Excel\Concerns\WithMapping; use Maatwebsite\Excel\Concerns\WithValidation; -use Maatwebsite\Excel\Validators\Failure; use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate; -abstract class Import implements ToModel, SkipsOnError, SkipsOnFailure, WithChunkReading, WithHeadingRow, WithMapping, WithValidation +abstract class Import implements HasLocalePreference, ShouldQueue, SkipsEmptyRows, WithChunkReading, WithHeadingRow, WithMapping, WithValidation, ToModel { use Importable, ImportHelper; - public $empty_field = 'empty---'; + public $user; + + public function __construct() + { + $this->user = user(); + } public function map($row): array { - $row['company_id'] = session('company_id'); + $row['company_id'] = company_id(); // Make enabled field integer if (isset($row['enabled'])) { @@ -67,31 +71,6 @@ abstract class Import implements ToModel, SkipsOnError, SkipsOnFailure, WithChun return 100; } - public function onFailure(Failure ...$failures) - { - $sheet = Str::snake((new \ReflectionClass($this))->getShortName()); - - foreach ($failures as $failure) { - // @todo remove after 3.2 release https://github.com/Maatwebsite/Laravel-Excel/issues/1834#issuecomment-474340743 - if (collect($failure->values())->first() == $this->empty_field) { - continue; - } - - $message = trans('messages.error.import_column', [ - 'message' => collect($failure->errors())->first(), - 'sheet' => $sheet, - 'line' => $failure->row(), - ]); - - flash($message)->error()->important(); - } - } - - public function onError(\Throwable $e) - { - flash($e->getMessage())->error()->important(); - } - public function isNotValid($row) { return Validator::make($row, $this->rules())->fails(); @@ -111,4 +90,9 @@ abstract class Import implements ToModel, SkipsOnError, SkipsOnFailure, WithChun return false; } + + public function preferredLocale() + { + return $this->user->locale; + } } diff --git a/app/Abstracts/Job.php b/app/Abstracts/Job.php index 2bd701a6d..2d3c41de4 100644 --- a/app/Abstracts/Job.php +++ b/app/Abstracts/Job.php @@ -6,14 +6,10 @@ use App\Abstracts\Http\FormRequest; use App\Traits\Jobs; use App\Traits\Relationships; use App\Traits\Uploads; -use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; -abstract class Job implements ShouldQueue +abstract class Job { - use InteractsWithQueue, Jobs, Queueable, Relationships, SerializesModels, Uploads; + use Jobs, Relationships, Uploads; public function getRequestInstance($request) { diff --git a/app/Abstracts/JobShouldQueue.php b/app/Abstracts/JobShouldQueue.php new file mode 100644 index 000000000..04adaa208 --- /dev/null +++ b/app/Abstracts/JobShouldQueue.php @@ -0,0 +1,49 @@ +getRequestAsCollection($request); + } + + /** + * Covert the request to collection. + * + * @param mixed $request + * @return \Illuminate\Support\Collection + */ + public function getRequestAsCollection($request) + { + if (is_array($request)) { + $data = $request; + + $request = new class() extends FormRequest {}; + + $request->merge($data); + } + + return collect($request->all()); + } +} diff --git a/app/Abstracts/Notification.php b/app/Abstracts/Notification.php index 6843920ac..36ff85072 100644 --- a/app/Abstracts/Notification.php +++ b/app/Abstracts/Notification.php @@ -2,19 +2,21 @@ namespace App\Abstracts; -use App\Models\Common\EmailTemplate; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification as BaseNotification; -abstract class Notification extends BaseNotification +abstract class Notification extends BaseNotification implements ShouldQueue { + use Queueable; + /** * Create a notification instance. */ public function __construct() { - $this->queue = 'high'; - $this->delay = config('queue.connections.database.delay'); + $this->onQueue('notifications'); } /** @@ -35,24 +37,24 @@ abstract class Notification extends BaseNotification */ public function initMessage() { - $template = EmailTemplate::alias($this->template)->first(); + app('url')->defaults(['company_id' => company_id()]); $message = (new MailMessage) ->from(config('mail.from.address'), config('mail.from.name')) - ->subject($this->getSubject($template)) - ->view('partials.email.body', ['body' => $this->getBody($template)]); + ->subject($this->getSubject()) + ->view('partials.email.body', ['body' => $this->getBody()]); return $message; } - public function getSubject($template) + public function getSubject() { - return $this->replaceTags($template->subject); + return $this->replaceTags($this->template->subject); } - public function getBody($template) + public function getBody() { - return $this->replaceTags($template->body); + return $this->replaceTags($this->template->body); } public function replaceTags($content) diff --git a/app/Abstracts/View/Components/DocumentShow.php b/app/Abstracts/View/Components/DocumentShow.php index 13702130c..f0d313a26 100644 --- a/app/Abstracts/View/Components/DocumentShow.php +++ b/app/Abstracts/View/Components/DocumentShow.php @@ -611,7 +611,7 @@ abstract class DocumentShow extends Base $image->make($path)->resize($width, $height)->encode(); }); } catch (NotReadableException | \Exception $e) { - Log::info('Company ID: ' . session('company_id') . ' components/documentshow.php exception.'); + Log::info('Company ID: ' . company_id() . ' components/documentshow.php exception.'); Log::info($e->getMessage()); $path = base_path('public/img/company.png'); @@ -651,11 +651,11 @@ abstract class DocumentShow extends Base $route .= 'signed.' . $page . '.show'; try { - route($route, [$this->document->id, 'company_id' => session('company_id')]); + route($route, [$this->document->id, 'company_id' => company_id()]); - $signedUrl = URL::signedRoute($route, [$this->document->id, 'company_id' => session('company_id')]); + $signedUrl = URL::signedRoute($route, [$this->document->id]); } catch (\Exception $e) { - $signedUrl = URL::signedRoute('signed.invoices.show', [$this->document->id, 'company_id' => session('company_id')]); + $signedUrl = URL::signedRoute('signed.invoices.show', [$this->document->id]); } return $signedUrl; diff --git a/app/Abstracts/View/Components/DocumentTemplate.php b/app/Abstracts/View/Components/DocumentTemplate.php index b7f4d7405..add41f9da 100644 --- a/app/Abstracts/View/Components/DocumentTemplate.php +++ b/app/Abstracts/View/Components/DocumentTemplate.php @@ -213,7 +213,7 @@ abstract class DocumentTemplate extends Base $image->make($path)->resize($width, $height)->encode(); }); } catch (NotReadableException | \Exception $e) { - Log::info('Company ID: ' . session('company_id') . ' components/documentshow.php exception.'); + Log::info('Company ID: ' . company_id() . ' components/documentshow.php exception.'); Log::info($e->getMessage()); $path = base_path('public/img/company.png'); diff --git a/app/BulkActions/Common/Companies.php b/app/BulkActions/Common/Companies.php index f4c120a10..7ffce5e22 100644 --- a/app/BulkActions/Common/Companies.php +++ b/app/BulkActions/Common/Companies.php @@ -35,7 +35,7 @@ class Companies extends BulkAction foreach ($companies as $company) { try { - $this->dispatch(new UpdateCompany($company, $request->merge(['enabled' => 1]), session('company_id'))); + $this->dispatch(new UpdateCompany($company, $request->merge(['enabled' => 1]))); } catch (\Exception $e) { flash($e->getMessage())->error()->important(); } @@ -48,7 +48,7 @@ class Companies extends BulkAction foreach ($companies as $company) { try { - $this->dispatch(new UpdateCompany($company, $request->merge(['enabled' => 0]), session('company_id'))); + $this->dispatch(new UpdateCompany($company, $request->merge(['enabled' => 0]))); } catch (\Exception $e) { flash($e->getMessage())->error()->important(); } @@ -61,7 +61,7 @@ class Companies extends BulkAction foreach ($companies as $company) { try { - $this->dispatch(new DeleteCompany($company, session('company_id'))); + $this->dispatch(new DeleteCompany($company)); } catch (\Exception $e) { flash($e->getMessage())->error()->important(); } diff --git a/app/Console/Commands/BillReminder.php b/app/Console/Commands/BillReminder.php index 5062daf11..a921a3311 100644 --- a/app/Console/Commands/BillReminder.php +++ b/app/Console/Commands/BillReminder.php @@ -47,12 +47,8 @@ class BillReminder extends Command $this->info('Sending bill reminders for ' . $company->name . ' company.'); - // Set company id - session(['company_id' => $company->id]); - - // Override settings and currencies - Overrider::load('settings'); - Overrider::load('currencies'); + // Set company + $company->makeCurrent(); // Don't send reminders if disabled if (!setting('schedule.send_bill_reminder')) { @@ -70,9 +66,7 @@ class BillReminder extends Command } } - // Unset company_id - session()->forget('company_id'); - setting()->forgetAll(); + Company::forgetCurrent(); } protected function remind($day) diff --git a/app/Console/Commands/DownloadModule.php b/app/Console/Commands/DownloadModule.php index 463a1b6f5..75e55163c 100644 --- a/app/Console/Commands/DownloadModule.php +++ b/app/Console/Commands/DownloadModule.php @@ -47,8 +47,7 @@ class DownloadModule extends Command $this->alias = $this->argument('alias'); $this->company = $this->argument('company'); - session(['company_id' => $this->company]); - setting()->setExtraColumns(['company_id' => $this->company]); + company($this->company)->makeCurrent(); if (!$path = $this->download()) { return self::CMD_ERROR; diff --git a/app/Console/Commands/FinishUpdate.php b/app/Console/Commands/FinishUpdate.php index 86e810157..15e6f6b4c 100644 --- a/app/Console/Commands/FinishUpdate.php +++ b/app/Console/Commands/FinishUpdate.php @@ -57,8 +57,7 @@ class FinishUpdate extends Command } } - session(['company_id' => $company_id]); - setting()->setExtraColumns(['company_id' => $company_id]); + company($company_id)->makeCurrent(); // Disable model cache during update config(['laravel-model-caching.enabled' => false]); diff --git a/app/Console/Commands/InvoiceReminder.php b/app/Console/Commands/InvoiceReminder.php index 7874e5bdb..25caccc53 100644 --- a/app/Console/Commands/InvoiceReminder.php +++ b/app/Console/Commands/InvoiceReminder.php @@ -47,12 +47,8 @@ class InvoiceReminder extends Command $this->info('Sending invoice reminders for ' . $company->name . ' company.'); - // Set company id - session(['company_id' => $company->id]); - - // Override settings and currencies - Overrider::load('settings'); - Overrider::load('currencies'); + // Set company + $company->makeCurrent(); // Don't send reminders if disabled if (!setting('schedule.send_invoice_reminder')) { @@ -70,9 +66,7 @@ class InvoiceReminder extends Command } } - // Unset company_id - session()->forget('company_id'); - setting()->forgetAll(); + Company::forgetCurrent(); } protected function remind($day) diff --git a/app/Console/Commands/RecurringCheck.php b/app/Console/Commands/RecurringCheck.php index c50475905..16f6e83fe 100644 --- a/app/Console/Commands/RecurringCheck.php +++ b/app/Console/Commands/RecurringCheck.php @@ -7,10 +7,10 @@ use App\Events\Banking\TransactionRecurring; use App\Events\Document\DocumentCreated; use App\Events\Document\DocumentRecurring; use App\Models\Banking\Transaction; +use App\Models\Common\Company; use App\Models\Common\Recurring; use App\Models\Document\Document; use App\Utilities\Date; -use App\Utilities\Overrider; use Illuminate\Console\Command; class RecurringCheck extends Command @@ -83,12 +83,7 @@ class RecurringCheck extends Command continue; } - // Set company id - session(['company_id' => $recur->company_id]); - - // Override settings and currencies - Overrider::load('settings'); - Overrider::load('currencies'); + company($recur->company_id)->makeCurrent(); $today = Date::today(); @@ -121,9 +116,7 @@ class RecurringCheck extends Command } } - // Unset company_id - session()->forget('company_id'); - setting()->forgetAll(); + Company::forgetCurrent(); } protected function recur($model, $type, $schedule_date) diff --git a/app/Console/Commands/Update.php b/app/Console/Commands/Update.php index 89ca9853b..dfdf4da9a 100644 --- a/app/Console/Commands/Update.php +++ b/app/Console/Commands/Update.php @@ -68,8 +68,7 @@ class Update extends Command $this->old = $this->getOldVersion(); - session(['company_id' => $this->company]); - setting()->setExtraColumns(['company_id' => $this->company]); + company($this->company)->makeCurrent(); if (!$path = $this->download()) { return self::CMD_ERROR; diff --git a/app/Console/Stubs/Modules/listeners/install.stub b/app/Console/Stubs/Modules/listeners/install.stub index 4210e4b10..1c8760457 100644 --- a/app/Console/Stubs/Modules/listeners/install.stub +++ b/app/Console/Stubs/Modules/listeners/install.stub @@ -40,7 +40,7 @@ class FinishInstallation protected function callSeeds() { Artisan::call('company:seed', [ - 'company' => session('company_id'), + 'company' => company_id(), '--class' => 'Modules\$STUDLY_NAME$\Database\Seeds\$STUDLY_NAME$DatabaseSeeder', ]); } diff --git a/app/Console/Stubs/Modules/routes/admin.stub b/app/Console/Stubs/Modules/routes/admin.stub index e3b0fc21c..db3c8b634 100644 --- a/app/Console/Stubs/Modules/routes/admin.stub +++ b/app/Console/Stubs/Modules/routes/admin.stub @@ -2,12 +2,12 @@ use Illuminate\Support\Facades\Route; -Route::group([ - 'middleware' => 'admin', - 'as' => '$ALIAS$.', - 'namespace' => '$MODULE_NAMESPACE$\$STUDLY_NAME$\Http\Controllers' -], function () { - Route::prefix('$ALIAS$')->group(function() { - // Route::get('/', 'Main@index'); - }); +/** + * 'admin' middleware and '$ALIAS$' prefix applied to all routes (including names) + * + * @see \App\Providers\Route::register + */ + +Route::admin('$ALIAS$', function () { + Route::get('/', 'Main@index'); }); diff --git a/app/Console/Stubs/Modules/routes/portal.stub b/app/Console/Stubs/Modules/routes/portal.stub index 238ebe11c..16a20fd58 100644 --- a/app/Console/Stubs/Modules/routes/portal.stub +++ b/app/Console/Stubs/Modules/routes/portal.stub @@ -2,11 +2,13 @@ use Illuminate\Support\Facades\Route; -Route::group([ - 'prefix' => 'portal', - 'middleware' => 'portal', - 'namespace' => '$MODULE_NAMESPACE$\$STUDLY_NAME$\Http\Controllers' -], function () { - // Route::get('invoices/{invoice}/$ALIAS$', 'Main@show')->name('portal.invoices.$ALIAS$.show'); - // Route::post('invoices/{invoice}/$ALIAS$/confirm', 'Main@confirm')->name('portal.invoices.$ALIAS$.confirm'); +/** + * 'portal' middleware and 'portal/$ALIAS$' prefix applied to all routes (including names) + * + * @see \App\Providers\Route::register + */ + +Route::portal('$ALIAS$', function () { + // Route::get('invoices/{invoice}', 'Main@show')->name('invoices.show'); + // Route::post('invoices/{invoice}/confirm', 'Main@confirm')->name('invoices.confirm'); }); diff --git a/app/Events/Common/CompanyForgettingCurrent.php b/app/Events/Common/CompanyForgettingCurrent.php new file mode 100644 index 000000000..dfd793765 --- /dev/null +++ b/app/Events/Common/CompanyForgettingCurrent.php @@ -0,0 +1,20 @@ +company = $company; + } +} diff --git a/app/Events/Common/CompanyForgotCurrent.php b/app/Events/Common/CompanyForgotCurrent.php new file mode 100644 index 000000000..15beb2b18 --- /dev/null +++ b/app/Events/Common/CompanyForgotCurrent.php @@ -0,0 +1,20 @@ +company = $company; + } +} diff --git a/app/Events/Common/CompanyMadeCurrent.php b/app/Events/Common/CompanyMadeCurrent.php new file mode 100644 index 000000000..828d643c0 --- /dev/null +++ b/app/Events/Common/CompanyMadeCurrent.php @@ -0,0 +1,20 @@ +company = $company; + } +} diff --git a/app/Events/Common/CompanyMakingCurrent.php b/app/Events/Common/CompanyMakingCurrent.php new file mode 100644 index 000000000..7787922b6 --- /dev/null +++ b/app/Events/Common/CompanyMakingCurrent.php @@ -0,0 +1,20 @@ +company = $company; + } +} diff --git a/app/Exports/Common/Items.php b/app/Exports/Common/Items.php index aaad65306..c2865fc11 100644 --- a/app/Exports/Common/Items.php +++ b/app/Exports/Common/Items.php @@ -4,10 +4,13 @@ namespace App\Exports\Common; use App\Exports\Common\Sheets\Items as Base; use App\Exports\Common\Sheets\ItemTaxes; +use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class Items implements WithMultipleSheets { + use Exportable; + public $ids; public function __construct($ids = null) diff --git a/app/Exports/Purchases/Bills.php b/app/Exports/Purchases/Bills.php index 6396c969a..32a450235 100644 --- a/app/Exports/Purchases/Bills.php +++ b/app/Exports/Purchases/Bills.php @@ -8,10 +8,13 @@ use App\Exports\Purchases\Sheets\BillItemTaxes; use App\Exports\Purchases\Sheets\BillHistories; use App\Exports\Purchases\Sheets\BillTotals; use App\Exports\Purchases\Sheets\BillTransactions; +use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class Bills implements WithMultipleSheets { + use Exportable; + public $ids; public function __construct($ids = null) diff --git a/app/Exports/Sales/Invoices.php b/app/Exports/Sales/Invoices.php index 00c8349f4..d6b8e8abc 100644 --- a/app/Exports/Sales/Invoices.php +++ b/app/Exports/Sales/Invoices.php @@ -8,10 +8,13 @@ use App\Exports\Sales\Sheets\InvoiceItemTaxes; use App\Exports\Sales\Sheets\InvoiceHistories; use App\Exports\Sales\Sheets\InvoiceTotals; use App\Exports\Sales\Sheets\InvoiceTransactions; +use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class Invoices implements WithMultipleSheets { + use Exportable; + public $ids; public function __construct($ids = null) diff --git a/app/Http/Controllers/Api/Common/Companies.php b/app/Http/Controllers/Api/Common/Companies.php index bbdb8270c..4f5b8a5a3 100644 --- a/app/Http/Controllers/Api/Common/Companies.php +++ b/app/Http/Controllers/Api/Common/Companies.php @@ -69,7 +69,7 @@ class Companies extends ApiController public function update(Company $company, Request $request) { try { - $company = $this->dispatch(new UpdateCompany($company, $request, session('company_id'))); + $company = $this->dispatch(new UpdateCompany($company, $request)); return $this->item($company->fresh(), new Transformer()); } catch (\Exception $e) { @@ -86,7 +86,7 @@ class Companies extends ApiController public function enable(Company $company) { try { - $company = $this->dispatch(new UpdateCompany($company, request()->merge(['enabled' => 1]), session('company_id'))); + $company = $this->dispatch(new UpdateCompany($company, request()->merge(['enabled' => 1]))); return $this->item($company->fresh(), new Transformer()); } catch (\Exception $e) { @@ -103,7 +103,7 @@ class Companies extends ApiController public function disable(Company $company) { try { - $company = $this->dispatch(new UpdateCompany($company, request()->merge(['enabled' => 0]), session('company_id'))); + $company = $this->dispatch(new UpdateCompany($company, request()->merge(['enabled' => 0]))); return $this->item($company->fresh(), new Transformer()); } catch (\Exception $e) { @@ -120,7 +120,7 @@ class Companies extends ApiController public function destroy(Company $company) { try { - $this->dispatch(new DeleteCompany($company, session('company_id'))); + $this->dispatch(new DeleteCompany($company)); return $this->response->noContent(); } catch (\Exception $e) { diff --git a/app/Http/Controllers/Auth/Login.php b/app/Http/Controllers/Auth/Login.php index 9b45ec5f4..5d8c3a035 100644 --- a/app/Http/Controllers/Auth/Login.php +++ b/app/Http/Controllers/Auth/Login.php @@ -37,16 +37,14 @@ class Login extends Controller { // Attempt to login if (!auth()->attempt($request->only('email', 'password'), $request->get('remember', false))) { - $response = [ + return response()->json([ 'status' => null, 'success' => false, 'error' => true, 'message' => trans('auth.failed'), 'data' => null, 'redirect' => null, - ]; - - return response()->json($response); + ]); } // Get user object @@ -56,49 +54,64 @@ class Login extends Controller if (!$user->enabled) { $this->logout(); - $response = [ + return response()->json([ 'status' => null, 'success' => false, 'error' => true, 'message' => trans('auth.disabled'), 'data' => null, 'redirect' => null, - ]; - - return response()->json($response); + ]); } - // Check if is customer - if ($user->can('read-client-portal')) { - $path = session('url.intended', 'portal'); + $company = $user->withoutEvents(function () use ($user) { + return $user->companies()->enabled()->first(); + }); - // Path must start with 'portal' prefix - if (!Str::startsWith($path, 'portal')) { - $path = 'portal'; + // Logout if no company assigned + if (!$company) { + $this->logout(); + + return response()->json([ + 'status' => null, + 'success' => false, + 'error' => true, + 'message' => trans('auth.error.no_company'), + 'data' => null, + 'redirect' => null, + ]); + } + + // Redirect to portal if is customer + if ($user->can('read-client-portal')) { + $path = session('url.intended', ''); + + // Path must start with company id and 'portal' prefix + if (!Str::startsWith($path, $company->id . '/portal')) { + $path = route('portal.dashboard', ['company_id' => $company->id]); } - $response = [ + return response()->json([ 'status' => null, 'success' => true, 'error' => false, 'message' => null, 'data' => null, 'redirect' => url($path), - ]; - - return response()->json($response); + ]); } - $response = [ + // Redirect to landing page if is user + $url = route($user->landing_page, ['company_id' => $company->id]); + + return response()->json([ 'status' => null, 'success' => true, 'error' => false, 'message' => null, 'data' => null, - 'redirect' => redirect()->intended(route($user->landing_page))->getTargetUrl(), - ]; - - return response()->json($response); + 'redirect' => redirect()->intended($url)->getTargetUrl(), + ]); } public function destroy() diff --git a/app/Http/Controllers/Banking/Transactions.php b/app/Http/Controllers/Banking/Transactions.php index 8ed90812b..9641dc223 100644 --- a/app/Http/Controllers/Banking/Transactions.php +++ b/app/Http/Controllers/Banking/Transactions.php @@ -42,20 +42,16 @@ class Transactions extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.transactions', 2)); if ($response['success']) { $response['redirect'] = route('transactions.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.transactions', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['banking', 'transactions']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Banking/Transfers.php b/app/Http/Controllers/Banking/Transfers.php index fd4a77ea3..35a72318b 100644 --- a/app/Http/Controllers/Banking/Transfers.php +++ b/app/Http/Controllers/Banking/Transfers.php @@ -97,20 +97,16 @@ class Transfers extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.transfers', 2)); if ($response['success']) { $response['redirect'] = route('transfers.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.transfers', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['banking', 'transfers']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Common/Companies.php b/app/Http/Controllers/Common/Companies.php index d72b7b0d6..4a1a49738 100644 --- a/app/Http/Controllers/Common/Companies.php +++ b/app/Http/Controllers/Common/Companies.php @@ -11,7 +11,6 @@ use App\Models\Common\Company; use App\Models\Setting\Currency; use App\Traits\Uploads; use App\Traits\Users; -use App\Utilities\Overrider; class Companies extends Controller { @@ -60,7 +59,7 @@ class Companies extends Controller */ public function store(Request $request) { - $company_id = session('company_id'); + $current_company_id = company_id(); $response = $this->ajaxDispatch(new CreateCompany($request)); @@ -78,9 +77,7 @@ class Companies extends Controller flash($message)->error()->important(); } - session(['company_id' => $company_id]); - - Overrider::load('settings'); + company($current_company_id)->makeCurrent(); return response()->json($response); } @@ -94,7 +91,7 @@ class Companies extends Controller */ public function edit(Company $company) { - if (!$this->isUserCompany($company->id)) { + if ($this->isNotUserCompany($company->id)) { return redirect()->route('companies.index'); } @@ -113,9 +110,9 @@ class Companies extends Controller */ public function update(Company $company, Request $request) { - $company_id = session('company_id'); + $current_company_id = company_id(); - $response = $this->ajaxDispatch(new UpdateCompany($company, $request, session('company_id'))); + $response = $this->ajaxDispatch(new UpdateCompany($company, $request, company_id())); if ($response['success']) { $response['redirect'] = route('companies.index'); @@ -131,9 +128,7 @@ class Companies extends Controller flash($message)->error()->important(); } - session(['company_id' => $company_id]); - - Overrider::load('settings'); + company($current_company_id)->makeCurrent(); return response()->json($response); } @@ -147,7 +142,7 @@ class Companies extends Controller */ public function enable(Company $company) { - $response = $this->ajaxDispatch(new UpdateCompany($company, request()->merge(['enabled' => 1]), session('company_id'))); + $response = $this->ajaxDispatch(new UpdateCompany($company, request()->merge(['enabled' => 1]))); if ($response['success']) { $response['message'] = trans('messages.success.enabled', ['type' => trans_choice('general.companies', 1)]); @@ -165,7 +160,7 @@ class Companies extends Controller */ public function disable(Company $company) { - $response = $this->ajaxDispatch(new UpdateCompany($company, request()->merge(['enabled' => 0]), session('company_id'))); + $response = $this->ajaxDispatch(new UpdateCompany($company, request()->merge(['enabled' => 0]))); if ($response['success']) { $response['message'] = trans('messages.success.disabled', ['type' => trans_choice('general.companies', 1)]); @@ -183,7 +178,7 @@ class Companies extends Controller */ public function destroy(Company $company) { - $response = $this->ajaxDispatch(new DeleteCompany($company, session('company_id'))); + $response = $this->ajaxDispatch(new DeleteCompany($company)); $response['redirect'] = route('companies.index'); @@ -210,22 +205,21 @@ class Companies extends Controller public function switch(Company $company) { if ($this->isUserCompany($company->id)) { - $old_company_id = session('company_id'); + $old_company_id = company_id(); + + $company->makeCurrent(); - session(['company_id' => $company->id]); session(['dashboard_id' => user()->dashboards()->enabled()->pluck('id')->first()]); - Overrider::load('settings'); - event(new \App\Events\Common\CompanySwitched($company, $old_company_id)); // Check wizard if (!setting('wizard.completed', false)) { - return redirect()->route('wizard.edit'); + return redirect()->route('wizard.edit', ['company_id' => $company->id]); } } - return redirect()->route('dashboard'); + return redirect()->route('dashboard', ['company_id' => $company->id]); } public function autocomplete() diff --git a/app/Http/Controllers/Common/Dashboards.php b/app/Http/Controllers/Common/Dashboards.php index 1180d24fa..22f7418dc 100644 --- a/app/Http/Controllers/Common/Dashboards.php +++ b/app/Http/Controllers/Common/Dashboards.php @@ -7,7 +7,6 @@ use App\Http\Requests\Common\Dashboard as Request; use App\Jobs\Common\CreateDashboard; use App\Jobs\Common\DeleteDashboard; use App\Jobs\Common\UpdateDashboard; -use App\Models\Common\Company; use App\Models\Common\Dashboard; use App\Models\Common\Widget; use App\Traits\DateTime; @@ -60,7 +59,7 @@ class Dashboards extends Controller if (empty($dashboard)) { $dashboard = $this->dispatch(new CreateDashboard([ - 'company_id' => session('company_id'), + 'company_id' => company_id(), 'name' => trans_choice('general.dashboards', 1), 'default_widgets' => 'core', ])); @@ -89,7 +88,7 @@ class Dashboards extends Controller */ public function create() { - $users = Company::find(session('company_id'))->users()->get()->sortBy('name'); + $users = company()->users()->get()->sortBy('name'); return view('common.dashboards.create', compact('users')); } @@ -130,11 +129,11 @@ class Dashboards extends Controller */ public function edit(Dashboard $dashboard) { - if (!$this->isUserDashboard($dashboard->id)) { + if ($this->isNotUserDashboard($dashboard->id)) { return redirect()->route('dashboards.index'); } - $users = Company::find(session('company_id'))->users()->get()->sortBy('name'); + $users = company()->users()->get()->sortBy('name'); return view('common.dashboards.edit', compact('dashboard', 'users')); } diff --git a/app/Http/Controllers/Common/Import.php b/app/Http/Controllers/Common/Import.php index c24a5b843..a5f1f51cc 100644 --- a/app/Http/Controllers/Common/Import.php +++ b/app/Http/Controllers/Common/Import.php @@ -16,7 +16,7 @@ class Import extends Controller */ public function create($group, $type, $route = null) { - $path = $group . '/' . $type; + $path = company_id() . '/' . $group . '/' . $type; if (module($group) instanceof \Akaunting\Module\Module) { $namespace = $group . '::'; diff --git a/app/Http/Controllers/Common/Items.php b/app/Http/Controllers/Common/Items.php index 5d1d002a8..cd8067d44 100644 --- a/app/Http/Controllers/Common/Items.php +++ b/app/Http/Controllers/Common/Items.php @@ -111,20 +111,16 @@ class Items extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.items', 2)); if ($response['success']) { $response['redirect'] = route('items.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.items', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['common', 'items']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Common/Uploads.php b/app/Http/Controllers/Common/Uploads.php index 7b4871693..71eefcd39 100644 --- a/app/Http/Controllers/Common/Uploads.php +++ b/app/Http/Controllers/Common/Uploads.php @@ -182,7 +182,7 @@ class Uploads extends Controller $folders = explode('/', $media->directory); // Check if company can access media - if ($folders[0] != session('company_id')) { + if ($folders[0] != company_id()) { return false; } diff --git a/app/Http/Controllers/Install/Updates.php b/app/Http/Controllers/Install/Updates.php index 7c82f02cb..22b1e70a9 100644 --- a/app/Http/Controllers/Install/Updates.php +++ b/app/Http/Controllers/Install/Updates.php @@ -73,7 +73,7 @@ class Updates extends Controller Cache::forget('updates'); Cache::forget('versions'); - event(new UpdateCacheCleared(session('company_id'))); + event(new UpdateCacheCleared(company_id())); return redirect()->back(); } @@ -274,7 +274,7 @@ class Updates extends Controller set_time_limit(900); // 15 minutes try { - $this->dispatch(new FinishUpdate($request['alias'], $request['version'], $request['installed'], session('company_id'))); + $this->dispatch(new FinishUpdate($request['alias'], $request['version'], $request['installed'], company_id())); $json = [ 'success' => true, diff --git a/app/Http/Controllers/Modals/DocumentItemColumns.php b/app/Http/Controllers/Modals/DocumentItemColumns.php index e28901b70..7281ce258 100644 --- a/app/Http/Controllers/Modals/DocumentItemColumns.php +++ b/app/Http/Controllers/Modals/DocumentItemColumns.php @@ -110,7 +110,7 @@ class DocumentItemColumns extends Controller $company_id = $request->get('company_id'); if (empty($company_id)) { - $company_id = session('company_id'); + $company_id = company_id(); } foreach ($fields as $key => $value) { diff --git a/app/Http/Controllers/Modals/InvoiceTemplates.php b/app/Http/Controllers/Modals/InvoiceTemplates.php index d7e47c138..873b2186d 100644 --- a/app/Http/Controllers/Modals/InvoiceTemplates.php +++ b/app/Http/Controllers/Modals/InvoiceTemplates.php @@ -32,7 +32,7 @@ class InvoiceTemplates extends Controller $company_id = $request->get('company_id'); if (empty($company_id)) { - $company_id = session('company_id'); + $company_id = company_id(); } foreach ($fields as $key => $value) { diff --git a/app/Http/Controllers/Modals/Items.php b/app/Http/Controllers/Modals/Items.php index 23cac8104..4449295b5 100644 --- a/app/Http/Controllers/Modals/Items.php +++ b/app/Http/Controllers/Modals/Items.php @@ -56,7 +56,7 @@ class Items extends Controller { if ($request->get('type', false) == 'inline') { $data = [ - 'company_id' => session('company_id'), + 'company_id' => company_id(), 'name' => '', 'sale_price' => 0, 'purchase_price' => 0, diff --git a/app/Http/Controllers/Modules/Item.php b/app/Http/Controllers/Modules/Item.php index 2aa6ed8bc..9d05d4515 100644 --- a/app/Http/Controllers/Modules/Item.php +++ b/app/Http/Controllers/Modules/Item.php @@ -204,7 +204,7 @@ class Item extends Controller try { $this->dispatch(new CopyFiles($request['alias'], $request['path'])); - event(new \App\Events\Module\Copied($request['alias'], session('company_id'))); + event(new \App\Events\Module\Copied($request['alias'], company_id())); $json = [ 'success' => true, @@ -236,9 +236,9 @@ class Item extends Controller public function install(Request $request) { try { - event(new \App\Events\Module\Installing($request['alias'], session('company_id'))); + event(new \App\Events\Module\Installing($request['alias'], company_id())); - $this->dispatch(new InstallModule($request['alias'], session('company_id'))); + $this->dispatch(new InstallModule($request['alias'], company_id())); $name = module($request['alias'])->getName(); @@ -277,7 +277,7 @@ class Item extends Controller try { $name = module($alias)->getName(); - $this->dispatch(new UninstallModule($alias, session('company_id'))); + $this->dispatch(new UninstallModule($alias, company_id())); $message = trans('modules.uninstalled', ['module' => $name]); @@ -296,7 +296,7 @@ class Item extends Controller try { $name = module($alias)->getName(); - $this->dispatch(new EnableModule($alias, session('company_id'))); + $this->dispatch(new EnableModule($alias, company_id())); $message = trans('modules.enabled', ['module' => $name]); @@ -315,7 +315,7 @@ class Item extends Controller try { $name = module($alias)->getName(); - $this->dispatch(new DisableModule($alias, session('company_id'))); + $this->dispatch(new DisableModule($alias, company_id())); $message = trans('modules.disabled', ['module' => $name]); diff --git a/app/Http/Controllers/Modules/My.php b/app/Http/Controllers/Modules/My.php index ded71f548..4cb009d81 100644 --- a/app/Http/Controllers/Modules/My.php +++ b/app/Http/Controllers/Modules/My.php @@ -19,7 +19,7 @@ class My extends Controller { $purchased = $this->getMyModules(); $modules = $this->getInstalledModules(); - $installed = Module::where('company_id', '=', session('company_id'))->pluck('enabled', 'alias')->toArray(); + $installed = Module::where('company_id', '=', company_id())->pluck('enabled', 'alias')->toArray(); return $this->response('modules.my.index', compact('purchased', 'modules', 'installed')); } diff --git a/app/Http/Controllers/Portal/Invoices.php b/app/Http/Controllers/Portal/Invoices.php index 3104cf9fb..68e96f3c0 100644 --- a/app/Http/Controllers/Portal/Invoices.php +++ b/app/Http/Controllers/Portal/Invoices.php @@ -108,7 +108,7 @@ class Invoices extends Controller public function signed(Document $invoice) { if (empty($invoice)) { - redirect()->route('login'); + return redirect()->route('login'); } $payment_actions = []; @@ -119,12 +119,12 @@ class Invoices extends Controller $codes = explode('.', $payment_method_key); if (!isset($payment_actions[$codes[0]])) { - $payment_actions[$codes[0]] = URL::signedRoute('signed.invoices.' . $codes[0] . '.show', [$invoice->id, 'company_id' => session('company_id')]); + $payment_actions[$codes[0]] = URL::signedRoute('signed.' . $codes[0] . '.invoices.show', [$invoice->id]); } } - $print_action = URL::signedRoute('signed.invoices.print', [$invoice->id, 'company_id' => session('company_id')]); - $pdf_action = URL::signedRoute('signed.invoices.pdf', [$invoice->id, 'company_id' => session('company_id')]); + $print_action = URL::signedRoute('signed.invoices.print', [$invoice->id]); + $pdf_action = URL::signedRoute('signed.invoices.pdf', [$invoice->id]); event(new \App\Events\Document\DocumentViewed($invoice)); diff --git a/app/Http/Controllers/Purchases/Bills.php b/app/Http/Controllers/Purchases/Bills.php index ac7606e2b..aee66508a 100644 --- a/app/Http/Controllers/Purchases/Bills.php +++ b/app/Http/Controllers/Purchases/Bills.php @@ -128,20 +128,16 @@ class Bills extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.bills', 2)); if ($response['success']) { $response['redirect'] = route('bills.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.bills', 1)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['purchases', 'bills']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Purchases/Payments.php b/app/Http/Controllers/Purchases/Payments.php index 8d9899ac3..c46880d32 100644 --- a/app/Http/Controllers/Purchases/Payments.php +++ b/app/Http/Controllers/Purchases/Payments.php @@ -134,20 +134,16 @@ class Payments extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.payments', 2)); if ($response['success']) { $response['redirect'] = route('payments.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.payments', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['purchases', 'payments']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Purchases/Vendors.php b/app/Http/Controllers/Purchases/Vendors.php index 1af867166..9e73c41c3 100644 --- a/app/Http/Controllers/Purchases/Vendors.php +++ b/app/Http/Controllers/Purchases/Vendors.php @@ -161,20 +161,16 @@ class Vendors extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.vendors', 2)); if ($response['success']) { $response['redirect'] = route('vendors.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.vendors', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['purchases', 'vendors']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Sales/Customers.php b/app/Http/Controllers/Sales/Customers.php index d2a02b9ba..70ee6f8ef 100644 --- a/app/Http/Controllers/Sales/Customers.php +++ b/app/Http/Controllers/Sales/Customers.php @@ -159,20 +159,16 @@ class Customers extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.customers', 2)); if ($response['success']) { $response['redirect'] = route('customers.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.customers', 1)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['sales', 'customers']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Sales/Invoices.php b/app/Http/Controllers/Sales/Invoices.php index 1742e25cc..52422b2dd 100644 --- a/app/Http/Controllers/Sales/Invoices.php +++ b/app/Http/Controllers/Sales/Invoices.php @@ -127,20 +127,16 @@ class Invoices extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.invoices', 2)); if ($response['success']) { $response['redirect'] = route('invoices.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.invoices', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['sales', 'invoices']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Sales/Revenues.php b/app/Http/Controllers/Sales/Revenues.php index 842d88d0d..10ec8abd0 100644 --- a/app/Http/Controllers/Sales/Revenues.php +++ b/app/Http/Controllers/Sales/Revenues.php @@ -134,20 +134,16 @@ class Revenues extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.revenues', 2)); if ($response['success']) { $response['redirect'] = route('revenues.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.revenues', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['sales', 'revenues']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Settings/Categories.php b/app/Http/Controllers/Settings/Categories.php index 6bdc533e5..3bdceaff1 100644 --- a/app/Http/Controllers/Settings/Categories.php +++ b/app/Http/Controllers/Settings/Categories.php @@ -92,20 +92,16 @@ class Categories extends Controller */ public function import(ImportRequest $request) { - $response = $this->importExcel(new Import, $request); + $response = $this->importExcel(new Import, $request, trans_choice('general.categories', 2)); if ($response['success']) { $response['redirect'] = route('categories.index'); - $message = trans('messages.success.imported', ['type' => trans_choice('general.categories', 2)]); - - flash($message)->success(); + flash($response['message'])->success(); } else { $response['redirect'] = route('import.create', ['settings', 'categories']); - $message = $response['message']; - - flash($message)->error()->important(); + flash($response['message'])->error()->important(); } return response()->json($response); diff --git a/app/Http/Controllers/Settings/Modules.php b/app/Http/Controllers/Settings/Modules.php index c6001e951..a9e61fb59 100644 --- a/app/Http/Controllers/Settings/Modules.php +++ b/app/Http/Controllers/Settings/Modules.php @@ -16,7 +16,7 @@ class Modules extends Controller */ public function __construct() { - $alias = request()->segment(1); + $alias = request()->segment(2); // Add CRUD permission check $this->middleware('permission:create-' . $alias . '-settings')->only('create', 'store', 'duplicate', 'import'); diff --git a/app/Http/Controllers/Settings/Settings.php b/app/Http/Controllers/Settings/Settings.php index 90364505e..5fdf4cb09 100644 --- a/app/Http/Controllers/Settings/Settings.php +++ b/app/Http/Controllers/Settings/Settings.php @@ -80,7 +80,7 @@ class Settings extends Controller $company_id = $request->get('company_id'); if (empty($company_id)) { - $company_id = session('company_id'); + $company_id = company_id(); } $company = Company::find($company_id); diff --git a/app/Http/Controllers/Wizard/Companies.php b/app/Http/Controllers/Wizard/Companies.php index e712499a9..d28d95afc 100644 --- a/app/Http/Controllers/Wizard/Companies.php +++ b/app/Http/Controllers/Wizard/Companies.php @@ -31,7 +31,7 @@ class Companies extends Controller */ public function edit() { - $company = Company::find(session('company_id')); + $company = Company::find(company_id()); return view('wizard.companies.edit', compact('company')); } @@ -46,7 +46,7 @@ class Companies extends Controller public function update(Request $request) { // Company - $company = Company::find(session('company_id')); + $company = Company::find(company_id()); $fields = $request->all(); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index cba2297bc..95a62f472 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -36,11 +36,8 @@ class Kernel extends HttpKernel // 'session.auth', 'session.errors', 'csrf', - 'bindings', 'install.redirect', 'header.x', - 'company.settings', - 'company.currencies', 'language', 'firewall.all', ], @@ -55,16 +52,16 @@ class Kernel extends HttpKernel 'auth.disabled', 'throttle:api', 'permission:read-api', - 'api.company', + 'company.identify', 'bindings', - 'company.settings', - 'company.currencies', 'language', 'firewall.all', ], 'common' => [ 'web', + 'company.identify', + 'bindings', 'wizard.redirect', ], @@ -77,6 +74,8 @@ class Kernel extends HttpKernel 'web', 'auth', 'auth.disabled', + 'company.identify', + 'bindings', 'wizard.redirect', 'menu.admin', 'permission:read-admin-panel', @@ -86,6 +85,8 @@ class Kernel extends HttpKernel 'web', 'auth', 'auth.disabled', + 'company.identify', + 'bindings', 'permission:read-admin-panel', ], @@ -93,6 +94,8 @@ class Kernel extends HttpKernel 'web', 'auth', 'auth.disabled', + 'company.identify', + 'bindings', 'menu.portal', 'permission:read-client-portal', ], @@ -105,11 +108,9 @@ class Kernel extends HttpKernel 'csrf', 'signature', 'signed.redirect', - 'company.signed', + 'company.identify', 'bindings', 'header.x', - 'company.settings', - 'company.currencies', 'language', 'firewall.all', ], @@ -141,13 +142,10 @@ class Kernel extends HttpKernel 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, // Akaunting - 'api.company' => \App\Http\Middleware\ApiCompany::class, - 'api.key' => \App\Http\Middleware\CanApiKey::class, + 'api.key' => \App\Http\Middleware\RedirectIfNoApiKey::class, 'auth.disabled' => \App\Http\Middleware\LogoutIfUserDisabled::class, 'auth.redirect' => \App\Http\Middleware\RedirectIfAuthenticated::class, - 'company.currencies' => \App\Http\Middleware\LoadCurrencies::class, - 'company.settings' => \App\Http\Middleware\LoadSettings::class, - 'company.signed' => \App\Http\Middleware\SignedCompany::class, + 'company.identify' => \App\Http\Middleware\IdentifyCompany::class, 'dropzone' => \App\Http\Middleware\Dropzone::class, 'header.x' => \App\Http\Middleware\AddXHeader::class, 'menu.admin' => \App\Http\Middleware\AdminMenu::class, diff --git a/app/Http/Middleware/ApiCompany.php b/app/Http/Middleware/ApiCompany.php deleted file mode 100644 index 1504a48ca..000000000 --- a/app/Http/Middleware/ApiCompany.php +++ /dev/null @@ -1,41 +0,0 @@ -get('company_id'); - - if (empty($company_id)) { - return $next($request); - } - - // Check if user can access company - if (!$this->isUserCompany($company_id)) { - return $next($request); - } - - // Set company id - session(['company_id' => $company_id]); - - // Set the company settings - setting()->setExtraColumns(['company_id' => $company_id]); - setting()->load(true); - - return $next($request); - } -} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 323a8297f..de3dbd461 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -10,7 +10,7 @@ class Authenticate extends Middleware * Get the path the user should be redirected to when they are not authenticated. * * @param \Illuminate\Http\Request $request - * @return string + * @return string|null */ protected function redirectTo($request) { @@ -18,4 +18,4 @@ class Authenticate extends Middleware return route('login'); } } -} \ No newline at end of file +} diff --git a/app/Http/Middleware/IdentifyCompany.php b/app/Http/Middleware/IdentifyCompany.php new file mode 100644 index 000000000..4ef15be58 --- /dev/null +++ b/app/Http/Middleware/IdentifyCompany.php @@ -0,0 +1,59 @@ +isApi() + ? $this->getCompanyIdFromApi($request) + : $this->getCompanyIdFromWeb($request); + + if (empty($company_id)) { + abort(500, 'Missing company'); + } + + // Check if user can access company + if ($request->isNotSigned($company_id) && $this->isNotUserCompany($company_id)) { + throw new AuthenticationException('Unauthenticated.', $guards); + } + + // Set company as current + company($company_id)->makeCurrent(); + + // Fix routes + app('url')->defaults(['company_id' => $company_id]); + $request->route()->forgetParameter('company_id'); + + return $next($request); + } + + protected function getCompanyIdFromWeb($request) + { + return (int) $request->route('company_id'); + } + + protected function getCompanyIdFromApi($request) + { + $company_id = $request->get('company_id', $request->header('X-Company')); + + return $company_id ?: optional($this->getFirstCompanyOfUser())->id; + } +} diff --git a/app/Http/Middleware/LoadCurrencies.php b/app/Http/Middleware/LoadCurrencies.php deleted file mode 100644 index b71a6b48b..000000000 --- a/app/Http/Middleware/LoadCurrencies.php +++ /dev/null @@ -1,29 +0,0 @@ -guard($guard)->check()) { - $user = user(); - - if ($user->contact) { - return redirect()->route('portal.dashboard'); - } - - return redirect()->route($user->landing_page); + if (!auth()->guard($guard)->check()) { + continue; } + + return redirect(user()->getLandingPageOfUser()); } return $next($request); diff --git a/app/Http/Middleware/CanApiKey.php b/app/Http/Middleware/RedirectIfNoApiKey.php similarity index 54% rename from app/Http/Middleware/CanApiKey.php rename to app/Http/Middleware/RedirectIfNoApiKey.php index 0680c40b4..046cff251 100644 --- a/app/Http/Middleware/CanApiKey.php +++ b/app/Http/Middleware/RedirectIfNoApiKey.php @@ -4,7 +4,7 @@ namespace App\Http\Middleware; use Closure; -class CanApiKey +class RedirectIfNoApiKey { /** * Handle an incoming request. @@ -14,15 +14,15 @@ class CanApiKey * @return mixed */ public function handle($request, Closure $next) - { - if ($request['alias'] != 'core') { - if (setting('apps.api_key')) { - return $next($request); - } else { - redirect('apps/api-key/create')->send(); - } - } else { + { + if ($request->get('alias') == 'core') { return $next($request); } + + if (setting('apps.api_key')) { + return $next($request); + } + + return redirect()->route('apps.api-key.create'); } -} \ No newline at end of file +} diff --git a/app/Http/Middleware/RedirectIfNotInstalled.php b/app/Http/Middleware/RedirectIfNotInstalled.php index f05d1e6ed..44f24dfe5 100644 --- a/app/Http/Middleware/RedirectIfNotInstalled.php +++ b/app/Http/Middleware/RedirectIfNotInstalled.php @@ -3,7 +3,6 @@ namespace App\Http\Middleware; use Closure; -use Illuminate\Support\Str; class RedirectIfNotInstalled { @@ -22,11 +21,11 @@ class RedirectIfNotInstalled } // Already in the installation wizard - if (Str::startsWith($request->getPathInfo(), '/install')) { + if ($request->isInstall()) { return $next($request); } // Not installed, redirect to installation wizard - redirect()->route('install.requirements')->send(); + return redirect()->route('install.requirements'); } } diff --git a/app/Http/Middleware/RedirectIfWizardNotCompleted.php b/app/Http/Middleware/RedirectIfWizardNotCompleted.php index 351842557..f78a3f999 100644 --- a/app/Http/Middleware/RedirectIfWizardNotCompleted.php +++ b/app/Http/Middleware/RedirectIfWizardNotCompleted.php @@ -3,7 +3,6 @@ namespace App\Http\Middleware; use Closure; -use Illuminate\Support\Str; class RedirectIfWizardNotCompleted { @@ -22,11 +21,11 @@ class RedirectIfWizardNotCompleted } // Check url - if (Str::startsWith($request->getPathInfo(), '/wizard') || Str::startsWith($request->getPathInfo(), '/settings')) { + if ($request->isWizard(company_id()) || $request->is(company_id() . '/settings/*')) { return $next($request); } // Redirect to wizard - redirect()->route('wizard.edit')->send(); + return redirect()->route('wizard.edit'); } } diff --git a/app/Http/Middleware/RedirectSignedIfAuthenticated.php b/app/Http/Middleware/RedirectSignedIfAuthenticated.php index 15a80396d..841c879cf 100644 --- a/app/Http/Middleware/RedirectSignedIfAuthenticated.php +++ b/app/Http/Middleware/RedirectSignedIfAuthenticated.php @@ -24,14 +24,14 @@ class RedirectSignedIfAuthenticated $page = 'dashboard'; $params = []; - if ($request->segment(2) == 'invoices') { + if ($request->segment(3) == 'invoices') { $page = 'invoices.show'; - $invoice = Document::find($request->segment(3)); + $invoice = Document::find($request->segment(4)); $params = [$invoice->id]; } - redirect()->route($prefix . $page, $params)->send(); + return redirect()->route($prefix . $page, $params); } } diff --git a/app/Http/Middleware/SignedCompany.php b/app/Http/Middleware/SignedCompany.php deleted file mode 100644 index ef8a08ec8..000000000 --- a/app/Http/Middleware/SignedCompany.php +++ /dev/null @@ -1,33 +0,0 @@ -get('company_id'); - - if (empty($company_id)) { - return $next($request); - } - - // Set company id - session(['company_id' => $company_id]); - - // Set the company settings - setting()->setExtraColumns(['company_id' => $company_id]); - setting()->load(true); - - return $next($request); - } -} diff --git a/app/Http/ViewComposers/DocumentType.php b/app/Http/ViewComposers/DocumentType.php index f5234faf3..75cbf6656 100644 --- a/app/Http/ViewComposers/DocumentType.php +++ b/app/Http/ViewComposers/DocumentType.php @@ -9,7 +9,6 @@ use Illuminate\View\View; class DocumentType { - /** * Bind data to the view. * @@ -18,14 +17,15 @@ class DocumentType */ public function compose(View $view) { - if (!empty(request()->route())) { - $route = request()->route(); + $route = request()->route(); - /** @var Invoices|Bills|PortalInvoices $controller */ - $controller = $route->getController(); - - $view->with(['type' => $controller->type ?? '']); + if (empty($route)) { + return; } - } + /** @var Invoices|Bills|PortalInvoices $controller */ + $controller = $route->getController(); + + $view->with(['type' => $controller->type ?? '']); + } } diff --git a/app/Http/ViewComposers/InvoiceText.php b/app/Http/ViewComposers/InvoiceText.php index e0e2711e4..6826ac531 100644 --- a/app/Http/ViewComposers/InvoiceText.php +++ b/app/Http/ViewComposers/InvoiceText.php @@ -6,7 +6,6 @@ use Illuminate\View\View; class InvoiceText { - /** * Bind data to the view. * @@ -41,5 +40,4 @@ class InvoiceText $view->with(['text_override' => $text_override]); } - -} \ No newline at end of file +} diff --git a/app/Http/ViewComposers/Logo.php b/app/Http/ViewComposers/Logo.php index 53a759131..c72680de7 100644 --- a/app/Http/ViewComposers/Logo.php +++ b/app/Http/ViewComposers/Logo.php @@ -42,7 +42,7 @@ class Logo $image->make($path)->resize($width, $height)->encode(); }); } catch (NotReadableException | \Exception $e) { - Log::info('Company ID: ' . session('company_id') . ' viewcomposer/logo.php exception.'); + Log::info('Company ID: ' . company_id() . ' viewcomposer/logo.php exception.'); Log::info($e->getMessage()); $path = base_path('public/img/company.png'); diff --git a/app/Http/ViewComposers/Notifications.php b/app/Http/ViewComposers/Notifications.php index a80dbc67e..41beec734 100644 --- a/app/Http/ViewComposers/Notifications.php +++ b/app/Http/ViewComposers/Notifications.php @@ -27,6 +27,8 @@ class Notifications return; } + $path = str_replace('{company_id}/', '', $path); + if (!$notifications = $this->getNotifications($path)) { return; } diff --git a/app/Http/ViewComposers/Suggestions.php b/app/Http/ViewComposers/Suggestions.php index 0992fa70f..e8a9c21df 100644 --- a/app/Http/ViewComposers/Suggestions.php +++ b/app/Http/ViewComposers/Suggestions.php @@ -31,6 +31,8 @@ class Suggestions return; } + $path = str_replace('{company_id}/', '', $path); + if (!$suggestions = $this->getSuggestions($path)) { return; } diff --git a/app/Imports/Banking/Transfers.php b/app/Imports/Banking/Transfers.php index 4a6b13b9f..351924cfa 100644 --- a/app/Imports/Banking/Transfers.php +++ b/app/Imports/Banking/Transfers.php @@ -49,7 +49,7 @@ class Transfers extends Import private function getExpenseTransactionId($row) { $expense_transaction = Transaction::create([ - 'company_id' => session('company_id'), + 'company_id' => company_id(), 'type' => 'expense', 'account_id' => $row['from_account_id'], 'paid_at' => $row['transferred_at'], @@ -81,7 +81,7 @@ class Transfers extends Import } $income_transaction = Transaction::create([ - 'company_id' => session('company_id'), + 'company_id' => company_id(), 'type' => 'income', 'account_id' => $row['to_account_id'], 'paid_at' => $row['transferred_at'], diff --git a/app/Imports/Common/Items.php b/app/Imports/Common/Items.php index dbec14d0d..8da2635cb 100644 --- a/app/Imports/Common/Items.php +++ b/app/Imports/Common/Items.php @@ -4,10 +4,13 @@ namespace App\Imports\Common; use App\Imports\Common\Sheets\Items as Base; use App\Imports\Common\Sheets\ItemTaxes; +use Maatwebsite\Excel\Concerns\Importable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class Items implements WithMultipleSheets { + use Importable; + public function sheets(): array { return [ diff --git a/app/Imports/Purchases/Bills.php b/app/Imports/Purchases/Bills.php index ca871a727..47edefe46 100644 --- a/app/Imports/Purchases/Bills.php +++ b/app/Imports/Purchases/Bills.php @@ -8,10 +8,13 @@ use App\Imports\Purchases\Sheets\BillItemTaxes; use App\Imports\Purchases\Sheets\BillHistories; use App\Imports\Purchases\Sheets\BillTotals; use App\Imports\Purchases\Sheets\BillTransactions; +use Maatwebsite\Excel\Concerns\Importable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class Bills implements WithMultipleSheets { + use Importable; + public function sheets(): array { return [ diff --git a/app/Imports/Sales/Invoices.php b/app/Imports/Sales/Invoices.php index ad99d8689..66da032a5 100644 --- a/app/Imports/Sales/Invoices.php +++ b/app/Imports/Sales/Invoices.php @@ -8,10 +8,13 @@ use App\Imports\Sales\Sheets\InvoiceItemTaxes; use App\Imports\Sales\Sheets\InvoiceHistories; use App\Imports\Sales\Sheets\InvoiceTotals; use App\Imports\Sales\Sheets\InvoiceTransactions; +use Maatwebsite\Excel\Concerns\Importable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class Invoices implements WithMultipleSheets { + use Importable; + public function sheets(): array { return [ diff --git a/app/Jobs/Auth/NotifyUser.php b/app/Jobs/Auth/NotifyUser.php new file mode 100644 index 000000000..c27f2c488 --- /dev/null +++ b/app/Jobs/Auth/NotifyUser.php @@ -0,0 +1,36 @@ +user = $user; + $this->notification = $notification; + + $this->onQueue('jobs'); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $this->user->notify($this->notification); + } +} diff --git a/app/Jobs/Common/CreateCompany.php b/app/Jobs/Common/CreateCompany.php index d20adf8d2..a16548fb1 100644 --- a/app/Jobs/Common/CreateCompany.php +++ b/app/Jobs/Common/CreateCompany.php @@ -31,14 +31,14 @@ class CreateCompany extends Job */ public function handle() { + $current_company_id = company_id(); + event(new CompanyCreating($this->request)); \DB::transaction(function () { $this->company = Company::create($this->request->all()); - // Clear settings - setting()->setExtraColumns(['company_id' => $this->company->id]); - setting()->forgetAll(); + $this->company->makeCurrent(); $this->callSeeds(); @@ -47,6 +47,10 @@ class CreateCompany extends Job event(new CompanyCreated($this->company)); + if (!empty($current_company_id)) { + company($current_company_id)->makeCurrent(); + } + return $this->company; } @@ -106,6 +110,5 @@ class CreateCompany extends Job } setting()->save(); - setting()->forgetAll(); } } diff --git a/app/Jobs/Common/CreateMediableForExport.php b/app/Jobs/Common/CreateMediableForExport.php new file mode 100644 index 000000000..4f176340a --- /dev/null +++ b/app/Jobs/Common/CreateMediableForExport.php @@ -0,0 +1,55 @@ +user = $user; + $this->file_name = $file_name; + + $this->onQueue('jobs'); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $source = storage_path('app/uploads/' . $this->file_name); + $destination = storage_path('app/uploads/' . company_id() . '/exports/'); + + // Create exports directory + if (!File::isDirectory($destination)) { + File::makeDirectory($destination); + } + + File::move($source, $destination . $this->file_name); + + // Create the media record + $media = $this->importMedia($this->file_name, 'exports'); + + $this->user->attachMedia($media, 'export'); + + $download_url = route('uploads.download', ['id' => $media->id, 'company_id' => company_id()]); + + $this->user->notify(new ExportCompleted($download_url)); + } +} diff --git a/app/Jobs/Common/DeleteCompany.php b/app/Jobs/Common/DeleteCompany.php index 53bb22d85..bde4121fe 100644 --- a/app/Jobs/Common/DeleteCompany.php +++ b/app/Jobs/Common/DeleteCompany.php @@ -11,17 +11,17 @@ class DeleteCompany extends Job protected $company; - protected $active_company_id; + protected $current_company_id; /** * Create a new job instance. * - * @param $request + * @param $company */ - public function __construct($company, $active_company_id) + public function __construct($company) { $this->company = $company; - $this->active_company_id = $active_company_id; + $this->current_company_id = company_id(); } /** @@ -56,14 +56,14 @@ class DeleteCompany extends Job public function authorize() { // Can't delete active company - if ($this->company->id == $this->active_company_id) { + if ($this->company->id == $this->current_company_id) { $message = trans('companies.error.delete_active'); throw new \Exception($message); } // Check if user can access company - if (!$this->isUserCompany($this->company->id)) { + if ($this->isNotUserCompany($this->company->id)) { $message = trans('companies.error.not_user_company'); throw new \Exception($message); diff --git a/app/Jobs/Common/DeleteDashboard.php b/app/Jobs/Common/DeleteDashboard.php index 69704dabc..95020aab1 100644 --- a/app/Jobs/Common/DeleteDashboard.php +++ b/app/Jobs/Common/DeleteDashboard.php @@ -60,7 +60,7 @@ class DeleteDashboard extends Job } // Check if user can access dashboard - if (!$this->isUserDashboard($this->dashboard->id)) { + if ($this->isNotUserDashboard($this->dashboard->id)) { $message = trans('dashboards.error.not_user_dashboard'); throw new \Exception($message); diff --git a/app/Jobs/Common/UpdateCompany.php b/app/Jobs/Common/UpdateCompany.php index 901c1036c..2ae8d6d03 100644 --- a/app/Jobs/Common/UpdateCompany.php +++ b/app/Jobs/Common/UpdateCompany.php @@ -16,7 +16,7 @@ class UpdateCompany extends Job protected $request; - protected $active_company_id; + protected $current_company_id; /** * Create a new job instance. @@ -24,11 +24,11 @@ class UpdateCompany extends Job * @param $company * @param $request */ - public function __construct($company, $request, $active_company_id) + public function __construct($company, $request) { $this->company = $company; $this->request = $this->getRequestInstance($request); - $this->active_company_id = $active_company_id; + $this->current_company_id = company_id(); } /** @@ -45,10 +45,7 @@ class UpdateCompany extends Job \DB::transaction(function () { $this->company->update($this->request->all()); - // Clear current and load given company settings - setting()->setExtraColumns(['company_id' => $this->company->id]); - setting()->forgetAll(); - setting()->load(true); + $this->company->makeCurrent(); if ($this->request->has('name')) { setting()->set('company.name', $this->request->get('name')); @@ -89,11 +86,14 @@ class UpdateCompany extends Job } setting()->save(); - setting()->forgetAll(); }); event(new CompanyUpdated($this->company, $this->request)); + if (!empty($this->current_company_id)) { + company($this->current_company_id)->makeCurrent(); + } + return $this->company; } @@ -105,14 +105,14 @@ class UpdateCompany extends Job public function authorize() { // Can't disable active company - if (($this->request->get('enabled', 1) == 0) && ($this->company->id == $this->active_company_id)) { + if (($this->request->get('enabled', 1) == 0) && ($this->company->id == $this->current_company_id)) { $message = trans('companies.error.disable_active'); throw new \Exception($message); } // Check if user can access company - if (!$this->isUserCompany($this->company->id)) { + if ($this->isNotUserCompany($this->company->id)) { $message = trans('companies.error.not_user_company'); throw new \Exception($message); diff --git a/app/Jobs/Common/UpdateDashboard.php b/app/Jobs/Common/UpdateDashboard.php index 736c3763a..6fef36ac7 100644 --- a/app/Jobs/Common/UpdateDashboard.php +++ b/app/Jobs/Common/UpdateDashboard.php @@ -77,7 +77,7 @@ class UpdateDashboard extends Job } // Check if user can access dashboard - if (!$this->isUserDashboard($this->dashboard->id)) { + if ($this->isNotUserDashboard($this->dashboard->id)) { $message = trans('dashboards.error.not_user_dashboard'); throw new \Exception($message); diff --git a/app/Listeners/Auth/Login.php b/app/Listeners/Auth/Login.php index 99bdfc01a..7032b0b2d 100644 --- a/app/Listeners/Auth/Login.php +++ b/app/Listeners/Auth/Login.php @@ -15,21 +15,6 @@ class Login */ public function handle(Event $event) { - // Get first company - $company = $event->user->companies()->enabled()->first(); - - // Logout if no company assigned - if (!$company) { - app('App\Http\Controllers\Auth\Login')->logout(); - - flash(trans('auth.error.no_company'))->error()->important(); - - return; - } - - // Set company id - session(['company_id' => $company->id]); - // Save user login time $event->user->last_logged_in_at = Date::now(); diff --git a/app/Listeners/Menu/AddAdminItems.php b/app/Listeners/Menu/AddAdminItems.php index 5d656ba51..b423c1934 100644 --- a/app/Listeners/Menu/AddAdminItems.php +++ b/app/Listeners/Menu/AddAdminItems.php @@ -29,17 +29,17 @@ class AddAdminItems if (session('dashboard_id') != $dashboard->id) { $sub->route('dashboards.switch', $dashboard->name, ['dashboard' => $dashboard->id], $key, $attr); } else { - $sub->url('/', $dashboard->name, $key, $attr); + $sub->url('/' . company_id(), $dashboard->name, $key, $attr); } } }, 10, [ - 'url' => '/', + 'url' => '/' . company_id(), 'title' => trans_choice('general.dashboards', 2), 'icon' => 'fa fa-tachometer-alt', ]); } else { $menu->add([ - 'url' => '/', + 'url' => '/' . company_id(), 'title' => trans_choice('general.dashboards', 1), 'icon' => 'fa fa-tachometer-alt', 'order' => 10, diff --git a/app/Listeners/Module/UpdateExtraModules.php b/app/Listeners/Module/UpdateExtraModules.php index 93c38ad1b..8e4a9fa81 100644 --- a/app/Listeners/Module/UpdateExtraModules.php +++ b/app/Listeners/Module/UpdateExtraModules.php @@ -51,7 +51,7 @@ class UpdateExtraModules continue; } - $company_id = session('company_id'); + $company_id = company_id(); $command = "update {$alias} {$company_id} {$latest_version}"; diff --git a/app/Listeners/Update/V20/Version200.php b/app/Listeners/Update/V20/Version200.php index 11fed20a6..3bed33012 100644 --- a/app/Listeners/Update/V20/Version200.php +++ b/app/Listeners/Update/V20/Version200.php @@ -70,34 +70,25 @@ class Version200 extends Listener protected function updateCompanies() { - $company_id = session('company_id'); + $company_id = company_id(); $companies = Company::cursor(); foreach ($companies as $company) { - session(['company_id' => $company->id]); + $company->makeCurrent(); - $this->updateSettings($company); + $this->updateSettings(); $this->createEmailTemplates($company); $this->createReports($company); } - setting()->forgetAll(); - - session(['company_id' => $company_id]); - - Overrider::load('settings'); + company($company_id)->makeCurrent(); } - public function updateSettings($company) + public function updateSettings() { - // Set the active company settings - setting()->setExtraColumns(['company_id' => $company->id]); - setting()->forgetAll(); - setting()->load(true); - // Override settings config(['app.url' => route('dashboard')]); config(['app.timezone' => setting('general.timezone', 'UTC')]); diff --git a/app/Listeners/Update/V20/Version203.php b/app/Listeners/Update/V20/Version203.php index bb46e49ee..aa4682279 100644 --- a/app/Listeners/Update/V20/Version203.php +++ b/app/Listeners/Update/V20/Version203.php @@ -30,30 +30,21 @@ class Version203 extends Listener protected function updateCompanies() { - $company_id = session('company_id'); + $company_id = company_id(); $companies = Company::cursor(); foreach ($companies as $company) { - session(['company_id' => $company->id]); + $company->makeCurrent(); $this->updateSettings($company); } - setting()->forgetAll(); - - session(['company_id' => $company_id]); - - Overrider::load('settings'); + company($company_id)->makeCurrent(); } public function updateSettings($company) { - // Set the active company settings - setting()->setExtraColumns(['company_id' => $company->id]); - setting()->forgetAll(); - setting()->load(true); - setting()->set(['invoice.payment_terms' => setting('invoice.payment_terms', 0)]); setting()->save(); diff --git a/app/Listeners/Update/V21/Version210.php b/app/Listeners/Update/V21/Version210.php index a66fce154..4008ac825 100644 --- a/app/Listeners/Update/V21/Version210.php +++ b/app/Listeners/Update/V21/Version210.php @@ -1031,24 +1031,20 @@ class Version210 extends Listener protected function updateCompanies() { - $company_id = session('company_id'); + $company_id = company_id(); $companies = Company::cursor(); foreach ($companies as $company) { - session(['company_id' => $company->id]); + $company->makeCurrent(); - $this->updateSettings($company); + $this->updateSettings(); } - setting()->forgetAll(); - - session(['company_id' => $company_id]); - - Overrider::load('settings'); + company($company_id)->makeCurrent(); } - public function updateSettings($company) + public function updateSettings() { $income_category = Category::income()->enabled()->first(); $expense_category = Category::expense()->enabled()->first(); @@ -1057,11 +1053,6 @@ class Version210 extends Listener return; } - // Set the active company settings - setting()->setExtraColumns(['company_id' => $company->id]); - setting()->forgetAll(); - setting()->load(true); - setting()->set(['default.income_category' => setting('default.income_category', $income_category->id)]); setting()->set(['default.expense_category' => setting('default.expense_category', $expense_category->id)]); diff --git a/app/Listeners/Update/V21/Version213.php b/app/Listeners/Update/V21/Version213.php index 003e847d5..67504389b 100644 --- a/app/Listeners/Update/V21/Version213.php +++ b/app/Listeners/Update/V21/Version213.php @@ -30,30 +30,21 @@ class Version213 extends Listener protected function updateCompanies() { - $company_id = session('company_id'); + $company_id = company_id(); $companies = Company::cursor(); foreach ($companies as $company) { - session(['company_id' => $company->id]); + $company->makeCurrent(); - $this->updateSettings($company); + $this->updateSettings(); } - setting()->forgetAll(); - - session(['company_id' => $company_id]); - - Overrider::load('settings'); + company($company_id)->makeCurrent(); } - public function updateSettings($company) + public function updateSettings() { - // Set the active company settings - setting()->setExtraColumns(['company_id' => $company->id]); - setting()->forgetAll(); - setting()->load(true); - $company_logo = setting('company.logo'); if (is_array($company_logo)) { diff --git a/app/Models/Auth/User.php b/app/Models/Auth/User.php index d7d1338af..a06692a74 100644 --- a/app/Models/Auth/User.php +++ b/app/Models/Auth/User.php @@ -5,7 +5,9 @@ namespace App\Models\Auth; use App\Traits\Tenants; use App\Notifications\Auth\Reset; use App\Traits\Media; +use App\Traits\Users; use Date; +use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; @@ -14,9 +16,9 @@ use Kyslik\ColumnSortable\Sortable; use Laratrust\Traits\LaratrustUserTrait; use Lorisleiva\LaravelSearchString\Concerns\SearchString; -class User extends Authenticatable +class User extends Authenticatable implements HasLocalePreference { - use HasFactory, LaratrustUserTrait, Notifiable, SearchString, SoftDeletes, Sortable, Media, Tenants; + use HasFactory, LaratrustUserTrait, Notifiable, SearchString, SoftDeletes, Sortable, Media, Tenants, Users; protected $table = 'users'; @@ -193,20 +195,39 @@ class User extends Authenticatable } /** - * Convert tax to Array. + * Attach company_ids attribute to model. * * @return void */ public function setCompanyIds() { - $this->setAttribute('company_ids', $this->companies->pluck('id')->toArray()); + $company_ids = $this->withoutEvents(function () { + return $this->companies->pluck('id')->toArray(); + }); + + $this->setAttribute('company_ids', $company_ids); } + /** + * Detach company_ids attribute from model. + * + * @return void + */ public function unsetCompanyIds() { $this->offsetUnset('company_ids'); } + /** + * Get the user's preferred locale. + * + * @return string + */ + public function preferredLocale() + { + return $this->locale; + } + /** * Create a new factory instance for the model. * diff --git a/app/Models/Common/Company.php b/app/Models/Common/Company.php index 7143b57f3..02dc23332 100644 --- a/app/Models/Common/Company.php +++ b/app/Models/Common/Company.php @@ -2,11 +2,16 @@ namespace App\Models\Common; +use App\Events\Common\CompanyForgettingCurrent; +use App\Events\Common\CompanyForgotCurrent; +use App\Events\Common\CompanyMadeCurrent; +use App\Events\Common\CompanyMakingCurrent; use App\Models\Document\Document; use App\Traits\Contacts; use App\Traits\Media; use App\Traits\Tenants; use App\Traits\Transactions; +use App\Utilities\Overrider; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Eloquent\SoftDeletes; use Kyslik\ColumnSortable\Sortable; @@ -435,4 +440,82 @@ class Company extends Eloquent { return $this->getMedia('company_logo')->last(); } + + public function makeCurrent($force = false) + { + if (!$force && $this->isCurrent()) { + return $this; + } + + static::forgetCurrent(); + + event(new CompanyMakingCurrent($this)); + + // Bind to container + app()->instance(static::class, $this); + + // Set session for backward compatibility @deprecated + //session(['company_id' => $this->id]); + + // Load settings + setting()->setExtraColumns(['company_id' => $this->id]); + setting()->forgetAll(); + setting()->load(true); + + // Override settings and currencies + Overrider::load('settings'); + Overrider::load('currencies'); + + event(new CompanyMadeCurrent($this)); + + return $this; + } + + public function isCurrent() + { + return optional(static::getCurrent())->id === $this->id; + } + + public function isNotCurrent() + { + return !$this->isCurrent(); + } + + public static function getCurrent() + { + if (!app()->has(static::class)) { + return null; + } + + return app(static::class); + } + + public static function forgetCurrent() + { + $current = static::getCurrent(); + + if (is_null($current)) { + return null; + } + + event(new CompanyForgettingCurrent($current)); + + // Remove from container + app()->forgetInstance(static::class); + + // Unset session for backward compatibility @deprecated + //session()->forget('company_id'); + + // Remove settings + setting()->forgetAll(); + + event(new CompanyForgotCurrent($current)); + + return $current; + } + + public static function hasCurrent() + { + return static::getCurrent() !== null; + } } diff --git a/app/Notifications/Common/ExportCompleted.php b/app/Notifications/Common/ExportCompleted.php new file mode 100644 index 000000000..effeb4a21 --- /dev/null +++ b/app/Notifications/Common/ExportCompleted.php @@ -0,0 +1,52 @@ +download_url = $download_url; + + $this->onQueue('notifications'); + } + + /** + * Get the notification's channels. + * + * @param mixed $notifiable + * @return array|string + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Build the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage) + ->subject(trans('notifications.export.completed.subject')) + ->line(trans('notifications.export.completed.description')) + ->action(trans('general.download'), $this->download_url); + } +} diff --git a/app/Notifications/Common/ExportFailed.php b/app/Notifications/Common/ExportFailed.php new file mode 100644 index 000000000..b44b366db --- /dev/null +++ b/app/Notifications/Common/ExportFailed.php @@ -0,0 +1,57 @@ +exception = $exception; + + $this->onQueue('notifications'); + } + + /** + * Get the notification's channels. + * + * @param mixed $notifiable + * @return array|string + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Build the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage) + ->subject(trans('notifications.export.failed.subject')) + ->line(trans('notifications.export.failed.description')) + ->line($this->exception->getMessage()); + } +} diff --git a/app/Notifications/Common/ImportCompleted.php b/app/Notifications/Common/ImportCompleted.php new file mode 100644 index 000000000..512b583b7 --- /dev/null +++ b/app/Notifications/Common/ImportCompleted.php @@ -0,0 +1,48 @@ +onQueue('notifications'); + } + + /** + * Get the notification's channels. + * + * @param mixed $notifiable + * @return array|string + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Build the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $dashboard_url = route('dashboard', ['company_id' => company_id()]); + + return (new MailMessage) + ->subject(trans('notifications.import.completed.subject')) + ->line(trans('notifications.import.completed.description')) + ->action(trans_choice('general.dashboards', 1), $dashboard_url); + } +} diff --git a/app/Notifications/Common/ImportFailed.php b/app/Notifications/Common/ImportFailed.php new file mode 100644 index 000000000..7eda94032 --- /dev/null +++ b/app/Notifications/Common/ImportFailed.php @@ -0,0 +1,62 @@ +errors = $errors; + + $this->onQueue('notifications'); + } + + /** + * Get the notification's channels. + * + * @param mixed $notifiable + * @return array|string + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Build the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $message = (new MailMessage) + ->subject(trans('notifications.import.failed.subject')) + ->line(trans('notifications.import.failed.description')); + + foreach ($this->errors as $error) { + $message->line($error); + } + + return $message; + } +} diff --git a/app/Notifications/Portal/PaymentReceived.php b/app/Notifications/Portal/PaymentReceived.php index 45f8d5c55..daa522502 100644 --- a/app/Notifications/Portal/PaymentReceived.php +++ b/app/Notifications/Portal/PaymentReceived.php @@ -3,6 +3,7 @@ namespace App\Notifications\Portal; use App\Abstracts\Notification; +use App\Models\Common\EmailTemplate; use Illuminate\Support\Facades\URL; class PaymentReceived extends Notification @@ -39,7 +40,7 @@ class PaymentReceived extends Notification $this->invoice = $invoice; $this->transaction = $transaction; - $this->template = $template; + $this->template = EmailTemplate::alias($template)->first(); } /** @@ -105,7 +106,7 @@ class PaymentReceived extends Notification money($this->invoice->amount, $this->invoice->currency_code, true), company_date($this->invoice->due_at), trans('documents.statuses.' . $this->invoice->status), - URL::signedRoute('signed.invoices.show', [$this->invoice->id, 'company_id' => $this->invoice->company_id]), + URL::signedRoute('signed.invoices.show', [$this->invoice->id]), route('invoices.show', $this->invoice->id), route('portal.invoices.show', $this->invoice->id), money($this->transaction->amount, $this->transaction->currency_code, true), diff --git a/app/Notifications/Purchase/Bill.php b/app/Notifications/Purchase/Bill.php index fe99f7423..a13317183 100644 --- a/app/Notifications/Purchase/Bill.php +++ b/app/Notifications/Purchase/Bill.php @@ -3,6 +3,7 @@ namespace App\Notifications\Purchase; use App\Abstracts\Notification; +use App\Models\Common\EmailTemplate; class Bill extends Notification { @@ -31,7 +32,7 @@ class Bill extends Notification parent::__construct(); $this->bill = $bill; - $this->template = $template; + $this->template = EmailTemplate::alias($template)->first(); } /** diff --git a/app/Notifications/Sale/Invoice.php b/app/Notifications/Sale/Invoice.php index 0dfb3e1d2..7c30a3521 100644 --- a/app/Notifications/Sale/Invoice.php +++ b/app/Notifications/Sale/Invoice.php @@ -3,6 +3,7 @@ namespace App\Notifications\Sale; use App\Abstracts\Notification; +use App\Models\Common\EmailTemplate; use Illuminate\Support\Facades\URL; class Invoice extends Notification @@ -32,7 +33,7 @@ class Invoice extends Notification parent::__construct(); $this->invoice = $invoice; - $this->template = $template; + $this->template = EmailTemplate::alias($template)->first(); } /** @@ -95,7 +96,7 @@ class Invoice extends Notification money($this->invoice->amount, $this->invoice->currency_code, true), money($this->invoice->amount_due, $this->invoice->currency_code, true), company_date($this->invoice->due_at), - URL::signedRoute('signed.invoices.show', [$this->invoice->id, 'company_id' => $this->invoice->company_id]), + URL::signedRoute('signed.invoices.show', [$this->invoice->id]), route('invoices.show', $this->invoice->id), route('portal.invoices.show', $this->invoice->id), $this->invoice->contact_name, diff --git a/app/Providers/Macro.php b/app/Providers/Macro.php index 6da03db44..c045b1627 100644 --- a/app/Providers/Macro.php +++ b/app/Providers/Macro.php @@ -9,6 +9,16 @@ use Illuminate\View\Factory as ViewFactory; class Macro extends ServiceProvider { + /** + * Register any application services. + * + * @return void + */ + public function register() + { + // + } + /** * Bootstrap any application services. * @@ -24,6 +34,59 @@ class Macro extends ServiceProvider return !$this->isApi(); }); + Request::macro('isAuth', function () { + return $this->is('auth/*'); + }); + + Request::macro('isNotAuth', function () { + return !$this->isAuth(); + }); + + Request::macro('isInstall', function () { + return $this->is('install/*'); + }); + + Request::macro('isNotInstall', function () { + return !$this->isInstall(); + }); + + Request::macro('isSigned', function ($company_id) { + return $this->is($company_id . '/signed/*'); + }); + + Request::macro('isNotSigned', function ($company_id) { + return !$this->isSigned($company_id); + }); + + Request::macro('isPortal', function ($company_id) { + return $this->is($company_id . '/portal') || $this->is($company_id . '/portal/*'); + }); + + Request::macro('isNotPortal', function ($company_id) { + return !$this->isPortal($company_id); + }); + + Request::macro('isWizard', function ($company_id) { + return $this->is($company_id . '/wizard') || $this->is($company_id . '/wizard/*'); + }); + + Request::macro('isNotWizard', function ($company_id) { + return !$this->isWizard($company_id); + }); + + Request::macro('isAdmin', function ($company_id) { + return $this->isNotApi() + && $this->isNotAuth() + && $this->isNotInstall() + && $this->isNotSigned($company_id) + && $this->isNotPortal($company_id) + && $this->isNotWizard($company_id); + }); + + Request::macro('isNotAdmin', function ($company_id) { + return !$this->isAdmin($company_id); + }); + Str::macro('filename', function ($string, $separator = '-') { // Replace @ with the word 'at' $string = str_replace('@', $separator.'at'.$separator, $string); @@ -47,14 +110,4 @@ class Macro extends ServiceProvider return false; }); } - - /** - * Register any application services. - * - * @return void - */ - public function register() - { - // - } } diff --git a/app/Providers/Observer.php b/app/Providers/Observer.php index 655ef52ee..27af5bdce 100644 --- a/app/Providers/Observer.php +++ b/app/Providers/Observer.php @@ -8,17 +8,7 @@ use Illuminate\Support\ServiceProvider as Provider; class Observer extends Provider { /** - * Register bindings in the container. - * - * @return void - */ - public function boot() - { - Transaction::observe('App\Observers\Transaction'); - } - - /** - * Register the service provider. + * Register any application services. * * @return void */ @@ -26,4 +16,14 @@ class Observer extends Provider { // } + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + Transaction::observe('App\Observers\Transaction'); + } } diff --git a/app/Providers/Queue.php b/app/Providers/Queue.php new file mode 100644 index 000000000..87b02ab5c --- /dev/null +++ b/app/Providers/Queue.php @@ -0,0 +1,102 @@ +createPayloadUsing(function ($connection, $queue, $payload) { + $company_id = company_id(); + + if (empty($company_id)) { + return []; + } + + return ['company_id' => $company_id]; + }); + + app('events')->listen(JobProcessing::class, function ($event) { + $payload = $event->job->payload(); + + if (!array_key_exists('company_id', $payload)) { + return; + } + + $company = company($payload['company_id']); + + if (empty($company)) { + $event->job->delete(); + } + + $company->makeCurrent(); + }); + + app('events')->listen(JobFailed::class, function ($event) { + if (!$event->exception instanceof \Maatwebsite\Excel\Validators\ValidationException) { + return; + } + + $body = $event->job->getRawBody(); + if (empty($body) || !is_string($body)) { + return; + } + + $payload = json_decode($body); + if (empty($payload) || empty($payload->data) || empty($payload->data->command)) { + return; + } + + $excel_job = unserialize($payload->data->command); + if (!$excel_job instanceof \Maatwebsite\Excel\Jobs\ReadChunk) { + return; + } + + $ref = new \ReflectionProperty($excel_job, 'import'); + $ref->setAccessible(true); + + // Get import class + $class = $ref->getValue($excel_job); + + if (!$class instanceof \App\Abstracts\Import) { + return; + } + + $errors = []; + + foreach ($event->exception->failures() as $failure) { + $message = trans('messages.error.import_column', [ + 'message' => collect($failure->errors())->first(), + 'column' => $failure->attribute(), + 'line' => $failure->row(), + ]); + + $errors[] = $message; + } + + if (!empty($errors)) { + $class->user->notify(new ImportFailed($errors)); + } + }); + } +} diff --git a/app/Providers/Route.php b/app/Providers/Route.php index 20dcefa37..b32ed9df8 100644 --- a/app/Providers/Route.php +++ b/app/Providers/Route.php @@ -28,6 +28,73 @@ class Route extends Provider */ protected $namespace = 'App\Http\Controllers'; + /** + * Register any application services. + * + * @return void + */ + public function register() + { + parent::register(); + + Facade::macro('module', function ($alias, $routes, $attrs) { + $attributes = [ + 'middleware' => $attrs['middleware'], + ]; + + if (isset($attrs['namespace'])) { + // null means don't add + if (!is_null($attrs['namespace'])) { + $attributes['namespace'] = $attrs['namespace']; + } + } else { + $attributes['namespace'] = 'Modules\\' . module($alias)->getStudlyName() . '\Http\Controllers'; + } + + if (isset($attrs['prefix'])) { + // null means don't add + if (!is_null($attrs['prefix'])) { + $attributes['prefix'] = '{company_id}/' . $attrs['prefix']; + } + } else { + $attributes['prefix'] = '{company_id}/' . $alias; + } + + if (isset($attrs['as'])) { + // null means don't add + if (!is_null($attrs['as'])) { + $attributes['as'] = $attrs['as']; + } + } else { + $attributes['as'] = $alias . '.'; + } + + return Facade::group($attributes, $routes); + }); + + Facade::macro('admin', function ($alias, $routes, $attributes = []) { + return Facade::module($alias, $routes, array_merge([ + 'middleware' => 'admin', + ], $attributes)); + }); + + Facade::macro('portal', function ($alias, $routes, $attributes = []) { + return Facade::module($alias, $routes, array_merge([ + 'middleware' => 'portal', + 'prefix' => 'portal/' . $alias, + 'as' => 'portal.' . $alias . '.', + ], $attributes)); + }); + + Facade::macro('signed', function ($alias, $routes, $attributes = []) { + return Facade::module($alias, $routes, array_merge([ + 'middleware' => 'signed', + 'prefix' => 'signed/' . $alias, + 'as' => 'signed.' . $alias . '.', + ], $attributes)); + }); + } + /** * Define the routes for the application. * @@ -92,7 +159,8 @@ class Route extends Provider */ protected function mapCommonRoutes() { - Facade::middleware('common') + Facade::prefix('{company_id}') + ->middleware('common') ->namespace($this->namespace) ->group(base_path('routes/common.php')); } @@ -120,7 +188,7 @@ class Route extends Provider */ protected function mapWizardRoutes() { - Facade::prefix('wizard') + Facade::prefix('{company_id}/wizard') ->middleware('wizard') ->namespace($this->namespace) ->group(base_path('routes/wizard.php')); @@ -135,7 +203,8 @@ class Route extends Provider */ protected function mapAdminRoutes() { - Facade::middleware('admin') + Facade::prefix('{company_id}') + ->middleware('admin') ->namespace($this->namespace) ->group(base_path('routes/admin.php')); } @@ -149,7 +218,7 @@ class Route extends Provider */ protected function mapPortalRoutes() { - Facade::prefix('portal') + Facade::prefix('{company_id}/portal') ->middleware('portal') ->namespace($this->namespace) ->group(base_path('routes/portal.php')); @@ -164,7 +233,7 @@ class Route extends Provider */ protected function mapSignedRoutes() { - Facade::prefix('signed') + Facade::prefix('{company_id}/signed') ->middleware('signed') ->namespace($this->namespace) ->group(base_path('routes/signed.php')); diff --git a/app/Scopes/Company.php b/app/Scopes/Company.php index 9105f0554..9fc85ea79 100644 --- a/app/Scopes/Company.php +++ b/app/Scopes/Company.php @@ -42,6 +42,6 @@ class Company implements Scope } // Apply company scope - $builder->where($table . '.company_id', '=', session('company_id')); + $builder->where($table . '.company_id', '=', company_id()); } } diff --git a/app/Traits/Import.php b/app/Traits/Import.php index d4a59d0f7..e851add97 100644 --- a/app/Traits/Import.php +++ b/app/Traits/Import.php @@ -116,9 +116,9 @@ trait Import public function getAccountIdFromCurrency($row) { return Account::firstOrCreate([ + 'company_id' => company_id(), 'currency_code' => $row['currency_code'], ], [ - 'company_id' => session('company_id'), 'name' => !empty($row['account_name']) ? $row['account_name'] : $row['currency_code'], 'number' => !empty($row['account_number']) ? $row['account_number'] : rand(1, 10000), 'opening_balance' => !empty($row['opening_balance']) ? $row['opening_balance'] : 0, @@ -129,9 +129,9 @@ trait Import public function getAccountIdFromName($row) { return Account::firstOrCreate([ + 'company_id' => company_id(), 'name' => $row['account_name'], ], [ - 'company_id' => session('company_id'), 'number' => !empty($row['account_number']) ? $row['account_number'] : rand(1, 10000), 'currency_code' => !empty($row['currency_code']) ? $row['currency_code'] : setting('default.currency'), 'opening_balance' => !empty($row['opening_balance']) ? $row['opening_balance'] : 0, @@ -142,9 +142,9 @@ trait Import public function getAccountIdFromNumber($row) { return Account::firstOrCreate([ + 'company_id' => company_id(), 'number' => $row['account_number'], ], [ - 'company_id' => session('company_id'), 'name' => !empty($row['account_name']) ? $row['account_name'] : $row['account_number'], 'currency_code' => !empty($row['currency_code']) ? $row['currency_code'] : setting('default.currency'), 'opening_balance' => !empty($row['opening_balance']) ? $row['opening_balance'] : 0, @@ -155,9 +155,9 @@ trait Import public function getCategoryIdFromName($row, $type) { return Category::firstOrCreate([ + 'company_id' => company_id(), 'name' => $row['category_name'], ], [ - 'company_id' => session('company_id'), 'type' => $type, 'color' => !empty($row['category_color']) ? $row['category_color'] : '#' . dechex(rand(0x000000, 0xFFFFFF)), 'enabled' => 1, @@ -167,9 +167,9 @@ trait Import public function getContactIdFromEmail($row, $type) { return Contact::firstOrCreate([ + 'company_id' => company_id(), 'email' => $row['contact_email'], ], [ - 'company_id' => session('company_id'), 'type' => $type, 'name' => !empty($row['contact_name']) ? $row['contact_name'] : $row['contact_email'], 'currency_code' => !empty($row['contact_currency']) ? $row['contact_currency'] : setting('default.currency'), @@ -180,9 +180,9 @@ trait Import public function getContactIdFromName($row, $type) { return Contact::firstOrCreate([ + 'company_id' => company_id(), 'name' => $row['contact_name'], ], [ - 'company_id' => session('company_id'), 'type' => $type, 'currency_code' => !empty($row['contact_currency']) ? $row['contact_currency'] : setting('default.currency'), 'enabled' => 1, @@ -192,9 +192,9 @@ trait Import public function getItemIdFromName($row) { return Item::firstOrCreate([ + 'company_id' => company_id(), 'name' => $row['item_name'], ], [ - 'company_id' => session('company_id'), 'sale_price' => !empty($row['sale_price']) ? $row['sale_price'] : (!empty($row['price']) ? $row['price'] : 0), 'purchase_price' => !empty($row['purchase_price']) ? $row['purchase_price'] : (!empty($row['price']) ? $row['price'] : 0), 'enabled' => 1, @@ -204,9 +204,9 @@ trait Import public function getTaxIdFromRate($row, $type = 'normal') { return Tax::firstOrCreate([ + 'company_id' => company_id(), 'rate' => $row['tax_rate'], ], [ - 'company_id' => session('company_id'), 'type' => $type, 'name' => !empty($row['tax_name']) ? $row['tax_name'] : $row['tax_rate'], 'enabled' => 1, diff --git a/app/Traits/Jobs.php b/app/Traits/Jobs.php index 731467584..783414a55 100644 --- a/app/Traits/Jobs.php +++ b/app/Traits/Jobs.php @@ -3,6 +3,7 @@ namespace App\Traits; use Exception; +use Illuminate\Bus\Dispatcher; use Throwable; trait Jobs @@ -17,7 +18,32 @@ trait Jobs { $function = $this->getDispatchFunction(); - return $function($job); + return $this->$function($job); + } + + /** + * Dispatch a job to its appropriate handler. + * + * @param mixed $command + * @return mixed + */ + public function dispatchQueue($job) + { + return app(Dispatcher::class)->dispatch($job); + } + + /** + * Dispatch a command to its appropriate handler in the current process. + * + * Queuable jobs will be dispatched to the "sync" queue. + * + * @param mixed $command + * @param mixed $handler + * @return mixed + */ + public function dispatchSync($job, $handler = null) + { + return app(Dispatcher::class)->dispatchSync($job, $handler); } /** @@ -26,12 +52,12 @@ trait Jobs * @param mixed $job * @param mixed $handler * @return mixed + * + * @deprecated Will be removed in a future Laravel version. */ public function dispatchNow($job, $handler = null) { - $result = dispatch_now($job, $handler); - - return $result; + return app(Dispatcher::class)->dispatchNow($job, $handler); } /** @@ -65,8 +91,6 @@ trait Jobs public function getDispatchFunction() { - $config = config('queue.default'); - - return ($config == 'sync') ? 'dispatch_now' : 'dispatch'; + return should_queue() ? 'dispatchQueue' : 'dispatchSync'; } } diff --git a/app/Traits/Modules.php b/app/Traits/Modules.php index 5a86f0ed5..f6fdfbceb 100644 --- a/app/Traits/Modules.php +++ b/app/Traits/Modules.php @@ -164,7 +164,7 @@ trait Modules public function getInstalledModules() { - $key = 'apps.installed.' . session('company_id'); + $key = 'apps.installed.' . company_id(); if ($installed = Cache::get($key)) { return $installed; diff --git a/app/Traits/Scopes.php b/app/Traits/Scopes.php index b679bc6a9..67bbb0d9e 100644 --- a/app/Traits/Scopes.php +++ b/app/Traits/Scopes.php @@ -83,7 +83,7 @@ trait Scopes return $type; } - $type = $request->get('type') ?: Str::singular((string) $request->segment(2)); + $type = $request->get('type') ?: Str::singular((string) $request->segment(3)); if ($type == 'revenue') { $type = 'income'; diff --git a/app/Traits/SiteApi.php b/app/Traits/SiteApi.php index 20e29a789..5d73e0f04 100644 --- a/app/Traits/SiteApi.php +++ b/app/Traits/SiteApi.php @@ -19,7 +19,7 @@ trait SiteApi $headers['headers'] = [ 'Authorization' => 'Bearer ' . setting('apps.api_key'), 'Accept' => 'application/json', - 'Referer' => app()->runningInConsole() ? config('app.url') : route('dashboard'), + 'Referer' => app()->runningInConsole() ? config('app.url') : url('/'), 'Akaunting' => version('short'), 'Language' => language()->getShortCode(), 'Information' => json_encode(Info::all()), diff --git a/app/Traits/Uploads.php b/app/Traits/Uploads.php index 1576ab5d1..aafd2dba4 100644 --- a/app/Traits/Uploads.php +++ b/app/Traits/Uploads.php @@ -2,8 +2,8 @@ namespace App\Traits; -use MediaUploader; use App\Models\Common\Media as MediaModel; +use MediaUploader; trait Uploads { @@ -16,7 +16,7 @@ trait Uploads } if (!$company_id) { - $company_id = session('company_id'); + $company_id = company_id(); } $file_name = $file->getClientOriginalName(); @@ -39,7 +39,7 @@ trait Uploads } if (!$company_id) { - $company_id = session('company_id'); + $company_id = company_id(); } $path = $company_id . '/' . $folder; @@ -56,7 +56,7 @@ trait Uploads } if (!$company_id) { - $company_id = session('company_id'); + $company_id = company_id(); } $path = $company_id . '/' . $folder . '/' . basename($file); diff --git a/app/Traits/Users.php b/app/Traits/Users.php index fedc0903c..11fd52578 100644 --- a/app/Traits/Users.php +++ b/app/Traits/Users.php @@ -29,11 +29,18 @@ trait Users return false; } - $company = $user->companies()->where('id', $id)->first(); + $company = $user->withoutEvents(function () use ($user, $id) { + return $user->companies()->where('id', $id)->first(); + }); return !empty($company); } + public function isNotUserCompany($id) + { + return !$this->isUserCompany($id); + } + /** * Check user dashboard assignment * @@ -49,8 +56,54 @@ trait Users return app()->runningInConsole() ? true : false; } - $dashboard = $user->dashboards()->where('id', $id)->first(); + $dashboard = $user->withoutEvents(function () use ($user, $id) { + return $user->dashboards()->where('id', $id)->first(); + }); return !empty($dashboard); } + + public function isNotUserDashboard($id) + { + return !$this->isUserDashboard($id); + } + + /** + * Get the fist company of active user + * + * @return null|\App\Models\Common\Company + */ + public function getFirstCompanyOfUser() + { + $user = user(); + + if (empty($user)) { + return null; + } + + $company = $user->withoutEvents(function () use ($user) { + return $user->companies()->enabled()->first(); + }); + + if (empty($company)) { + return null; + } + + return $company; + } + + public function getLandingPageOfUser() + { + $user = user(); + + if (empty($user)) { + return route('login'); + } + + $route_name = $user->contact ? 'portal.dashboard' : $user->landing_page; + + $company_id = company_id() ?: optional($this->getFirstCompanyOfUser())->id; + + return route($route_name, ['company_id' => $company_id]); + } } diff --git a/app/Utilities/Modules.php b/app/Utilities/Modules.php index 69a8f68c9..e55b9c6e3 100644 --- a/app/Utilities/Modules.php +++ b/app/Utilities/Modules.php @@ -72,7 +72,7 @@ class Modules public static function getPaymentMethodsCacheKey($type) { - return 'payment_methods.' . session('company_id') . '.' . $type; + return 'payment_methods.' . company_id() . '.' . $type; } protected static function sortPaymentMethods(&$list) diff --git a/app/Utilities/Overrider.php b/app/Utilities/Overrider.php index 73fbec4dd..6622cdce7 100644 --- a/app/Utilities/Overrider.php +++ b/app/Utilities/Overrider.php @@ -11,7 +11,7 @@ class Overrider public static function load($type) { // Overrides apply per company - $company_id = session('company_id'); + $company_id = company_id(); if (empty($company_id)) { return; } @@ -25,11 +25,6 @@ class Overrider protected static function loadSettings() { - // Set the active company settings - setting()->setExtraColumns(['company_id' => static::$company_id]); - setting()->forgetAll(); - setting()->load(true); - // Timezone config(['app.timezone' => setting('localisation.timezone', 'UTC')]); date_default_timezone_set(config('app.timezone')); @@ -56,7 +51,7 @@ class Overrider } // Set app url dynamically - config(['app.url' => route('dashboard')]); + config(['app.url' => url('/')]); } protected static function loadCurrencies() diff --git a/app/Utilities/Widgets.php b/app/Utilities/Widgets.php index 60f5d709b..4cc5fcfb9 100644 --- a/app/Utilities/Widgets.php +++ b/app/Utilities/Widgets.php @@ -68,7 +68,7 @@ class Widgets $model = new Widget(); $model->id = 0; - $model->company_id = session('company_id'); + $model->company_id = company_id(); $model->dashboard_id = session('dashboard_id'); $model->class = $class_name; $model->name = $class->getDefaultName(); diff --git a/app/Utilities/helpers.php b/app/Utilities/helpers.php index 92e750aa7..6a14ac412 100644 --- a/app/Utilities/helpers.php +++ b/app/Utilities/helpers.php @@ -1,5 +1,6 @@ id; + } +} + +if (!function_exists('should_queue')) { + /** + * Check if queue is enabled. + * + * @return bool + */ + function should_queue() { + return config('queue.default') != 'sync'; + } +} + if (!function_exists('cache_prefix')) { /** * Cache system added company_id prefix. @@ -74,6 +122,6 @@ if (!function_exists('cache_prefix')) { * @return string */ function cache_prefix() { - return session('company_id') . '_'; + return company_id() . '_'; } } diff --git a/app/View/Components/Documents/Form/Company.php b/app/View/Components/Documents/Form/Company.php index 1c0e1aa10..9dce2ab4f 100644 --- a/app/View/Components/Documents/Form/Company.php +++ b/app/View/Components/Documents/Form/Company.php @@ -14,7 +14,7 @@ class Company extends Component */ public function render() { - $company = Model::find(session('company_id')); + $company = Model::find(company_id()); $inputNameType = config('type.' . $this->type . '.route.parameter'); diff --git a/composer.json b/composer.json index 429f753e2..b30c02219 100644 --- a/composer.json +++ b/composer.json @@ -88,6 +88,7 @@ "Database\\Seeds\\": "database/seeds/", "Illuminate\\Translation\\": "overrides/Illuminate/Translation/", "Illuminate\\View\\Concerns\\": "overrides/Illuminate/View/Concerns/", + "Maatwebsite\\Excel\\": "overrides/maatwebsite/excel/", "Modules\\": "modules/", "Symfony\\Component\\Process\\": "overrides/symfony/process/" }, @@ -98,6 +99,8 @@ "vendor/akaunting/laravel-module/src/Commands/InstallCommand.php", "vendor/laravel/framework/src/Illuminate/Translation/MessageSelector.php", "vendor/laravel/framework/src/Illuminate/View/Concerns/ManagesStacks.php", + "vendor/maatwebsite/excel/src/Fakes/ExcelFake.php", + "vendor/maatwebsite/excel/src/QueuedWriter.php", "vendor/symfony/process/PhpExecutableFinder.php" ], "files": [ diff --git a/composer.lock b/composer.lock index 12f7a4f39..3a6899463 100644 --- a/composer.lock +++ b/composer.lock @@ -8,23 +8,23 @@ "packages": [ { "name": "akaunting/laravel-firewall", - "version": "1.2.13", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/akaunting/laravel-firewall.git", - "reference": "e686eda1826f83dea2b403480274800c67181d4a" + "reference": "5803f8166b98491feafb2367c8232361e800fea9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/akaunting/laravel-firewall/zipball/e686eda1826f83dea2b403480274800c67181d4a", - "reference": "e686eda1826f83dea2b403480274800c67181d4a", + "url": "https://api.github.com/repos/akaunting/laravel-firewall/zipball/5803f8166b98491feafb2367c8232361e800fea9", + "reference": "5803f8166b98491feafb2367c8232361e800fea9", "shasum": "" }, "require": { "guzzlehttp/guzzle": ">=6.0", "jenssegers/agent": "2.6.*", - "laravel/framework": ">=5.4", - "php": ">=5.6.4" + "laravel/framework": ">=5.5", + "php": ">=7.0" }, "require-dev": { "orchestra/testbench": ">=3.4", @@ -69,9 +69,9 @@ ], "support": { "issues": "https://github.com/akaunting/laravel-firewall/issues", - "source": "https://github.com/akaunting/laravel-firewall/tree/1.2.13" + "source": "https://github.com/akaunting/laravel-firewall/tree/1.3.0" }, - "time": "2021-03-12T19:05:08+00:00" + "time": "2021-04-17T08:14:42+00:00" }, { "name": "akaunting/laravel-language", @@ -505,16 +505,16 @@ }, { "name": "akaunting/module-offline-payments", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/akaunting/module-offline-payments.git", - "reference": "09bd63c03bd81c524d97bc112ca29f0d82c14e46" + "reference": "dea7391efa3c5f8a9426c7f8201a45f1283beb85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/akaunting/module-offline-payments/zipball/09bd63c03bd81c524d97bc112ca29f0d82c14e46", - "reference": "09bd63c03bd81c524d97bc112ca29f0d82c14e46", + "url": "https://api.github.com/repos/akaunting/module-offline-payments/zipball/dea7391efa3c5f8a9426c7f8201a45f1283beb85", + "reference": "dea7391efa3c5f8a9426c7f8201a45f1283beb85", "shasum": "" }, "type": "library", @@ -533,22 +533,22 @@ ], "support": { "issues": "https://github.com/akaunting/module-offline-payments/issues", - "source": "https://github.com/akaunting/module-offline-payments/tree/2.0.0" + "source": "https://github.com/akaunting/module-offline-payments/tree/2.0.1" }, - "time": "2021-03-04T09:00:22+00:00" + "time": "2021-04-16T22:29:03+00:00" }, { "name": "akaunting/module-paypal-standard", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/akaunting/module-paypal-standard.git", - "reference": "0dd391492c6ae47f2d91abe27165907029bf7960" + "reference": "49671f6f3c2c6319c7b319716292d31c2ad7db51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/akaunting/module-paypal-standard/zipball/0dd391492c6ae47f2d91abe27165907029bf7960", - "reference": "0dd391492c6ae47f2d91abe27165907029bf7960", + "url": "https://api.github.com/repos/akaunting/module-paypal-standard/zipball/49671f6f3c2c6319c7b319716292d31c2ad7db51", + "reference": "49671f6f3c2c6319c7b319716292d31c2ad7db51", "shasum": "" }, "type": "library", @@ -556,19 +556,20 @@ "license": [ "GPL-3.0+" ], - "description": "Paypal Standard app for Akaunting", + "description": "PayPal Standard app for Akaunting", "homepage": "https://akaunting.com", "keywords": [ "Accounting", + "akaunting", "invoice", "laravel", "paypal" ], "support": { "issues": "https://github.com/akaunting/module-paypal-standard/issues", - "source": "https://github.com/akaunting/module-paypal-standard/tree/2.0.0" + "source": "https://github.com/akaunting/module-paypal-standard/tree/2.0.1" }, - "time": "2021-03-04T08:53:43+00:00" + "time": "2021-04-16T22:28:17+00:00" }, { "name": "asm89/stack-cors", @@ -674,16 +675,16 @@ }, { "name": "barryvdh/laravel-debugbar", - "version": "v3.5.2", + "version": "v3.5.5", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "cae0a8d1cb89b0f0522f65e60465e16d738e069b" + "reference": "6420113d90bb746423fa70b9940e9e7c26ebc121" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/cae0a8d1cb89b0f0522f65e60465e16d738e069b", - "reference": "cae0a8d1cb89b0f0522f65e60465e16d738e069b", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/6420113d90bb746423fa70b9940e9e7c26ebc121", + "reference": "6420113d90bb746423fa70b9940e9e7c26ebc121", "shasum": "" }, "require": { @@ -743,7 +744,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.5.2" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.5.5" }, "funding": [ { @@ -751,7 +752,7 @@ "type": "github" } ], - "time": "2021-01-06T14:21:44+00:00" + "time": "2021-04-07T11:19:20+00:00" }, { "name": "barryvdh/laravel-dompdf", @@ -1595,76 +1596,6 @@ ], "time": "2020-09-10T14:20:26+00:00" }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.1", - "source": { - "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/fe390591e0241955f22eb9ba327d137e501c771c", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "*", - "phpcompatibility/php-compatibility": "^9.0", - "sensiolabs/security-checker": "^4.1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" - }, - "time": "2020-12-07T18:04:37+00:00" - }, { "name": "dingo/api", "version": "v3.0.5", @@ -1811,43 +1742,6 @@ }, "time": "2020-09-13T12:32:17+00:00" }, - { - "name": "dnoegel/php-xdg-base-dir", - "version": "v0.1.1", - "source": { - "type": "git", - "url": "https://github.com/dnoegel/php-xdg-base-dir.git", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "XdgBaseDir\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "implementation of xdg base directory specification for php", - "support": { - "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", - "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" - }, - "time": "2019-12-04T15:06:13+00:00" - }, { "name": "doctrine/annotations", "version": "1.12.1", @@ -2670,16 +2564,16 @@ }, { "name": "enlightn/enlightn", - "version": "v1.21.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/enlightn/enlightn.git", - "reference": "959c9dc6d4dc95c6182569e96fc6e3c48ac538fc" + "reference": "0958011684210838bb50646bedd6a33f73994e7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/enlightn/enlightn/zipball/959c9dc6d4dc95c6182569e96fc6e3c48ac538fc", - "reference": "959c9dc6d4dc95c6182569e96fc6e3c48ac538fc", + "url": "https://api.github.com/repos/enlightn/enlightn/zipball/0958011684210838bb50646bedd6a33f73994e7c", + "reference": "0958011684210838bb50646bedd6a33f73994e7c", "shasum": "" }, "require": { @@ -2747,9 +2641,9 @@ "support": { "docs": "https://www.laravel-enlightn.com/docs/", "issues": "https://github.com/enlightn/enlightn/issues", - "source": "https://github.com/enlightn/enlightn/tree/v1.21.0" + "source": "https://github.com/enlightn/enlightn/tree/v1.22.0" }, - "time": "2021-03-23T07:38:44+00:00" + "time": "2021-04-15T15:05:41+00:00" }, { "name": "enlightn/security-checker", @@ -3007,16 +2901,16 @@ }, { "name": "genealabs/laravel-model-caching", - "version": "0.11.2", + "version": "0.11.3", "source": { "type": "git", "url": "https://github.com/GeneaLabs/laravel-model-caching.git", - "reference": "7019f1e1a9ab070ebdee5cbb563449f05e161a7e" + "reference": "b8ffa347f6269f32dbd4b74ed7cb0bcd700e0793" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GeneaLabs/laravel-model-caching/zipball/7019f1e1a9ab070ebdee5cbb563449f05e161a7e", - "reference": "7019f1e1a9ab070ebdee5cbb563449f05e161a7e", + "url": "https://api.github.com/repos/GeneaLabs/laravel-model-caching/zipball/b8ffa347f6269f32dbd4b74ed7cb0bcd700e0793", + "reference": "b8ffa347f6269f32dbd4b74ed7cb0bcd700e0793", "shasum": "" }, "require": { @@ -3028,8 +2922,7 @@ "illuminate/database": "^8.0", "illuminate/http": "^8.0", "illuminate/support": "^8.0", - "php": "^7.3|^8.0", - "slevomat/coding-standard": "^6.4" + "php": "^7.3|^8.0" }, "require-dev": { "doctrine/dbal": "^2.10", @@ -3041,6 +2934,7 @@ "php-coveralls/php-coveralls": "^2.2", "phpmd/phpmd": "^2.7", "phpunit/phpunit": "^9.0", + "slevomat/coding-standard": "^6.4", "squizlabs/php_codesniffer": "^3.4", "symfony/thanks": "^1.2" }, @@ -3070,9 +2964,9 @@ "description": "Automatic caching for Eloquent models.", "support": { "issues": "https://github.com/GeneaLabs/laravel-model-caching/issues", - "source": "https://github.com/GeneaLabs/laravel-model-caching/tree/0.11.2" + "source": "https://github.com/GeneaLabs/laravel-model-caching/tree/0.11.3" }, - "time": "2021-03-16T15:04:15+00:00" + "time": "2021-04-13T14:47:33+00:00" }, { "name": "genealabs/laravel-pivot-events", @@ -4894,16 +4788,16 @@ }, { "name": "laravel/framework", - "version": "v8.35.1", + "version": "v8.37.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "d118c0df39e7524131176aaf76493eae63a8a602" + "reference": "cf4082973abc796ec285190f0603380021f6d26f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/d118c0df39e7524131176aaf76493eae63a8a602", - "reference": "d118c0df39e7524131176aaf76493eae63a8a602", + "url": "https://api.github.com/repos/laravel/framework/zipball/cf4082973abc796ec285190f0603380021f6d26f", + "reference": "cf4082973abc796ec285190f0603380021f6d26f", "shasum": "" }, "require": { @@ -5058,7 +4952,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-30T21:34:17+00:00" + "time": "2021-04-13T13:49:49+00:00" }, { "name": "laravel/slack-notification-channel", @@ -5898,16 +5792,16 @@ }, { "name": "maatwebsite/excel", - "version": "3.1.29", + "version": "3.1.30", "source": { "type": "git", "url": "https://github.com/Maatwebsite/Laravel-Excel.git", - "reference": "1e567e6e19a04fd65b5876d5bc92f4015f09fab4" + "reference": "aa5d2e4d25c5c8218ea0a15103da95f5f8728953" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/1e567e6e19a04fd65b5876d5bc92f4015f09fab4", - "reference": "1e567e6e19a04fd65b5876d5bc92f4015f09fab4", + "url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/aa5d2e4d25c5c8218ea0a15103da95f5f8728953", + "reference": "aa5d2e4d25c5c8218ea0a15103da95f5f8728953", "shasum": "" }, "require": { @@ -5960,7 +5854,7 @@ ], "support": { "issues": "https://github.com/Maatwebsite/Laravel-Excel/issues", - "source": "https://github.com/Maatwebsite/Laravel-Excel/tree/3.1.29" + "source": "https://github.com/Maatwebsite/Laravel-Excel/tree/3.1.30" }, "funding": [ { @@ -5972,7 +5866,7 @@ "type": "github" } ], - "time": "2021-03-16T11:56:39+00:00" + "time": "2021-04-06T17:17:02+00:00" }, { "name": "maennchen/zipstream-php", @@ -6925,16 +6819,16 @@ }, { "name": "nunomaduro/larastan", - "version": "v0.7.1", + "version": "v0.7.4", "source": { "type": "git", "url": "https://github.com/nunomaduro/larastan.git", - "reference": "bbbe09ec16a565e6423878bd17fc4355fa0d0a4c" + "reference": "0ceef2a39b45be9d7f7dd96192a1721ba5112278" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/larastan/zipball/bbbe09ec16a565e6423878bd17fc4355fa0d0a4c", - "reference": "bbbe09ec16a565e6423878bd17fc4355fa0d0a4c", + "url": "https://api.github.com/repos/nunomaduro/larastan/zipball/0ceef2a39b45be9d7f7dd96192a1721ba5112278", + "reference": "0ceef2a39b45be9d7f7dd96192a1721ba5112278", "shasum": "" }, "require": { @@ -6949,7 +6843,7 @@ "illuminate/support": "^6.0 || ^7.0 || ^8.0 || ^9.0", "mockery/mockery": "^0.9 || ^1.0", "php": "^7.2 || ^8.0", - "phpstan/phpstan": "0.12.81", + "phpstan/phpstan": "^0.12.83", "symfony/process": "^4.3 || ^5.0" }, "require-dev": { @@ -6998,7 +6892,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/larastan/issues", - "source": "https://github.com/nunomaduro/larastan/tree/v0.7.1" + "source": "https://github.com/nunomaduro/larastan/tree/v0.7.4" }, "funding": [ { @@ -7018,7 +6912,7 @@ "type": "patreon" } ], - "time": "2021-03-19T09:41:48+00:00" + "time": "2021-04-16T08:25:31+00:00" }, { "name": "omnipay/common", @@ -7108,16 +7002,16 @@ }, { "name": "opis/closure", - "version": "3.6.1", + "version": "3.6.2", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5" + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5", - "reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5", + "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", + "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", "shasum": "" }, "require": { @@ -7167,9 +7061,9 @@ ], "support": { "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.1" + "source": "https://github.com/opis/closure/tree/3.6.2" }, - "time": "2020-11-07T02:01:34+00:00" + "time": "2021-04-09T13:42:10+00:00" }, { "name": "paragonie/random_compat", @@ -8012,71 +7906,18 @@ ], "time": "2020-07-20T17:29:33+00:00" }, - { - "name": "phpstan/phpdoc-parser", - "version": "0.4.9", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "98a088b17966bdf6ee25c8a4b634df313d8aa531" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/98a088b17966bdf6ee25c8a4b634df313d8aa531", - "reference": "98a088b17966bdf6ee25c8a4b634df313d8aa531", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "consistence/coding-standard": "^3.5", - "ergebnis/composer-normalize": "^2.0.2", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "phing/phing": "^2.16.0", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.26", - "phpstan/phpstan-strict-rules": "^0.12", - "phpunit/phpunit": "^6.3", - "slevomat/coding-standard": "^4.7.2", - "symfony/process": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - }, - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/master" - }, - "time": "2020-08-03T20:32:43+00:00" - }, { "name": "phpstan/phpstan", - "version": "0.12.81", + "version": "0.12.83", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8" + "reference": "4a967cec6efb46b500dd6d768657336a3ffe699f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0dd5b0ebeff568f7000022ea5f04aa86ad3124b8", - "reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a967cec6efb46b500dd6d768657336a3ffe699f", + "reference": "4a967cec6efb46b500dd6d768657336a3ffe699f", "shasum": "" }, "require": { @@ -8107,7 +7948,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.81" + "source": "https://github.com/phpstan/phpstan/tree/0.12.83" }, "funding": [ { @@ -8123,7 +7964,7 @@ "type": "tidelift" } ], - "time": "2021-03-08T22:03:02+00:00" + "time": "2021-04-03T15:35:45+00:00" }, { "name": "plank/laravel-mediable", @@ -8560,20 +8401,19 @@ }, { "name": "psy/psysh", - "version": "v0.10.7", + "version": "v0.10.8", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "a395af46999a12006213c0c8346c9445eb31640c" + "reference": "e4573f47750dd6c92dca5aee543fa77513cbd8d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/a395af46999a12006213c0c8346c9445eb31640c", - "reference": "a395af46999a12006213c0c8346c9445eb31640c", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e4573f47750dd6c92dca5aee543fa77513cbd8d3", + "reference": "e4573f47750dd6c92dca5aee543fa77513cbd8d3", "shasum": "" }, "require": { - "dnoegel/php-xdg-base-dir": "0.1.*", "ext-json": "*", "ext-tokenizer": "*", "nikic/php-parser": "~4.0|~3.0|~2.0|~1.3", @@ -8630,9 +8470,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.10.7" + "source": "https://github.com/bobthecow/psysh/tree/v0.10.8" }, - "time": "2021-03-14T02:14:56+00:00" + "time": "2021-04-10T16:23:39+00:00" }, { "name": "ralouphie/getallheaders", @@ -9320,123 +9160,6 @@ }, "time": "2021-03-25T23:00:49+00:00" }, - { - "name": "slevomat/coding-standard", - "version": "6.4.1", - "source": { - "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "696dcca217d0c9da2c40d02731526c1e25b65346" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/696dcca217d0c9da2c40d02731526c1e25b65346", - "reference": "696dcca217d0c9da2c40d02731526c1e25b65346", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", - "php": "^7.1 || ^8.0", - "phpstan/phpdoc-parser": "0.4.5 - 0.4.9", - "squizlabs/php_codesniffer": "^3.5.6" - }, - "require-dev": { - "phing/phing": "2.16.3", - "php-parallel-lint/php-parallel-lint": "1.2.0", - "phpstan/phpstan": "0.12.48", - "phpstan/phpstan-deprecation-rules": "0.12.5", - "phpstan/phpstan-phpunit": "0.12.16", - "phpstan/phpstan-strict-rules": "0.12.5", - "phpunit/phpunit": "7.5.20|8.5.5|9.4.0" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-master": "6.x-dev" - } - }, - "autoload": { - "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", - "support": { - "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/6.4.1" - }, - "funding": [ - { - "url": "https://github.com/kukulich", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", - "type": "tidelift" - } - ], - "time": "2020-10-05T12:39:37+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.5.8", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards" - ], - "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" - }, - "time": "2020-10-23T02:01:07+00:00" - }, { "name": "staudenmeir/belongs-to-through", "version": "v2.11.1", @@ -12479,16 +12202,16 @@ }, { "name": "facade/flare-client-php", - "version": "1.5.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "9dd6f2b56486d939c4467b3f35475d44af57cf17" + "reference": "6bf380035890cb0a09b9628c491ae3866b858522" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/9dd6f2b56486d939c4467b3f35475d44af57cf17", - "reference": "9dd6f2b56486d939c4467b3f35475d44af57cf17", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/6bf380035890cb0a09b9628c491ae3866b858522", + "reference": "6bf380035890cb0a09b9628c491ae3866b858522", "shasum": "" }, "require": { @@ -12532,7 +12255,7 @@ ], "support": { "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.5.0" + "source": "https://github.com/facade/flare-client-php/tree/1.7.0" }, "funding": [ { @@ -12540,26 +12263,26 @@ "type": "github" } ], - "time": "2021-03-31T07:32:54+00:00" + "time": "2021-04-12T09:30:36+00:00" }, { "name": "facade/ignition", - "version": "2.7.0", + "version": "2.8.3", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "bdc8b0b32c888f6edc838ca641358322b3d9506d" + "reference": "a8201d51aae83addceaef9344592a3b068b5d64d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/bdc8b0b32c888f6edc838ca641358322b3d9506d", - "reference": "bdc8b0b32c888f6edc838ca641358322b3d9506d", + "url": "https://api.github.com/repos/facade/ignition/zipball/a8201d51aae83addceaef9344592a3b068b5d64d", + "reference": "a8201d51aae83addceaef9344592a3b068b5d64d", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "facade/flare-client-php": "^1.3.7", + "facade/flare-client-php": "^1.6", "facade/ignition-contracts": "^1.0.2", "filp/whoops": "^2.4", "illuminate/support": "^7.0|^8.0", @@ -12617,7 +12340,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-03-30T15:55:38+00:00" + "time": "2021-04-09T20:45:59+00:00" }, { "name": "facade/ignition-contracts", @@ -12868,16 +12591,16 @@ }, { "name": "nunomaduro/collision", - "version": "v5.3.0", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "aca63581f380f63a492b1e3114604e411e39133a" + "reference": "41b7e9999133d5082700d31a1d0977161df8322a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/aca63581f380f63a492b1e3114604e411e39133a", - "reference": "aca63581f380f63a492b1e3114604e411e39133a", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/41b7e9999133d5082700d31a1d0977161df8322a", + "reference": "41b7e9999133d5082700d31a1d0977161df8322a", "shasum": "" }, "require": { @@ -12952,7 +12675,7 @@ "type": "patreon" } ], - "time": "2021-01-25T15:34:13+00:00" + "time": "2021-04-09T13:38:32+00:00" }, { "name": "phar-io/manifest", diff --git a/config/app.php b/config/app.php index d8831bcbb..6d844fa16 100644 --- a/config/app.php +++ b/config/app.php @@ -180,6 +180,7 @@ return [ App\Providers\Form::class, App\Providers\Macro::class, App\Providers\Observer::class, + App\Providers\Queue::class, App\Providers\Route::class, App\Providers\Validation::class, App\Providers\ViewComposer::class, diff --git a/config/excel.php b/config/excel.php index 5557fbae3..6d06f6a38 100644 --- a/config/excel.php +++ b/config/excel.php @@ -13,7 +13,7 @@ return [ | Here you can specify how big the chunk should be. | */ - 'chunk_size' => 1000, + 'chunk_size' => 100, /* |-------------------------------------------------------------------------- @@ -114,20 +114,75 @@ return [ 'pdf' => 'Dompdf', ], + /* + |-------------------------------------------------------------------------- + | Value Binder + |-------------------------------------------------------------------------- + | + | PhpSpreadsheet offers a way to hook into the process of a value being + | written to a cell. In there some assumptions are made on how the + | value should be formatted. If you want to change those defaults, + | you can implement your own default value binder. + | + | Possible value binders: + | + | [x] Maatwebsite\Excel\DefaultValueBinder::class + | [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class + | [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class + | + */ 'value_binder' => [ + 'default' => 'Maatwebsite\Excel\DefaultValueBinder', + ], + + 'cache' => [ + /* + |-------------------------------------------------------------------------- + | Default cell caching driver + |-------------------------------------------------------------------------- + | + | By default PhpSpreadsheet keeps all cell values in memory, however when + | dealing with large files, this might result into memory issues. If you + | want to mitigate that, you can configure a cell caching driver here. + | When using the illuminate driver, it will store each value in a the + | cache store. This can slow down the process, because it needs to + | store each value. You can use the "batch" store if you want to + | only persist to the store when the memory limit is reached. + | + | Drivers: memory|illuminate|batch + | + */ + 'driver' => env('EXCEL_CACHE_DRIVER', 'memory'), /* |-------------------------------------------------------------------------- - | Default Value Binder + | Batch memory caching |-------------------------------------------------------------------------- | - | PhpSpreadsheet offers a way to hook into the process of a value being - | written to a cell. In there some assumptions are made on how the - | value should be formatted. If you want to change those defaults, - | you can implement your own default value binder. + | When dealing with the "batch" caching driver, it will only + | persist to the store when the memory limit is reached. + | Here you can tweak the memory limit to your liking. | */ - 'default' => 'Maatwebsite\Excel\DefaultValueBinder', + 'batch' => [ + 'memory_limit' => env('EXCEL_CACHE_BATCH_MEMORY_LIMIT', 60000), + ], + + /* + |-------------------------------------------------------------------------- + | Illuminate cache + |-------------------------------------------------------------------------- + | + | When using the "illuminate" caching driver, it will automatically use + | your default cache store. However if you prefer to have the cell + | cache on a separate store, you can configure the store name here. + | You can use any store defined in your cache config. When leaving + | at "null" it will use the default store. + | + */ + 'illuminate' => [ + 'store' => null, + ], ], 'transactions' => [ @@ -177,7 +232,25 @@ return [ | in conjunction with queued imports and exports. | */ - 'remote_disk' => null, + 'remote_disk' => env('EXCEL_TEMPORARY_FILES_REMOTE_DISK', null), + 'remote_prefix' => env('EXCEL_TEMPORARY_FILES_REMOTE_PREFIX', null), + + /* + |-------------------------------------------------------------------------- + | Force Resync + |-------------------------------------------------------------------------- + | + | When dealing with a multi server setup as above, it's possible + | for the clean up that occurs after entire queue has been run to only + | cleanup the server that the last AfterImportJob runs on. The rest of the server + | would still have the local temporary file stored on it. In this case your + | local storage limits can be exceeded and future imports won't be processed. + | To mitigate this you can set this config value to be true, so that after every + | queued chunk is processed the local temporary file is deleted on the server that + | processed it. + | + */ + 'force_resync_remote' => env('EXCEL_TEMPORARY_FILES_FORCE_RESYNC_REMOTE', null), ], diff --git a/config/mediable.php b/config/mediable.php index 9f468220e..1e4ad4703 100644 --- a/config/mediable.php +++ b/config/mediable.php @@ -6,12 +6,12 @@ return [ * * Should extend `Plank\Mediable\Media` */ - 'model' => Plank\Mediable\Media::class, + 'model' => env('MEDIABLE_MODEL', 'Plank\Mediable\Media'), /* * Filesystem disk to use if none is specified */ - 'default_disk' => 'uploads', + 'default_disk' => env('MEDIABLE_DEFAULT_DISK', 'uploads'), /* * Filesystems that can be used for media storage @@ -20,6 +20,7 @@ return [ */ 'allowed_disks' => [ 'uploads', + 's3', ], /* diff --git a/database/seeds/TestCompany.php b/database/seeds/TestCompany.php index 0029cfc94..7191464a8 100644 --- a/database/seeds/TestCompany.php +++ b/database/seeds/TestCompany.php @@ -50,18 +50,11 @@ class TestCompany extends Seeder 'schedule.send_invoice_reminder' => '1', 'schedule.send_bill_reminder' => '1', 'wizard.completed' => '1', + 'email.protocol' => 'array', ], ])); - session(['company_id' => $company->id]); - - // Set Company settings - setting()->setExtraColumns(['company_id' => $company->id]); - setting()->forgetAll(); - setting()->load(true); - - setting()->set(['email.protocol' => 'array']); - setting()->save(); + $company->makeCurrent(true); $this->command->info('Test company created.'); } @@ -73,7 +66,7 @@ class TestCompany extends Seeder 'email' => 'test@company.com', 'password' => '123456', 'locale' => 'en-GB', - 'companies' => [session('company_id')], + 'companies' => [company_id()], 'roles' => ['1'], 'enabled' => '1', ])); @@ -90,7 +83,7 @@ class TestCompany extends Seeder 'currency_code' => setting('default.currency'), 'password' => '123456', 'password_confirmation' => '123456', - 'company_id' => session('company_id'), + 'company_id' => company_id(), 'enabled' => '1', 'create_user' => 'true', ])); @@ -113,7 +106,7 @@ class TestCompany extends Seeder Artisan::call('module:install', [ 'alias' => $alias, - 'company' => session('company_id'), + 'company' => company_id(), 'locale' => session('locale', app()->getLocale()), ]); } diff --git a/overrides/maatwebsite/excel/Fakes/ExcelFake.php b/overrides/maatwebsite/excel/Fakes/ExcelFake.php new file mode 100644 index 000000000..8a6c0a12d --- /dev/null +++ b/overrides/maatwebsite/excel/Fakes/ExcelFake.php @@ -0,0 +1,358 @@ +downloads[$fileName] = $export; + + return new BinaryFileResponse(__DIR__ . '/fake_file'); + } + + /** + * {@inheritdoc} + */ + public function store($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = []) + { + if ($export instanceof ShouldQueue) { + // @todo removed to fix explicit queue exports + //return $this->queue($export, $filePath, $disk, $writerType); + } + + $this->stored[$disk ?? 'default'][$filePath] = $export; + + return true; + } + + /** + * {@inheritdoc} + */ + public function queue($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = []) + { + Queue::fake(); + + $this->stored[$disk ?? 'default'][$filePath] = $export; + $this->queued[$disk ?? 'default'][$filePath] = $export; + + $this->job = new class { + use Queueable; + + public function handle() + { + // + } + }; + + Queue::push($this->job); + + return new PendingDispatch($this->job); + } + + /** + * @param object $export + * @param string $writerType + * + * @return string + */ + public function raw($export, string $writerType) + { + return 'RAW-CONTENTS'; + } + + /** + * @param object $import + * @param string|UploadedFile $file + * @param string|null $disk + * @param string|null $readerType + * + * @return Reader|PendingDispatch + */ + public function import($import, $file, string $disk = null, string $readerType = null) + { + if ($import instanceof ShouldQueue) { + // @todo removed to fix explicit queue imports + //return $this->queueImport($import, $file, $disk, $readerType); + } + + $filePath = ($file instanceof UploadedFile) ? $file->getClientOriginalName() : $file; + + $this->imported[$disk ?? 'default'][$filePath] = $import; + + return $this; + } + + /** + * @param object $import + * @param string|UploadedFile $file + * @param string|null $disk + * @param string|null $readerType + * + * @return array + */ + public function toArray($import, $file, string $disk = null, string $readerType = null): array + { + $filePath = ($file instanceof UploadedFile) ? $file->getFilename() : $file; + + $this->imported[$disk ?? 'default'][$filePath] = $import; + + return []; + } + + /** + * @param object $import + * @param string|UploadedFile $file + * @param string|null $disk + * @param string|null $readerType + * + * @return Collection + */ + public function toCollection($import, $file, string $disk = null, string $readerType = null): Collection + { + $filePath = ($file instanceof UploadedFile) ? $file->getFilename() : $file; + + $this->imported[$disk ?? 'default'][$filePath] = $import; + + return new Collection(); + } + + /** + * @param ShouldQueue $import + * @param string|UploadedFile $file + * @param string|null $disk + * @param string $readerType + * + * @return PendingDispatch + */ + public function queueImport(ShouldQueue $import, $file, string $disk = null, string $readerType = null) + { + Queue::fake(); + + $filePath = ($file instanceof UploadedFile) ? $file->getFilename() : $file; + + $this->queued[$disk ?? 'default'][$filePath] = $import; + $this->imported[$disk ?? 'default'][$filePath] = $import; + + return new PendingDispatch(new class { + use Queueable; + + public function handle() + { + // + } + }); + } + + /** + * When asserting downloaded, stored, queued or imported, use regular expression + * to look for a matching file path. + * + * @return void + */ + public function matchByRegex() + { + $this->matchByRegex = true; + } + + /** + * When asserting downloaded, stored, queued or imported, use regular string + * comparison for matching file path. + * + * @return void + */ + public function doNotMatchByRegex() + { + $this->matchByRegex = false; + } + + /** + * @param string $fileName + * @param callable|null $callback + */ + public function assertDownloaded(string $fileName, $callback = null) + { + $fileName = $this->assertArrayHasKey($fileName, $this->downloads, sprintf('%s is not downloaded', $fileName)); + + $callback = $callback ?: function () { + return true; + }; + + Assert::assertTrue( + $callback($this->downloads[$fileName]), + "The file [{$fileName}] was not downloaded with the expected data." + ); + } + + /** + * @param string $filePath + * @param string|callable|null $disk + * @param callable|null $callback + */ + public function assertStored(string $filePath, $disk = null, $callback = null) + { + if (is_callable($disk)) { + $callback = $disk; + $disk = null; + } + + $disk = $disk ?? 'default'; + $storedOnDisk = $this->stored[$disk] ?? []; + + $filePath = $this->assertArrayHasKey( + $filePath, + $storedOnDisk, + sprintf('%s is not stored on disk %s', $filePath, $disk) + ); + + $callback = $callback ?: function () { + return true; + }; + + Assert::assertTrue( + $callback($storedOnDisk[$filePath]), + "The file [{$filePath}] was not stored with the expected data." + ); + } + + /** + * @param string $filePath + * @param string|callable|null $disk + * @param callable|null $callback + */ + public function assertQueued(string $filePath, $disk = null, $callback = null) + { + if (is_callable($disk)) { + $callback = $disk; + $disk = null; + } + + $disk = $disk ?? 'default'; + $queuedForDisk = $this->queued[$disk] ?? []; + + $filePath = $this->assertArrayHasKey( + $filePath, + $queuedForDisk, + sprintf('%s is not queued for export on disk %s', $filePath, $disk) + ); + + $callback = $callback ?: function () { + return true; + }; + + Assert::assertTrue( + $callback($queuedForDisk[$filePath]), + "The file [{$filePath}] was not stored with the expected data." + ); + } + + public function assertQueuedWithChain($chain): void + { + Queue::assertPushedWithChain(get_class($this->job), $chain); + } + + /** + * @param string $filePath + * @param string|callable|null $disk + * @param callable|null $callback + */ + public function assertImported(string $filePath, $disk = null, $callback = null) + { + if (is_callable($disk)) { + $callback = $disk; + $disk = null; + } + + $disk = $disk ?? 'default'; + $importedOnDisk = $this->imported[$disk] ?? []; + + $filePath = $this->assertArrayHasKey( + $filePath, + $importedOnDisk, + sprintf('%s is not stored on disk %s', $filePath, $disk) + ); + + $callback = $callback ?: function () { + return true; + }; + + Assert::assertTrue( + $callback($importedOnDisk[$filePath]), + "The file [{$filePath}] was not imported with the expected data." + ); + } + + /** + * Asserts that an array has a specified key and returns the key if successful. + * @see matchByRegex for more information about file path matching + * + * @param string $key + * @param array $array + * @param string $message + * + * @return string + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + protected function assertArrayHasKey(string $key, array $disk, string $message = ''): string + { + if ($this->matchByRegex) { + $files = array_keys($disk); + $results = preg_grep($key, $files); + Assert::assertGreaterThan(0, count($results), $message); + Assert::assertEquals(1, count($results), "More than one result matches the file name expression '$key'."); + + return $results[0]; + } + Assert::assertArrayHasKey($key, $disk, $message); + + return $key; + } +} diff --git a/overrides/maatwebsite/excel/Fakes/fake_file b/overrides/maatwebsite/excel/Fakes/fake_file new file mode 100644 index 000000000..e69de29bb diff --git a/overrides/maatwebsite/excel/QueuedWriter.php b/overrides/maatwebsite/excel/QueuedWriter.php new file mode 100644 index 000000000..e1949045f --- /dev/null +++ b/overrides/maatwebsite/excel/QueuedWriter.php @@ -0,0 +1,215 @@ +writer = $writer; + $this->chunkSize = config('excel.exports.chunk_size', 1000); + $this->temporaryFileFactory = $temporaryFileFactory; + } + + /** + * @param object $export + * @param string $filePath + * @param string $disk + * @param string|null $writerType + * @param array|string $diskOptions + * + * @return \Illuminate\Foundation\Bus\PendingDispatch + */ + public function store($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = []) + { + $extension = pathinfo($filePath, PATHINFO_EXTENSION); + $temporaryFile = $this->temporaryFileFactory->make($extension); + + $jobs = $this->buildExportJobs($export, $temporaryFile, $writerType); + + $jobs->push(new StoreQueuedExport( + $temporaryFile, + $filePath, + $disk, + $diskOptions + )); + + return new PendingDispatch( + (new QueueExport($export, $temporaryFile, $writerType))->chain($jobs->toArray()) + ); + } + + /** + * @param object $export + * @param TemporaryFile $temporaryFile + * @param string $writerType + * + * @return Collection + */ + private function buildExportJobs($export, TemporaryFile $temporaryFile, string $writerType): Collection + { + $sheetExports = [$export]; + if ($export instanceof WithMultipleSheets) { + $sheetExports = $export->sheets(); + } + + $jobs = new Collection; + foreach ($sheetExports as $sheetIndex => $sheetExport) { + if ($sheetExport instanceof FromCollection) { + $jobs = $jobs->merge($this->exportCollection($sheetExport, $temporaryFile, $writerType, $sheetIndex)); + } elseif ($sheetExport instanceof FromQuery) { + $jobs = $jobs->merge($this->exportQuery($sheetExport, $temporaryFile, $writerType, $sheetIndex)); + } elseif ($sheetExport instanceof FromView) { + $jobs = $jobs->merge($this->exportView($sheetExport, $temporaryFile, $writerType, $sheetIndex)); + } + + $jobs->push(new CloseSheet($sheetExport, $temporaryFile, $writerType, $sheetIndex)); + } + + return $jobs; + } + + /** + * @param FromCollection $export + * @param TemporaryFile $temporaryFile + * @param string $writerType + * @param int $sheetIndex + * + * @return LazyCollection // @todo original: Collection + */ + private function exportCollection( + FromCollection $export, + TemporaryFile $temporaryFile, + string $writerType, + int $sheetIndex + ): LazyCollection { // @todo original: Collection + return $export + ->collection() + ->chunk($this->getChunkSize($export)) + ->map(function ($rows) use ($writerType, $temporaryFile, $sheetIndex, $export) { + if ($rows instanceof Traversable) { + $rows = iterator_to_array($rows); + } + + return new AppendDataToSheet( + $export, + $temporaryFile, + $writerType, + $sheetIndex, + $rows + ); + }); + } + + /** + * @param FromQuery $export + * @param TemporaryFile $temporaryFile + * @param string $writerType + * @param int $sheetIndex + * + * @return Collection + */ + private function exportQuery( + FromQuery $export, + TemporaryFile $temporaryFile, + string $writerType, + int $sheetIndex + ): Collection { + $query = $export->query(); + + $count = $export instanceof WithCustomQuerySize ? $export->querySize() : $query->count(); + $spins = ceil($count / $this->getChunkSize($export)); + + $jobs = new Collection(); + + for ($page = 1; $page <= $spins; $page++) { + $jobs->push(new AppendQueryToSheet( + $export, + $temporaryFile, + $writerType, + $sheetIndex, + $page, + $this->getChunkSize($export) + )); + } + + return $jobs; + } + + /** + * @param FromView $export + * @param TemporaryFile $temporaryFile + * @param string $writerType + * @param int $sheetIndex + * + * @return Collection + */ + private function exportView( + FromView $export, + TemporaryFile $temporaryFile, + string $writerType, + int $sheetIndex + ): Collection { + $jobs = new Collection(); + $jobs->push(new AppendViewToSheet( + $export, + $temporaryFile, + $writerType, + $sheetIndex + )); + + return $jobs; + } + + /** + * @param object|WithCustomChunkSize $export + * + * @return int + */ + private function getChunkSize($export): int + { + if ($export instanceof WithCustomChunkSize) { + return $export->chunkSize(); + } + + return $this->chunkSize; + } +} diff --git a/public/files/import/bills.xlsx b/public/files/import/bills.xlsx index d04e1ff72..b4f3c2e49 100644 Binary files a/public/files/import/bills.xlsx and b/public/files/import/bills.xlsx differ diff --git a/public/files/import/invoices.xlsx b/public/files/import/invoices.xlsx index 670f152c2..d7be144b8 100644 Binary files a/public/files/import/invoices.xlsx and b/public/files/import/invoices.xlsx differ diff --git a/resources/assets/js/views/portal/invoices.js b/resources/assets/js/views/portal/invoices.js index fb5905be7..5b6764a71 100644 --- a/resources/assets/js/views/portal/invoices.js +++ b/resources/assets/js/views/portal/invoices.js @@ -55,7 +55,7 @@ const app = new Vue({ let method = payment_method.split('.'); - let path = url + '/portal/invoices/' + this.form.document_id + '/' + method[0]; + let path = url + '/portal/' + method[0] + '/invoices/' + this.form.document_id; this.method_show_html = Vue.component('payment-method-confirm', function (resolve, reject) { resolve({ diff --git a/resources/lang/en-GB/messages.php b/resources/lang/en-GB/messages.php index e14d19be0..366d9f8dd 100644 --- a/resources/lang/en-GB/messages.php +++ b/resources/lang/en-GB/messages.php @@ -8,7 +8,9 @@ return [ 'deleted' => ':type deleted!', 'duplicated' => ':type duplicated!', 'imported' => ':type imported!', + 'import_queued' => ':type import has been scheduled! You will receive an email when it is finished.', 'exported' => ':type exported!', + 'export_queued' => ':type export has been scheduled! You will receive an email when it is ready to download.', 'enabled' => ':type enabled!', 'disabled' => ':type disabled!', ], @@ -21,7 +23,7 @@ return [ 'last_category' => 'Error: Can not delete the last :type category!', 'change_type' => 'Error: Can not change the type because it has :text related!', 'invalid_apikey' => 'Error: The API Key entered is invalid!', - 'import_column' => 'Error: :message Sheet name: :sheet. Line number: :line.', + 'import_column' => 'Error: :message Column name: :column. Line number: :line.', 'import_sheet' => 'Error: Sheet name is not valid. Please, check the sample file.', ], diff --git a/resources/lang/en-GB/notifications.php b/resources/lang/en-GB/notifications.php index 7ae710144..384577473 100644 --- a/resources/lang/en-GB/notifications.php +++ b/resources/lang/en-GB/notifications.php @@ -24,4 +24,31 @@ return [ ], + 'import' => [ + + 'completed' => [ + 'subject' => 'Import completed', + 'description' => 'The import has been completed and the records are available in your panel.', + ], + + 'failed' => [ + 'subject' => 'Import failed', + 'description' => 'Not able to import the file due to the following issues:', + ], + ], + + 'export' => [ + + 'completed' => [ + 'subject' => 'Export is ready', + 'description' => 'The export file is ready to download from the following link:', + ], + + 'failed' => [ + 'subject' => 'Export failed', + 'description' => 'Not able to create the export file due to the following issue:', + ], + + ], + ]; diff --git a/resources/views/common/companies/index.blade.php b/resources/views/common/companies/index.blade.php index 40049bbe9..513874347 100644 --- a/resources/views/common/companies/index.blade.php +++ b/resources/views/common/companies/index.blade.php @@ -43,7 +43,7 @@ @foreach($companies as $item) - @if ((session('company_id') != $item->id)) + @if ((company_id() != $item->id)) {{ Form::bulkActionGroup($item->id, $item->name) }} @else {{ Form::bulkActionGroup($item->id, $item->name, ['disabled' => 'true']) }} @@ -54,7 +54,7 @@ {{ $item->email }} @date($item->created_at) - @if ((session('company_id') != $item->id) && user()->can('update-common-companies')) + @if ((company_id() != $item->id) && user()->can('update-common-companies')) {{ Form::enabledGroup($item->id, $item->name, $item->enabled) }} @else @if ($item->enabled) diff --git a/resources/views/components/documents/form/company.blade.php b/resources/views/components/documents/form/company.blade.php index 24bcf6f8d..c43a1aa14 100644 --- a/resources/views/components/documents/form/company.blade.php +++ b/resources/views/components/documents/form/company.blade.php @@ -23,7 +23,7 @@ @endif @if (!$hideCompanyEdit) -

{{ trans('errors.message.403') }}

- @php $landing_page = user() ? route(user()->landing_page) : route('login'); @endphp + @php $landing_page = user() ? user()->getLandingPageOfUser() : route('login'); @endphp {{ trans('general.go_to_dashboard') }} diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php index 3cf4cdeca..96cd230ed 100644 --- a/resources/views/errors/404.blade.php +++ b/resources/views/errors/404.blade.php @@ -13,7 +13,7 @@

{{ trans('errors.message.404') }}

- @php $landing_page = user() ? route(user()->landing_page) : route('login'); @endphp + @php $landing_page = user() ? user()->getLandingPageOfUser() : route('login'); @endphp {{ trans('general.go_to_dashboard') }}
diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php index 301fef4cb..572546a6f 100644 --- a/resources/views/errors/500.blade.php +++ b/resources/views/errors/500.blade.php @@ -13,7 +13,7 @@

{{ trans('errors.message.500') }}

- @php $landing_page = user() ? route(user()->landing_page) : route('login'); @endphp + @php $landing_page = user() ? user()->getLandingPageOfUser() : route('login'); @endphp {{ trans('general.go_to_dashboard') }}
diff --git a/resources/views/partials/admin/head.blade.php b/resources/views/partials/admin/head.blade.php index 8e59fa5ba..5f6a93648 100644 --- a/resources/views/partials/admin/head.blade.php +++ b/resources/views/partials/admin/head.blade.php @@ -35,7 +35,7 @@ @livewireStyles diff --git a/routes/guest.php b/routes/guest.php index 5dd0c2f54..a473932b9 100644 --- a/routes/guest.php +++ b/routes/guest.php @@ -20,3 +20,7 @@ Route::group(['prefix' => 'auth'], function () { Route::get('reset/{token}', 'Auth\Reset@create')->name('reset'); Route::post('reset', 'Auth\Reset@store')->name('reset.store'); }); + +Route::get('/', function () { + return redirect()->route('login'); +}); diff --git a/tests/Feature/FeatureTestCase.php b/tests/Feature/FeatureTestCase.php index 7d30ddff8..f431a7103 100644 --- a/tests/Feature/FeatureTestCase.php +++ b/tests/Feature/FeatureTestCase.php @@ -4,8 +4,7 @@ namespace Tests\Feature; use App\Models\Auth\User; use App\Models\Common\Company; -use App\Utilities\Overrider; -use Faker\Factory; +use Faker\Factory as Faker; use Tests\TestCase; abstract class FeatureTestCase extends TestCase @@ -22,14 +21,12 @@ abstract class FeatureTestCase extends TestCase $this->withoutExceptionHandling(); - $this->faker = Factory::create(); + $this->faker = Faker::create(); $this->user = User::first(); $this->company = $this->user->companies()->first(); // Disable debugbar config(['debugbar.enabled', false]); - - Overrider::load('currencies'); } /** @@ -45,13 +42,13 @@ abstract class FeatureTestCase extends TestCase $user = $this->user; } - if (!$company) { - $company = $this->company; + if ($company) { + $company->makeCurrent(); } - $this->startSession(); + app('url')->defaults(['company_id' => company_id()]); - return $this->actingAs($user)->withSession(['company_id' => $company->id]); + return $this->actingAs($user); } public function assertFlashLevel($excepted)