diff --git a/.github/workflows/react_release.yml b/.github/workflows/react_release.yml new file mode 100644 index 000000000000..f94ad90e6c63 --- /dev/null +++ b/.github/workflows/react_release.yml @@ -0,0 +1,76 @@ +on: + release: + types: [released] + +name: React Release + +jobs: + build: + name: Upload Release Asset + runs-on: ubuntu-latest + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.1 + extensions: mysql, mysqlnd, sqlite3, bcmath, gd, curl, zip, openssl, mbstring, xml + + - name: Checkout code + uses: actions/checkout@v1 + with: + ref: v5-develop + + - name: Copy .env file + run: | + cp .env.example .env + + - name: Install composer dependencies + run: | + composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} + composer install --no-dev + + - name: Prepare Laravel Application + run: | + cp .env.example .env + php artisan key:generate --force + php artisan optimize + php artisan storage:link --force + sudo php artisan cache:clear + sudo find ./vendor/bin/ -type f -exec chmod +x {} \; + sudo find ./ -type d -exec chmod 755 {} \; + sudo rm -f public/main.* + sudo rm -f public/flutter* + + - name: Prepare React FrontEnd + run: | + git clone https://${{secrets.commit_secret}}@github.com/invoiceninja/ui.git + cd ui + git checkout develop + npm i + npm run build + cp -r dist/* ../public/ + + - name: Prepare JS/CSS assets + run: | + npm i + npm run production + + - name: Cleanup Builds + run: | + sudo rm -rf bootstrap/cache/* + sudo rm -rf node_modules + sudo rm -rf .git + sudo rm .env + + - name: Build project + run: | + shopt -s dotglob + tar --exclude='public/storage' --exclude='.htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/react-invoiceninja.tar * + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: | + /home/runner/work/invoiceninja/react-invoiceninja.tar \ No newline at end of file diff --git a/VERSION.txt b/VERSION.txt index cbfa2cc121b7..261553830a70 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.8.24 \ No newline at end of file +5.8.25 \ No newline at end of file diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 79c98f656c7f..ba95b675c5dd 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -891,7 +891,7 @@ class CheckData extends Command $this->logMessage("Fixing country for # {$client->id}"); }); - Client::query()->whereNull("settings->currency_id")->cursor()->each(function ($client){ + Client::query()->whereNull("settings->currency_id")->cursor()->each(function ($client) { $settings = $client->settings; $settings->currency_id = (string)$client->company->settings->currency_id; $client->settings = $settings; @@ -901,7 +901,7 @@ class CheckData extends Command }); - Payment::withTrashed()->where('exchange_rate', 0)->cursor()->each(function ($payment){ + Payment::withTrashed()->where('exchange_rate', 0)->cursor()->each(function ($payment) { $payment->exchange_rate = 1; $payment->saveQuietly(); @@ -917,11 +917,11 @@ class CheckData extends Command $p->currency_id = $p->client->settings->currency_id; $p->saveQuietly(); - + $this->logMessage("Fixing currency for # {$p->id}"); }); - + Company::whereNull("subdomain") ->cursor() ->when(Ninja::isHosted()) @@ -942,7 +942,7 @@ class CheckData extends Command $i->partial_due_date = null; $i->saveQuietly(); - + $this->logMessage("Fixing partial due date for # {$i->id}"); }); diff --git a/app/Console/Commands/EncryptNinja.php b/app/Console/Commands/EncryptNinja.php index 162b574d8564..d3acd2a8b7fb 100644 --- a/app/Console/Commands/EncryptNinja.php +++ b/app/Console/Commands/EncryptNinja.php @@ -52,9 +52,10 @@ class EncryptNinja extends Command */ public function handle() { - if($this->option('encrypt')) + if($this->option('encrypt')) { return $this->encryptFiles(); - + } + if($this->option('decrypt')) { return $this->decryptFiles(); } @@ -67,7 +68,7 @@ class EncryptNinja extends Command $contents = Storage::disk('base')->get($file); $encrypted = encrypt($contents); Storage::disk('base')->put($file.".enc", $encrypted); - Storage::disk('base')->delete($file); + // Storage::disk('base')->delete($file); } } @@ -80,4 +81,4 @@ class EncryptNinja extends Command Storage::disk('base')->put($file, $decrypted); } } -} \ No newline at end of file +} diff --git a/app/Console/Commands/OpenApiYaml.php b/app/Console/Commands/OpenApiYaml.php index 6cee6d48d411..5ea0ecfbbbe8 100644 --- a/app/Console/Commands/OpenApiYaml.php +++ b/app/Console/Commands/OpenApiYaml.php @@ -79,7 +79,7 @@ class OpenApiYaml extends Command Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components.yaml')); Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/examples.yaml')); - + Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/responses.yaml')); $directory = new DirectoryIterator($path . '/components/responses/'); diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 0980ed8507f3..3079a50988c3 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -494,7 +494,7 @@ class CompanySettings extends BaseSettings public $payment_email_all_contacts = false; public $show_pdfhtml_on_mobile = true; - + public static $casts = [ 'show_pdfhtml_on_mobile' => 'bool', 'payment_email_all_contacts' => 'bool', @@ -878,7 +878,7 @@ class CompanySettings extends BaseSettings { $notification = new stdClass(); $notification->email = []; - $notification->email = ['invoice_sent_all']; + $notification->email = ['invoice_sent_all','payment_success_all','payment_manual_all']; return $notification; } diff --git a/app/DataProviders/Domains.php b/app/DataProviders/Domains.php index 2c6920d47311..f4c025b0b151 100644 --- a/app/DataProviders/Domains.php +++ b/app/DataProviders/Domains.php @@ -59391,7 +59391,7 @@ class Domains 'wireconnected.com' ]; - public static function getDomains() + public static function getDomains(): array { return self::$verify_domains; } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index ddb0ad957f1e..444733d814ee 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -105,8 +105,8 @@ class Handler extends ExceptionHandler if (Ninja::isHosted()) { // if($exception instanceof ThrottleRequestsException && class_exists(\Modules\Admin\Events\ThrottledExceptionRaised::class)) { - // $uri = urldecode(request()->getRequestUri()); - // event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip())); + // $uri = urldecode(request()->getRequestUri()); + // event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip())); // } Integration::configureScope(function (Scope $scope): void { diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 91c1e8ebdb72..debee0f7dd38 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -451,17 +451,19 @@ class BaseExport { if (isset($this->input['client_id']) && $this->input['client_id'] != 'all') { - if(!is_int($this->input['client_id'])) + if(!is_int($this->input['client_id'])) { $this->input['client_id'] = $this->decodePrimaryKey($this->input['client_id']); + } $client = Client::withTrashed()->find($this->input['client_id']); - if(!$client) + if(!$client) { return $query; + } $this->client_description = $client->present()->name; return $query->where('client_id', $this->input['client_id']); - + } elseif(isset($this->input['clients']) && count($this->input['clients']) > 0) { $this->client_description = 'Multiple Clients'; @@ -844,64 +846,69 @@ class BaseExport } protected function addClientFilter($query, $clients): Builder - { - if(is_string($clients)) - $clients = explode(',', $clients); + { + if(is_string($clients)) { + $clients = explode(',', $clients); + } $transformed_clients = $this->transformKeys($clients); nlog($clients); nlog($transformed_clients); - if(count($transformed_clients) > 0) + if(count($transformed_clients) > 0) { $query->whereIn('client_id', $transformed_clients); - + } + return $query; } protected function addVendorFilter($query, $vendors): Builder - { - + { + if(is_string($vendors)) { $vendors = explode(',', $vendors); } - + $transformed_vendors = $this->transformKeys($vendors); - if(count($transformed_vendors) > 0) + if(count($transformed_vendors) > 0) { $query->whereIn('vendor_id', $transformed_vendors); - + } + return $query; } protected function addProjectFilter($query, $projects): Builder - { - + { + if(is_string($projects)) { $projects = explode(',', $projects); } $transformed_projects = $this->transformKeys($projects); - - if(count($transformed_projects) > 0) + + if(count($transformed_projects) > 0) { $query->whereIn('project_id', $transformed_projects); - + } + return $query; } protected function addCategoryFilter($query, $expense_categories): Builder - { - + { + if(is_string($expense_categories)) { $expense_categories = explode(',', $expense_categories); } $transformed_expense_categories = $this->transformKeys($expense_categories); - - if(count($transformed_expense_categories) > 0) + + if(count($transformed_expense_categories) > 0) { $query->whereIn('category_id', $transformed_expense_categories); - + } + return $query; } @@ -1299,12 +1306,12 @@ class BaseExport public function queueDocuments(Builder $query) { nlog("queue docs pls"); - if($query->getModel() instanceof Document) + if($query->getModel() instanceof Document) { $documents = $query->pluck('id')->toArray(); - else{ + } else { $documents = $query->cursor() - ->map(function ($entity){ - return $entity->documents()->pluck('id')->toArray(); + ->map(function ($entity) { + return $entity->documents()->pluck('id')->toArray(); })->flatten() ->toArray(); } @@ -1315,11 +1322,13 @@ class BaseExport $user = $this->company->owner(); - if(auth()->user() && auth()->user()->account_id == $this->company->account_id) + if(auth()->user() && auth()->user()->account_id == $this->company->account_id) { $user = auth()->user(); + } - if($this->input['user_id'] ?? false) + if($this->input['user_id'] ?? false) { $user = User::where('id', $this->input['user_id'])->where('account_id', $this->company->account_id)->first(); + } ZipDocuments::dispatch($documents, $this->company, $user); } diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index 1ef2af5fe70c..0973f7a70473 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -106,7 +106,7 @@ class CreditExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index cbe77f0f26ba..5822a1a8bbc0 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -77,7 +77,7 @@ class DocumentExport extends BaseExport $query = Document::query()->where('company_id', $this->company->id); $query = $this->addDateRange($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Export/CSV/ExpenseExport.php b/app/Export/CSV/ExpenseExport.php index 3ab505511330..b5be8b4f8458 100644 --- a/app/Export/CSV/ExpenseExport.php +++ b/app/Export/CSV/ExpenseExport.php @@ -23,7 +23,6 @@ use League\Csv\Writer; class ExpenseExport extends BaseExport { - private $expense_transformer; private Decorator $decorator; @@ -103,7 +102,7 @@ class ExpenseExport extends BaseExport if(isset($this->input['categories'])) { $query = $this->addCategoryFilter($query, $this->input['categories']); } - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } @@ -206,23 +205,21 @@ class ExpenseExport extends BaseExport if($expense->calculate_tax_by_amount) { $total_tax_amount = round($expense->tax_amount1 + $expense->tax_amount2 + $expense->tax_amount3, $precision); - } - else { - - if($expense->uses_inclusive_taxes){ - $total_tax_amount = ($this->calcInclusiveLineTax($expense->tax_rate1 ?? 0, $expense->amount,$precision)) + ($this->calcInclusiveLineTax($expense->tax_rate2 ?? 0, $expense->amount,$precision)) + ($this->calcInclusiveLineTax($expense->tax_rate3 ?? 0, $expense->amount,$precision)); + } else { + + if($expense->uses_inclusive_taxes) { + $total_tax_amount = ($this->calcInclusiveLineTax($expense->tax_rate1 ?? 0, $expense->amount, $precision)) + ($this->calcInclusiveLineTax($expense->tax_rate2 ?? 0, $expense->amount, $precision)) + ($this->calcInclusiveLineTax($expense->tax_rate3 ?? 0, $expense->amount, $precision)); $entity['expense.net_amount'] = round(($expense->amount - round($total_tax_amount, $precision)), $precision); - } - else{ - $total_tax_amount = ($expense->amount * (($expense->tax_rate1 ?? 0)/100)) + ($expense->amount * (($expense->tax_rate2 ?? 0)/100)) + ($expense->amount * (($expense->tax_rate3 ?? 0)/100)); + } else { + $total_tax_amount = ($expense->amount * (($expense->tax_rate1 ?? 0) / 100)) + ($expense->amount * (($expense->tax_rate2 ?? 0) / 100)) + ($expense->amount * (($expense->tax_rate3 ?? 0) / 100)); $entity['expense.net_amount'] = round(($expense->amount + round($total_tax_amount, $precision)), $precision); } } $entity['expense.tax_amount'] = round($total_tax_amount, $precision); - + return $entity; - + } private function calcInclusiveLineTax($tax_rate, $amount, $precision): float diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index e56eb7142e4c..b701b2faa2f1 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -76,7 +76,7 @@ class InvoiceItemExport extends BaseExport $query = $this->addDateRange($query); $query = $this->applyFilters($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Export/CSV/PaymentExport.php b/app/Export/CSV/PaymentExport.php index d4646d143078..93550f9545c3 100644 --- a/app/Export/CSV/PaymentExport.php +++ b/app/Export/CSV/PaymentExport.php @@ -60,7 +60,7 @@ class PaymentExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Export/CSV/ProductExport.php b/app/Export/CSV/ProductExport.php index 5c2dd3401ebc..2c82efb9d43e 100644 --- a/app/Export/CSV/ProductExport.php +++ b/app/Export/CSV/ProductExport.php @@ -77,7 +77,7 @@ class ProductExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Export/CSV/PurchaseOrderExport.php b/app/Export/CSV/PurchaseOrderExport.php index 094fbc87fcbf..f1fa4501510b 100644 --- a/app/Export/CSV/PurchaseOrderExport.php +++ b/app/Export/CSV/PurchaseOrderExport.php @@ -107,7 +107,7 @@ class PurchaseOrderExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Export/CSV/QuoteItemExport.php b/app/Export/CSV/QuoteItemExport.php index b7b86c9a123f..bdb16061d53b 100644 --- a/app/Export/CSV/QuoteItemExport.php +++ b/app/Export/CSV/QuoteItemExport.php @@ -69,7 +69,7 @@ class QuoteItemExport extends BaseExport ->where('is_deleted', 0); $query = $this->addDateRange($query); - + if($this->input['document_email_attachment'] ?? false) { $this->queueDocuments($query); } diff --git a/app/Filters/ClientFilters.php b/app/Filters/ClientFilters.php index a3504cce4e45..b79a381da692 100644 --- a/app/Filters/ClientFilters.php +++ b/app/Filters/ClientFilters.php @@ -165,8 +165,7 @@ class ClientFilters extends QueryFilters $dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc'; - if($sort_col[0] == 'number') - { + if($sort_col[0] == 'number') { return $this->builder->orderByRaw('ABS(number) ' . $dir); } diff --git a/app/Filters/InvoiceFilters.php b/app/Filters/InvoiceFilters.php index aa0c51f0defc..568fb03c9a4b 100644 --- a/app/Filters/InvoiceFilters.php +++ b/app/Filters/InvoiceFilters.php @@ -318,13 +318,12 @@ class InvoiceFilters extends QueryFilters if ($sort_col[0] == 'client_id') { - return $this->builder->orderBy(\App\Models\Client::select ('name') + return $this->builder->orderBy(\App\Models\Client::select('name') ->whereColumn('clients.id', 'invoices.client_id'), $dir); } - if($sort_col[0] == 'number') - { + if($sort_col[0] == 'number') { return $this->builder->orderByRaw('ABS(number) ' . $dir); } diff --git a/app/Filters/ProjectFilters.php b/app/Filters/ProjectFilters.php index cd4015596903..4f4ef99b2ca4 100644 --- a/app/Filters/ProjectFilters.php +++ b/app/Filters/ProjectFilters.php @@ -59,7 +59,7 @@ class ProjectFilters extends QueryFilters public function sort(string $sort = ''): Builder { $sort_col = explode('|', $sort); - + if (!is_array($sort_col) || count($sort_col) != 2) { return $this->builder; } diff --git a/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php b/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php index a18a9b4429cd..ebef634daa45 100644 --- a/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php +++ b/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php @@ -70,8 +70,9 @@ class TransactionTransformer implements BankRevenueInterface { $data = []; - if (!array_key_exists('transactions', $transactionResponse) || !array_key_exists('booked', $transactionResponse["transactions"])) + if (!array_key_exists('transactions', $transactionResponse) || !array_key_exists('booked', $transactionResponse["transactions"])) { throw new \Exception('invalid dataset'); + } foreach ($transactionResponse["transactions"]["booked"] as $transaction) { $data[] = $this->transformTransaction($transaction); @@ -83,11 +84,11 @@ class TransactionTransformer implements BankRevenueInterface { // depending on institution, the result can be different, so we load the first available unique id $transactionId = ''; - if (array_key_exists('transactionId', $transaction)) + if (array_key_exists('transactionId', $transaction)) { $transactionId = $transaction["transactionId"]; - else if (array_key_exists('internalTransactionId', $transaction)) + } elseif (array_key_exists('internalTransactionId', $transaction)) { $transactionId = $transaction["internalTransactionId"]; - else { + } else { nlog(`Invalid Input for nordigen transaction transformer: ` . $transaction); throw new \Exception('invalid dataset: missing transactionId - Please report this error to the developer'); } @@ -96,23 +97,25 @@ class TransactionTransformer implements BankRevenueInterface // description could be in varios places $description = ''; - if (array_key_exists('remittanceInformationStructured', $transaction)) + if (array_key_exists('remittanceInformationStructured', $transaction)) { $description = $transaction["remittanceInformationStructured"]; - else if (array_key_exists('remittanceInformationStructuredArray', $transaction)) + } elseif (array_key_exists('remittanceInformationStructuredArray', $transaction)) { $description = implode('\n', $transaction["remittanceInformationStructuredArray"]); - else if (array_key_exists('remittanceInformationUnstructured', $transaction)) + } elseif (array_key_exists('remittanceInformationUnstructured', $transaction)) { $description = $transaction["remittanceInformationUnstructured"]; - else if (array_key_exists('remittanceInformationUnstructuredArray', $transaction)) + } elseif (array_key_exists('remittanceInformationUnstructuredArray', $transaction)) { $description = implode('\n', $transaction["remittanceInformationUnstructuredArray"]); - else + } else { Log::warning("Missing description for the following transaction: " . json_encode($transaction)); + } // enrich description with currencyExchange informations - if (array_key_exists('currencyExchange', $transaction)) + if (isset($transaction['currencyExchange'])) { foreach ($transaction["currencyExchange"] as $exchangeRate) { - $targetAmount = round($amount * (float) $exchangeRate["exchangeRate"], 2); - $description .= '\nexchangeRate: ' . $amount . " " . $exchangeRate["sourceCurrency"] . " = " . $targetAmount . " " . $exchangeRate["targetCurrency"] . " (" . $exchangeRate["quotationDate"] . ")"; + $targetAmount = round($amount * (float) ($exchangeRate["exchangeRate"] ?? 1) , 2); + $description .= '\nexchangeRate: ' . $amount . " " . ($exchangeRate["sourceCurrency"] ?? '?') . " = " . $targetAmount . " " . ($exchangeRate["targetCurrency"] ?? '?') . " (" . ($exchangeRate["quotationDate"] ?? '?') . ")"; } + } // participant data $participant = array_key_exists('debtorAccount', $transaction) && array_key_exists('iban', $transaction["debtorAccount"]) ? @@ -153,8 +156,9 @@ class TransactionTransformer implements BankRevenueInterface return $item->code == $code; })->first(); - if ($currency) + if ($currency) { return $currency->id; + } return 1; diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 4db4198879d5..474a11b42389 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -62,7 +62,7 @@ class ActivityController extends BaseController $system = ctrans('texts.system'); $data = $activities->cursor()->map(function ($activity) { - + /** @var \App\Models\Activity $activity */ return $activity->activity_string(); diff --git a/app/Http/Controllers/BankTransactionController.php b/app/Http/Controllers/BankTransactionController.php index 7613bb9ce0ed..b47779d1a9fa 100644 --- a/app/Http/Controllers/BankTransactionController.php +++ b/app/Http/Controllers/BankTransactionController.php @@ -112,8 +112,9 @@ class BankTransactionController extends BaseController $this->bank_transaction_repo->convert_matched($bank_transactions); } else { $bank_transactions->each(function ($bank_transaction, $key) use ($action, $user) { - if($user->can('edit', $bank_transaction)) + if($user->can('edit', $bank_transaction)) { $this->bank_transaction_repo->{$action}($bank_transaction); + } }); } diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 9f19c338aaec..5f43373501e3 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -412,19 +412,19 @@ class ClientController extends BaseController } - public function documents(ClientDocumentsRequest $request, Client $client) + public function documents(ClientDocumentsRequest $request, Client $client) { - + $this->entity_type = Document::class; $this->entity_transformer = DocumentTransformer::class; - + $documents = Document::query() ->company() - ->whereHasMorph('documentable', [Invoice::class, Quote::class, Credit::class, Expense::class, Payment::class, Task::class], function ($query) use($client) { + ->whereHasMorph('documentable', [Invoice::class, Quote::class, Credit::class, Expense::class, Payment::class, Task::class], function ($query) use ($client) { $query->where('client_id', $client->id); }) - ->orWhereHasMorph('documentable', [Client::class], function ($query) use ($client){ + ->orWhereHasMorph('documentable', [Client::class], function ($query) use ($client) { $query->where('id', $client->id); }); diff --git a/app/Http/Controllers/ClientGatewayTokenController.php b/app/Http/Controllers/ClientGatewayTokenController.php index 87fb8aa9ab18..aa5792fdbb87 100644 --- a/app/Http/Controllers/ClientGatewayTokenController.php +++ b/app/Http/Controllers/ClientGatewayTokenController.php @@ -353,7 +353,7 @@ class ClientGatewayTokenController extends BaseController */ public function store(StoreClientGatewayTokenRequest $request) { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/ClientPortal/DocumentController.php b/app/Http/Controllers/ClientPortal/DocumentController.php index 92c17bc32071..19a94182f28e 100644 --- a/app/Http/Controllers/ClientPortal/DocumentController.php +++ b/app/Http/Controllers/ClientPortal/DocumentController.php @@ -73,12 +73,13 @@ class DocumentController extends Controller { $hash = Cache::pull($hash); - - if(!$hash) + + if(!$hash) { abort(404); + } MultiDB::setDb($hash['db']); - + /** @var \App\Models\Document $document **/ $document = Document::where('hash', $hash['doc_hash'])->firstOrFail(); diff --git a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php index 6fd5063756aa..5abf591f0602 100644 --- a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php +++ b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php @@ -58,4 +58,3 @@ class EmailPreferencesController extends Controller return back()->with('message', ctrans('texts.updated_settings')); } } - diff --git a/app/Http/Controllers/ClientPortal/InvoiceController.php b/app/Http/Controllers/ClientPortal/InvoiceController.php index e9ef3ba7aead..2fb5ea47d8b2 100644 --- a/app/Http/Controllers/ClientPortal/InvoiceController.php +++ b/app/Http/Controllers/ClientPortal/InvoiceController.php @@ -70,7 +70,7 @@ class InvoiceController extends Controller } $variables = ($invitation && auth()->guard('contact')->user()->client->getSetting('show_accept_invoice_terms')) ? (new HtmlEngine($invitation))->generateLabelsAndValues() : false; - + $data = [ 'invoice' => $invoice, 'invitation' => $invitation ?: $invoice->invitations->first(), @@ -224,8 +224,9 @@ class InvoiceController extends Controller $settings = auth()->guard('contact')->user()->client->getMergedSettings(); $variables = false; - if(($invitation = $invoices->first()->invitations()->first() ?? false) && $settings->show_accept_invoice_terms) + if(($invitation = $invoices->first()->invitations()->first() ?? false) && $settings->show_accept_invoice_terms) { $variables = (new HtmlEngine($invitation))->generateLabelsAndValues(); + } $data = [ 'settings' => $settings, diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 84a238757632..6d1ac7865d39 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -12,24 +12,25 @@ namespace App\Http\Controllers\ClientPortal; -use App\Factory\PaymentFactory; -use App\Http\Controllers\Controller; -use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; -use App\Models\CompanyGateway; -use App\Models\GatewayType; use App\Models\Invoice; use App\Models\Payment; +use App\Utils\HtmlEngine; +use Illuminate\View\View; +use App\Models\GatewayType; use App\Models\PaymentHash; use App\Models\PaymentType; +use Illuminate\Http\Request; +use App\Models\CompanyGateway; +use App\Factory\PaymentFactory; +use App\Utils\Traits\MakesHash; +use App\Utils\Traits\MakesDates; +use App\Http\Controllers\Controller; +use Illuminate\Http\RedirectResponse; +use Illuminate\Contracts\View\Factory; use App\PaymentDrivers\Stripe\BankTransfer; use App\Services\ClientPortal\InstantPayment; use App\Services\Subscription\SubscriptionService; -use App\Utils\Traits\MakesDates; -use App\Utils\Traits\MakesHash; -use Illuminate\Contracts\View\Factory; -use Illuminate\Http\RedirectResponse; -use Illuminate\Http\Request; -use Illuminate\View\View; +use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; /** * Class PaymentController. @@ -125,10 +126,16 @@ class PaymentController extends Controller // 09-07-2022 catch duplicate responses for invoices that already paid here. if ($invoice && $invoice->status_id == Invoice::STATUS_PAID) { + + $invitation = $invoice->invitations->first(); + + $variables = ($invitation && auth()->guard('contact')->user()->client->getSetting('show_accept_invoice_terms')) ? (new HtmlEngine($invitation))->generateLabelsAndValues() : false; + $data = [ 'invoice' => $invoice, 'key' => false, - 'invitation' => $invoice->invitations->first() + 'invitation' => $invitation, + 'variables' => $variables, ]; if ($request->query('mode') === 'fullscreen') { diff --git a/app/Http/Controllers/ClientPortal/PaymentMethodController.php b/app/Http/Controllers/ClientPortal/PaymentMethodController.php index 5d131daad74d..bc5b0203b888 100644 --- a/app/Http/Controllers/ClientPortal/PaymentMethodController.php +++ b/app/Http/Controllers/ClientPortal/PaymentMethodController.php @@ -147,7 +147,7 @@ class PaymentMethodController extends Controller $payment_method->is_deleted = true; $payment_method->delete(); $payment_method->save(); - + } catch (Exception $e) { nlog($e->getMessage()); diff --git a/app/Http/Controllers/ClientPortal/QuoteController.php b/app/Http/Controllers/ClientPortal/QuoteController.php index 43d60122384c..b9251edc4a5b 100644 --- a/app/Http/Controllers/ClientPortal/QuoteController.php +++ b/app/Http/Controllers/ClientPortal/QuoteController.php @@ -215,7 +215,7 @@ class QuoteController extends Controller ->withSuccess('Quote(s) approved successfully.'); } - + $variables = false; if($invitation = $quotes->first()->invitations()->first() ?? false) { diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index 6b5b151b4071..6c58f090a248 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -149,7 +149,7 @@ class CompanyGatewayController extends BaseController */ public function create(CreateCompanyGatewayRequest $request) { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/CompanyLedgerController.php b/app/Http/Controllers/CompanyLedgerController.php index 91eba243468e..1361e62c93db 100644 --- a/app/Http/Controllers/CompanyLedgerController.php +++ b/app/Http/Controllers/CompanyLedgerController.php @@ -64,7 +64,7 @@ class CompanyLedgerController extends BaseController */ public function index(ShowCompanyLedgerRequest $request) { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/ConnectedAccountController.php b/app/Http/Controllers/ConnectedAccountController.php index 7d0aeb46d1fa..9fc1376cff49 100644 --- a/app/Http/Controllers/ConnectedAccountController.php +++ b/app/Http/Controllers/ConnectedAccountController.php @@ -121,7 +121,7 @@ class ConnectedAccountController extends BaseController 'email_verified_at' => now() ]; - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/ExpenseCategoryController.php b/app/Http/Controllers/ExpenseCategoryController.php index 51b8dc49a0f7..f4f5629508d8 100644 --- a/app/Http/Controllers/ExpenseCategoryController.php +++ b/app/Http/Controllers/ExpenseCategoryController.php @@ -128,7 +128,7 @@ class ExpenseCategoryController extends BaseController */ public function create(CreateExpenseCategoryRequest $request) { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/HostedMigrationController.php b/app/Http/Controllers/HostedMigrationController.php index ea62dad70056..e2aca7f082ff 100644 --- a/app/Http/Controllers/HostedMigrationController.php +++ b/app/Http/Controllers/HostedMigrationController.php @@ -21,7 +21,7 @@ class HostedMigrationController extends Controller { public function checkStatus(Request $request) { - + if ($request->header('X-API-HOSTED-SECRET') != config('ninja.ninja_hosted_secret')) { return; } @@ -29,19 +29,20 @@ class HostedMigrationController extends Controller MultiDB::findAndSetDbByCompanyKey($request->company_key); $c = Company::where('company_key', $request->company_key)->first(); - if(!$c || $c->is_disabled) + if(!$c || $c->is_disabled) { return response()->json(['message' => 'ok'], 200); + } // if(\App\Models\Invoice::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))->first()) // return response()->json(['message' => 'New data exists, are you sure? Please log in here https://app.invoicing.co and delete the company if you really need to migrate again.'], 400); - - // if(\App\Models\Client::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))->first()) - // return response()->json(['message' => 'New data exists, are you sure? Please log in here https://app.invoicing.co and delete the company if you really need to migrate again.'], 400); - - // if(\App\Models\Quote::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))) + + // if(\App\Models\Client::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))->first()) // return response()->json(['message' => 'New data exists, are you sure? Please log in here https://app.invoicing.co and delete the company if you really need to migrate again.'], 400); - // if(\App\Models\RecurringInvoice::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))) + // if(\App\Models\Quote::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))) + // return response()->json(['message' => 'New data exists, are you sure? Please log in here https://app.invoicing.co and delete the company if you really need to migrate again.'], 400); + + // if(\App\Models\RecurringInvoice::query()->where('company_id', $c->id)->where('created_at', '>', now()->subMonths(2))) // return response()->json(['message' => 'New data exists, are you sure? Please log in here https://app.invoicing.co and delete the company if you really need to migrate again.'], 400); return response()->json(['message' => 'You have already activated this company on v5!!!!!! This migration may be a BAD idea. Contact us contact@invoiceninja.com to confirm this action.'], 400); diff --git a/app/Http/Controllers/MailgunWebhookController.php b/app/Http/Controllers/MailgunWebhookController.php index 812501d3eb27..341236caa85f 100644 --- a/app/Http/Controllers/MailgunWebhookController.php +++ b/app/Http/Controllers/MailgunWebhookController.php @@ -22,18 +22,22 @@ class MailgunWebhookController extends BaseController { private $invitation; - public function __construct() {} + public function __construct() + { + } public function webhook(Request $request) { $input = $request->all(); - if (\abs(\time() - $request['signature']['timestamp']) > 15) + if (\abs(\time() - $request['signature']['timestamp']) > 15) { return response()->json(['message' => 'Success'], 200); + } - if(\hash_equals(\hash_hmac('sha256', $input['signature']['timestamp'] . $input['signature']['token'], config('services.mailgun.webhook_signing_key')), $input['signature']['signature'])) + if(\hash_equals(\hash_hmac('sha256', $input['signature']['timestamp'] . $input['signature']['token'], config('services.mailgun.webhook_signing_key')), $input['signature']['signature'])) { ProcessMailgunWebhook::dispatch($request->all())->delay(10); + } return response()->json(['message' => 'Success.'], 200); } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 442a76319706..812885d60f61 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -520,7 +520,7 @@ class PaymentController extends BaseController if($action == 'template' && $user->can('view', $payments->first())) { $hash_or_response = request()->boolean('send_email') ? 'email sent' : \Illuminate\Support\Str::uuid(); - + TemplateAction::dispatch( $payments->pluck('hashed_id')->toArray(), $request->template_id, diff --git a/app/Http/Controllers/PreviewPurchaseOrderController.php b/app/Http/Controllers/PreviewPurchaseOrderController.php index ea6a0065f8d4..8ddf82d9360f 100644 --- a/app/Http/Controllers/PreviewPurchaseOrderController.php +++ b/app/Http/Controllers/PreviewPurchaseOrderController.php @@ -316,8 +316,8 @@ class PreviewPurchaseOrderController extends BaseController return; } - /** @var \App\Models\User $user */ - $user = auth()->user(); + /** @var \App\Models\User $user */ + $user = auth()->user(); //if phantom js...... inject here.. if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') { diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index f3f82132a473..e42c090c34bb 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -181,7 +181,7 @@ class ProductController extends BaseController */ public function store(StoreProductRequest $request) { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index b2af3a1b560e..78a5bf625247 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -399,7 +399,7 @@ class QuoteController extends BaseController $quote->service() ->triggeredActions($request); - + event(new QuoteWasUpdated($quote, $quote->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); return $this->itemResponse($quote); diff --git a/app/Http/Controllers/StripeConnectController.php b/app/Http/Controllers/StripeConnectController.php index 84080a9bc2ab..a8de13091bf4 100644 --- a/app/Http/Controllers/StripeConnectController.php +++ b/app/Http/Controllers/StripeConnectController.php @@ -86,7 +86,7 @@ class StripeConnectController extends BaseController ]); nlog($response); - + } catch (\Exception $e) { return view('auth.connect.access_denied'); } diff --git a/app/Http/Controllers/TwoFactorController.php b/app/Http/Controllers/TwoFactorController.php index a108d6c67012..083aea6ac011 100644 --- a/app/Http/Controllers/TwoFactorController.php +++ b/app/Http/Controllers/TwoFactorController.php @@ -84,7 +84,7 @@ class TwoFactorController extends BaseController public function disableTwoFactor() { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Controllers/VendorController.php b/app/Http/Controllers/VendorController.php index 7802a8838f01..0f0328ec5a1e 100644 --- a/app/Http/Controllers/VendorController.php +++ b/app/Http/Controllers/VendorController.php @@ -499,7 +499,7 @@ class VendorController extends BaseController $ids = request()->input('ids'); $vendors = Vendor::withTrashed()->find($this->transformKeys($ids)); - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Middleware/TokenAuth.php b/app/Http/Middleware/TokenAuth.php index ab62859f2f9b..c6fc35662c94 100644 --- a/app/Http/Middleware/TokenAuth.php +++ b/app/Http/Middleware/TokenAuth.php @@ -67,7 +67,7 @@ class TokenAuth $truth->setUser($company_token->user); $truth->setCompany($company_token->company); $truth->setCompanyToken($company_token); - + $truth->setPremiumHosted($company_token->account->isPremium()); /* | This method binds the db to the jobs created using this | session diff --git a/app/Http/Requests/ClientPortal/PaymentMethod/CreatePaymentMethodRequest.php b/app/Http/Requests/ClientPortal/PaymentMethod/CreatePaymentMethodRequest.php index 5ba9c2fa104a..76ffa929dfd7 100644 --- a/app/Http/Requests/ClientPortal/PaymentMethod/CreatePaymentMethodRequest.php +++ b/app/Http/Requests/ClientPortal/PaymentMethod/CreatePaymentMethodRequest.php @@ -27,7 +27,7 @@ class CreatePaymentMethodRequest extends FormRequest ->filter(function ($method) use (&$available_methods) { $available_methods[] = $method['gateway_type_id']; }); - + if (in_array($this->query('method'), $available_methods)) { return true; } diff --git a/app/Http/Requests/ExpenseCategory/StoreExpenseCategoryRequest.php b/app/Http/Requests/ExpenseCategory/StoreExpenseCategoryRequest.php index 45c614b8fd7f..2fbf74bb2cfd 100644 --- a/app/Http/Requests/ExpenseCategory/StoreExpenseCategoryRequest.php +++ b/app/Http/Requests/ExpenseCategory/StoreExpenseCategoryRequest.php @@ -32,7 +32,7 @@ class StoreExpenseCategoryRequest extends Request public function rules() { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Requests/ExpenseCategory/UpdateExpenseCategoryRequest.php b/app/Http/Requests/ExpenseCategory/UpdateExpenseCategoryRequest.php index 1ff371ff6920..f5b57df5a407 100644 --- a/app/Http/Requests/ExpenseCategory/UpdateExpenseCategoryRequest.php +++ b/app/Http/Requests/ExpenseCategory/UpdateExpenseCategoryRequest.php @@ -26,7 +26,7 @@ class UpdateExpenseCategoryRequest extends Request */ public function authorize(): bool { - + /** @var \App\Models\User $user */ $user = auth()->user(); @@ -35,7 +35,7 @@ class UpdateExpenseCategoryRequest extends Request public function rules() { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/Requests/Request.php b/app/Http/Requests/Request.php index 1a058e1eb50c..e70c7f6b3a55 100644 --- a/app/Http/Requests/Request.php +++ b/app/Http/Requests/Request.php @@ -198,18 +198,22 @@ class Request extends FormRequest } } - if(isset($input['public_notes'])) - $input['public_notes'] = str_replace("where('company_user.account_id', $user->account_id) ->join('users', 'users.id', '=', 'company_user.user_id') @@ -69,7 +69,7 @@ class CanAddUserRule implements Rule */ public function message() { - + /** @var \App\Models\User $user */ $user = auth()->user(); diff --git a/app/Http/ValidationRules/PaymentAppliedValidAmount.php b/app/Http/ValidationRules/PaymentAppliedValidAmount.php index 9c0ea741e79c..c6257fde8d1f 100644 --- a/app/Http/ValidationRules/PaymentAppliedValidAmount.php +++ b/app/Http/ValidationRules/PaymentAppliedValidAmount.php @@ -88,10 +88,9 @@ class PaymentAppliedValidAmount implements Rule nlog($inv->amount); nlog($invoice['amount']); - if($inv->status_id == Invoice::STATUS_DRAFT && $inv->amount >= $invoice['amount']){ + if($inv->status_id == Invoice::STATUS_DRAFT && $inv->amount >= $invoice['amount']) { - } - elseif ($inv->balance < $invoice['amount']) { + } elseif ($inv->balance < $invoice['amount']) { $this->message = 'Amount cannot be greater than invoice balance'; return false; diff --git a/app/Import/Providers/BaseImport.php b/app/Import/Providers/BaseImport.php index 56bda23e86af..297973e364ff 100644 --- a/app/Import/Providers/BaseImport.php +++ b/app/Import/Providers/BaseImport.php @@ -152,7 +152,7 @@ class BaseImport } } - + return $bestDelimiter ?? ','; } diff --git a/app/Import/Providers/Wave.php b/app/Import/Providers/Wave.php index 5d822c2092d2..03c0e00f1003 100644 --- a/app/Import/Providers/Wave.php +++ b/app/Import/Providers/Wave.php @@ -117,10 +117,8 @@ class Wave extends BaseImport implements ImportInterface $this->transformer = new InvoiceTransformer($this->company); - foreach($data as $key => $invoice) - { - if(!isset($invoice['Invoice Number']) || empty($invoice['Invoice Number'])) - { + foreach($data as $key => $invoice) { + if(!isset($invoice['Invoice Number']) || empty($invoice['Invoice Number'])) { unset($data[$key]); } } diff --git a/app/Jobs/Company/CompanyExport.php b/app/Jobs/Company/CompanyExport.php index 00b69d235bd7..7736a3fdca6b 100644 --- a/app/Jobs/Company/CompanyExport.php +++ b/app/Jobs/Company/CompanyExport.php @@ -72,13 +72,13 @@ class CompanyExport implements ShouldQueue $this->file_name = date('Y-m-d') . '_' . str_replace([" ", "/"], ["_",""], $this->company->present()->name() . '_' . $this->company->company_key . '.json'); -$this->writer = new File($this->file_name); + $this->writer = new File($this->file_name); set_time_limit(0); -$this->writer->value('app_version', config('ninja.app_version')); -$this->writer->value('storage_url', Storage::url('')); - + $this->writer->value('app_version', config('ninja.app_version')); + $this->writer->value('storage_url', Storage::url('')); + $this->export_data['activities'] = $this->company->all_activities->map(function ($activity) { $activity = $this->transformArrayOfKeys($activity, [ 'user_id', @@ -104,9 +104,9 @@ $this->writer->value('storage_url', Storage::url('')); })->makeHidden(['id'])->all(); -$x = $this->writer->collection('activities'); -$x->addItems($this->export_data['activities']); -$this->export_data = null; + $x = $this->writer->collection('activities'); + $x->addItems($this->export_data['activities']); + $this->export_data = null; $this->export_data['users'] = $this->company->users()->withTrashed()->cursor()->map(function ($user) { @@ -116,9 +116,9 @@ $this->export_data = null; -$x = $this->writer->collection('users'); -$x->addItems($this->export_data['users']); -$this->export_data = null; + $x = $this->writer->collection('users'); + $x->addItems($this->export_data['users']); + $this->export_data = null; $this->export_data['client_contacts'] = $this->company->client_contacts->map(function ($client_contact) { @@ -140,9 +140,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('client_contacts'); -$x->addItems($this->export_data['client_contacts']); -$this->export_data = null; + $x = $this->writer->collection('client_contacts'); + $x->addItems($this->export_data['client_contacts']); + $this->export_data = null; $this->export_data['client_gateway_tokens'] = $this->company->client_gateway_tokens->map(function ($client_gateway_token) { $client_gateway_token = $this->transformArrayOfKeys($client_gateway_token, ['company_id', 'client_id', 'company_gateway_id']); @@ -151,9 +151,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('client_gateway_tokens'); -$x->addItems($this->export_data['client_gateway_tokens']); -$this->export_data = null; + $x = $this->writer->collection('client_gateway_tokens'); + $x->addItems($this->export_data['client_gateway_tokens']); + $this->export_data = null; $this->export_data['clients'] = $this->company->clients()->orderBy('number', 'DESC')->cursor()->map(function ($client) { $client = $this->transformArrayOfKeys($client, ['company_id', 'user_id', 'assigned_user_id', 'group_settings_id']); @@ -162,18 +162,18 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('clients'); -$x->addItems($this->export_data['clients']); -$this->export_data = null; + $x = $this->writer->collection('clients'); + $x->addItems($this->export_data['clients']); + $this->export_data = null; // $this->export_data['company'] = $this->company->toArray(); // $this->export_data['company']['company_key'] = $this->createHash(); -$this->writer->value('company', $this->company->toJson(), encode: false); - -// $x = $this->writer->collection('company'); -// $x->addItems($this->export_data['company']); -// $this->export_data = null; + $this->writer->value('company', $this->company->toJson(), encode: false); + + // $x = $this->writer->collection('company'); + // $x->addItems($this->export_data['company']); + // $this->export_data = null; $this->export_data['company_gateways'] = $this->company->company_gateways()->withTrashed()->cursor()->map(function ($company_gateway) { @@ -184,11 +184,11 @@ $this->writer->value('company', $this->company->toJson(), encode: false); })->all(); -$x = $this->writer->collection('company_gateways'); -$x->addItems($this->export_data['company_gateways']); -$this->export_data = null; + $x = $this->writer->collection('company_gateways'); + $x->addItems($this->export_data['company_gateways']); + $this->export_data = null; + - $this->export_data['company_tokens'] = $this->company->tokens->map(function ($token) { @@ -198,9 +198,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('company_tokens'); -$x->addItems($this->export_data['company_tokens']); -$this->export_data = null; + $x = $this->writer->collection('company_tokens'); + $x->addItems($this->export_data['company_tokens']); + $this->export_data = null; $this->export_data['company_ledger'] = $this->company->ledger->map(function ($ledger) { @@ -210,20 +210,20 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('company_ledger'); -$x->addItems($this->export_data['company_ledger']); -$this->export_data = null; + $x = $this->writer->collection('company_ledger'); + $x->addItems($this->export_data['company_ledger']); + $this->export_data = null; + - $this->export_data['company_users'] = $this->company->company_users()->without(['user','account'])->cursor()->map(function ($company_user) { $company_user = $this->transformArrayOfKeys($company_user, ['company_id', 'account_id', 'user_id']); return $company_user; })->all(); -$x = $this->writer->collection('company_users'); -$x->addItems($this->export_data['company_users']); -$this->export_data = null; + $x = $this->writer->collection('company_users'); + $x->addItems($this->export_data['company_users']); + $this->export_data = null; $this->export_data['credits'] = $this->company->credits()->orderBy('number', 'DESC')->cursor()->map(function ($credit) { @@ -233,9 +233,9 @@ $this->export_data = null; return $credit->makeVisible(['id']); })->all(); -$x = $this->writer->collection('credits'); -$x->addItems($this->export_data['credits']); -$this->export_data = null; + $x = $this->writer->collection('credits'); + $x->addItems($this->export_data['credits']); + $this->export_data = null; $this->export_data['credit_invitations'] = CreditInvitation::query()->where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($credit) { @@ -244,18 +244,18 @@ $this->export_data = null; return $credit->makeVisible(['id']); })->all(); - -$x = $this->writer->collection('credit_invitations'); -$x->addItems($this->export_data['credit_invitations']); -$this->export_data = null; + + $x = $this->writer->collection('credit_invitations'); + $x->addItems($this->export_data['credit_invitations']); + $this->export_data = null; $this->export_data['designs'] = $this->company->user_designs->makeHidden(['id'])->all(); - -$x = $this->writer->collection('designs'); -$x->addItems($this->export_data['designs']); -$this->export_data = null; + + $x = $this->writer->collection('designs'); + $x->addItems($this->export_data['designs']); + $this->export_data = null; $this->export_data['documents'] = $this->company->all_documents->map(function ($document) { @@ -265,9 +265,9 @@ $this->export_data = null; return $document->makeVisible(['id']); })->all(); -$x = $this->writer->collection('documents'); -$x->addItems($this->export_data['documents']); -$this->export_data = null; + $x = $this->writer->collection('documents'); + $x->addItems($this->export_data['documents']); + $this->export_data = null; $this->export_data['expense_categories'] = $this->company->expense_categories()->cursor()->map(function ($expense_category) { $expense_category = $this->transformArrayOfKeys($expense_category, ['user_id', 'company_id']); @@ -275,9 +275,9 @@ $this->export_data = null; return $expense_category->makeVisible(['id']); })->all(); -$x = $this->writer->collection('expense_categories'); -$x->addItems($this->export_data['expense_categories']); -$this->export_data = null; + $x = $this->writer->collection('expense_categories'); + $x->addItems($this->export_data['expense_categories']); + $this->export_data = null; $this->export_data['expenses'] = $this->company->expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense) { @@ -288,9 +288,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('expenses'); -$x->addItems($this->export_data['expenses']); -$this->export_data = null; + $x = $this->writer->collection('expenses'); + $x->addItems($this->export_data['expenses']); + $this->export_data = null; $this->export_data['group_settings'] = $this->company->group_settings->map(function ($gs) { @@ -299,10 +299,10 @@ $this->export_data = null; return $gs->makeVisible(['id']); })->all(); - -$x = $this->writer->collection('group_settings'); -$x->addItems($this->export_data['group_settings']); -$this->export_data = null; + + $x = $this->writer->collection('group_settings'); + $x->addItems($this->export_data['group_settings']); + $this->export_data = null; $this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice) { @@ -318,9 +318,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('invoices'); -$x->addItems($this->export_data['invoices']); -$this->export_data = null; + $x = $this->writer->collection('invoices'); + $x->addItems($this->export_data['invoices']); + $this->export_data = null; $this->export_data['invoice_invitations'] = InvoiceInvitation::query()->where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($invoice) { $invoice = $this->transformArrayOfKeys($invoice, ['company_id', 'user_id', 'client_contact_id', 'invoice_id']); @@ -329,9 +329,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('invoice_invitations'); -$x->addItems($this->export_data['invoice_invitations']); -$this->export_data = null; + $x = $this->writer->collection('invoice_invitations'); + $x->addItems($this->export_data['invoice_invitations']); + $this->export_data = null; $this->export_data['payment_terms'] = $this->company->user_payment_terms->map(function ($term) { @@ -340,10 +340,10 @@ $this->export_data = null; return $term; })->makeHidden(['id'])->all(); - -$x = $this->writer->collection('payment_terms'); -$x->addItems($this->export_data['payment_terms']); -$this->export_data = null; + + $x = $this->writer->collection('payment_terms'); + $x->addItems($this->export_data['payment_terms']); + $this->export_data = null; $this->export_data['payments'] = $this->company->payments()->orderBy('number', 'DESC')->cursor()->map(function ($payment) { @@ -357,9 +357,9 @@ $this->export_data = null; -$x = $this->writer->collection('payments'); -$x->addItems($this->export_data['payments']); -$this->export_data = null; + $x = $this->writer->collection('payments'); + $x->addItems($this->export_data['payments']); + $this->export_data = null; $this->export_data['products'] = $this->company->products->map(function ($product) { @@ -370,9 +370,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('products'); -$x->addItems($this->export_data['products']); -$this->export_data = null; + $x = $this->writer->collection('products'); + $x->addItems($this->export_data['products']); + $this->export_data = null; $this->export_data['projects'] = $this->company->projects()->orderBy('number', 'DESC')->cursor()->map(function ($project) { @@ -383,9 +383,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('projects'); -$x->addItems($this->export_data['projects']); -$this->export_data = null; + $x = $this->writer->collection('projects'); + $x->addItems($this->export_data['projects']); + $this->export_data = null; $this->export_data['quotes'] = $this->company->quotes()->orderBy('number', 'DESC')->cursor()->map(function ($quote) { @@ -395,10 +395,10 @@ $this->export_data = null; return $quote->makeVisible(['id']); })->all(); - -$x = $this->writer->collection('quotes'); -$x->addItems($this->export_data['quotes']); -$this->export_data = null; + + $x = $this->writer->collection('quotes'); + $x->addItems($this->export_data['quotes']); + $this->export_data = null; $this->export_data['quote_invitations'] = QuoteInvitation::query()->where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($quote) { @@ -408,9 +408,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('quote_invitations'); -$x->addItems($this->export_data['quote_invitations']); -$this->export_data = null; + $x = $this->writer->collection('quote_invitations'); + $x->addItems($this->export_data['quote_invitations']); + $this->export_data = null; $this->export_data['recurring_expenses'] = $this->company->recurring_expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense) { @@ -422,9 +422,9 @@ $this->export_data = null; -$x = $this->writer->collection('recurring_expenses'); -$x->addItems($this->export_data['recurring_expenses']); -$this->export_data = null; + $x = $this->writer->collection('recurring_expenses'); + $x->addItems($this->export_data['recurring_expenses']); + $this->export_data = null; $this->export_data['recurring_invoices'] = $this->company->recurring_invoices()->orderBy('number', 'DESC')->cursor()->map(function ($ri) { @@ -434,10 +434,10 @@ $this->export_data = null; return $ri->makeVisible(['id']); })->all(); - -$x = $this->writer->collection('recurring_invoices'); -$x->addItems($this->export_data['recurring_invoices']); -$this->export_data = null; + + $x = $this->writer->collection('recurring_invoices'); + $x->addItems($this->export_data['recurring_invoices']); + $this->export_data = null; $this->export_data['recurring_invoice_invitations'] = RecurringInvoiceInvitation::query()->where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($ri) { @@ -447,9 +447,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('recurring_invoice_invitations'); -$x->addItems($this->export_data['recurring_invoice_invitations']); -$this->export_data = null; + $x = $this->writer->collection('recurring_invoice_invitations'); + $x->addItems($this->export_data['recurring_invoice_invitations']); + $this->export_data = null; @@ -467,9 +467,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('subscriptions'); -$x->addItems($this->export_data['subscriptions']); -$this->export_data = null; + $x = $this->writer->collection('subscriptions'); + $x->addItems($this->export_data['subscriptions']); + $this->export_data = null; $this->export_data['system_logs'] = $this->company->system_logs->map(function ($log) { $log->client_id = $this->encodePrimaryKey($log->client_id); @@ -479,9 +479,9 @@ $this->export_data = null; })->makeHidden(['id'])->all(); -$x = $this->writer->collection('system_logs'); -$x->addItems($this->export_data['system_logs']); -$this->export_data = null; + $x = $this->writer->collection('system_logs'); + $x->addItems($this->export_data['system_logs']); + $this->export_data = null; $this->export_data['tasks'] = $this->company->tasks()->orderBy('number', 'DESC')->cursor()->map(function ($task) { @@ -493,9 +493,9 @@ $this->export_data = null; -$x = $this->writer->collection('tasks'); -$x->addItems($this->export_data['tasks']); -$this->export_data = null; + $x = $this->writer->collection('tasks'); + $x->addItems($this->export_data['tasks']); + $this->export_data = null; $this->export_data['task_statuses'] = $this->company->task_statuses->map(function ($status) { @@ -508,9 +508,9 @@ $this->export_data = null; -$x = $this->writer->collection('task_statuses'); -$x->addItems($this->export_data['task_statuses']); -$this->export_data = null; + $x = $this->writer->collection('task_statuses'); + $x->addItems($this->export_data['task_statuses']); + $this->export_data = null; $this->export_data['tax_rates'] = $this->company->tax_rates->map(function ($rate) { @@ -522,9 +522,9 @@ $this->export_data = null; -$x = $this->writer->collection('tax_rates'); -$x->addItems($this->export_data['tax_rates']); -$this->export_data = null; + $x = $this->writer->collection('tax_rates'); + $x->addItems($this->export_data['tax_rates']); + $this->export_data = null; $this->export_data['vendors'] = $this->company->vendors()->orderBy('number', 'DESC')->cursor()->map(function ($vendor) { @@ -532,10 +532,10 @@ $this->export_data = null; })->all(); - -$x = $this->writer->collection('vendors'); -$x->addItems($this->export_data['vendors']); -$this->export_data = null; + + $x = $this->writer->collection('vendors'); + $x->addItems($this->export_data['vendors']); + $this->export_data = null; $this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor) { @@ -547,9 +547,9 @@ $this->export_data = null; -$x = $this->writer->collection('vendor_contacts'); -$x->addItems($this->export_data['vendor_contacts']); -$this->export_data = null; + $x = $this->writer->collection('vendor_contacts'); + $x->addItems($this->export_data['vendor_contacts']); + $this->export_data = null; $this->export_data['webhooks'] = $this->company->webhooks->map(function ($hook) { @@ -560,9 +560,9 @@ $this->export_data = null; })->makeHidden(['id'])->all(); -$x = $this->writer->collection('webhooks'); -$x->addItems($this->export_data['webhooks']); -$this->export_data = null; + $x = $this->writer->collection('webhooks'); + $x->addItems($this->export_data['webhooks']); + $this->export_data = null; $this->export_data['purchase_orders'] = $this->company->purchase_orders()->orderBy('number', 'DESC')->cursor()->map(function ($purchase_order) { @@ -578,9 +578,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('purchase_orders'); -$x->addItems($this->export_data['purchase_orders']); -$this->export_data = null; + $x = $this->writer->collection('purchase_orders'); + $x->addItems($this->export_data['purchase_orders']); + $this->export_data = null; @@ -591,9 +591,9 @@ $this->export_data = null; })->all(); -$x = $this->writer->collection('purchase_order_invitations'); -$x->addItems($this->export_data['purchase_order_invitations']); -$this->export_data = null; + $x = $this->writer->collection('purchase_order_invitations'); + $x->addItems($this->export_data['purchase_order_invitations']); + $this->export_data = null; $this->export_data['bank_integrations'] = $this->company->bank_integrations()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($bank_integration) { $bank_integration = $this->transformArrayOfKeys($bank_integration, ['account_id','company_id', 'user_id']); @@ -601,9 +601,9 @@ $this->export_data = null; return $bank_integration->makeVisible(['id','user_id','company_id','account_id','hashed_id']); })->all(); -$x = $this->writer->collection('bank_integrations'); -$x->addItems($this->export_data['bank_integrations']); -$this->export_data = null; + $x = $this->writer->collection('bank_integrations'); + $x->addItems($this->export_data['bank_integrations']); + $this->export_data = null; $this->export_data['bank_transactions'] = $this->company->bank_transactions()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($bank_transaction) { $bank_transaction = $this->transformArrayOfKeys($bank_transaction, ['company_id', 'user_id','bank_integration_id','expense_id','ninja_category_id','vendor_id']); @@ -611,9 +611,9 @@ $this->export_data = null; return $bank_transaction->makeVisible(['id','user_id','company_id']); })->all(); -$x = $this->writer->collection('bank_transactions'); -$x->addItems($this->export_data['bank_transactions']); -$this->export_data = null; + $x = $this->writer->collection('bank_transactions'); + $x->addItems($this->export_data['bank_transactions']); + $this->export_data = null; $this->export_data['schedulers'] = $this->company->schedulers()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($scheduler) { $scheduler = $this->transformArrayOfKeys($scheduler, ['company_id', 'user_id']); @@ -621,14 +621,14 @@ $this->export_data = null; return $scheduler->makeVisible(['id','user_id','company_id']); })->all(); -$x = $this->writer->collection('schedulers'); -$x->addItems($this->export_data['schedulers']); -$this->export_data = null; + $x = $this->writer->collection('schedulers'); + $x->addItems($this->export_data['schedulers']); + $this->export_data = null; //write to tmp and email to owner(); -$this->writer->end(); + $this->writer->end(); $this->zipAndSend(); @@ -680,20 +680,20 @@ $this->writer->end(); $zip->close(); - Storage::disk(config('filesystems.default'))->put('backups/'.str_replace(".json", ".zip",$this->file_name), file_get_contents($zip_path)); + Storage::disk(config('filesystems.default'))->put('backups/'.str_replace(".json", ".zip", $this->file_name), file_get_contents($zip_path)); if(file_exists($zip_path)) { unlink($zip_path); } - if(file_exists($this->file_name)){ + if(file_exists($this->file_name)) { unlink($this->file_name); } if(Ninja::isSelfHost()) { - $storage_path = 'backups/'.str_replace(".json", ".zip",$this->file_name); + $storage_path = 'backups/'.str_replace(".json", ".zip", $this->file_name); } else { - $storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.str_replace(".json", ".zip",$this->file_name)); + $storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.str_replace(".json", ".zip", $this->file_name)); } $url = Cache::get($this->hash); diff --git a/app/Jobs/Company/CompanyImport.php b/app/Jobs/Company/CompanyImport.php index 0fe90c3e229d..ca0c8d7adef6 100644 --- a/app/Jobs/Company/CompanyImport.php +++ b/app/Jobs/Company/CompanyImport.php @@ -338,7 +338,7 @@ class CompanyImport implements ShouldQueue private function unzipFile() { $path = TempFile::filePath(Storage::disk(config('filesystems.default'))->get($this->file_location), basename($this->file_location)); - + $zip = new ZipArchive(); $res = $zip->open($path); $file_path = sys_get_temp_dir().'/'.sha1(microtime()); @@ -357,7 +357,7 @@ class CompanyImport implements ShouldQueue } $file_path = "{$file_path}/backup.json"; - + nlog($file_path); if (! file_exists($file_path)) { diff --git a/app/Jobs/Cron/CompanyRecurringCron.php b/app/Jobs/Cron/CompanyRecurringCron.php deleted file mode 100644 index e50d72643f46..000000000000 --- a/app/Jobs/Cron/CompanyRecurringCron.php +++ /dev/null @@ -1,65 +0,0 @@ -whereHas('recurring_invoices', function ($query) { - $query->where('next_send_date', '<=', now()->toDateTimeString()) - ->whereNotNull('next_send_date') - ->whereNull('deleted_at') - ->where('is_deleted', false) - ->where('status_id', RecurringInvoice::STATUS_ACTIVE) - ->where('remaining_cycles', '!=', '0') - ->whereHas('client', function ($query) { - $query->where('is_deleted', 0) - ->where('deleted_at', null); - }); - }) - ->cursor()->each(function ($company) { - SendCompanyRecurring::dispatch($company->id, $company->db); - }); - } - } -} diff --git a/app/Jobs/Cron/RecurringExpensesCron.php b/app/Jobs/Cron/RecurringExpensesCron.php index fa04f0cbc383..b9a564c84db4 100644 --- a/app/Jobs/Cron/RecurringExpensesCron.php +++ b/app/Jobs/Cron/RecurringExpensesCron.php @@ -51,7 +51,7 @@ class RecurringExpensesCron Auth::logout(); if (! config('ninja.db.multi_db_enabled')) { - $recurring_expenses = RecurringExpense::where('next_send_date', '<=', now()->toDateTimeString()) + $recurring_expenses = RecurringExpense::query()->where('next_send_date', '<=', now()->toDateTimeString()) ->whereNotNull('next_send_date') ->whereNull('deleted_at') ->where('status_id', RecurringInvoice::STATUS_ACTIVE) @@ -76,7 +76,7 @@ class RecurringExpensesCron foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); - $recurring_expenses = RecurringExpense::where('next_send_date', '<=', now()->toDateTimeString()) + $recurring_expenses = RecurringExpense::query()->where('next_send_date', '<=', now()->toDateTimeString()) ->whereNotNull('next_send_date') ->whereNull('deleted_at') ->where('status_id', RecurringInvoice::STATUS_ACTIVE) diff --git a/app/Jobs/Cron/RecurringInvoicesCron.php b/app/Jobs/Cron/RecurringInvoicesCron.php index 679af2ae5724..0fd4e636a621 100644 --- a/app/Jobs/Cron/RecurringInvoicesCron.php +++ b/app/Jobs/Cron/RecurringInvoicesCron.php @@ -48,7 +48,7 @@ class RecurringInvoicesCron Auth::logout(); if (! config('ninja.db.multi_db_enabled')) { - $recurring_invoices = RecurringInvoice::where('status_id', RecurringInvoice::STATUS_ACTIVE) + $recurring_invoices = RecurringInvoice::query()->where('status_id', RecurringInvoice::STATUS_ACTIVE) ->where('is_deleted', false) ->where('remaining_cycles', '!=', '0') ->whereNotNull('next_send_date') @@ -87,7 +87,7 @@ class RecurringInvoicesCron foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); - $recurring_invoices = RecurringInvoice::where('status_id', RecurringInvoice::STATUS_ACTIVE) + $recurring_invoices = RecurringInvoice::query()->where('status_id', RecurringInvoice::STATUS_ACTIVE) ->where('is_deleted', false) ->where('remaining_cycles', '!=', '0') ->whereNull('deleted_at') diff --git a/app/Jobs/Cron/SendCompanyRecurring.php b/app/Jobs/Cron/SendCompanyRecurring.php deleted file mode 100644 index 28d66012b070..000000000000 --- a/app/Jobs/Cron/SendCompanyRecurring.php +++ /dev/null @@ -1,74 +0,0 @@ -db); - - $recurring_invoices = Company::where('id', $this->company_id) - ->where('is_disabled', 0) - ->whereHas('recurring_invoices', function ($query) { - $query->where('next_send_date', '<=', now()->toDateTimeString()) - ->whereNotNull('next_send_date') - ->whereNull('deleted_at') - ->where('is_deleted', false) - ->where('status_id', RecurringInvoice::STATUS_ACTIVE) - ->where('remaining_cycles', '!=', '0') - ->whereHas('client', function ($query) { - $query->where('is_deleted', 0) - ->where('deleted_at', null); - }); - }) - ->cursor()->each(function ($recurring_invoice) { - nlog("Trying to send {$recurring_invoice->number}"); - - if ($recurring_invoice->company->stop_on_unpaid_recurring) { - if ($recurring_invoice->invoices()->whereIn('status_id', [2, 3])->where('is_deleted', 0)->where('balance', '>', 0)->exists()) { - return; - } - } - - try { - (new SendRecurring($recurring_invoice, $recurring_invoice->company->db))->handle(); - } catch (\Exception $e) { - nlog("Unable to sending recurring invoice {$recurring_invoice->id} ".$e->getMessage()); - } - }); - } -} diff --git a/app/Jobs/Cron/SubscriptionCron.php b/app/Jobs/Cron/SubscriptionCron.php index 2eedf262c576..42b61a2ddcd8 100644 --- a/app/Jobs/Cron/SubscriptionCron.php +++ b/app/Jobs/Cron/SubscriptionCron.php @@ -52,7 +52,7 @@ class SubscriptionCron ->whereNotNull('subscription_id') ->cursor(); - $invoices->each(function ($invoice) { + $invoices->each(function (Invoice $invoice) { $subscription = $invoice->subscription; $body = [ @@ -80,7 +80,7 @@ class SubscriptionCron ->whereNotNull('subscription_id') ->cursor(); - $invoices->each(function ($invoice) { + $invoices->each(function (Invoice $invoice) { $subscription = $invoice->subscription; $body = [ diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index a9c0a65d2620..0330156f7419 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -99,10 +99,9 @@ class NinjaMailerJob implements ShouldQueue } $this->nmo->mailable->replyTo($this->nmo->settings->reply_to_email, $reply_to_name); - }elseif(isset($this->nmo->invitation->user)){ + } elseif(isset($this->nmo->invitation->user)) { $this->nmo->mailable->replyTo($this->nmo->invitation->user->email, $this->nmo->invitation->user->present()->name()); - } - else { + } else { $this->nmo->mailable->replyTo($this->company->owner()->email, $this->company->owner()->present()->name()); } @@ -135,7 +134,7 @@ class NinjaMailerJob implements ShouldQueue } $mailable = $this->nmo->mailable; - + /** May need to re-build it here */ if(Ninja::isHosted() && method_exists($mailable, 'build')) { $mailable->build(); @@ -269,14 +268,14 @@ class NinjaMailerJob implements ShouldQueue if(Ninja::isHosted() && $this->company->account->isPaid() && $this->nmo->settings->email_sending_method == 'default') { //check if outlook. - - try{ + + try { $email = $this->nmo->to_user->email; $domain = explode("@", $email)[1] ?? ""; $dns = dns_get_record($domain, DNS_MX); $server = $dns[0]["target"]; - if(stripos($server, "outlook.com") !== false){ - + if(stripos($server, "outlook.com") !== false) { + $this->mailer = 'postmark'; $this->client_postmark_secret = config('services.postmark-outlook.token'); @@ -286,8 +285,7 @@ class NinjaMailerJob implements ShouldQueue return $this; } - } - catch(\Exception $e){ + } catch(\Exception $e) { nlog($e->getMessage()); } } @@ -409,7 +407,7 @@ class NinjaMailerJob implements ShouldQueue private function setHostedMailgunMailer() { - + if (property_exists($this->nmo->settings, 'email_from_name') && strlen($this->nmo->settings->email_from_name) > 1) { $email_from_name = $this->nmo->settings->email_from_name; } else { diff --git a/app/Jobs/Mail/NinjaMailerObject.php b/app/Jobs/Mail/NinjaMailerObject.php index f2cf0f646111..6a1ba07dd81e 100644 --- a/app/Jobs/Mail/NinjaMailerObject.php +++ b/app/Jobs/Mail/NinjaMailerObject.php @@ -16,7 +16,6 @@ namespace App\Jobs\Mail; */ class NinjaMailerObject { - /* @var Illuminate\Mail\Mailable */ public $mailable; diff --git a/app/Jobs/Mailgun/ProcessMailgunWebhook.php b/app/Jobs/Mailgun/ProcessMailgunWebhook.php index 5b7182ecc298..3797d810214d 100644 --- a/app/Jobs/Mailgun/ProcessMailgunWebhook.php +++ b/app/Jobs/Mailgun/ProcessMailgunWebhook.php @@ -34,7 +34,10 @@ use App\Notifications\Ninja\EmailBounceNotification; class ProcessMailgunWebhook implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable; + use InteractsWithQueue; + use Queueable; + use SerializesModels; public $tries = 1; @@ -89,8 +92,9 @@ class ProcessMailgunWebhook implements ShouldQueue { nlog($this->request); - if(!$this->request['event-data']['tags'][0]) + if(!$this->request['event-data']['tags'][0]) { return; + } MultiDB::findAndSetDbByCompanyKey($this->request['event-data']['tags'][0]); $company = Company::where('company_key', $this->request['event-data']['tags'][0])->first(); @@ -112,7 +116,7 @@ class ProcessMailgunWebhook implements ShouldQueue if (isset($this->request['event-details']['delivery-status']['message'])) { $this->invitation->email_error = $this->request['event-details']['delivery-status']['message']; } - + switch ($this->request['event-data']['event']) { case 'delivered': return $this->processDelivery(); @@ -128,50 +132,50 @@ class ProcessMailgunWebhook implements ShouldQueue } } -/* -{ - "signature": { - "token": "7f388cf8096aa0bca1477aee9d91e156c61f8fa8282c7f1c0c", - "timestamp": "1705376308", - "signature": "a22b7c3dd4861e27a1664cef3611a1954c0665cfcaca9b8f35ee216243a4ce3f" - }, - "event-data": { - "id": "Ase7i2zsRYeDXztHGENqRA", - "timestamp": 1521243339.873676, - "log-level": "info", - "event": "opened", - "message": { - "headers": { - "message-id": "20130503182626.18666.16540@mail.invoicing.co" + /* + { + "signature": { + "token": "7f388cf8096aa0bca1477aee9d91e156c61f8fa8282c7f1c0c", + "timestamp": "1705376308", + "signature": "a22b7c3dd4861e27a1664cef3611a1954c0665cfcaca9b8f35ee216243a4ce3f" + }, + "event-data": { + "id": "Ase7i2zsRYeDXztHGENqRA", + "timestamp": 1521243339.873676, + "log-level": "info", + "event": "opened", + "message": { + "headers": { + "message-id": "20130503182626.18666.16540@mail.invoicing.co" + } + }, + "recipient": "alice@example.com", + "recipient-domain": "example.com", + "ip": "50.56.129.169", + "geolocation": { + "country": "US", + "region": "CA", + "city": "San Francisco" + }, + "client-info": { + "client-os": "Linux", + "device-type": "desktop", + "client-name": "Chrome", + "client-type": "browser", + "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31" + }, + "campaigns": [], + "tags": [ + "my_tag_1", + "my_tag_2" + ], + "user-variables": { + "my_var_1": "Mailgun Variable #1", + "my-var-2": "awesome" + } } - }, - "recipient": "alice@example.com", - "recipient-domain": "example.com", - "ip": "50.56.129.169", - "geolocation": { - "country": "US", - "region": "CA", - "city": "San Francisco" - }, - "client-info": { - "client-os": "Linux", - "device-type": "desktop", - "client-name": "Chrome", - "client-type": "browser", - "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31" - }, - "campaigns": [], - "tags": [ - "my_tag_1", - "my_tag_2" - ], - "user-variables": { - "my_var_1": "Mailgun Variable #1", - "my-var-2": "awesome" } - } -} -*/ + */ private function processOpen() { $this->invitation->opened_date = now(); @@ -180,8 +184,9 @@ class ProcessMailgunWebhook implements ShouldQueue $sl = $this->getSystemLog($this->request['MessageID']); /** Prevents Gmail tracking from firing inappropriately */ - if($this->request['signature']['timestamp'] < $sl->log['signature']['timestamp'] + 3) + if($this->request['signature']['timestamp'] < $sl->log['signature']['timestamp'] + 3) { return; + } $event = [ 'bounce_id' => '', @@ -201,74 +206,74 @@ class ProcessMailgunWebhook implements ShouldQueue } -/* -{ - "signature": { - "token": "70b91a64ed0f1bdf90fb9c6ea7e3c31d5792a3d0945ffc20fe", - "timestamp": "1705376276", - "signature": "ba96f841fc236e1bf5840b02fad512d0bd15b0731b5e6b154764c7a05f7ee999" - }, - "event-data": { - "id": "CPgfbmQMTCKtHW6uIWtuVe", - "timestamp": 1521472262.908181, - "log-level": "info", - "event": "delivered", - "delivery-status": { - "tls": true, - "mx-host": "smtp-in.example.com", - "code": 250, - "description": "", - "session-seconds": 0.4331989288330078, - "utf8": true, - "attempt-no": 1, - "message": "OK", - "certificate-verified": true - }, - "flags": { - "is-routed": false, - "is-authenticated": true, - "is-system-test": false, - "is-test-mode": false - }, - "envelope": { - "transport": "smtp", - "sender": "bob@mail.invoicing.co", - "sending-ip": "209.61.154.250", - "targets": "alice@example.com" - }, - "message": { - "headers": { - "to": "Alice ", - "message-id": "20130503182626.18666.16540@mail.invoicing.co", - "from": "Bob ", - "subject": "Test delivered webhook" + /* + { + "signature": { + "token": "70b91a64ed0f1bdf90fb9c6ea7e3c31d5792a3d0945ffc20fe", + "timestamp": "1705376276", + "signature": "ba96f841fc236e1bf5840b02fad512d0bd15b0731b5e6b154764c7a05f7ee999" }, - "attachments": [], - "size": 111 - }, - "recipient": "alice@example.com", - "recipient-domain": "example.com", - "storage": { - "url": "https://se.api.mailgun.net/v3/domains/mail.invoicing.co/messages/message_key", - "key": "message_key" - }, - "campaigns": [], - "tags": [ - "my_tag_1", - "my_tag_2" - ], - "user-variables": { - "my_var_1": "Mailgun Variable #1", - "my-var-2": "awesome" + "event-data": { + "id": "CPgfbmQMTCKtHW6uIWtuVe", + "timestamp": 1521472262.908181, + "log-level": "info", + "event": "delivered", + "delivery-status": { + "tls": true, + "mx-host": "smtp-in.example.com", + "code": 250, + "description": "", + "session-seconds": 0.4331989288330078, + "utf8": true, + "attempt-no": 1, + "message": "OK", + "certificate-verified": true + }, + "flags": { + "is-routed": false, + "is-authenticated": true, + "is-system-test": false, + "is-test-mode": false + }, + "envelope": { + "transport": "smtp", + "sender": "bob@mail.invoicing.co", + "sending-ip": "209.61.154.250", + "targets": "alice@example.com" + }, + "message": { + "headers": { + "to": "Alice ", + "message-id": "20130503182626.18666.16540@mail.invoicing.co", + "from": "Bob ", + "subject": "Test delivered webhook" + }, + "attachments": [], + "size": 111 + }, + "recipient": "alice@example.com", + "recipient-domain": "example.com", + "storage": { + "url": "https://se.api.mailgun.net/v3/domains/mail.invoicing.co/messages/message_key", + "key": "message_key" + }, + "campaigns": [], + "tags": [ + "my_tag_1", + "my_tag_2" + ], + "user-variables": { + "my_var_1": "Mailgun Variable #1", + "my-var-2": "awesome" + } + } } - } -} -*/ + */ private function processDelivery() { $this->invitation->email_status = 'delivered'; $this->invitation->save(); - + $sl = $this->getSystemLog($this->request['MessageID']); if($sl) { @@ -384,47 +389,47 @@ class ProcessMailgunWebhook implements ShouldQueue } -/* -{ - "signature": { - "token": "d7be371deef49c8b187119df295e3eb17fd1974d513a4be2cb", - "timestamp": "1705376380", - "signature": "52f31c75b492d67be906423279e0effe563e28790ee65ba23a1b30006df649df" - }, - "event-data": { - "id": "-Agny091SquKnsrW2NEKUA", - "timestamp": 1521233123.501324, - "log-level": "warn", - "event": "complained", - "envelope": { - "sending-ip": "173.193.210.33" - }, - "flags": { - "is-test-mode": false - }, - "message": { - "headers": { - "to": "Alice ", - "message-id": "20110215055645.25246.63817@mail.invoicing.co", - "from": "Bob ", - "subject": "Test complained webhook" + /* + { + "signature": { + "token": "d7be371deef49c8b187119df295e3eb17fd1974d513a4be2cb", + "timestamp": "1705376380", + "signature": "52f31c75b492d67be906423279e0effe563e28790ee65ba23a1b30006df649df" }, - "attachments": [], - "size": 111 - }, - "recipient": "alice@example.com", - "campaigns": [], - "tags": [ - "my_tag_1", - "my_tag_2" - ], - "user-variables": { - "my_var_1": "Mailgun Variable #1", - "my-var-2": "awesome" + "event-data": { + "id": "-Agny091SquKnsrW2NEKUA", + "timestamp": 1521233123.501324, + "log-level": "warn", + "event": "complained", + "envelope": { + "sending-ip": "173.193.210.33" + }, + "flags": { + "is-test-mode": false + }, + "message": { + "headers": { + "to": "Alice ", + "message-id": "20110215055645.25246.63817@mail.invoicing.co", + "from": "Bob ", + "subject": "Test complained webhook" + }, + "attachments": [], + "size": 111 + }, + "recipient": "alice@example.com", + "campaigns": [], + "tags": [ + "my_tag_1", + "my_tag_2" + ], + "user-variables": { + "my_var_1": "Mailgun Variable #1", + "my-var-2": "awesome" + } + } } - } -} -*/ + */ private function processSpamComplaint() { $this->invitation->email_status = 'spam'; diff --git a/app/Jobs/Ninja/TaskScheduler.php b/app/Jobs/Ninja/TaskScheduler.php index af0c2efc9c58..ff200ba0f2ba 100644 --- a/app/Jobs/Ninja/TaskScheduler.php +++ b/app/Jobs/Ninja/TaskScheduler.php @@ -56,7 +56,7 @@ class TaskScheduler implements ShouldQueue ->where('next_run', '<=', now()) ->cursor() ->each(function ($scheduler) { - + nlog("Doing job {$scheduler->name}"); try { @@ -81,7 +81,7 @@ class TaskScheduler implements ShouldQueue ->where('next_run', '<=', now()) ->cursor() ->each(function ($scheduler) { - + nlog("Doing job {$scheduler->name}"); try { diff --git a/app/Jobs/Payment/EmailPayment.php b/app/Jobs/Payment/EmailPayment.php index c40f40de7905..e894408ed3f2 100644 --- a/app/Jobs/Payment/EmailPayment.php +++ b/app/Jobs/Payment/EmailPayment.php @@ -106,7 +106,7 @@ class EmailPayment implements ShouldQueue (new NinjaMailerJob($nmo))->handle(); event(new PaymentWasEmailed($this->payment, $this->payment->company, $this->contact, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); - + } private function emailAllContacts($email_builder): void diff --git a/app/Jobs/User/UserEmailChanged.php b/app/Jobs/User/UserEmailChanged.php index a9e017f945aa..d1e540d9be82 100644 --- a/app/Jobs/User/UserEmailChanged.php +++ b/app/Jobs/User/UserEmailChanged.php @@ -94,6 +94,7 @@ class UserEmailChanged implements ShouldQueue 'logo' => $this->company->present()->logo(), 'settings' => $this->settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; } } diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index 06edfa791b30..99da853cc753 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -233,7 +233,6 @@ class Import implements ShouldQueue ['name' => ctrans('texts.ready_to_do'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 2], ['name' => ctrans('texts.in_progress'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 3], ['name' => ctrans('texts.done'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 4], - ]; TaskStatus::insert($task_statuses); @@ -1144,7 +1143,7 @@ class Import implements ShouldQueue ); $key = "invoices_{$resource['id']}"; - + nlog($invoice->id); $this->ids['invoices'][$key] = [ @@ -1409,7 +1408,7 @@ class Import implements ShouldQueue } nlog($payment->id); - + $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id; $this->ids['payments'] = [ @@ -1528,8 +1527,8 @@ class Import implements ShouldQueue } } - - // throw new Exception("Resource invoice/quote document not available."); + + // throw new Exception("Resource invoice/quote document not available."); } if (array_key_exists('expense_id', $resource) && $resource['expense_id'] && array_key_exists('expenses', $this->ids)) { @@ -2078,7 +2077,7 @@ class Import implements ShouldQueue nlog(print_r($exception->getMessage(), 1)); // if (Ninja::isHosted()) { - app('sentry')->captureException($exception); + app('sentry')->captureException($exception); // } } diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index 2c79b7c67490..c299232d2e50 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -38,7 +38,7 @@ class ReminderJob implements ShouldQueue use SerializesModels; use MakesReminders; use MakesDates; - + public $tries = 1; public function __construct() diff --git a/app/Jobs/Util/VersionCheck.php b/app/Jobs/Util/VersionCheck.php index 4a69a1586232..73f956d69766 100644 --- a/app/Jobs/Util/VersionCheck.php +++ b/app/Jobs/Util/VersionCheck.php @@ -94,7 +94,7 @@ class VersionCheck implements ShouldQueue Client::doesntHave('contacts') ->cursor() - ->each(function ($client) { + ->each(function (Client $client) { $new_contact = ClientContactFactory::create($client->company_id, $client->user_id); $new_contact->client_id = $client->id; @@ -107,7 +107,7 @@ class VersionCheck implements ShouldQueue Vendor::doesntHave('contacts') ->cursor() - ->each(function ($vendor) { + ->each(function (Vendor $vendor) { $new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id); $new_contact->vendor_id = $vendor->id; diff --git a/app/Listeners/Invoice/InvoiceEmailFailedActivity.php b/app/Listeners/Invoice/InvoiceEmailFailedActivity.php index d2df49622fae..be8b1430e21d 100644 --- a/app/Listeners/Invoice/InvoiceEmailFailedActivity.php +++ b/app/Listeners/Invoice/InvoiceEmailFailedActivity.php @@ -59,7 +59,7 @@ class InvoiceEmailFailedActivity implements ShouldQueue $fields->company_id = $event->invitation->invoice->company_id; $fields->activity_type_id = Activity::EMAIL_INVOICE_FAILED; $fields->notes = $event->message ?? ''; - + $this->activity_repo->save($fields, $event->invitation->invoice, $event->event_vars); } } diff --git a/app/Listeners/Invoice/InvoiceFailedEmailNotification.php b/app/Listeners/Invoice/InvoiceFailedEmailNotification.php index f2d58edbe872..b830f9f5cf44 100644 --- a/app/Listeners/Invoice/InvoiceFailedEmailNotification.php +++ b/app/Listeners/Invoice/InvoiceFailedEmailNotification.php @@ -37,8 +37,9 @@ class InvoiceFailedEmailNotification { MultiDB::setDb($event->company->db); - if(Cache::has("invoice_failed_email_notification_{$event->invitation->key}")) + if(Cache::has("invoice_failed_email_notification_{$event->invitation->key}")) { return; + } $invoice = $event->invitation->invoice; diff --git a/app/Livewire/BillingPortalPurchase.php b/app/Livewire/BillingPortalPurchase.php index 8ba6fe855d35..2e11b6b258d3 100644 --- a/app/Livewire/BillingPortalPurchase.php +++ b/app/Livewire/BillingPortalPurchase.php @@ -326,7 +326,7 @@ class BillingPortalPurchase extends Component $this->contact = $contact; if ($contact->showRff()) { - return $this->rff(); + return $this->rff(); } Auth::guard('contact')->loginUsingId($contact->id, true); diff --git a/app/Livewire/PdfSlot.php b/app/Livewire/PdfSlot.php index 709b14940dca..047f8cc812d2 100644 --- a/app/Livewire/PdfSlot.php +++ b/app/Livewire/PdfSlot.php @@ -131,7 +131,7 @@ class PdfSlot extends Component $this->settings = $this->entity->client ? $this->entity->client->getMergedSettings() : $this->entity->company->settings; $this->html_entity_option = $this->entity->client ? $this->entity->client->getSetting('show_pdfhtml_on_mobile') : $this->entity->company->getSetting('show_pdfhtml_on_mobile'); - + $this->show_cost = in_array('$product.unit_cost', $this->settings->pdf_variables->product_columns); $this->show_line_total = in_array('$product.line_total', $this->settings->pdf_variables->product_columns); $this->show_quantity = in_array('$product.quantity', $this->settings->pdf_variables->product_columns); diff --git a/app/Mail/Admin/ClientUnsubscribedObject.php b/app/Mail/Admin/ClientUnsubscribedObject.php index eb0190ab161f..32193d3f62fd 100644 --- a/app/Mail/Admin/ClientUnsubscribedObject.php +++ b/app/Mail/Admin/ClientUnsubscribedObject.php @@ -44,6 +44,7 @@ class ClientUnsubscribedObject 'settings' => $this->company->settings, 'logo' => $this->company->present()->logo(), 'text_body' => "\n\n".ctrans('texts.client_unsubscribed_help', ['client' => $this->contact->present()->name()])."\n\n", + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; $mail_obj = new \stdClass(); diff --git a/app/Mail/Admin/EntityCreatedObject.php b/app/Mail/Admin/EntityCreatedObject.php index baab3068db25..324e7aeeeea6 100644 --- a/app/Mail/Admin/EntityCreatedObject.php +++ b/app/Mail/Admin/EntityCreatedObject.php @@ -76,13 +76,13 @@ class EntityCreatedObject $mail_obj->text_view = 'email.template.text'; $content = ctrans( - $this->template_body, - [ + $this->template_body, + [ 'amount' => $mail_obj->amount, 'vendor' => $this->entity->vendor->present()->name(), 'purchase_order' => $this->entity->number, ] - ); + ); $mail_obj->data = [ 'title' => $mail_obj->subject, @@ -94,7 +94,8 @@ class EntityCreatedObject 'settings' => $this->company->settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => str_replace(['$view_button','$viewButton','$viewLink','$view_url'], '$view_url', $content), - ]; + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', + ]; } else { $this->entity->load('client.country', 'client.company'); $this->client = $this->entity->client; @@ -181,6 +182,7 @@ class EntityCreatedObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => str_replace(['$view_button','$viewButton','$view_link','$view_button'], '$view_url', $content), + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; } } diff --git a/app/Mail/Admin/EntityFailedSendObject.php b/app/Mail/Admin/EntityFailedSendObject.php index 53ce0de33500..3d099d6b1c47 100644 --- a/app/Mail/Admin/EntityFailedSendObject.php +++ b/app/Mail/Admin/EntityFailedSendObject.php @@ -132,15 +132,15 @@ class EntityFailedSendObject $html_variables = (new HtmlEngine($this->invitation))->makeValues(); $signature = str_replace(array_keys($html_variables), array_values($html_variables), $signature); $content = ctrans( - $this->template_body, - [ + $this->template_body, + [ 'amount' => $this->getAmount(), 'client' => $this->contact->present()->name(), 'invoice' => $this->entity->number, 'error' => $this->message_content ?? '', 'contact' => $this->contact->present()->name(), ] - ); + ); $data = [ "title" => $this->getSubject(), @@ -152,6 +152,7 @@ class EntityFailedSendObject "settings" => $settings, "whitelabel" => $this->company->account->isPaid() ? true : false, "text_body" => str_replace("
", "\n", $content), + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/EntityNotificationMailer.php b/app/Mail/Admin/EntityNotificationMailer.php index fe131b3e4eec..007d8fc2b744 100644 --- a/app/Mail/Admin/EntityNotificationMailer.php +++ b/app/Mail/Admin/EntityNotificationMailer.php @@ -12,6 +12,7 @@ namespace App\Mail\Admin; use Illuminate\Mail\Mailable; + //@deprecated? class EntityNotificationMailer extends Mailable { diff --git a/app/Mail/Admin/EntityPaidObject.php b/app/Mail/Admin/EntityPaidObject.php index 143119d8af05..ed2d058fe4f4 100644 --- a/app/Mail/Admin/EntityPaidObject.php +++ b/app/Mail/Admin/EntityPaidObject.php @@ -85,8 +85,8 @@ class EntityPaidObject $invoice_texts = substr($invoice_texts, 0, -1); $content = ctrans( - 'texts.notification_payment_paid', - ['amount' => $amount, + 'texts.notification_payment_paid', + ['amount' => $amount, 'client' => $this->payment->client->present()->name(), 'invoice' => $invoice_texts, ] @@ -105,6 +105,7 @@ class EntityPaidObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/EntitySentObject.php b/app/Mail/Admin/EntitySentObject.php index 8ba5700eb270..52531daaf8fe 100644 --- a/app/Mail/Admin/EntitySentObject.php +++ b/app/Mail/Admin/EntitySentObject.php @@ -87,6 +87,8 @@ class EntitySentObject 'logo' => $this->company->present()->logo(), 'settings' => $this->company->settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', + ]; $mail_obj->markdown = 'email.admin.generic'; $mail_obj->tag = $this->company->company_key; @@ -98,7 +100,7 @@ class EntitySentObject $mail_obj->markdown = 'email.admin.generic'; $mail_obj->tag = $this->company->company_key; } - + $mail_obj->text_view = 'email.template.text'; return $mail_obj; @@ -186,7 +188,7 @@ class EntitySentObject { $settings = $this->entity->client->getMergedSettings(); $content = $this->getMessage(); - + return [ 'title' => $this->getSubject(), 'content' => $content, @@ -197,6 +199,8 @@ class EntitySentObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', + ]; } } diff --git a/app/Mail/Admin/EntityViewedObject.php b/app/Mail/Admin/EntityViewedObject.php index c9272fa98bf5..e3723d0ca18a 100644 --- a/app/Mail/Admin/EntityViewedObject.php +++ b/app/Mail/Admin/EntityViewedObject.php @@ -98,13 +98,13 @@ class EntityViewedObject } $content = ctrans( - "texts.notification_{$this->entity_type}_viewed", - [ + "texts.notification_{$this->entity_type}_viewed", + [ 'amount' => $this->getAmount(), 'client' => $this->contact->present()->name(), 'invoice' => $this->entity->number, ] - ); + ); $data = [ 'title' => $this->getSubject(), @@ -116,6 +116,7 @@ class EntityViewedObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/InventoryNotificationObject.php b/app/Mail/Admin/InventoryNotificationObject.php index b73fd181e4e8..1beb298cb830 100644 --- a/app/Mail/Admin/InventoryNotificationObject.php +++ b/app/Mail/Admin/InventoryNotificationObject.php @@ -60,12 +60,12 @@ class InventoryNotificationObject private function getData() { $content = ctrans( - 'texts.inventory_notification_body', - ['amount' => $this->getAmount(), + 'texts.inventory_notification_body', + ['amount' => $this->getAmount(), 'product' => $this->product->product_key.': '.$this->product->notes, ] ); - + $data = [ 'title' => $this->getSubject(), 'content' => $content, @@ -76,6 +76,7 @@ class InventoryNotificationObject 'settings' => $this->product->company->settings, 'whitelabel' => $this->product->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->product->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/PaymentFailureObject.php b/app/Mail/Admin/PaymentFailureObject.php index 61fe41c71ef8..fd3c9f414885 100644 --- a/app/Mail/Admin/PaymentFailureObject.php +++ b/app/Mail/Admin/PaymentFailureObject.php @@ -75,14 +75,14 @@ class PaymentFailureObject { $signature = $this->client->getSetting('email_signature'); $content = ctrans( - 'texts.notification_invoice_payment_failed', - [ + 'texts.notification_invoice_payment_failed', + [ 'client' => $this->client->present()->name(), 'invoice' => $this->getDescription(), 'amount' => Number::formatMoney($this->amount, $this->client), ] - ); - + ); + $data = [ 'title' => ctrans( 'texts.payment_failed_subject', @@ -99,6 +99,7 @@ class PaymentFailureObject 'button' => $this->use_react_url ? ctrans('texts.view_client') : ctrans('texts.login'), 'additional_info' => $this->error, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/PurchaseOrderAcceptedObject.php b/app/Mail/Admin/PurchaseOrderAcceptedObject.php index 00ae2b1b36ea..1f0df6bf959d 100644 --- a/app/Mail/Admin/PurchaseOrderAcceptedObject.php +++ b/app/Mail/Admin/PurchaseOrderAcceptedObject.php @@ -74,14 +74,14 @@ class PurchaseOrderAcceptedObject $settings = $this->company->settings; $content = ctrans( - 'texts.notification_purchase_order_accepted', - [ + 'texts.notification_purchase_order_accepted', + [ 'amount' => $this->getAmount(), 'vendor' => $this->purchase_order->vendor->present()->name(), 'purchase_order' => $this->purchase_order->number, ] ); - + $data = [ 'title' => $this->getSubject(), 'content' => $content, @@ -92,6 +92,7 @@ class PurchaseOrderAcceptedObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/QuoteApprovedObject.php b/app/Mail/Admin/QuoteApprovedObject.php index e3675dec19cf..5ea8733ae540 100644 --- a/app/Mail/Admin/QuoteApprovedObject.php +++ b/app/Mail/Admin/QuoteApprovedObject.php @@ -73,13 +73,13 @@ class QuoteApprovedObject { $settings = $this->quote->client->getMergedSettings(); $content = ctrans( - 'texts.notification_quote_approved', - [ + 'texts.notification_quote_approved', + [ 'amount' => $this->getAmount(), 'client' => $this->quote->client->present()->name(), 'invoice' => $this->quote->number, ] - ); + ); $data = [ 'title' => $this->getSubject(), @@ -91,6 +91,7 @@ class QuoteApprovedObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; return $data; diff --git a/app/Mail/Admin/QuoteExpiredObject.php b/app/Mail/Admin/QuoteExpiredObject.php index d07969a1384c..07b8e3af0144 100644 --- a/app/Mail/Admin/QuoteExpiredObject.php +++ b/app/Mail/Admin/QuoteExpiredObject.php @@ -73,13 +73,13 @@ class QuoteExpiredObject { $settings = $this->quote->client->getMergedSettings(); $content = ctrans( - 'texts.notification_quote_expired', - [ + 'texts.notification_quote_expired', + [ 'amount' => $this->getAmount(), 'client' => $this->quote->client->present()->name(), 'invoice' => $this->quote->number, ] - ); + ); $data = [ 'title' => $this->getSubject(), @@ -91,6 +91,8 @@ class QuoteExpiredObject 'settings' => $settings, 'whitelabel' => $this->company->account->isPaid() ? true : false, 'text_body' => $content, + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', + ]; return $data; diff --git a/app/Mail/Admin/ResetPasswordObject.php b/app/Mail/Admin/ResetPasswordObject.php index 66668b56d631..c644ff429909 100644 --- a/app/Mail/Admin/ResetPasswordObject.php +++ b/app/Mail/Admin/ResetPasswordObject.php @@ -41,6 +41,7 @@ class ResetPasswordObject 'settings' => $this->company->settings, 'logo' => $this->company->present()->logo(), 'text_body' => ctrans('texts.reset_password'), + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; $mail_obj = new \stdClass(); diff --git a/app/Mail/Admin/VerifyUserObject.php b/app/Mail/Admin/VerifyUserObject.php index ea69c3fc6052..03361994b927 100644 --- a/app/Mail/Admin/VerifyUserObject.php +++ b/app/Mail/Admin/VerifyUserObject.php @@ -53,6 +53,7 @@ class VerifyUserObject 'logo' => $this->company->present()->logo(), 'signature' => $this->company->settings->email_signature, 'text_body' => ctrans('texts.confirmation_message'), + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; $mail_obj = new \stdClass(); diff --git a/app/Mail/Client/ClientStatement.php b/app/Mail/Client/ClientStatement.php index b715840083ed..d7a131fa2f0f 100644 --- a/app/Mail/Client/ClientStatement.php +++ b/app/Mail/Client/ClientStatement.php @@ -52,7 +52,7 @@ class ClientStatement extends Mailable public function content() { return new Content( - view: 'email.template.client', + view: $this->data['company']->account->isPremium() ? 'email.template.client_premium' : 'email.template.client', text: 'email.template.text', with: [ 'text_body' => $this->data['body'], diff --git a/app/Mail/Engine/BaseEmailEngine.php b/app/Mail/Engine/BaseEmailEngine.php index a850dc804e21..3a5268d8395c 100644 --- a/app/Mail/Engine/BaseEmailEngine.php +++ b/app/Mail/Engine/BaseEmailEngine.php @@ -125,7 +125,7 @@ class BaseEmailEngine implements EngineInterface { if (! empty($this->variables)) { - + $text = str_replace(['$paymentLink', '$viewButton', '$view_button', '$viewLink', '$view_link'], '$view_url', $text); $text = str_replace(array_keys($this->variables), array_values($this->variables), $text); $text = str_replace(array_keys($this->variables), array_values($this->variables), $text); diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index 8c0593f43636..cadc1e21da53 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -134,9 +134,9 @@ class InvoiceEmailEngine extends BaseEmailEngine $this->setAttachments([['file' => base64_encode($pdf), 'name' => $this->invoice->numberFormatter().'.pdf']]); } -// $hash = Str::uuid(); -// $url = \Illuminate\Support\Facades\URL::temporarySignedRoute('protected_download', now()->addHour(), ['hash' => $hash]); -// Cache::put($hash, $url, now()->addHour()); + // $hash = Str::uuid(); + // $url = \Illuminate\Support\Facades\URL::temporarySignedRoute('protected_download', now()->addHour(), ['hash' => $hash]); + // Cache::put($hash, $url, now()->addHour()); //attach third party documents if ($this->client->getSetting('document_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { @@ -155,7 +155,7 @@ class InvoiceEmailEngine extends BaseEmailEngine // Storage::url $this->invoice->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { - + $hash = Str::random(64); Cache::put($hash, ['db' => $this->invoice->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); @@ -193,9 +193,9 @@ class InvoiceEmailEngine extends BaseEmailEngine ->each(function ($expense) { $expense->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { - - $hash = Str::random(64); - Cache::put($hash, ['db' => $this->invoice->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); + + $hash = Str::random(64); + Cache::put($hash, ['db' => $this->invoice->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); $this->setAttachmentLinks([" $hash]) ."'>". $document->name .""]); } else { @@ -217,9 +217,9 @@ class InvoiceEmailEngine extends BaseEmailEngine ->each(function ($task) { $task->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { - - $hash = Str::random(64); - Cache::put($hash, ['db' => $this->invoice->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); + + $hash = Str::random(64); + Cache::put($hash, ['db' => $this->invoice->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); $this->setAttachmentLinks([" $hash]) ."'>". $document->name .""]); } else { diff --git a/app/Mail/Engine/QuoteEmailEngine.php b/app/Mail/Engine/QuoteEmailEngine.php index ace3f40512a4..f0dad52d58bf 100644 --- a/app/Mail/Engine/QuoteEmailEngine.php +++ b/app/Mail/Engine/QuoteEmailEngine.php @@ -125,7 +125,7 @@ class QuoteEmailEngine extends BaseEmailEngine // Storage::url $this->quote->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { - + $hash = Str::random(64); Cache::put($hash, ['db' => $this->quote->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); @@ -137,7 +137,7 @@ class QuoteEmailEngine extends BaseEmailEngine $this->quote->company->documents()->where('is_public', true)->cursor()->each(function ($document) { if ($document->size > $this->max_attachment_size) { - + $hash = Str::random(64); Cache::put($hash, ['db' => $this->quote->company->db, 'doc_hash' => $document->hash], now()->addDays(7)); diff --git a/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php b/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php index bd16c701f9f5..19c07ec424ce 100644 --- a/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php +++ b/app/Mail/RecurringInvoice/ClientContactRequestCancellationObject.php @@ -48,6 +48,7 @@ class ClientContactRequestCancellationObject 'signature' => $this->company->settings->email_signature, 'settings' => $this->company->settings, 'logo' => $this->company->present()->logo(), + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]; $mail_obj = new \stdClass(); diff --git a/app/Mail/Subscription/OtpCode.php b/app/Mail/Subscription/OtpCode.php index b97f7fb1dd28..28fd20fe72e7 100644 --- a/app/Mail/Subscription/OtpCode.php +++ b/app/Mail/Subscription/OtpCode.php @@ -58,6 +58,7 @@ class OtpCode extends Mailable 'title' => ctrans('texts.otp_code_subject'), 'content' => ctrans('texts.otp_code_body', ['code' => $this->code]), 'whitelabel' => $this->company->account->isPaid(), + 'template' => $this->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ]); } } diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php index 90352e00b68e..84814520e9db 100644 --- a/app/Mail/TemplateEmail.php +++ b/app/Mail/TemplateEmail.php @@ -75,7 +75,7 @@ class TemplateEmail extends Mailable $template_name = 'email.template.'.$this->build_email->getTemplate(); if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') { - $template_name = 'email.template.client'; + $template_name = $this->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client'; } if ($this->build_email->getTemplate() == 'custom') { diff --git a/app/Mail/User/UserLoggedIn.php b/app/Mail/User/UserLoggedIn.php index dd2a329f0080..98aca6acd190 100644 --- a/app/Mail/User/UserLoggedIn.php +++ b/app/Mail/User/UserLoggedIn.php @@ -19,7 +19,6 @@ use Illuminate\Support\Facades\App; class UserLoggedIn extends Mailable { - /** * Create a new message instance. * diff --git a/app/Mail/VendorTemplateEmail.php b/app/Mail/VendorTemplateEmail.php index 18e491491bab..593d711e7cf4 100644 --- a/app/Mail/VendorTemplateEmail.php +++ b/app/Mail/VendorTemplateEmail.php @@ -72,7 +72,7 @@ class VendorTemplateEmail extends Mailable $template_name = 'email.template.'.$this->build_email->getTemplate(); if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') { - $template_name = 'email.template.client'; + $template_name = $this->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client'; } if ($this->build_email->getTemplate() == 'custom') { diff --git a/app/Models/Account.php b/app/Models/Account.php index 32b81723e4a2..382eec8692ee 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -296,6 +296,7 @@ class Account extends BaseModel public function isPremium(): bool { + // return true; return Ninja::isHosted() && $this->isPaidHostedClient() && !$this->isTrial() && Carbon::createFromTimestamp($this->created_at)->diffInMonths() > 2; } diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index 2d81fbfba56d..9e1c1b884d2e 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -316,7 +316,7 @@ class BaseModel extends Model return "data:application/pdf;base64,".base64_encode((new CreateRawPdf($invitation))->handle()); } - + /** * Takes a entity prop as first argument * along with an array of variables and performs @@ -328,9 +328,10 @@ class BaseModel extends Model */ public function parseHtmlVariables(string $field, array $variables): string { - if(!$this->{$field}) + if(!$this->{$field}) { return ''; - + } + $section = strtr($this->{$field}, $variables['labels']); return strtr($section, $variables['values']); diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php index 04307dce367e..67abadeb873c 100644 --- a/app/Models/ClientContact.php +++ b/app/Models/ClientContact.php @@ -254,7 +254,7 @@ class ClientContact extends Authenticatable implements HasLocalePreference { return $this->hasMany(CreditInvitation::class); } - + public function sendPasswordResetNotification($token) { $this->token = $token; diff --git a/app/Models/CompanyUser.php b/app/Models/CompanyUser.php index c6811ddf3e3a..c9e3aa74b9cd 100644 --- a/app/Models/CompanyUser.php +++ b/app/Models/CompanyUser.php @@ -201,7 +201,8 @@ class CompanyUser extends Pivot * @return bool */ public function portalType(): bool - { nlog(isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link); + { + nlog(isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link); return isset($this->react_settings->react_notification_link) && $this->react_settings->react_notification_link; } diff --git a/app/Models/InvoiceInvitation.php b/app/Models/InvoiceInvitation.php index 58c191fc4a41..3b8b918a2531 100644 --- a/app/Models/InvoiceInvitation.php +++ b/app/Models/InvoiceInvitation.php @@ -101,7 +101,7 @@ class InvoiceInvitation extends BaseModel { return 'invoice'; } - + public function entityType() { return Invoice::class; diff --git a/app/Models/Payment.php b/app/Models/Payment.php index d43cacf6f043..5ce3805f6bca 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -325,8 +325,9 @@ class Payment extends BaseModel return '
'.ctrans('texts.payment_status_3').'
'; case self::STATUS_COMPLETED: - if($this->amount > $this->applied) + if($this->amount > $this->applied) { return '
' . ctrans('texts.partially_unapplied') . '
'; + } return '
'.ctrans('texts.payment_status_4').'
'; case self::STATUS_PARTIALLY_REFUNDED: diff --git a/app/Models/RecurringExpense.php b/app/Models/RecurringExpense.php index b83bf4b7a3df..c46a9fffc00e 100644 --- a/app/Models/RecurringExpense.php +++ b/app/Models/RecurringExpense.php @@ -78,7 +78,6 @@ use Illuminate\Support\Carbon; * @property-read \App\Models\User $user * @property-read \App\Models\Vendor|null $vendor * @property-read \App\Models\ExpenseCategory|null $category - * @method static \Illuminate\Database\Eloquent\Builder|BaseModel company() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns) * @method static \Database\Factories\RecurringExpenseFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|RecurringExpense filter(\App\Filters\QueryFilters $filters) @@ -222,7 +221,7 @@ class RecurringExpense extends BaseModel return $this->belongsTo(User::class, 'assigned_user_id', 'id'); } - public function company() + public function company():\Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Company::class); } diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index c94bfda43f8f..a29e9f4023b6 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -106,7 +106,6 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \App\Models\Subscription|null $subscription * @property-read \App\Models\User $user * @property-read \App\Models\Vendor|null $vendor - * @method static \Illuminate\Database\Eloquent\Builder|BaseModel company() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns) * @method static \Database\Factories\RecurringInvoiceFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|RecurringInvoice filter(\App\Filters\QueryFilters $filters) @@ -342,18 +341,27 @@ class RecurringInvoice extends BaseModel return $this->status_id; } } - - public function calculateStatus() + + /** + * CalculateStatus + * + * Calculates the status of the Recurring Invoice. + * + * We only apply the pending status on new models, we never revert an invoice back to + * pending. + * @param bool $new_model + * @return int + */ + public function calculateStatus(bool $new_model = false) //15-02-2024 - $new_model needed { if($this->remaining_cycles == 0) { return self::STATUS_COMPLETED; - } elseif ($this->status_id == self::STATUS_ACTIVE && Carbon::parse($this->next_send_date)->isFuture()) { + } elseif ($new_model && $this->status_id == self::STATUS_ACTIVE && Carbon::parse($this->next_send_date)->isFuture()) return self::STATUS_PENDING; - } else { - return $this->status_id; - } - + + return $this->status_id; + } public function nextSendDate(): ?Carbon diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index ec5bfeec1731..5c29b1e71139 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -231,7 +231,7 @@ class CreditCard implements MethodInterface try { $response = $this->checkout->gateway->getPaymentsClient()->requestPayment($paymentRequest); - + if($this->checkout->company_gateway->update_details && isset($response['customer'])) { $this->checkout->updateCustomer($response['customer']['id'] ?? ''); } diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 469986059b33..176a763507b9 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -213,9 +213,10 @@ class CheckoutComPaymentDriver extends BaseDriver public function refund(Payment $payment, $amount, $return_client_response = false) { $this->init(); - - if($this->company_gateway->update_details) + + if($this->company_gateway->update_details) { $this->updateCustomer(); + } $request = new RefundRequest(); $request->reference = "{$payment->transaction_reference} ".now(); @@ -332,11 +333,12 @@ class CheckoutComPaymentDriver extends BaseDriver public function updateCustomer($customer_id = null) { - if(!$customer_id) + if(!$customer_id) { return; + } try { - + $request = new CustomerRequest(); $phone = new Phone(); @@ -387,7 +389,7 @@ class CheckoutComPaymentDriver extends BaseDriver $this->payment_hash = $payment_hash; $this->init(); - + $paymentRequest = $this->bootTokenRequest($cgt->token); $paymentRequest->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode()); $paymentRequest->reference = '#'.$invoice->number.' - '.now(); diff --git a/app/PaymentDrivers/GoCardlessPaymentDriver.php b/app/PaymentDrivers/GoCardlessPaymentDriver.php index 3b1fb23e9589..0ec94d1032c5 100644 --- a/app/PaymentDrivers/GoCardlessPaymentDriver.php +++ b/app/PaymentDrivers/GoCardlessPaymentDriver.php @@ -91,7 +91,7 @@ class GoCardlessPaymentDriver extends BaseDriver if ($this->client->currency()->code === 'GBP') { $types[] = GatewayType::INSTANT_BANK_PAY; } - + return $types; } diff --git a/app/PaymentDrivers/PayPalPPCPPaymentDriver.php b/app/PaymentDrivers/PayPalPPCPPaymentDriver.php index 5fcb5ab1c183..5b757d907600 100644 --- a/app/PaymentDrivers/PayPalPPCPPaymentDriver.php +++ b/app/PaymentDrivers/PayPalPPCPPaymentDriver.php @@ -272,10 +272,9 @@ class PayPalPPCPPaymentDriver extends BaseDriver //capture $orderID = $response['orderID']; - if($this->company_gateway->require_shipping_address) - { + if($this->company_gateway->require_shipping_address) { - $shipping_data = + $shipping_data = [[ "op" => "replace", "path" => "/purchase_units/@reference_id=='default'/shipping/address", @@ -288,7 +287,7 @@ class PayPalPPCPPaymentDriver extends BaseDriver "country_code" => $this->client->present()->shipping_country_code(), ], ]]; - + $r = $this->gatewayRequest("/v2/checkout/orders/{$orderID}", 'patch', $shipping_data); } @@ -497,7 +496,7 @@ class PayPalPPCPPaymentDriver extends BaseDriver "country_code" => $this->client->present()->shipping_country_code(), ], ] - + : null; } diff --git a/app/PaymentDrivers/PayPalRestPaymentDriver.php b/app/PaymentDrivers/PayPalRestPaymentDriver.php index 18ae5ce8113a..f08decd67501 100644 --- a/app/PaymentDrivers/PayPalRestPaymentDriver.php +++ b/app/PaymentDrivers/PayPalRestPaymentDriver.php @@ -42,7 +42,7 @@ class PayPalRestPaymentDriver extends BaseDriver private string $paypal_payment_method = ''; private ?int $gateway_type_id = null; - + protected mixed $access_token = null; protected ?Carbon $token_expiry = null; @@ -451,7 +451,7 @@ class PayPalRestPaymentDriver extends BaseDriver "country_code" => $this->client->present()->shipping_country_code(), ], ] - + : null; } diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php index 4f71bdf6a2a6..7c8199142f9e 100644 --- a/app/Providers/ComposerServiceProvider.php +++ b/app/Providers/ComposerServiceProvider.php @@ -24,18 +24,6 @@ class ComposerServiceProvider extends ServiceProvider public function boot() { view()->composer('portal.*', PortalComposer::class); - - // view()->composer( - // ['email.admin.generic', 'email.client.generic'], - // function ($view) { - // $view->with( - // 'template', - // Ninja::isHosted() - // ); - // } - // ); - - } /** diff --git a/app/Providers/MultiDBProvider.php b/app/Providers/MultiDBProvider.php index 4f01911ea087..9743e6c8b92a 100644 --- a/app/Providers/MultiDBProvider.php +++ b/app/Providers/MultiDBProvider.php @@ -33,7 +33,7 @@ class MultiDBProvider extends ServiceProvider */ public function register() { - + $this->app['events']->listen( JobProcessing::class, function ($event) { diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 6ac2775eeeed..c14324089fe0 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -365,7 +365,7 @@ class BaseRepository $model = $model->calc()->getRecurringInvoice(); - $model->status_id = $model->calculateStatus(); + $model->status_id = $model->calculateStatus($this->new_model); if ($this->new_model) { event('eloquent.created: App\Models\RecurringInvoice', $model); diff --git a/app/Repositories/ClientContactRepository.php b/app/Repositories/ClientContactRepository.php index 4434a8a80c8e..e2212e1523d6 100644 --- a/app/Repositories/ClientContactRepository.php +++ b/app/Repositories/ClientContactRepository.php @@ -85,14 +85,14 @@ class ClientContactRepository extends BaseRepository if (array_key_exists('password', $contact) && strlen($contact['password']) > 1 && strlen($update_contact->email) > 3) { //updating on a blank contact email will cause large table scanning $update_contact->password = Hash::make($contact['password']); - ClientContact::withTrashed() - ->where('company_id', $client->company_id) - ->where('client_id', $client->id) - ->where('email', $update_contact->email)->cursor() - ->each(function ($saveable_contact) use ($update_contact){ - $saveable_contact->password = $update_contact->password; - $saveable_contact->save(); - }); + ClientContact::withTrashed() + ->where('company_id', $client->company_id) + ->where('client_id', $client->id) + ->where('email', $update_contact->email)->cursor() + ->each(function ($saveable_contact) use ($update_contact) { + $saveable_contact->password = $update_contact->password; + $saveable_contact->save(); + }); } if (array_key_exists('email', $contact)) { diff --git a/app/Services/Client/ClientService.php b/app/Services/Client/ClientService.php index fe0f2381259c..2b65807a2822 100644 --- a/app/Services/Client/ClientService.php +++ b/app/Services/Client/ClientService.php @@ -26,7 +26,8 @@ use Illuminate\Database\QueryException; class ClientService { - use MakesDates, GeneratesCounter; + use MakesDates; + use GeneratesCounter; private string $client_start_date; @@ -153,9 +154,10 @@ class ClientService { $x = 1; - if(isset($this->client->number)) + if(isset($this->client->number)) { return $this; - + } + do { try { $this->client->number = $this->getNextClientNumber($this->client); diff --git a/app/Services/ClientPortal/InstantPayment.php b/app/Services/ClientPortal/InstantPayment.php index 8868a3df8ddc..660ed9a345e0 100644 --- a/app/Services/ClientPortal/InstantPayment.php +++ b/app/Services/ClientPortal/InstantPayment.php @@ -45,7 +45,7 @@ class InstantPayment public function run() { nlog($this->request->all()); - + $cc = auth()->guard('contact')->user(); $cc->first_name = $this->request->contact_first_name; diff --git a/app/Services/Email/AdminEmailMailable.php b/app/Services/Email/AdminEmailMailable.php index 7745a9b48e7e..eb90be6cb915 100644 --- a/app/Services/Email/AdminEmailMailable.php +++ b/app/Services/Email/AdminEmailMailable.php @@ -68,6 +68,7 @@ class AdminEmailMailable extends Mailable 'logo' => $this->email_object->company->present()->logo(), 'settings' => $this->email_object->settings, 'whitelabel' => $this->email_object->company->account->isPaid() ? true : false, + 'template' => $this->email_object->company->account->isPremium() ? 'email.template.admin_premium' : 'email.template.admin', ] ); } diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php index 7052dc5f56ee..a567839883d9 100644 --- a/app/Services/Email/Email.php +++ b/app/Services/Email/Email.php @@ -465,7 +465,7 @@ class Email implements ShouldQueue private function setHostedMailgunMailer() { - + if (property_exists($this->email_object->settings, 'email_from_name') && strlen($this->email_object->settings->email_from_name) > 1) { $email_from_name = $this->email_object->settings->email_from_name; } else { @@ -477,7 +477,7 @@ class Email implements ShouldQueue } - + /** * Sets the mail driver to use and applies any specific configuration * the the mailable @@ -495,7 +495,7 @@ class Email implements ShouldQueue if(Ninja::isHosted() && $this->company->account->isPaid() && $this->email_object->settings->email_sending_method == 'default') { try { - + $address_object = reset($this->email_object->to); $email = $address_object->address ?? ''; $domain = explode("@", $email)[1] ?? ""; diff --git a/app/Services/Email/EmailDefaults.php b/app/Services/Email/EmailDefaults.php index 8eb8765ca69b..033b2ad77478 100644 --- a/app/Services/Email/EmailDefaults.php +++ b/app/Services/Email/EmailDefaults.php @@ -107,10 +107,10 @@ class EmailDefaults match ($this->email->email_object->settings->email_style) { 'plain' => $this->template = 'email.template.plain', - 'light' => $this->template = 'email.template.client', - 'dark' => $this->template = 'email.template.client', + 'light' => $this->template = $this->email->email_object->company->account->isPremium() ? 'email.template.client_premium' : 'email.template.client', + 'dark' => $this->template = $this->email->email_object->company->account->isPremium() ? 'email.template.client_premium' :'email.template.client', 'custom' => $this->template = 'email.template.custom', - default => $this->template = 'email.template.client', + default => $this->template = $this->email->email_object->company->account->isPremium() ? 'email.template.client_premium' :'email.template.client', }; $this->email->email_object->html_template = $this->template; @@ -211,17 +211,15 @@ class EmailDefaults $reply_to_email = $this->email->company->owner()->email; $reply_to_name = $this->email->company->owner()->present()->name(); - if(str_contains($this->email->email_object->settings->reply_to_email, "@")){ - $reply_to_email = $this->email->email_object->settings->reply_to_email; - } - elseif(isset($this->email->email_object->invitation->user)) { + if(str_contains($this->email->email_object->settings->reply_to_email, "@")) { + $reply_to_email = $this->email->email_object->settings->reply_to_email; + } elseif(isset($this->email->email_object->invitation->user)) { $reply_to_email = $this->email->email_object->invitation->user->email; } - + if(strlen($this->email->email_object->settings->reply_to_name) > 3) { - $reply_to_name =$this->email->email_object->settings->reply_to_name; - } - elseif(isset($this->email->email_object->invitation->user)) { + $reply_to_name = $this->email->email_object->settings->reply_to_name; + } elseif(isset($this->email->email_object->invitation->user)) { $reply_to_name = $this->email->email_object->invitation->user->present()->name(); } diff --git a/app/Services/Email/EmailMailable.php b/app/Services/Email/EmailMailable.php index fae76d738759..845be3308a34 100644 --- a/app/Services/Email/EmailMailable.php +++ b/app/Services/Email/EmailMailable.php @@ -84,8 +84,8 @@ class EmailMailable extends Mailable 'company' => $this->email_object->company, 'greeting' => '', 'links' => array_merge($this->email_object->links, $links->toArray()), - 'email_preferences' => (Ninja::isHosted() && in_array($this->email_object->settings->email_sending_method, ['default', 'mailgun']) && $this->email_object->invitation) - ? URL::signedRoute('client.email_preferences', ['entity' => $this->email_object->invitation->getEntityString(), 'invitation_key' => $this->email_object->invitation->key]) + 'email_preferences' => (Ninja::isHosted() && in_array($this->email_object->settings->email_sending_method, ['default', 'mailgun']) && $this->email_object->invitation) + ? URL::signedRoute('client.email_preferences', ['entity' => $this->email_object->invitation->getEntityString(), 'invitation_key' => $this->email_object->invitation->key]) : false, ] ); diff --git a/app/Services/Invoice/AutoBillInvoice.php b/app/Services/Invoice/AutoBillInvoice.php index 1c65aa6999d3..73eac355eefe 100644 --- a/app/Services/Invoice/AutoBillInvoice.php +++ b/app/Services/Invoice/AutoBillInvoice.php @@ -330,7 +330,7 @@ class AutoBillInvoice extends AbstractService $query->where('is_deleted', 0) ->where('deleted_at', null); })->orderBy('is_default', 'DESC') - ->get(); + ->get(); // $gateway_tokens = $this->client // ->gateway_tokens() diff --git a/app/Services/Invoice/EInvoice/RoEInvoice.php b/app/Services/Invoice/EInvoice/RoEInvoice.php index 43691d632d73..d01aae492022 100644 --- a/app/Services/Invoice/EInvoice/RoEInvoice.php +++ b/app/Services/Invoice/EInvoice/RoEInvoice.php @@ -34,7 +34,6 @@ use CleverIt\UBL\Invoice\Price; class RoEInvoice extends AbstractService { - public function __construct(public Invoice $invoice) { } diff --git a/app/Services/Payment/SendEmail.php b/app/Services/Payment/SendEmail.php index bb0872706dfc..d3551205ba58 100644 --- a/app/Services/Payment/SendEmail.php +++ b/app/Services/Payment/SendEmail.php @@ -18,7 +18,9 @@ use Illuminate\Database\QueryException; class SendEmail { - public function __construct(public Payment $payment, public ?ClientContact $contact) {} + public function __construct(public Payment $payment, public ?ClientContact $contact) + { + } /** * Builds the correct template to send. diff --git a/app/Services/Scheduler/EmailReport.php b/app/Services/Scheduler/EmailReport.php index bb06fdf69b2f..2351153bfff1 100644 --- a/app/Services/Scheduler/EmailReport.php +++ b/app/Services/Scheduler/EmailReport.php @@ -65,7 +65,7 @@ class EmailReport $data['end_date'] = $start_end_dates[1]; $data['date_range'] = $data['date_range'] ?? 'all'; $data['report_keys'] = $data['report_keys'] ?? []; - + $export = false; match($this->scheduler->parameters['report_name']) { diff --git a/app/Services/Subscription/ChangePlanInvoice.php b/app/Services/Subscription/ChangePlanInvoice.php index b732072e892a..6823bd62b7e1 100644 --- a/app/Services/Subscription/ChangePlanInvoice.php +++ b/app/Services/Subscription/ChangePlanInvoice.php @@ -24,7 +24,7 @@ use App\Repositories\InvoiceRepository; use App\Repositories\SubscriptionRepository; class ChangePlanInvoice extends AbstractService -{ +{ protected \App\Services\Subscription\SubscriptionStatus $status; public function __construct(protected RecurringInvoice $recurring_invoice, public Subscription $target, public string $hash) @@ -46,14 +46,15 @@ class ChangePlanInvoice extends AbstractService $invoice = $this->generateInvoice($refund); - if($refund >= $new_charge){ + if($refund >= $new_charge) { $invoice = $invoice->markPaid()->save(); //generate new recurring invoice at this point as we know the user has succeeded with their upgrade. } - - if($refund > $new_charge) + + if($refund > $new_charge) { return $this->generateCredit($refund - $new_charge); + } return $invoice; } @@ -125,4 +126,4 @@ class ChangePlanInvoice extends AbstractService return $invoice; } -} \ No newline at end of file +} diff --git a/app/Services/Subscription/InvoiceToRecurring.php b/app/Services/Subscription/InvoiceToRecurring.php index 8ba371a37bd7..240ed436b3dd 100644 --- a/app/Services/Subscription/InvoiceToRecurring.php +++ b/app/Services/Subscription/InvoiceToRecurring.php @@ -20,8 +20,7 @@ use App\Factory\RecurringInvoiceFactory; use App\Repositories\SubscriptionRepository; class InvoiceToRecurring extends AbstractService -{ - +{ protected \App\Services\Subscription\SubscriptionStatus $status; public function __construct(protected int $client_id, public Subscription $subscription, public array $bundle = []) @@ -67,4 +66,4 @@ class InvoiceToRecurring extends AbstractService return false; } -} \ No newline at end of file +} diff --git a/app/Services/Subscription/PaymentLinkService.php b/app/Services/Subscription/PaymentLinkService.php index d62e4f51a7c7..a87d3bfb6ceb 100644 --- a/app/Services/Subscription/PaymentLinkService.php +++ b/app/Services/Subscription/PaymentLinkService.php @@ -31,25 +31,25 @@ use App\Services\Subscription\ChangePlanInvoice; class PaymentLinkService { use MakesHash; - + public const WHITE_LABEL = 4316; public function __construct(public Subscription $subscription) { } - + /** * CompletePurchase * - * Perform the initial purchase of a one time + * Perform the initial purchase of a one time * or recurring product - * + * * @param PaymentHash $payment_hash * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse|null */ public function completePurchase(PaymentHash $payment_hash): \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse|null { - + if (!property_exists($payment_hash->data, 'billing_context')) { throw new \Exception("Illegal entrypoint into method, payload must contain billing context"); } @@ -134,7 +134,7 @@ class PaymentLinkService */ public function isEligible(ClientContact $contact): array { - + $context = [ 'context' => 'is_eligible', 'subscription' => $this->subscription->hashed_id, @@ -187,7 +187,7 @@ class PaymentLinkService } $recurring_invoice = (new InvoiceToRecurring($client_contact->client_id, $this->subscription, $bundle))->run(); - + $recurring_invoice->next_send_date = now()->addSeconds($this->subscription->trial_duration); $recurring_invoice->next_send_date_client = now()->addSeconds($this->subscription->trial_duration); $recurring_invoice->backup = 'is_trial'; @@ -221,21 +221,21 @@ class PaymentLinkService return $this->handleRedirect('/client/recurring_invoices/' . $recurring_invoice->hashed_id); } - + /** * calculateUpdatePriceV2 * * Need to change the naming of the method - * + * * @param RecurringInvoice $recurring_invoice - The Current Recurring Invoice for the subscription. * @param Subscription $target - The new target subscription to move to * @return float - the upgrade price */ public function calculateUpgradePriceV2(RecurringInvoice $recurring_invoice, Subscription $target): ?float { - return (new UpgradePrice($recurring_invoice, $target))->run()->upgrade_price; + return (new UpgradePrice($recurring_invoice, $target))->run()->upgrade_price; } - + /** * When changing plans, we need to generate a pro rata invoice * @@ -244,11 +244,11 @@ class PaymentLinkService */ public function createChangePlanInvoice($data): Invoice | Credit { - $recurring_invoice = $data['recurring_invoice']; - $old_subscription = $data['subscription']; - $target_subscription = $data['target']; - $hash = $data['hash']; - + $recurring_invoice = $data['recurring_invoice']; + $old_subscription = $data['subscription']; + $target_subscription = $data['target']; + $hash = $data['hash']; + return (new ChangePlanInvoice($recurring_invoice, $target_subscription, $hash))->run(); } @@ -319,7 +319,7 @@ class PaymentLinkService $old_recurring_invoice->service()->stop()->save(); $recurring_invoice = (new InvoiceToRecurring($old_recurring_invoice->client_id, $this->subscription, []))->run(); - + $recurring_invoice->service() ->start() ->save(); @@ -361,7 +361,7 @@ class PaymentLinkService /** * Handles redirecting the user */ - private function handleRedirect($default_redirect): \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse + private function handleRedirect($default_redirect): \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse { if (array_key_exists('return_url', $this->subscription->webhook_configuration) && strlen($this->subscription->webhook_configuration['return_url']) >= 1) { return method_exists(redirect(), "send") ? redirect($this->subscription->webhook_configuration['return_url'])->send() : redirect($this->subscription->webhook_configuration['return_url']); @@ -466,4 +466,4 @@ class PaymentLinkService return array_merge($body, ['message' => $e->getMessage(), 'status_code' => 500]); } } -} \ No newline at end of file +} diff --git a/app/Services/Subscription/SubscriptionStatus.php b/app/Services/Subscription/SubscriptionStatus.php index 90633404a51f..bd6de8adff9b 100644 --- a/app/Services/Subscription/SubscriptionStatus.php +++ b/app/Services/Subscription/SubscriptionStatus.php @@ -19,20 +19,22 @@ use App\Services\AbstractService; class SubscriptionStatus extends AbstractService { - public function __construct(public Subscription $subscription, protected RecurringInvoice $recurring_invoice) {} - + public function __construct(public Subscription $subscription, protected RecurringInvoice $recurring_invoice) + { + } + /** @var bool $is_trial */ public bool $is_trial = false; - + /** @var bool $is_refundable */ public bool $is_refundable = false; - + /** @var bool $is_in_good_standing */ public bool $is_in_good_standing = false; - + /** @var Invoice $refundable_invoice */ public Invoice $refundable_invoice; - + public function run(): self { $this->checkTrial() @@ -41,7 +43,7 @@ class SubscriptionStatus extends AbstractService return $this; } - + /** * GetProRataRefund * @@ -65,18 +67,18 @@ class SubscriptionStatus extends AbstractService ->first(); $this->refundable_invoice = $primary_invoice; - - return $primary_invoice ? max(0, round(($primary_invoice->paid_to_date * $this->getProRataRatio()),2)) : 0; + + return $primary_invoice ? max(0, round(($primary_invoice->paid_to_date * $this->getProRataRatio()), 2)) : 0; } - + /** * GetProRataRatio * * The ratio of days used / days in interval * @return float */ - public function getProRataRatio():float + public function getProRataRatio(): float { $subscription_interval_end_date = Carbon::parse($this->recurring_invoice->next_send_date_client); @@ -93,9 +95,10 @@ class SubscriptionStatus extends AbstractService ->orderBy('id', 'desc') ->first(); - if(!$primary_invoice) + if(!$primary_invoice) { return 0; - + } + $subscription_start_date = Carbon::parse($primary_invoice->date)->startOfDay(); $days_of_subscription_used = $subscription_start_date->copy()->diffInDays(now()); @@ -106,9 +109,9 @@ class SubscriptionStatus extends AbstractService /** * CheckInGoodStanding - * + * * Are there any outstanding invoices? - * + * * @return self */ private function checkInGoodStanding(): self @@ -127,21 +130,22 @@ class SubscriptionStatus extends AbstractService return $this; } - + /** * CheckTrial * * Check if this subscription is in its trial window. - * + * * Trials do not have an invoice yet - only a pending recurring invoice. - * + * * @return self */ private function checkTrial(): self { - if(!$this->subscription->trial_enabled) + if(!$this->subscription->trial_enabled) { return $this->setIsTrial(false); + } $primary_invoice = Invoice::query() ->where('company_id', $this->recurring_invoice->company_id) @@ -153,7 +157,7 @@ class SubscriptionStatus extends AbstractService ->doesntExist(); if($primary_invoice && Carbon::parse($this->recurring_invoice->next_send_date_client)->gte(now()->startOfDay()->addSeconds($this->recurring_invoice->client->timezone_offset()))) { - return $this->setIsTrial(true); + return $this->setIsTrial(true); } $this->setIsTrial(false); @@ -170,9 +174,10 @@ class SubscriptionStatus extends AbstractService */ private function checkRefundable(): self { - if(!$this->recurring_invoice->subscription->refund_period || $this->recurring_invoice->subscription->refund_period === 0) + if(!$this->recurring_invoice->subscription->refund_period || $this->recurring_invoice->subscription->refund_period === 0) { return $this->setRefundable(false); - + } + $primary_invoice = $this->recurring_invoice ->invoices() ->where('is_deleted', 0) @@ -183,7 +188,7 @@ class SubscriptionStatus extends AbstractService if($primary_invoice && $primary_invoice->status_id == Invoice::STATUS_PAID && Carbon::parse($primary_invoice->date)->addSeconds($this->recurring_invoice->subscription->refund_period)->lte(now()->startOfDay()->addSeconds($primary_invoice->client->timezone_offset())) - ){ + ) { return $this->setRefundable(true); } diff --git a/app/Services/Subscription/UpgradePrice.php b/app/Services/Subscription/UpgradePrice.php index c4cc6e3e81e2..2a3832469624 100644 --- a/app/Services/Subscription/UpgradePrice.php +++ b/app/Services/Subscription/UpgradePrice.php @@ -18,7 +18,7 @@ use App\Models\RecurringInvoice; use App\Services\AbstractService; class UpgradePrice extends AbstractService -{ +{ protected \App\Services\Subscription\SubscriptionStatus $status; public float $upgrade_price = 0; @@ -38,13 +38,14 @@ class UpgradePrice extends AbstractService ->subscription ->status($this->recurring_invoice); - if($this->status->is_in_good_standing) + if($this->status->is_in_good_standing) { $this->calculateUpgrade(); - else + } else { $this->upgrade_price = $this->subscription->price; + } return $this; - + } private function calculateUpgrade(): self @@ -57,10 +58,10 @@ class UpgradePrice extends AbstractService ->where('is_proforma', 0) ->orderBy('id', 'desc') ->first(); - + $this->refund = $this->getRefundableAmount($last_invoice, $ratio); $this->outstanding_credit = $this->getCredits(); - + nlog("{$this->subscription->price} - {$this->refund} - {$this->outstanding_credit}"); $this->upgrade_price = $this->subscription->price - $this->refund - $this->outstanding_credit; @@ -70,10 +71,11 @@ class UpgradePrice extends AbstractService private function getRefundableAmount(?Invoice $invoice, float $ratio): float { - if (!$invoice || !$invoice->date || $invoice->status_id != Invoice::STATUS_PAID || $ratio == 0) + if (!$invoice || !$invoice->date || $invoice->status_id != Invoice::STATUS_PAID || $ratio == 0) { return 0; + } - return max(0, round(($invoice->paid_to_date*$ratio),2)); + return max(0, round(($invoice->paid_to_date * $ratio), 2)); } private function getCredits(): float @@ -82,8 +84,8 @@ class UpgradePrice extends AbstractService $use_credit_setting = $this->recurring_invoice->client->getSetting('use_credits_payment'); - if($use_credit_setting){ - + if($use_credit_setting) { + $outstanding_credits = Credit::query() ->where('client_id', $this->recurring_invoice->client_id) ->whereIn('status_id', [Credit::STATUS_SENT,Credit::STATUS_PARTIAL]) @@ -95,5 +97,5 @@ class UpgradePrice extends AbstractService return $outstanding_credits; } - -} \ No newline at end of file + +} diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index d1b3d601c872..db365f1e8dff 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -745,9 +745,10 @@ class HtmlEngine if((int)$this->client->country_id !== (int)$this->company->settings->country_id) { $tax_label .= ctrans('texts.intracommunity_tax_info') . "
"; - if($this->entity_calc->getTotalTaxes() > 0) + if($this->entity_calc->getTotalTaxes() > 0) { $tax_label = ''; - + } + } return $tax_label; diff --git a/app/Utils/SystemHealth.php b/app/Utils/SystemHealth.php index 1db1eaacbbd1..6b60a7d845e7 100644 --- a/app/Utils/SystemHealth.php +++ b/app/Utils/SystemHealth.php @@ -102,9 +102,9 @@ class SystemHealth return true; //fresh installs, there may be no DB connection, nor migrations could have run yet. } - $currency_count = $cs->unique('id')->filter(function ($value) { - return !is_null($value->id); - })->count(); + $currency_count = $cs->unique('id')->filter(function ($value) { + return !is_null($value->id); + })->count(); if ($currency_count > 1) { diff --git a/app/Utils/Traits/CleanLineItems.php b/app/Utils/Traits/CleanLineItems.php index bf144823864b..9cb96b913664 100644 --- a/app/Utils/Traits/CleanLineItems.php +++ b/app/Utils/Traits/CleanLineItems.php @@ -74,11 +74,13 @@ trait CleanLineItems } - if(isset($item['notes'])) + if(isset($item['notes'])) { $item['notes'] = str_replace("writeString($this->getPaymentLink(), 'utf-8'); - return $qr; + return $qr; } @@ -111,7 +111,7 @@ trait Inviteable // if(Ninja::isHosted()) // return 'https://router.invoiceninja.com/route/'.encrypt($domain.'/client/'.$entity_type.'/'.$this->key); // else - return $domain.'/client/'.$entity_type.'/'.$this->key; + return $domain.'/client/'.$entity_type.'/'.$this->key; break; case 'iframe': return $domain.'/client/'.$entity_type.'/'.$this->key; diff --git a/app/Utils/TruthSource.php b/app/Utils/TruthSource.php index c4f732f34be9..fe294d0b3158 100644 --- a/app/Utils/TruthSource.php +++ b/app/Utils/TruthSource.php @@ -21,6 +21,15 @@ class TruthSource public $company_token; + public $premium_hosted; + + public function setPremiumHosted($premium_hosted) + { + $this->premium_hosted = $premium_hosted; + + return $this; + } + public function setCompanyUser($company_user) { $this->company_user = $company_user; @@ -49,6 +58,11 @@ class TruthSource return $this; } + public function getPremiumHosted() + { + return $this->premium_hosted; + } + public function getCompany() { return $this->company; diff --git a/composer.lock b/composer.lock index 8d43e5a2e3a8..4d08ab1ceac6 100644 --- a/composer.lock +++ b/composer.lock @@ -707,16 +707,16 @@ }, { "name": "amphp/socket", - "version": "v2.2.2", + "version": "v2.2.3", "source": { "type": "git", "url": "https://github.com/amphp/socket.git", - "reference": "eb6c5e6baae5aebd9a209f50e81bff38c7efef97" + "reference": "40c80bdc67a9f975ecb5f4083e3c84ef9f23eace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/socket/zipball/eb6c5e6baae5aebd9a209f50e81bff38c7efef97", - "reference": "eb6c5e6baae5aebd9a209f50e81bff38c7efef97", + "url": "https://api.github.com/repos/amphp/socket/zipball/40c80bdc67a9f975ecb5f4083e3c84ef9f23eace", + "reference": "40c80bdc67a9f975ecb5f4083e3c84ef9f23eace", "shasum": "" }, "require": { @@ -735,7 +735,7 @@ "amphp/phpunit-util": "^3", "amphp/process": "^2", "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" + "psalm/phar": "5.20" }, "type": "library", "autoload": { @@ -779,7 +779,7 @@ ], "support": { "issues": "https://github.com/amphp/socket/issues", - "source": "https://github.com/amphp/socket/tree/v2.2.2" + "source": "https://github.com/amphp/socket/tree/v2.2.3" }, "funding": [ { @@ -787,7 +787,7 @@ "type": "github" } ], - "time": "2023-12-31T18:12:01+00:00" + "time": "2024-02-13T21:03:09+00:00" }, { "name": "amphp/sync", @@ -1343,16 +1343,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.298.3", + "version": "3.298.9", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "70fde185df4a8dd99983a308b823991fb5b39060" + "reference": "db225c3a1c5dabfbb5071349cfb7e4c396c3d9ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/70fde185df4a8dd99983a308b823991fb5b39060", - "reference": "70fde185df4a8dd99983a308b823991fb5b39060", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/db225c3a1c5dabfbb5071349cfb7e4c396c3d9ec", + "reference": "db225c3a1c5dabfbb5071349cfb7e4c396c3d9ec", "shasum": "" }, "require": { @@ -1432,9 +1432,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.298.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.298.9" }, - "time": "2024-02-05T19:05:28+00:00" + "time": "2024-02-13T19:08:16+00:00" }, { "name": "bacon/bacon-qr-code", @@ -1717,16 +1717,16 @@ }, { "name": "checkout/checkout-sdk-php", - "version": "3.0.20", + "version": "3.0.21", "source": { "type": "git", "url": "https://github.com/checkout/checkout-sdk-php.git", - "reference": "4310ef994a663b925d1209f8c579f0965f5e14f8" + "reference": "0195aa0153b79b3f8350509e54a5654e57f62bd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/4310ef994a663b925d1209f8c579f0965f5e14f8", - "reference": "4310ef994a663b925d1209f8c579f0965f5e14f8", + "url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/0195aa0153b79b3f8350509e54a5654e57f62bd3", + "reference": "0195aa0153b79b3f8350509e54a5654e57f62bd3", "shasum": "" }, "require": { @@ -1779,9 +1779,9 @@ ], "support": { "issues": "https://github.com/checkout/checkout-sdk-php/issues", - "source": "https://github.com/checkout/checkout-sdk-php/tree/3.0.20" + "source": "https://github.com/checkout/checkout-sdk-php/tree/3.0.21" }, - "time": "2024-01-10T13:50:01+00:00" + "time": "2024-02-08T17:30:23+00:00" }, { "name": "clue/stream-filter", @@ -3455,16 +3455,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.334.0", + "version": "v0.335.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "5d2ebd6199b34b4b207eff2118bb783ae7b6f413" + "reference": "3e6cea8f43066378babdf00e718f01c7c55233fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/5d2ebd6199b34b4b207eff2118bb783ae7b6f413", - "reference": "5d2ebd6199b34b4b207eff2118bb783ae7b6f413", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/3e6cea8f43066378babdf00e718f01c7c55233fd", + "reference": "3e6cea8f43066378babdf00e718f01c7c55233fd", "shasum": "" }, "require": { @@ -3493,9 +3493,9 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.334.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.335.0" }, - "time": "2024-02-04T01:06:40+00:00" + "time": "2024-02-12T01:08:15+00:00" }, { "name": "google/auth", @@ -5326,16 +5326,16 @@ }, { "name": "laravel/framework", - "version": "v10.43.0", + "version": "v10.44.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "4f7802dfc9993cb57cf69615491ce1a7eb2e9529" + "reference": "1199dbe361787bbe9648131a79f53921b4148cf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/4f7802dfc9993cb57cf69615491ce1a7eb2e9529", - "reference": "4f7802dfc9993cb57cf69615491ce1a7eb2e9529", + "url": "https://api.github.com/repos/laravel/framework/zipball/1199dbe361787bbe9648131a79f53921b4148cf6", + "reference": "1199dbe361787bbe9648131a79f53921b4148cf6", "shasum": "" }, "require": { @@ -5383,6 +5383,7 @@ "conflict": { "carbonphp/carbon-doctrine-types": ">=3.0", "doctrine/dbal": ">=4.0", + "phpunit/phpunit": ">=11.0.0", "tightenco/collect": "<5.5.33" }, "provide": { @@ -5527,7 +5528,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-01-30T16:25:02+00:00" + "time": "2024-02-13T16:01:16+00:00" }, { "name": "laravel/prompts", @@ -5709,16 +5710,16 @@ }, { "name": "laravel/socialite", - "version": "v5.11.0", + "version": "v5.12.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "4f6a8af6f3f7c18da03d19842dd0514315501c10" + "reference": "ffeeb2cdf723b4c88b25479968e2d3a61a83dbe5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/4f6a8af6f3f7c18da03d19842dd0514315501c10", - "reference": "4f6a8af6f3f7c18da03d19842dd0514315501c10", + "url": "https://api.github.com/repos/laravel/socialite/zipball/ffeeb2cdf723b4c88b25479968e2d3a61a83dbe5", + "reference": "ffeeb2cdf723b4c88b25479968e2d3a61a83dbe5", "shasum": "" }, "require": { @@ -5775,7 +5776,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2023-12-02T18:22:36+00:00" + "time": "2024-02-11T18:29:55+00:00" }, { "name": "laravel/tinker", @@ -8024,16 +8025,16 @@ }, { "name": "nordigen/nordigen-php", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/nordigen/nordigen-php.git", - "reference": "1770384ceb8042c7275cb0e404d8b7131bdccc56" + "reference": "573a9935fc7444ba84d0cdd7dba46e033dbf7bd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nordigen/nordigen-php/zipball/1770384ceb8042c7275cb0e404d8b7131bdccc56", - "reference": "1770384ceb8042c7275cb0e404d8b7131bdccc56", + "url": "https://api.github.com/repos/nordigen/nordigen-php/zipball/573a9935fc7444ba84d0cdd7dba46e033dbf7bd5", + "reference": "573a9935fc7444ba84d0cdd7dba46e033dbf7bd5", "shasum": "" }, "require": { @@ -8073,9 +8074,9 @@ ], "support": { "issues": "https://github.com/nordigen/nordigen-php/issues", - "source": "https://github.com/nordigen/nordigen-php/tree/1.1.1" + "source": "https://github.com/nordigen/nordigen-php/tree/1.1.2" }, - "time": "2023-06-22T10:53:06+00:00" + "time": "2024-02-13T14:06:32+00:00" }, { "name": "nunomaduro/termwind", @@ -15831,36 +15832,36 @@ "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.9.2", + "version": "v3.10.4", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "bfd0131c146973cab164e50f5cdd8a67cc60cab1" + "reference": "09d3dc77d7dc1b063e3728a6029c39ee0fbebf1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/bfd0131c146973cab164e50f5cdd8a67cc60cab1", - "reference": "bfd0131c146973cab164e50f5cdd8a67cc60cab1", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/09d3dc77d7dc1b063e3728a6029c39ee0fbebf1d", + "reference": "09d3dc77d7dc1b063e3728a6029c39ee0fbebf1d", "shasum": "" }, "require": { - "illuminate/routing": "^9|^10", - "illuminate/session": "^9|^10", - "illuminate/support": "^9|^10", - "maximebf/debugbar": "^1.18.2", + "illuminate/routing": "^9|^10|^11", + "illuminate/session": "^9|^10|^11", + "illuminate/support": "^9|^10|^11", + "maximebf/debugbar": "~1.20.1", "php": "^8.0", - "symfony/finder": "^6" + "symfony/finder": "^6|^7" }, "require-dev": { "mockery/mockery": "^1.3.3", - "orchestra/testbench-dusk": "^5|^6|^7|^8", + "orchestra/testbench-dusk": "^5|^6|^7|^8|^9", "phpunit/phpunit": "^8.5.30|^9.0", "squizlabs/php_codesniffer": "^3.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.8-dev" + "dev-master": "3.10-dev" }, "laravel": { "providers": [ @@ -15899,7 +15900,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.9.2" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.10.4" }, "funding": [ { @@ -15911,7 +15912,7 @@ "type": "github" } ], - "time": "2023-08-25T18:43:57+00:00" + "time": "2024-02-14T08:52:12+00:00" }, { "name": "barryvdh/laravel-ide-helper", @@ -16507,16 +16508,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "85193c0b0cb5c47894b5eaec906e946f054e7077" + "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/85193c0b0cb5c47894b5eaec906e946f054e7077", - "reference": "85193c0b0cb5c47894b5eaec906e946f054e7077", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", "shasum": "" }, "require": { @@ -16556,7 +16557,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.0.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" }, "funding": [ { @@ -16564,7 +16565,7 @@ "type": "github" } ], - "time": "2023-09-17T21:38:23+00:00" + "time": "2024-02-07T09:43:46+00:00" }, { "name": "filp/whoops", @@ -16884,16 +16885,16 @@ }, { "name": "larastan/larastan", - "version": "v2.8.1", + "version": "v2.9.0", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022" + "reference": "35fa9cbe1895e76215bbe74571a344f2705fbe01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/b7cc6a29c457a7d4f3de90466392ae9ad3e17022", - "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022", + "url": "https://api.github.com/repos/larastan/larastan/zipball/35fa9cbe1895e76215bbe74571a344f2705fbe01", + "reference": "35fa9cbe1895e76215bbe74571a344f2705fbe01", "shasum": "" }, "require": { @@ -16961,7 +16962,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v2.8.1" + "source": "https://github.com/larastan/larastan/tree/v2.9.0" }, "funding": [ { @@ -16981,26 +16982,26 @@ "type": "patreon" } ], - "time": "2024-01-08T09:11:17+00:00" + "time": "2024-02-13T11:49:22+00:00" }, { "name": "maximebf/debugbar", - "version": "v1.19.1", + "version": "v1.20.1", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "03dd40a1826f4d585ef93ef83afa2a9874a00523" + "reference": "06ebf922ccedfa4cc43015825697ee8c1fb80f7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/03dd40a1826f4d585ef93ef83afa2a9874a00523", - "reference": "03dd40a1826f4d585ef93ef83afa2a9874a00523", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/06ebf922ccedfa4cc43015825697ee8c1fb80f7e", + "reference": "06ebf922ccedfa4cc43015825697ee8c1fb80f7e", "shasum": "" }, "require": { "php": "^7.1|^8", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^4|^5|^6" + "symfony/var-dumper": "^4|^5|^6|^7" }, "require-dev": { "phpunit/phpunit": ">=7.5.20 <10.0", @@ -17014,7 +17015,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-master": "1.20-dev" } }, "autoload": { @@ -17045,9 +17046,9 @@ ], "support": { "issues": "https://github.com/maximebf/php-debugbar/issues", - "source": "https://github.com/maximebf/php-debugbar/tree/v1.19.1" + "source": "https://github.com/maximebf/php-debugbar/tree/v1.20.1" }, - "time": "2023-10-12T08:10:52+00:00" + "time": "2024-02-13T19:03:14+00:00" }, { "name": "mockery/mockery", @@ -17488,16 +17489,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.57", + "version": "1.10.58", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e" + "reference": "a23518379ec4defd9e47cbf81019526861623ec2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e", - "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a23518379ec4defd9e47cbf81019526861623ec2", + "reference": "a23518379ec4defd9e47cbf81019526861623ec2", "shasum": "" }, "require": { @@ -17546,7 +17547,7 @@ "type": "tidelift" } ], - "time": "2024-01-24T11:51:34+00:00" + "time": "2024-02-12T20:02:57+00:00" }, { "name": "phpunit/php-code-coverage", @@ -19101,16 +19102,16 @@ }, { "name": "spatie/laravel-ignition", - "version": "2.4.1", + "version": "2.4.2", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ignition.git", - "reference": "005e1e7b1232f3b22d7e7be3f602693efc7dba67" + "reference": "351504f4570e32908839fc5a2dc53bf77d02f85e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/005e1e7b1232f3b22d7e7be3f602693efc7dba67", - "reference": "005e1e7b1232f3b22d7e7be3f602693efc7dba67", + "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/351504f4570e32908839fc5a2dc53bf77d02f85e", + "reference": "351504f4570e32908839fc5a2dc53bf77d02f85e", "shasum": "" }, "require": { @@ -19189,7 +19190,7 @@ "type": "github" } ], - "time": "2024-01-12T13:14:58+00:00" + "time": "2024-02-09T16:08:40+00:00" }, { "name": "spaze/phpstan-stripe", diff --git a/config/ninja.php b/config/ninja.php index 07147f9b62ae..c71db78427aa 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.8.24'), - 'app_tag' => env('APP_TAG', '5.8.24'), + 'app_version' => env('APP_VERSION', '5.8.25'), + 'app_tag' => env('APP_TAG', '5.8.25'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), diff --git a/resources/views/email/template/admin_premium.blade.php.enc b/resources/views/email/template/admin_premium.blade.php.enc index 56fe343c6a4f..3b6e5ed158f7 100644 --- a/resources/views/email/template/admin_premium.blade.php.enc +++ b/resources/views/email/template/admin_premium.blade.php.enc @@ -1 +1 @@ -eyJpdiI6ImxQL09xZ29ScER1bEtLbktHenNleUE9PSIsInZhbHVlIjoiMXE0Rk9LdEp1N285SzdqYXlDRmJycXlHY0xoTVF4eHpoTUN4L1ZXM2lIMTFVVjNpOHFIelFiODNzRTBEVllkdTc5SHNCUE5UVUN3R1hiYkxwcUR5V1J2SzJkZHk1bTR0NXNESitTOWFEaWZRTWF3NzZaQ1ZNQU5oOHJwc2Y5aDUwMTdVcXpuMWlURW1mN241aSt0NG9CK29nMVN6T3Q1L1RRVVVMMm5WMVJINUZHSEFRYi92Z21lQjBuL1h6OUZmOTRoSHNhZnE4N29WQ29hSWI5ck9FemxQMGdXY2dUK3FmSGRIWlV2dkhzblJYQzZmdWFISG9OcUFzOFlCY1B0cTd0VDBFNGpsMHpRbkl4dTBwYTVMVENNRVVMaEpkRnpHcTRNdytDQk5JbzNqbmV0M3RIV3phbmdWbkNQMXVBZ3h1aVkyUW5mMy80a0t4R2RxdmV0dlpXRFY2M3pmeWJnNk44ckZjdTJ3VEtRekNIdnRqbWR2UWxNT3lZQ1J5TmFHeU85Rm43QWhBMC9JMUpjcm15TVBZVzdmSmlBU0QxRm5CczFtaUpqdzRHQ1B5YlkwclZtc0trWHI0NnUyZkNMUHQ2a1FBdGx3VE4rU0t6MWxhQjAxMEMrNThKQjZ4QlQ0WWQ0QStzMFNHNGVVRXlKSVZYSjRkQ2NCRy84OEVXRkNUL1ZTMmNWRFMwOW5Vd1J2a3d2QVhTcUxEdFpURXIrVDRyZWJLbTdSOHpseUxCSHBBRVVaSnFEV0oxRHJuZU1GeUh4dVVLYnkzWHBUaitDM0p1dzQ0SVY3cE1YL2dQR1VxWWRkVVFHTGQ0ZUFVanhHYTBkZjlvamhEaHBlUmh6THdIMGhjNmNJVEZTdHhsN29KSjhFclNHNDZKUlJPMjRDa3oyaTdwRXFkTTQ0MGhoZkJnR2kvOGprbUVaMk1sejhNbDY4WkxaU0RNeWhnNGY2RTFmN1A0T3R0V2h1QnlXRXV6OEgyRCtPczFZMmhNcTdFYU9IeTBGaHRXVXBOSnFubXVsNjk4dUo1MGQyVkw3eGxqMzN6dlN4SytmaXF6eHZMMjkwSHNKSnZ4N3lReDM4UWd3T05rQnVMbEdmOW9zbEt4ZEI1V3phaUlkUUxPRStLUnhBdDlIdWNhUzYwV3N4NDhBVnA0MXJxWk05K2xFU1pmNDlWaU5mazVPcE5ScERyeUxqbzFheGk4ci9iL1hObXJQRXpaZVYzV3RySEdIK2djOTdIRGQ4cE9oWG1jdU96ZkFjNWV5QStYZ0k1cDgwOHUxQlRuSkJEaFJSVUR0V25ZY1VyekZDdHZqVHIvU2hxbjR5MVRGc3owL2lqbE9tWm9ZNHZQdVdtcVVrR2xTTDIyYzlGRWE3TXRCUHZPZkdYYkhuUEhTUDFEV3M1V3hLYkkrdFovbFV0QXpRMnZBK296VU02bmNSUWNOYTZYR3JsdG5GK2VNTG5weThmTHVuVURLc2tLYVNpV3IvZ2ROT0JLOWxyVnRBY1o2QnV1WWVkYkFvQ01pdDByVVpqbkpBK096cFZ0M2xLRm9USS93ME5pTEtmNUJMY1ByTjA4SERLc2ZkdXBUSmhUMzdGM1d1NGx6RDVFK0dpK1plYitoYW1JbGwxNUhRR2p6WmNLWVk4c2ZvNkI3emhOTDUrdmhsTHJvZWpnWGF6VGd6cm9Ocld6bDFWS0xKV2ZuMEo2QnVoOEpMdUl2ZHg1TmtBY2ZuSCtQSGVRRXVRdWl6M1lpS2pHaDlEZVVyb203VDgxNkVsK3plZTZGcmdXU2x2WnRlak9JR3dxZmdGcWRnYm5YNnhuQ1NTc2lXWEsrZFNzWkdMM3lkZHJJTzJFeEUzcjZUVnlYL0lSSTA1UDFJNXJaNVhiRW1xOTg3d2ExRzBMd05ZSXZoZFhSM0tQTUJnTzYwRnh6akZNdkpuUlBmWStWbDl2WW96UEVOWWF5TDZlcXJoa0xVWk82VEtQWVB5TGFQWEd1TjBCL2JwcjNkUDdqZUlCUm83dnVIRGk3Ulc3ZFJBWnJRbDNJZ3hzWnMyQ3hIMXk1OENxaW5vMkdEaXFYTmRzZzhYa3RGdWoyR1FvMk5OSjhEQmdkRWEwV29FWTVCSmxQUjV0Z015MVQ3NG5VY0w1TGp2VEJkRTlRK1JodC9FQzhJdkd3TmdxK1Jac2lDOCtock81SDgrblB4TlgwWGpGYklUS0ZseXA4a3YzZFRIRjNsVVVpKzhGemd3UGNUS0pLMmZBZktrRnlOSXNWc1BWdU9IVXRUOW1LZTlGU2c5Ym81R2hkSnBIU29Kdmhsd3NzTVdva05LZ1ZOaDVpaHdleFJOMEI4YmtyT0FkK1pMTVhocitjYi84aENXVSszcHVXWFJTRlpDWUY5Q3NCU25aRkxQdkdLWUhINHB1TEVsZVNoVEQ0Q2Y0c2U2Q0N5dGlZaTNsdHgwdVgyODI2M2NKUXN5YzdtdDhYaVhNV0dUREtEQmtWeWpaOVJjUTBtR004WmxIY2l5Vy9KRGtLWXNveWwvbFlSZjJhaDd4eW8zU3BrNzBoZ0lKZEdXUGN4M0g2b3p5aWQvRCs3T1lTdkZESjdCcDBKMStJb2J0WDIzaUFCem92NC9sRUt2NXF5SEtrcFQ1TFBmUDJOZ2F3WllzaVB4RHpEa0RYMTlpaWVYNHlSMUdEMkkzcGRNL04vZnVaU2dmTGZrTkx2SnNkcjBnWld6YzFjZFZ4SjJ0MWhCRkpNV2ZpN29rNkdPSkpYbTFHN243US94REFGNTUrS3NVcE9sMGg0QWpLMVU3V3pnQXNPSjMyRHBPUVNieDZkcTlZV3FicVNPcmZ1ZW5BOWJ6T1F0b2xLM2FhbjVVbVJHcTAwbTlyNXNXS2xsdTZzbHdheVRIc0RBamZORnUxeWt3bFZyRm5LL2NPRWoycVhmY1VHT3JQUGkvcmhMM0FLcWMvbi9EZm84eDhvUlNMTjBFWVpKaFBpVW4zaHM5UmcvQXBlRXJFZTRLU3lvMlRjYi83aUdVRUg1a3hCSHJWN2M5TnF2RFdjeFlGaUJtNkZWK0lmTW9IVjJETEQ0a2ExeVpmRGlFRnRhYnJPc0dHc3pUQ1ZWbFJsTkd2QjNjNnhBMEZSRk83RytUYWxzUVQvdjJRTDlrTDVrQTJCSUI5c0hPRzNqcC9iQjdZRUZNb2lFTHhaeHRmZGpxakxUTUgxanpiVzVHLzUvZlFhbjVwSHBiclB6YUEwRFFzTmdXZHVWZVVnTStnRTVUditkY3orbS9EKzh6WlcvLzAyQ3A2Tkh1N0ptTDVGSXlDUVYvN05ub1VZZ0RONzFxeHRYZUUxVWRUT0JGRjI4UzZBckhublJEdTA2QXVOb0dlSDVxT0w3a0RGNUpHVlVpd2pvUTQ0WFdHRnl0L3FvLzNuTHR6M1Y5Mk83OWM4Tm5tYXB1OTRBWUEzM2orMWVLcWdKODhia2RCbTUwSG9XalhvdHpPMnFLZjhKa0UvZ3dLUHZYVExveGZaVkk1NTFXL3ZLdFg2Rlc5U1p1Sm1LQ0F4R2hwSEF6Qk5KU2x3cVB6Z1FBcWlESTR5UkJTQ3NtRzMyc3hPMnQzVXo0Wk55QldKK0pjcVlLaE9uOEU3V2ZDY0NWSWl4aENQbllXVTRkTG9uQjk1clZLclFwZ1lScmZnL29UdGVjWXBhUDlnWE9wWWZ2bHU1V2lVaU5TdFNsaWpRVFZiaHByOXJkdnp5dS9oVWh1QkdBL2w4SWZ6cTg0Nmw5QVEzWG9qdlVhNThUeSszdGJzWDlWd2NRWG90enF6RFZEQitDdlhtUmN3OEJYU3JZeUt0SUpyTHpNb1A2N2Q2WlNIZ2VsTlpzcU1XT0srNzJiVHNUOXRDYytkWE5QVUV3a1ZMdm5oSmNUV1Z5MW5JcnNOQnlhYW13TzFaenNCdFcxSkhGc0ZsRHc3YTE5SDdoUEFlUEFxNVE4ZENkVExaRWFZbVNlMDNEWnlDTVZkcjRMaWtZMXp2dm1tSjhrcWl3NlJ2MjJUN2dDRXpLZVVUSkYzSmJSL0tuZytvUm1CWWtZTzd5eGdhaG1pUHUvK3BzdnR6QTJkN3FQNmJyRmNwc0VjUktOVnBwWDFscXNTY3NBRGhNWituMDQ3TW9ObzNXbk1iNE9aeDNibDhiSlBxZlo2ejc2T1cyNGdMczBxNG1PUUp0Z285WUJaTjFtaDA0N3lTT3MxYnRYa1hXRzJzVFZ6d0FVV2c0M1Q4NUY1c0JEclZWWmtpdldZcHo1cW80dmovNnlnWUkyVWVndnBKL21hR3FXd0k4Vlp5OFNTWmxDWnV3WDJDaHRyMEdtMUpPK3lRUENKWDhzMHVZdU53WGFTRDVpVjZhaFV0bXBUYUNaa1JrQ29FSkV5aU9sMUsvU2hwSXEwdU50WElvNE9oMFVSMzdHenhuVmhsZFZoVnpRdmVOU0wwWGhzcjA3N1RFYVJPK0tqMi82c1I1ZnhqYUlRZXBNbXFINk1VSU9xOC94VjFDeTdwSUNabnl5cDIvb3dDVkQzMkJob29UQXNLK0hybkZobTVIbzdTS25sbmJ0ZExwYmdGdEhIbnAxa3d0YmgvWHorbUlGZTJXc2lxcWRUcCt3UE9XR3ZDVHJsbEs2S000eGNZcXMxNk1iZVRJb2hWVHk4bDhQWHZsOEsxZlI2QmRBUUpUZzlFTSt3QUNYSSt3TzVNVkF2UUozd0szckJDYVQ4aHpkWXRQL3lCN2dqQnhENzFoVnVxRUNNeGR6MlcrSlJNZ3lHOEpnblJPWmtucWMvU0RsdjdXZ3c5aTc1eFl4a3lvZkpZVDFwK3RHNFJwejBQNzcvWHR5YUR0V0xzNHFzTDBlOVdUUVQwVzFyeFUwd0JwRmxCdCtKS1g1dE11VDV1YmpScnh1ZzdocUg0K2o4Tm1ta0o5RnEzMjA0N3Jsb05yZVQ5TS9IM0d1WnpVVFgybVdxcllWOEducFhxMk9yWnJPQWh5SDdVRFcyTnN5cGZrVDgzbFNldis5MEhkc3NQL09lSFJPSEhBRFhGNjFOSk50cnpuN2hWc2tTK3FFU0p1NElwSjhoV2hDUTBTRlFpeWVTTzBrYjJQd0hmZE9mMStPV0J0NGljV2RYaEhQUEJVMEVFejBhNWN6RmxxbFVPMVBNQ3FIbTZ3TWhwUWpjbmM4WndMWmxMdzNoNktQUW5uYjJTRk1mVi9rVWpHSVRrbW5ua2JtTXhUSHdDd1JCeVNyMU1VQTgrR1RFSUhHbWdXUDdac1VhdDVhTjZFWEtWRlNaelZ5UGUzNUhraVZLdFFLN2prQTRHNFFTckJkNmxlcS9qSCtRUVZnRHk2YzVTZ0gyK0NQcG12aTlYanY4NVRnY1NrYThuZEc5cUw4T0d3QWZBbFgwVWMyQ0ZVb0hKRndvZFFmbVVrc3ZnTzk5alo1ZC80aVE1WVNMang2Q2dFcm5kVHl4NXg2RnJRNk8zVXJCaXhJS2pBdE16QUMvOVFBdFhsL253SU9vdEdXTzJJOHR6aWd5MDRoS1dUSU1aaE5WaTBzRlRWTUpoK3MySS9odzY0NE1YUmlwOGVGSkg0WmRJOGJENFJEZUc4WWpOdDNJWm8xcndHVURyYzdKeVlTVXVJM3dsdW1CNStyaTQ1aW1QM0FRTGFnaForNk5xeWNpM01HUkJHVTZWREdCcVQ2MklhQXhnTGE5TG1GbE5uRHFma013ZHRUbGU3K1BkcG5Da3pvQWkwazdDK2pFcU1MZ2ZYVEVXcnBqWVMvL2VUZEVGRDhEamtBTCtKTURaR0dQdVRlL1A1Z0w5bThRd0dDQUUzQVQvUm9BSWZITkxEckxlbjRDMDdINXZTVGU5eDl3SmY3Uk11eGxaOWhrV3FON3drbXV1TU9xbVRYRkRnUjFkaXo4UkVzNXU1Tzl1eUF3dCtlTWlWRjQwN2U5dnNPVmF1SnFQV1NkK0xUZStGRThBZHJaWVM1dlR6NTlHYjJ4NzVEU2xDd3g0OW9HbUtSYmZmVnJJWEtaNEdiNThhV09lUVhqNmNoRWFwdzRJeFlsdkI4Vjhpc2hscjZhY3JvMVViYmpSMU11b2FiY29RUk5lbmorUHdFY1p0M2tLQ29PTGh2UmdzQURtZEpEalFPeHNLQzQvNVFnelo3dWNSL2VuMkV0dUVqbVdwQXkxbnJjV0xMUHdIQ2NPNEQ1RDFWWDFnWVBxOGc4V29JZU43SG91dGtDS2dpdVViNisySlh4OW1KRDlPU0tsNS9IWWpCMDJHb2VlNWpCcHpXSDlLMHFJQ1FwTHo1OE9LOGppbnFQOW13aGZsY2F5MnhvZ3FzTmlMelhVUVZLUktZYXpkamw3dEhwUTJyZXpRbm90WER6V0FtUlFSdGo2K1VjMG5LVHk3VTQ2QnhFaUIxbGd0dk1RZkpKZEZQWEt0ZjlqYm5pZkZLc2t5dXAwU0R1MU1KUWl4bDJTS2V1OVlrQXAzbVpXOE01a0htV1JSR28yOFZQTWRwQjhucFQ3V2ZTaVBRNlhzRm9vbFJzYTZRbmtrKzhOaHY4Y3N4TTZha1R6RkFTY3BIWGM4L1M2dnBpdnNLWktVZHBJTGdDbXNpM1lPTHF1cEM0SGJiekRWVmxoanI1Q0lKakM5aXNzQWkxTnlkQllPU3ZIRU5JMElnTzVzaWQ0SnhjRkRBelNMdklzUXVkMllrRGtIdVErZEV4NTdYaGZSTE85NU55THhkR0NNTi9sRVp2VjJSdmxFSXJUNldQNVF2NkZBTVVDdzY1ZEhqdEFyTjhRQTZVakIySFFoWEZ4TTZ4bkovbUVHUVVXY3NqbzRvdEswS1o4YkZiWWtmMEtqSFAwYnRZRGowc0NwRWJxVzV3L2hEM3lmZkdkSThtSDJmNkdUTFh1U3hTNUlSNWVjU2RJdlFvNHNSelZsQjBQQzllMkpKU0M1YkNkVVJWSEpJb1VnYnpoc1UrREZDS3BuVnVPUTFHa2NtMnl3Nndndmk2K1ZDR2JlSmVpYllWWGVaTEw1UExnc053aFE1b0lvU3JyM0pFTlNnNFlESys3N2E1ZUxjWTZxRjlEWi9DU0x4ekU5RlVKRjJHbUxZNHFxN0xjaXVoVitWanRpQXVNVmZ2YmtMNU8xNldDYXpYQW1ibXBUd09FS2NuczgyZUFPRjFWWG9LdlZ0OTFTL2ZHSGJqZGFUNVBuYTE0SWx3d3JPUTNxVlZQSlFBY2M0OWRRR2czRkpEYXRaV1QwczhTRkNMRjd3OUwxVWJ3OTgySEtvaHFuSnlVOW5VRWtVUnlqeHBQemVPRjhJeVJReWdoYTlGNUUrb0t5QkY3ZHNtdDJyTUF5QkFBU2dIQUpZcUZCbmpRT2xadmN2VFAra2dTZ0crbGJWeWNISEFua3AwbnUvdWdoZFZNNWd2S01QQml1MDZuQWlUcSt0Vk51dlZuWHkwQUV4elR3NlpPUmp3a3QwRk1OM2hGQVpnRm1sSE44dWFTZkplRnA5aHpMK3c1NGlXeXZUbC9leG9nUFZzT0JMVTlpOVZZVmlhcGRhNWVvUzdrb3kwdlNRK2pLZXNDUk9iVWNmSmZMdXhPaFczVEJTdUtURFUzaEFCMTg2MUtpU011SWV0S2YvVFZJY25kQ3JnQ1NEYkNnMEdDVnpraHJsaWpjV3pOeW5udVBLSC9nN1NBNVp0QW9mMktPRTJhelBVREJLVnFuMTdkN3M5S1UzbDEyenlpMC9wa3Y1d0RJS0duQU5icktPR2ZHd2VmcXlwQ2grbWFLSmkrWTQwU0pvYko1R3VPOWlPZUxpdml2NlBBdWNuSStPaHo3R3BQK0NrZlZQcVQrOFV4K3JYUno0Q2YzUk1KeWVHWkdMb1ZtNGdROXV3QkVTM2RLSFdVODJvYVovTktjOWNaZi83YzEzejZsbnY4VzdsMUY5aDFOSjZBdHhkL0owSzYwMXMwWjlxbHc1OTJ4MXZRWDdaaGRHNUpqKzAreUE0VGlaeG5WdkxlMWNvL0wxNzB0bktvcDBSUTA3bFlsc0Vpd2pncEZTRUprZUFjRGpvY3BRd3greXBIRHN2ZFFjUWUxaEZCT2RYdFhrVHdkVjVCbGFDcWtON0YrOVQ3OFl1bUNYdDZhd2RkNEhXdEF1TG1VY1RuaTdUWXZISWQxQ2tvYjVmcnJyU3BOZVd1N3dNcUJGYlJPQmJFY0FkaGYwMUdXMkRqa3Bxdkg2RlZDWnhISk16VHF0Rk1SWmd4S29TMWplaS9IL3lwa05YeUkwSzUvNHlLVmVKclU3SGZCbHhoRTIrajNPcDA1NGhqWFA3cks4M0hGdHhLTmF4NUovUGk5MFBSdnArSVZCcU84MVNQYUxhdzl6NmREVGdrelo1dTJUY1k0QWtJNGt4QUk2QkRncmQ2QzFxQS9mdllvNVAzUWdFQS9RWDdlbTkyc0RaT3hEdW5UbWhMdFJCdEpEMXliY2tYdWZUSDB0V1hSK1RTazFNWnBsQUtrNXBXL2VxTFdzbXpKTEVTOFZ4ZVp5WjcrbEEvV2Z2MTNLZ1QwTmZIMGlxcFRqN0NNSmdLTTFhVERZZFBYU1l2VXBKS3lJL3lCRXRpVCtZMFZiTVVJT0gvd1ZMU0VWMGp1Q2s2YTB6NVhVeDl4bjlRUFVxRXdBUStVNnBpcDRvOWtQZVlBZmpWS1pKNzFjU0lJWDA3S3R1d1BaVlRYUzZiZkFiNmJBVW1jZzcvMU04Z1JudmorR2VQbXhvMXRlUzZuU1BWeXl4c0R1UXZwb05UUXphUUxVWGJMOVNpdXE5b3hRNVltd1F6NWpjaldJOVo5SEkwenZ1amJaN3o5eEdzVWt5dUpUSzVveFZzcmV2ZVBtNFdIRzRwK2dIYm11S1JrR1BJTUpYK0xPZndXWVNUREFpMFBIQ0tuc1B0QmdMME5jWnZqcUdxcjF5WUtNNFMwMms2bjRQcUZGZHFybzV1Q3FSQWo0bjVmMExxeGliNlZPcWJJUDEzVmNsekYyd0VIZi9HejVVcFFLUitHcXZSYzlHa1Q0REFRUHhrOWRIb21ZN2lKZFN5VDB6cDR6NEJkaWtkMDYrOFVyWGJaOVFSRDNZU1EvWGdacW5sdnl2YTBiUTlYS0Y1NDQweGszMkFUMm9NS2VuWFk4djJaVFdHbmxlQXZSTEkvUWt4VUNQMUZhaDY5bjAxMHBRd2tXM1ZaSzY4U1MxdTVEMEdvYUtrcUZoeXpqSmRTMXQ3aE4rcGtDc3BlYW5IOEd0Zmd4dTA3QzAvVVBJZUVxZkFpUng3Q3pQb2czR1ArQkV3SU15cGl5SHd2NzVhZVArQlBQM3VhQ1ZxbnVtcVpYOXByQkxhcUpzUjhkT2lxYjlScXN6Y2h3UXFVb1pqNkUzT2FjUHh5KzVvQ1JHeU9xQUtJNmVUell0dWRudWVxMDcvTU50NU4vZFlCWXhBTnhRQW4xbG1uRkdJNnFpVW5meDZ0VStzdW1XSGlDNkVoajE0NC9KL01KeU80YTZMd1NMWVo2czI2OHFkMmpoUkYyZGJrTSt0dkg4eHdtWmdhMG1xbFN1WGx4N01Wak1ZU2o1MUtObXBFVHhESkNuTHJFWGtQZ2x6N3Z1UEJIaDE1bXNHa2g0V1NyVU1nT1lIVnVvN2hxMWNUSHNXZkxHV0c2cDdVNEpHckVXQzZtd3dSTU9nUDRGaUVuSEZhSVNBSC9oK1pVS3JNN0RERkFCSkQxNU81ZHYwdWRQNm93NlVBWDZ3Rm5vUzdLZWlpSzBKWjRzeVNLcVp4SUJvYzBRQnRFY3dEbVFTN3ppLzV2dWFuRDZ4QmFOVEtmQk5wblRTaytzRHlENUdWc25EY2hZbmlmcmkwTE9xbE1aV0JDMjFZTEJYOWNzSGhrelcraUpnUGNZOWRwak42NWp6TStDbldCWXlpOTRVUHBOZjVTMklFMlJRZlRyam1rM0tQbUx2Rk51WjcrVkhUNldIa3hzU3JPNnVmdUlMdGZ4eDBvR040bmtiRkl1NUZNR1VOL2Vtalk2NHpWL3ZPb0srdURmM0VJSlQ5K1BvNmhDeTVpL1Y5UEE1cW5DaVFqOXdwZ3NoMG1VNmxkTU5peS8rTmw1Rk1CQzZpTFZNSFY2ekVKQ1l2S2lIRFRPZ0FsOVQxeHEyS2pkdTF0MDFvRnJ3K1lYYVdqWmtwOWs3a0NhcmJaRHNMbXo1OEoxK1RydlgwS20yUERzRkVLN0xpbk1sblowUmErQVR4Q3lJdHZyZW5zMTUzRm8yQyttUFVxMXpPOExpWXBteFJYaitFTjZmYzBzZDMyK3Q2YStweURWenBNQ2l6aitVREdBU2NuVVZRZk1VZzJ3dTN6L051cTc2Uko5cVhIRVY0azA2NWFFUjZSUW0rMWU5Tkk2WHJ3ajFKNGg0STkxU0JUSXJaZjJycExzKzU2a0dIczYxSTJtZUhnTG81Z2NBV2JTbDV3WXVDL3MvVjFiMDU1N0t3Skd1aTZKVlFLWHpqYUt4Q0NQeFczSCt6Y3krcEs3N1RsSGRXcHBGTVZHVVBZZmNrWXAwcFl6WnIwcFlMZFh5OG9oOHh1d28ydDY5UCs3cGpZblIzU296QzY5OEhITFRkeEZMNU1YeWRlbkZ6Z3ZRSkJwbmkyaTgxU3FHUHgweEZ4WG1CcXlTNGFNRGRsZ0Y0ZmdrczQrS2g1RDBLNEtUOXA3YjBmMmZVZ3YwZGM3Wm5rc0t3dE5FclNBbGRqOWxqZnpaZXRyTFNybmZOcjFhS0N6b2N2dGwrb1R6TGdoY2JBQUI3aEFvL2o4NllORGJIM3NUcHlPekQ0aU5jcEpIcFViemJJd2ZUR2JwY0g5QXk3SkVtNlVEOWdsbG5tSGdHR3NNY1BQT3NkOEJuMzVFRmpqc1ZzVmdjcFZKbW84Rm5ib2FxSi9ZdW1OcmppcGV2bTRiODBtL01PWnJvUEZZTkJsUDZEdEhmbUFoU3R2ZUkyMmZpY3l0SVRYVmprODlNOHdHRVVkdGxYK2xVVGF5UkJVT2xMeGgremVpSnBpTm8wUGhMUWtLd1ZVRkJUUjJ3VmNLeEdraDFMd1BZOFNGMk1ZQWNHQ2VoTnlJcVc5amxFTlpyUGwrbmhhdUtIcEN3cGJyMmxEY3N2Vml2VERCTDR6cnJUVlRDT3hxQlpjVjBSclhLK2NNZEdQOVAzRU9vb0diWjlOYnRWTDJHT0JDVG1PTnB5R2JQckNiOHJVSXRmQzRMenVzYXhMYUF5NUEyL09RREh6aFNOMHhxS3F0UUI2TVRXWXdtRGVjUjU2b1FYbmpMZnkyTFhuNG1CalNnampmb0E3NVlWNC9jLzlYZ0R1TlRSVEVZdS9ZaUJBSnJxUVdaSUgxZ1FTeFVJS3RoK1RmeUJQT0xpaHByd1lQaTZFek13bEtrU2tyTU9PUmxrZ1ViM3ZVa1JCcHFnS2VJNURMcDNsR1BSc0p4NWFQUzdSVkZOVThGZzFSMThXSGZjSlNQQllaWUdmVHlGN1p1OE1MZlRQYmFwaStMdk9ZSVk2QzhMdlVVdnlnbkVJYTVJdFVGMU52T3Z5Q3Z3RStHMU1MM3AwcUdYVFgxT2ZFZEhKQlE5VTZra3BBRnhBNVl4UFV5QnNLN1RJUm5iOFlORFFWZjN3cUZPNkxZbDlmYSt5THU3RHBSZGI0c2gzSDRQbG01am92dW5jUkFHcWNaZnV6UnVIam9uVmY1NXVvcXl4N3U4NzZxUXhUZm00TlZsT0ZVUHNnTEtLNm9RR2dCM2tGWUdaSDVNelJMUTZtRE9mUHYrQS9ycGpYTUtqWXd5dVk1TEhKTkU4SVV4YlB0TGIvVk1aNWROOThGdFlLYm43N1pIOVFuYW1WNVdGYVBlVFphOW9uNE5jMStIbkx3bGtxTXdUNVB3ZkdDSVZpUlI4T3VxRkRldHFHY3pLaDhqbEVMVTNXRUs5eHBzVDVRZmlNSFRDbDkvekRTQVU0Q3plUURHRkxkdTU4Zm44aVIrM014UW5oMjc0ZzdjTnVCNUV4RG92Zkw2VmYwUTZxSWpwWFlwSEMzVmd1clh2Y0F6c1ExalZWNU5CTzFPK1RLaUpXQWJ6S3NVM3haQTNja2ZrNG5uVlJZcWpGRWxzdEU2SjkvZHJJODMzdVVtOHNLZ096QUdUQ0E9PSIsIm1hYyI6ImE2MGExZDgwZGE4YTAwNGMzYWI3NjM5NGZlYTE1NzlkNGVlZDkwZDhiZTA4Mzc0YTk5Y2M5MzVkMTk0MjdmOWQiLCJ0YWciOiIifQ== \ No newline at end of file +eyJpdiI6ImZlSVRDdGcxMFhqTEppdkVqTWh4eFE9PSIsInZhbHVlIjoiTlNzWFRXRlkvc1BFL3hiZnBzbWZqblVvcnpSRzl5OVdodTF6UUthd3RaWXRiakNiYjVlMUR5SlovNUR4cmRvdW90dDBLNE85RFRhbGc4VFh4VnpDTjRvZTlCQWFvZldwSkhDQitMUExZOXZWVEJlK1hWMjJGbWRrUFlKQ291UXAyWnZxTlpXbFViMlpYQ09OK0pTVkQ1NVV1MHdzMG9iWTE2VHhhMCtRK21HbGpheGdVNGR4TUorUklWcGlRaGFFLy9UQ1doWFMvdjNkVlMrNWVrb3B1NlQ2VHBqWjI0U1B2eEwwV3haZFNmbW5pVE8xcVZKeG9zdzlKTkZBWnE3b2g2b0lDS0dvbjh5M3haVDNyWVY2cnRFZERDS01KRmNXeTY0VWxIN0RDa3VZemZabnJ0M1BndTZLci9qREFtZmtZUGZDVWdFVjcxeDk2SUNTTmUwekpQUnIxajBVU0x4UUt4SjJiUkVpeUhiNlNxQW03SSt5WWhDRFlwc3JBTEVBMUo2NWN4UGpSYWpkNDFVL1RHU3FDY2pMY01nSUhqMlk2c1p3eWg3VTc3WTFhL3dFcWJBMyszdDcyQ3U0K084T2VIa2E2dTNJQzRFVDNmeXhVck1zbEptN2R0a3NTQk9URkFpbVUxWXYyekZoNUxWUG9OZDEzenljNVNDQVY3N1pNRXhWd1NEV01ySnpIaUFaSlg5dEhxait1ZFkzZmJad1l2QnhrckFDQ0gyMW14OThJNFlFUHptWGRVN1FDdVJtdnlYZ25ZbWZtVnNFaExjSmZGZGNBVlhOY2pyRDlzMVZzVjFKQWVMdGt5a3NEWnhaTDVVblYvQ2lWcWxLYTRBdnVhd0doZ3piYXhERVlwVmJoSGlRTW1TUzgveHNLWGZPeDJ5TEtNWmwrQjNSQWZjSWJkZUc2aDdlT3BKMHdibGdPN1hZbjR2eDBnSUFTRGszWlVKc2ZLOTZmOUd1eFdBRytxWk14REVianJheGhFUEZjSytLYTBUSWdMQlNWaU9PQ1VXMk1BZmVVc2lyL21Xc3Zxc2dtM29IaXFKcWxXU1EyTWROeWJCZzJnSEkxeGtVTnAwWWlROFpJakFqWHdqdkdTNzQ2cmx5MUFKemR5Q1JVRFYzY2xPRU8vRDRWbmpwSURaQU1vNnAzc0lKaTJqRmsyTzJXYUliVGhXcUhUOVJNalhKLzcxQWNjVDhCQ2dKTmVFeWhsSE93cXJXMEltblVaS3RLSkZmM3U5TzlQMUtkUEkvSlJTQ3FJWktXUitJcWY5ek1UbzNjTUR1djlzWkc1WGxGUjVNQ3BlVjM2YkZud3RJSTloZ0tmL0VEYjhkNGc0RmJkSFdZeFIxK1FLWjgrSTBuZDg0eUlpRHR1QjJmMmdlL0Y4YndnVitIVDRNYU8rNy80aG1aYU1LOExPNk04SHVxWGZpZSszMTJybFBrUHlrZlBnZzRrc2VpTTFRRzlwakxvZ0YvRjd2NVkydzdJdWZsNWVVd2Q5NFFXdUw5bmRSMEQzdzg4dXBlZ3ltQTUzakxmZFRlTUNWNGJydzE3N21qbjA0WDlocXZ5dWZHMzJSNGZ1YTF0NjlFcmtkeEpaY2Zsa0FsQnlxODZBYkpGc2RLWC80WHVEL1oraERwS2p0M3MrNHd0R0VoQ05lTWpRV0Y5UVEyYjVRVjAzSWZZN3hwbExrTi9DbjlJZTFSMDFqUDhmV0hMTWp4Q01sZ2tKYXB6dDJ3d2duaXp5NFBucW1UdHVVU01TaEZDeFEwWFF4UElWdEttWGtaUG8wK2dwaVMyRU1GTVIxZ21PQmwzMWhKVnZDbVBWKzNiTW1CbHhxZ0FMWTZGY2ZrNnc0dDBaYXRsTk9pajN3dUt0QnlibG9NeUFsUE0xa3JOa0hGcTNuQkNybEJsNmtnbzJNdFNBek1zeG1KNE1neUtPYWtrQlQyOENwQURKMDBIWU1DS0xxenFpalJMM2RqZjI2VkJIU1dzOFpBbERjMVVQeUhzRzNBY2JwZDBieHYrL0doNncwL01YUjZFTWk4UlNhVHpRbCtqeStCOEpBakswZDV5YTNvTTFuOW1ON0w1QXUwT2NYdm1VdVM4R0EzTXlHaXMxTWRjcXZyVDJCVmpyOHJxY3YyT055WUJ3QTVnYVhYYUdkNmYvK1VqZ0lYTm84bDZBVlFIOWhiaDZadlRSVnIwbXArQU5DdmlPRTM3VjhNRVQ2VUk5V1hhRVp4dlFINldWY0MzSjc2UGRsSkxBMDBxTHBXcUdSUmpYTHg4Uzd1K0tmeCsrOGlqM1JHeWtpaUNyd3QzeGVRZC9hYTBQdXgxUjhMK2VtOGtaUkVmN3ovQ0NiMFVTWjJHL0hzL1RlUWJRMklHVUtqK2x6QXZWZjBwdytieEs5STNmaG5mekloTldWOVRHd21pdlZXRWUvakpwazZ0cUtrMFF1dzYydzBBSXFMQytycEpDMjM0bjlLWUYrQXQ5cm1aUGdDcFJsZkR4Y0E2QUNmRTRwY0kvdGNFQnl5OFBMYnl2eHpTOGh2Y2JUNEg2Ym94K1FUc2NXS3NPMU5McEdLcGw5cCtYdTZEeUFRUVZzcGlpeGNkbzhXUzNzWnYrMW90MnExVndPMXJ5cEwxWGkwUGlYYTlqSmlYeUpGVkhWc051amUzeDcvcVdqaTZTayswNTduNWhxNkd4SllxajEvTS9rTkMwYjJNdWs5Z1lHd1RoYTVPZmpud3ZoN0hoM2hDUmx3c0t0bkhCN0QwWENuQ3FDbmlXeDB1WU45aGJaWm1rajVDa21LMk9aZVNwOHU0djdqOFhueisxKy9BeG1vbE9IbmhFZ3k3TmJja1IrcUxDSm9aS0JMYkVnbWoyd2J3NC9KSUw0NVpZa3FzeE1Ib1drK25POS9nd0g1QXNtMGFhR3hXcDZzMTdGQW96SkIzVHFlUVo0RWppTTFlbzVCeXRuMDFScUROY0l5a21kLzJjdWQwc2lqekY2NVFNU0VFYjR6RU0vNmlIOGpvRzRsbTZKL2hzT0R6MnRTZGhJUkVrbk5OKzNWaTZob3kwZzFyV0VyK2xnZG41MWlnSXN6R1hzQXpyaXYvY3VQeXc3TmNMMnJteDNUclM2ZTdpTHFJYmdkRFhsUHRtRmh1bkM2V0tJdkNaZ3VOc3djSktISjBOMHRIWWJTRHdhS3hoWTh2Wk5Dc283c0UvNnpUYTM3MlBDcGk0dkZ3eVpMSVlMMEFRVVRJQXhyMkVsZVc0azdwcUk5WjJjdGI3WUZpMm9BNGd5ZzBIUksyYUFJOFpVRWd6Y1puWUdnN0ZWNkpoVnp3Y3FaK0ZZb3ZGMVhDWitXbm5seUlkWFRHcWtYNnkzeVlwSHBUVkhRYkxMdDNPam9lUE9WaU8wNjZ5a0xTMmtYdHp2MXFJZFE1eXRLU3Q3NFN6RDZtZ1hTZXYyS2VaWTBMaUJYbVJOdTBlc2twZVRDWWw3VkdKU0lkZ1MwOHQrLzMyY2kvVnpQRHgxNjJXeC81Z05sWTBSRVNmV0lKV2FRY3NGQ0Y3V3VTTkpYTThaeVpocHlRZzhMbW9mSnE2U3dSU0FFQ0lIVVE0dDc4SjdndHlpc05YeWphMEsrM1U3SVdxMk5sQks2L2xPKzdFbWdVMXhWR1o1SmIvWUpwcVZkdmdmOStOWVMvOWpQM3FCV1Z1OE5hMDZpeEhTMVlIeFNmQW9mbTV5MUxyVXB0VFhxdk5sZ2dFbkZoYWxGTFhuaTRVd25yeVNoTS82OU53ajRyRnNGeWJHV2YrUjYzbVZNQkNuS3RTK0lYbXVvZGdRTS9WQS80VnRhQzhiUzlMNjByYUhVOVA3SmZQa05WUDVLTk4rZnJTY0dSSWwrMEJhQnhVZ3c2MnBSakJkMGFlWU9VNFhPWWgydyt6eUVhRVByOWk5WHp2VFhnckRuampXT2IyNjM2U0QxYStBSTlibDRNSlhmZlFoL3JQbXRrRHdrdGFLbWk2a0NDNFEyTXI3ZW1xUUlrU0RwQTd3YVg2cWxvQ3BJNlBabFB1WXlTMG10QytaMWtUalNsc2tBSzlkc0VjeGwyVUw1eHN5b2hLYTFYaFZHQVNzdUJoVjBPZkRTOUpiSTQzdTVlZlA1Z2VXdy9OVnN0NFlUODlmM1hrQnVpdnhkUlo2Z09iRmRaa2NxNW9MODdkeCtScXJGS2JyYWRIdGh1amFyWE5peGhZcWlBRjhzMWdObHdGNzZpZzd1Mnd1Smc0WnFHTkkxWk5idW9kSG05UFBYSzhZak85UUkxd21CMGo5bkJkN0FwZzBUcFJ3NjVBVG0vRDBDU3F3WUtaYmw3eXM4UXBzemRtbWUrU2FYR1IxTXhwMTBHYWpuUUZjaTlvZjlLSGw4b2pKdEpkdFpya1VkQitFSGtWcGNSQ09QdSsrMFJ4N1FzNEg5aDMwaFQ5eGYrWjVrc2JTdzA3c3NwNzVjaXZaUzNUeVZrVHZsdG1WSFJJUG5rOTRiWDdoN1g0TWtFL3hJcEtrNHBPQllHSXRydTVsRFNhRzQ5b1R6dXAweDhUTHRaSmYydmFLMnNTRHF1ejMzMEVCaUNiVnNFQjJ4MmJDeVFFTlA1N282Q01rN0lMY1NKbTJZZXdXR0hQeHFHVTJ4N21LNG0vdFR1N2QxNml4d0tqWXpNTUN4Y0h2L1haVEpNNFhWcEFHQXRzK1c2bDk2OTVRQU82Yi9lVXVVODNwVzNOZkROVXFoRDZWdG04bUgwSWpDMVJqQkhVMGt2akZ1NWN2NVV5VVp4U1J2ZENkRkR3RDQrVXFFaVZFbHVoWUxNcmRoVUxKcDYyRUxRdUVtZjNlRnd1dlk2VmVaUXRibTVabDJRZmhDNng2TU5kV0xma2t4aXUvY1E4SnpOOSs3RFdVNzREa3BBQU0zbFo5UVVkVWVYcTlubFRqM1BnL0FYNHdBOWFPZ1h5MjFmRm1XK2ptM3ZJMmZKU245a0dZWURMNE4xZXBPa0JGcitTMnBBekF3YVE0TE0zMCtGaG9JSFk5N05vWkEyeE41WUVkV3dvUUI0OE5IT2kwNVpaVmRrbFhiVmVPREU5ZzIzSlVnRnFBbXlyYzhVNzQ3cktnbk9BNzFuN3RmZGdrcFVPcndtcGEvMVU1Njh6RG9pM3krOXZEc2xsdUZaTGloT29qSWZCVFRuQzdQYnNreWZvendsNmQxUkl1VVA2Rzh3Ky90TGZUZVFibVIza0hXTy9CaENJSzVvOFBXSVJ0R2V3VVVKL0hrcEF5ZklPSXBHUGdvblhxQVVGSkRBaWY4alNHQmtId0lkQmpTTzVmcDhSQVR5VFAzdHl1RXZsRVFVandNNHJFNW9FSlEzLzB2MHZ3dERSekxidEZKMm5qK1ZwU2s3d0ZEb1FxMHhXYXpJSSt0RHhlZm9TRTEvRTVvL1d0T3VXaDFlSmxxbWg3UDBraWptVTNpRTJYclc5ZStyU1ZYMXh4YzZFTk40NFdMQWQwZlptSUdOOTg4bXE0UmdNSnNZaUpVMHlDd0kzaGJVbWFqVGQ1czZZRFhMeGhWLzg2NWJZdHcwN25QY0pScHJES1QxS0h3a2JqeTlGR3lZRFRtNTVJZG1vWDdIc0pNNm02MnFFcnZ1OU1PSXViQm9kWENaRGtYK3VaemhneU13NW5MRmNvSmNIZGJCVmVVRnhBL3BrOWwvbjVaR0g4eHF1TUduUXI4cm5TcDBCS3Q2ZWszT21rK2I4enFUQjY4b2VVeEw4elh1dWwwTTRyYnJtTGJKdDVMc0Y5U0l1WWdtaFFDdGc4TERtSkR1VmljSTVyenNMYnNvYnY0YWdWNU9ma1dzZ003dC9WWWpjdGZ4Zk9YOFU5WG9tNUtoRnhBb0ZXQVo1UDUvdEFhMlNuYWdzeGpXKzhHbzRWeFFrMWJqbit6Tko5NitZMVFBMWNXUTgzdndxc01XaEUvdngrN3RXb3V4aWlMVTc1bUFEUUJic3U5VHJaNXlhMGlvNS90cmxla0RiNnZIVDBHanZaVkxyYUxuOEhIQ21peEIxT0oram1sbEU4dmEvYUFrN28vQVVMSXFMK2k3cWFHOHJSUDV6d1c5YjZjTno5bmZQU3dSdnNVQkNPbU1zSEpENEExMUsrZWVJT2tvT0RrRGtXNTRLY3I0VkdPMEVlYXRoa0NZWFE2SWFYN2xoS1JIcWJvSjY2UGQ5VFRRdDYzdkEwVnZLbWpxS2RHMGZmVlVPNURwa3NlSDRKaXFZSjNMbE5SMkcraXlDZ0RlQ3dyL1FjY0ZpSW93Wm1XYkQvOHZSbTI2ZHhSc0VBaVM5L2xBdndNNW9rR0VLTDJ5MWxlMUFrS2tLUkVCTTZ4MVFIYU8zd1NyNnExSDM5dlZtcGZQMzhqS0Fmc0hvaVhHVmhidkZTRXJTcjljSVlTb2FvMy9aMTdUSzVsQ00welVUWE1RSno4SEhRelNzY1hoaXk1TkoyRUtJeG5PS3BYNjVSNkp1cVRxMXFvNzZsK3FoYzZQOHlCbHRKMll4aTJiOTZKa2lHSWFqZ2YxWW9oYlM5elNwRVRoSi9KeXBjR2xueVNjSkcrUzlJL3hXWncxOWhLU2paMkhXMTFnV1AxTG5wZXNkWWR1SE9keVAwNk5PTENtckFtaVNTT0JiNU40czhObG1DekVWZmYrUWxwL2U1QWZqeVBPWktkR2VtRVkrMjR3QzZFMW0rZkZBakZZL29WVkxmcEJzNzdSeDl2TTZjRnhXVWkrMkNidlE0YjRvUVluc1dhdnRwOEhvUjNuYjFEV0YwbW53dmRRdzQ3TXhwQ2NYbjJrMTBNSTdMd3JmMnZlTXNHU1BFbVdSRklncWozbHE5bEZmN1I5ZVVPaUswejJsd20yUFAxbStJNlI0UW5ZUDdENlJVZ3JpZS95ZE9uQWlZOHlsSnE0SEh4eW5LazdOck9aU2ZqMnFaTGxCdTZKZHo2NkNBVG5OSmtzVGhkTVNXN2RrUElvTnE5bGpGTHhpSVU3Y004U2FWMTUzcXhDQm95OS9hb0NMSlZPRkluMkJaeUgwYitJbjdESEU3bUlqU29NVnZBV01NNEwwRXpwVjArR0djUkJmallWNGVoNFJZaUNZU3lMaXdxckV0SjlkRnc2ckxmY0pOeDJubDJidld6QldtQ1RUUlVZVEtPZ1hsTHhSU1cxVEhRdnpZSHNkZEt5VERKN3JhdTlTb0RkN1lST3BiVVJtK2RMVXNXd1pYVGFRbTZWQ0VZcGNvZnFBdEpWSXVRNUdVc3l4U25jK1l2WG5TUzRibXBzd05TVndkN3EwUG1LWmxNUEUzcFArUTZNS01SdHduV0tQazFpVkN6djYwM0ZibjI1Ync4UWxkR2RyNEZNN0lrL3J2Z2hLQXBZS0JUb2I3RWZUUkh4S1hIQkl4UXBaR2E2emwyWHZMZ1ZPNXdsMmFGSDA0dlhvaytjNlErMlhvZDJiaG01ZGEyRTFER3FkcnIzWlJtaW1rQlZCR1NWQ3IyZUhFU01WaVVja0x1WVRaV0RYQisrUGhxTXdzTEJRaFFaNUhSUVMzTTdjZGxvS3ZNYjY0OEJWRGdZYS9VZ1RKenQ4Z2RoMkhZSVpONitKSldxK0xlQ05uVE8zRHFkeE1jQUNvMnp1c1JiblBzRFdqR2pLTEtyd2F2MzB6b0R0WFNGZEhWVkZWdGh6Y0VZVkhVNngxcXZ0dGlmbFU4VFlYTTAzSmRwV0k3WjF2REdmT3pESFZESkt2b0ZnRzBSd1V3NXUxdDFtaXZXdW4yMU42VFFvbS9kdGN5V05PTUVhUjErVURGNGF5UFd6cWwzcHR6RFhsVDdxZmwxTFJzY0pFc2lDV2hSM3M4R3hUdTlOUXRJSVkwR01ZSUM3bXl1QnhLSEhnZWd1SDNhUEcrWnZncEM5N1Q5S001bjg5WmZOK09POFJ3ekV5bWJSeEQwK0lFU3gxT3ByT1pBUUlUeGlONDJGV25HbkwwTnBQSWtGRnhlMm4wc281K1loNTBUMFlZSDA0ZkZma2cvQ3cwNmt2NnRaTEQxQ2U0QjVIVElwMzk1OXBIN2dFYi9PN01YMkt3SVhkYnZwbllpd1FDK0hzeUdySjdjTFhhU0wwbHJSSHNBZzUxTFVzT253R01PYmVnWmNVMWhnWW13T3NyTG43endRaGhmMUNJdHBrakRWeFNZNEdya21QelJtUFplWG5pRDFFWFJTZUM1NDNMdnVTTmQzeEZad21PNDI4WnlKTWJ4eTdjbkgxRC80SHlkV1czYkhPZ1ZSUWVFd01pcm5sTHIvYWxGUi9qejBvNUI2MkZiMHV1OEtCNHgrQ2dBcTZwbXRBQVR2NWdJc3phWHp0c0hpRy80Qk8zMldHeHgza20rRVA2N211TzBPYlhZV2g5MnpLZllKcFhqeUlld3R4N24wVk1SOWVpaS80QVJqbEt1WTJ4eDNIaHdPUE9SZzc0Vy9sQVNWdEFqQjNZQUZHMFRmd1RWbUJGWjQ4NDlMcDVETXBjY1RiMnFZeXNZSm5GaGJBUWZERzgybGVNS1lFVHk3d1JBdG1IZFNQNjc3NjNudmVpVFBQczd1dFRNVW94c1VFbXl4dFFjMkhkblBFbCtEQkk2YXV2MS9vR0FWdjl1ZitaZDRCSk1oTkpDeGZQQlg5NGJvMUNXMklWUnNoK0JCcnRTTFc4YjdIV2tiY0xvQkdycWhJSUx2U0hKSlhNRkJQa0psd0lYVkhGMCtuMitFVC8yQkErVXQ5WWZ4VThwOXlsU2lKVDI3bXFBVXJYQWpneDJaYUo5M3B2ai9TT3krUzRJbVdWV09jbUJicUFYSFlmUk5OMmxMdTNTVnU2NzZVUjlVbTk0aWRObnptNm4rajlReDRKbWRNMzVIOXVPU1c3MEJ6OHJLb0MwN1RYSTUrd0NhWTl4MlRZcU90eUY3b29UWG44RTdzRGRMTzlKZmNobVRyNHNUV25PWFNoSEo4L0ZFWE5LZkFob2Q3b1granUyc1FtejFMOGJzK1RmSUdkdnZVZ0c3MlpwZ29aZytiWmpMSkdnZkFKNHdscE1lQWtNUE04VEg5SHlGM3hUc3RlVTlOM1IyNkp0b1JDZlpNMTRSUndYd0JJWGh2KzN5RU5ZcS90UkpFTWNWaW1EVXh5QzRxTWFYTlpYcFpKVjZxNk1mcEUzNzZMZlRNVWc3YTl1Ky8zNDhpQ2NGbFB0YmplR05RRzVCNndIQ2JZaGlnZ29QbkFrRTNtZzAzRkNCbElWY3c2YVZCaitiMmdoR1Z0OGtCYUxPVUxyb2ZoZ3dPUkdkciswRUtJa3B3bmdOY0F4a29hNmE1N3VBa2d6ZlJWL2g5VUZSN2J5eEV1U29ZZUlWR2h2aXJIMUpnSGdsRzdlUU1nVG5JbTM2MTVNT1lzVEp3ZU1oaHJQeGd1R1RpR2x3RE1UNlVKQ3FKdUtaUjNmWFg4SmFiN1NpL0hueTBkWS9WUEt1SXlBbWlVZHpCNVF6QWRndjRtRDhQSk9EemdIemZValdBUEpURnViWkdLeExxV2lNaXBIMFY2SEFuRCtVMlg4c3pjTXBOZmxjMkw1NEllMFRzZnMyUjI4cjgzczZ6dEdOWVhTK2taRnczY2pkUzJMdSt0bkJIRldlUE9mbk03Q2Z1L3VsN25YaHMyWUhjNFFPTGZGdktvRFlVU3pwUHgwem5YdGVGVU9BYkZ4U1BxVitnVllJR1B1YnM3SmtMMXV5NGV6MGpOWjcxZ1c2NVl2Mkl4aXczME0vc0JxN0gzK3FCNkhpaVh5OE5jT2M3S21MWS9VM3VPZG11dlVGNWxmTURBalRId094Rml1V2cwWDlab1liL2ZXQjlaQjJrcWNlWGhpamI1YmJLWDhFVm1aQ0tmWmt5d1k5bC9pYW5rSzV4dG93Q1NuWFRkQUtjN1BKOHUxYW1kaVgrU0U5MjQvOGJRSllHQjU5ZWxKeUhsRWRxR3NRNDhVcDBITEVDVkdWZGpqM2VlWnBicVJuOHREdTJXY25WaS9CZ3N4L0IyZktNK0ZOSTYrYXJRUWFTdXJlc0x6WklTTVJhUGVvUDVKK1NScFNkNDJ0UGZUOWdRK215ODlFa0RMQnl2aWpKbitTR2Y2SXBYcHVsaHo4VUtWL0NjQlBGKzF1SDFjdnBra296LzB2SExkVmhyc2VjTTEweGlRZU4rdm9xeVFlMGhEdHcwYWZxWUUyRXpLQkN4ZTlOTG9tSndDVENCb1oxM3cwbURia1ViUmk2RzMzTWROanROQ3lUOHljYUlRNHRZWHpRTnZJMU9hTDdzTVdYMDdaQVU2cWJ2RUJOSVdNMVNWODNDOGZwS2VEVFUvWVBUZmR3YVFaQTdUUTFSQzAvN1pQWncxUjZ3L1FKeHpsREhmWEVGNlUySmVSY0hOU2sxSGZrQmFwNWhMYlB6YUI0NXVOZnl0eE1KSXNxTlBhWk5pRTM3Q3o1K3o1eTdyVWVlZC94WndwNWJGaE5pbktLY1NlSTYzWkVrc2FLa05CMEQzeElHUTFqYSt6SjdwZVJpSytCcnA5eDEyMDMwMy9rdGNJbVhMOHJ6bkdlSStkTFMwTnAwaWt1RWFMc2ZEUlgxVkkxcGRVY1ZMVEJFMG4velNMbGhrYXlhYnZGNm9VRmh3N2gzbncrb1dCeld4anEvVGVZVnRTRUxOelArQlZZcFlrWU92ZVQzaytJOWdadHJ4dzJ2UHo3YnpER1RIb1l5VkV2bXA4SkNndkZQOFJkT012ekVucVA0OEdIdjZ0b0c5MGVpaGl3K3BWVUZGa1BlYUtianl5YVdCNzdrTmFwbS91QWpNUFFJck5zL0diQ3pqYWdxUVFHcWFMQ1FrdHlUeUxJU0pyWHdrZ2xZQVVjbW9EQ1NaZkZhY0RIYi85V00xWFJaVlAvQmp5TzNPNk5zOWl1VExGZkpRc09Ec0toekd6L3lqZkFCeWFQY2VuSEczVXpTNEpBekNjeFNhTVIwb09tZzIzOHFKRzBaR0hsbFBwbzhOVGRTMDVPMFVHRkFwTkJCMG5mcVE0VWhueGR0RXhYTjJjMUxJUHhwdUxFaFZtcXBER095YU9PNE5KYXFyRnliY0MzbDJCMTlhek1EYWNUeFAvRzg5c1gyZG4vZVFuaEJ5b1RTaDd4Z1lOc1RrcHNvQ2NnWHlpZ3RIOHFNRi81MFlXdDVlZ0tNQ09DZnlBWmFRZkJGa2haTXJFaFJ0b1d0enlTSDFwZjI0bFFGckcvbHZ4NE5MZkFydExKSmxVOVI5QnNFRDBYMXFteFI3NXlhbGUyaG1QQkZ6WDVjd3ZuUW9nSkJqM2tTaGVSclNEaUZNV0Izc0pwcEg3WkZtVU0yeXhaZUlZeGxkSDhTSTVsVUx4a3VLbWNvMVRLWDBMM3k4OS9aQ3ZjWWtTNXVyQm5YQXFsTWoySkNXMy9mbTRham5kc0FvTjlScitLc0lKQ0RPcWJjczNUaE9jc0p4U2FQRmdwd1ZOcGZwVmZFQWVGZkt0TjVvUzdRT3pkMFNqVnhrdStvZUlDR0ZKeUlXTS9VRnNvbnpYWnE0aElBeVRhd2FpZ3lIWmhKZGt3VGdsVzRpL2E2amZtRVArcTZJMU53NHplQURLYk00MGtKbFBZUUdyTjdrUzFTQzVtQVFwUFRONnNKMGUzdDc2cDlUNHpiTW93SEVyOTU1b09FY0ZBZE05Y2ZHYWN3LzQ4MDkvNzNnZkJsNy91TXRkeFV4N0hvYjQ2ZHRZVGRDMHBwZGdBTXNiNVF2TnJHUUhtaW51VmppSGoxcUNUNDBwbmdNVzNxdjRTZnJxR0orWGhJNHZzWDA0L2FHVHlIMDhMalB2V0lzRk1SWVkyUFdzK3BBWnlWeFQ4eFdCWm1vbDNUcGl3cVd0YmRlRFgzS3FQaU1ITnVJM3Y4WlZyYXZYN0NtTytOM083THkwZXlYbEdVQjMwWStCL2pGQXFMdVVXL2FrOGZhbEtWM3g0M2tvcEFCK1ZZa0txcERzRkdqZCtibVZFbXFMR1JoZ0YyYUtPNjhOQyt3TURucmMyUlhHMzczb2hhV1ljcTVtM1VObVNkVGZlRUU0dHZydGowR0xtWmZ5UG1NMzRmV3VoUUN0bGZMcGNiRWdGZUJlRFJDQ1dDbm84cDZkWWNGQ1Avd05udkRHTjdLSkNuV3VhVjJyZHhzSjZNdGd4NDZOYlV5V01BYW5VWWNOTzlQTTd6UjlTSXJUVDJyemx5VHp4L3JKRWpyekk1ZWVLUEowRnV0eUF2djF6Um1IK2lkekk0aDhJR2FLeEluUUFjMmpZdE5QSXJ6ZG1HQlh0SUNPa08vNlZwQkFIZEVNMUh1VWpNaDlTb3VDZnJqTFhyR2VjQ3FaVERqT3NYWXZNaGErZUtPbi9oeUJ1Yy90NzlpcUpTUWlRdUQvaTNGQlhRUHl4STF1cTByUTdHVENESWp6aWJOK1N0VzhrRkJZRVJNcC9tWFN2NlRaa1Qzc0RsZUhuMGUxbmNQT0dLNG9Ua0JXTmgwMFNLY3U5Y2VQUm1MazMrNjhQK3pxSDFUTlVXeGQvSXdoWks3K3pnN2pXa2VZc3JhVi8zNVFldkg4cnFOcWRjTitrbHZtS1l1dUQwWjNHcFdwUmtGMkRINnNidEdPeXRoM0l1WDVLUUZIc3puVndhZWlMeUo0VllCWW5wZUNzYVFVRzNMa05WZG5GQ3pEb09DWmZoMVd2eDIwdFE2cHFZOGx6SWdsbDdjMlJLR2NlRVlZdXJwOEY3ZW5mYmd4c0VURHlmaEZJbUI2NmxQYVJzbmVRMGdocGhwWlplMVNrc29ZRTA4eVF4VTdnWU9BZmYvcnYzdlZWZkkrY3FnL3IvZUV4dDlPNmRPaGFJTUQ1ZjA1emxnRUMxUzlKUE83OCtKNldPR0k4WkQzdFZVaHE2OFZBZmJoMkIrYVdsUXFDNzF0aXA2QUVRUTh6R0hyNkFHelhGcEFSMm5tSk9tMWZVL2lpM3Z6aWF3MlJGRlhqRnVKc0dMb285bTh6WlNzam40bXFybXhrN29jVUt0a25jWTNEZG02Vkh0T2o3VmpxZXRRUHIyc0lqK2xPVjlNUnU4S09ZTFVLdjJxdUVJRT0iLCJtYWMiOiI5MjJhZDBkZTA1ODQ4ZTA1YmE4YWQ0YWRkNmE3ZGQzMzdlZGQxYjEzMzQ2N2I1NDJiNTAxZTVhNGZiNTdlODQzIiwidGFnIjoiIn0= \ No newline at end of file diff --git a/resources/views/email/template/client.blade.php b/resources/views/email/template/client.blade.php index f13a3572b40a..e73dfa3630bd 100644 --- a/resources/views/email/template/client.blade.php +++ b/resources/views/email/template/client.blade.php @@ -3,7 +3,6 @@ $email_alignment = isset($settings->email_alignment) ? $settings->email_alignment : 'center'; @endphp - diff --git a/resources/views/email/template/client_premium.blade.php.enc b/resources/views/email/template/client_premium.blade.php.enc index 4de854848a74..2d19b86dbc2e 100644 --- a/resources/views/email/template/client_premium.blade.php.enc +++ b/resources/views/email/template/client_premium.blade.php.enc @@ -1 +1 @@ -eyJpdiI6ImgvQXJrQ0Q2L1F3STdEYWNmOVJqSUE9PSIsInZhbHVlIjoiNkFSMkJKOUNCeTFUczRnQzNKbEV1bS93RnYvWHVnanEwREF1YVJHSXhrM2dBRS84ZkhjZWZRTVNCR2Q5L2lsd2pPVExEYzVvbXJ5bExDM2ZhYnorODVZQWdqK3hmMjZOekw4QW12SlFSdkowOWc2YjdkOU9HQ2ZYSmw3SXhXVVk1dnZtdU1VcndHN1pwUFNMaUZPS1BnaHRJK1I3NllwRWltNk85OFdyQWtpSkNGRDJxN0tTME1SSDM3QkdVa2xYcmpKVk1PMkR0TTZXZmZEVU12U054aFE2amdNMW41UWJ3UGJJKzFXQVlVR1JoSk1Sd3lnZGVYeGxySm9iWUVNby9vY09kK2E0cUd2UW1WeEROemV1UTR3TGVHQ1ZTUFhCbENpelcwdVh5WHRJLzcxT2trQVZpaFRtMGF6ZDJVL285M2NQaG55SjYzMUplaXdqQWlJU1JONnpFSXVTRzlPK0JJcmZSWldPS3lvVSsraUFNcXhPaXBFbHpxY1J5cVBSODd2Y3Bybzk4Z25PclhPN2p1bEhmaENzenRMSllSRzdXdXpoZmk1SXBvTXY4MmlVWmpIcHgwVThpVGZLb2RTNWxNQkZmNC9OV3FDVzF2RnZ1Z2lSVk9SazNQWFo2QjJkbjdSbEZRNkRjcytJbm9OSVY5dzkySkZPdnFhY2hZOEpNdWs5SEFFSHBERUgvNUlkSUE3UTlscC9OOWRNSXJEOTdxSDB0MXRjWkNYeUpHM3FPN3p1STMwcW9NT25SQ1FBWWw0YTdVbUg2YjA5eG1CRlI3RTdjUVBFdUJxN2MvWGc2Z0hQcitPNEFjQTBMc2xuTERRbnpLd09tc0J4VERMVnpLTmJWNGNWQVZ0NDkyNmtsUTFEcUg5Vkl3WmlMdTdYdlRYckUwN2NTTEJkekpIVzlPWG42dU5VUnhoSk1waW9ORkRuTkJnQTAxOURyQUxta2lxeVVZOFJRK0lzQlhFY3Yzcm9iQ1ZaODJwYW42YWRqaEQwdm43aEtQUEdKN2VEcUR6aGt4U1JLRnhOZ284Qm1WSTRNR1dqVXhZVHZsbTNiZFVWV2pDTm50LzBqb08zRjc3eHhkTnBkTi8wT0lKN3lFSXVlWHNFNTR5K2lLeDFwL1BHbW1BZWxOeWtzM0dKdG95cjBTSGxpY2d4LzU2WTZ3N3pSRkpleVNzZFk4WXdwOUszc3k4cVJSeStVN0lkakt6VEZCVGExK3JHZW10UWNTVEVkbCtrQk85SzdOSUlKZXRJN3JidVpvSGJ2SWJ6RVhaaVdIS1VKOHpoSUs0MzRDTmRsWElOZFpqYzFjWGF0Tm01elltNjkybVRBNUkxL1cyUEt3WHRNR0dVRlNPc3BCVml3bXhBbk4rMUJkNVJ6NER0V3h3M2NIcEhPVjdpeHJuMnpjRkphWTI5WE5pVzY5SlJ1azBuenFPbmVUamJNK0NNdjVhSDQzcHNyUndWdXlQQkNsRDhNR2RYSmlsQVVaSXAzMzhsVkRxeGNtaEY2cXlzakFSMGRiaFVRc3c4cmc2NEEvQkNzZGNJa2dFWEhlQkE1RUFWbnFhZFJmZHpFZjJMYkNmL3BQZEtzNUJId0NrZXRwZVdkUnBmNWRVa3B0anh0NEtDTlFZVVdzK3FlY0dDQWpoUzY1SDJjaU1QQW5LcG4weWpoWTlKU0UvUEJtazZDVmoyL0JTSkxCYzRHKzJJZUVGUWhaL0JsVFNraTlIQkc0L3pWSUFIcndDaEpOYVo3VGdOcXFUVHNiZmV4L0VUbXd3MnRnODYrdzNLRzdkS2JDL25lbGVRTXVML0RYZEdSeElpUDJ2cUQ1SzVvMDRZZ0pZWEZ1U0hqNlBDZ3A5bXBTTWNHT1hnMlRkQmNGOVJCYjNjOXJ5M2dBMUtiSmdxMXJrTG0rM29GN2Vma2xua1F3YU9EdjJ4RXlLdXkyYVU5ZzN5VFBqTTRyUi9kaHhlNEJBaU16ejlrcStGUUc4QkpHV3NETzhJOHJ0MU93a21qRVBuN0I3TnNWQzRYM0ljVVdCSHUxMCtZYS9CNHJTTWFmWUQ2cHRPSFozWHNQU21HVTFjeGF2WEgvOTJ5cXp6NTZoQldtcTJNc0I1SGw2aVNOcTYvRlpXRDZsUStmZGwwOU1UK29ERDlOMHlBL21LTUI1UVhSVUVpdGZtdG9LVjArbTZ2YVlEQ2plWkxaY3BSbFVZM2N1YStNbUc3ZHFFYVQ5U3luVjJNTUVZQmI1SnpWbFdzNWRibTA3cnR6cnpVeGNESHFrT0p2UHRUc3ZTVGpBREtTU1hOamRnQ2l1dUswczNEWUFST0VVc1hxN2I3L3FLY3MyWEhnYjhDZFB5MU9RMktvYkR3UVBkQ1kydHFMQUZET1NBU2FwQ1ppVjNMaDQxWFlvKzFKZGw0eHFONjBodkNuTnIwUHV2bjZWUFV3VnB2ZURwSlJTY0w5SlZoekM0SDdlWXdqNEFneFpxbGUranVPMVNBMnNiOTY2ODJLS2htV21JMnNHMlpDS09Ca0ZzWTdaQnorQXNpTm5sNEQ1S20wQm54YWh1eWJrdFpOVDk4MzZYem1ENXBvbGpFQm5UYWRKaFc1V2VGeDNqTVlwTDB6bjFGQnNBcmo2VDJDNW9aYnBRTElhZUowOU9iSnVDRmpvdllGeDVXU2tKSHFxSnI4Mk16UUV4V1ZibzUzL3R5Rk1YQXltRFVrSGVrTTliNEdtbVlUWThZd3hna3BzMVBmUThkSCsrYTdTb3J6czAreHNKcXI4VTlPVEdhdGNHeEJrZXZnV1FUcnJScUxmTGZOWU4rb3ZPZG1TTi8wSVY0cG53OE9OU3RKY2tIOFRXS0lFdDR0TG9WYnJkQmNkN1lzMGV5b0VNdmwzanBXTGFRMTBiLzhyU25YcHpXUnM1ZWhQaEdvMVZrZ1dsUk95WjdXSzJXbWdiK1UvMy9rb2Z5NEZEM3hwdEJORlFGRk1VR28vaC9OOHllV3hjb0VsdStQUXdsY1pOOTd1L0RRNnJqZDR0VnRDWE00Z3lVcDdJVnNqWGZNcWF6Q1BJTWUwNUhQbGRDc0pXUUptbUo5NzhxVHVZYW5lNG54R3FGMHlnNlpaOHhuUS9jWEd5enhGMTc4TEM1M0RCVUFZSjRpbWNKSVMvRXVsQmE0S3EwdTJKV2t4bEJqTGJ1QXE0b2c4K0Uwck1seVhHQ0srNDd5WWEyMm5KcUFoNHl5UktLV0hjVjRNcDlPaHBRTlpzRXQxa3RNeHVVSXZtK2V0REpNYUFJdHppMW5kUnA4RHhwRW5uWUVPdEl0NUt5c2YwM2thbGdXRE9tTFRBZTRBL0RXcjFTZlYzbkZzRmxXZE9pbDFGR1IrTG80TGZ4bXgrcGxMSGtyNDNBQ2xnQUpqN1RPczR6anN0VzRVeUl0SFFsbDR0L3RhSXgraFBOblNBbnNMS2d6THQ5SlpDMHJpeS9yUzNISUNwVnV2RnByNXZ0QStPL3ZEUG1mckxvZ3JpSXRvdVlic2UwY3Y3NXFJS3ZsaWxDT3JTUEdqODBTdnhZNVpPdHorWXFpR1Y0QllCaW1ibGtwSGZ6Qk1WSkthanlmNERPcktmVmFzMHF1YXhxbVdVQ3J3YTgzd3YrMHc3R2ZVSnBDVTJqUGlaOThaYzJ5dVZueVJwV0pNT3l4Sjg3aWxHMjFnZXVXaFBnaUdaQUcyUDFNWVVxVjVMbVduR3JqK0JXSnBsTk9BR1hRdngxMVdOTFpwM3VXNkdmTWhya2ZXT3VERi9rRUt4OWNhWmd5bHFiaDAyRXVFc1NLTkVaaFNheHRwLy9UU0pRbEo0eGhDSEkxRmQveURoaWtNVjkxcEpJZngzblBUWHFjUmJTdkwvdUl5SGoyb1JwQlhncUVPeHN6b2VoZmpPOEp2QXFpY0VkekpMaXRsc1JjSWZnaDV0NzNZNEdSdGlQM3J6VGdsSFo0WlA2dTUvTHp3ZHpKdkhmNXRoSUVLbVN5UlRHdXhIemloV0hoM2VobmorU0RnOWd3YkxqcEZ5L3Q3aER2UW5MZENwQ1VaeEJvdFRaaEIwNU9sNXJReHNPQ3dhMWwvNDh3UlV0WHQxM3lWR3RURVhTUGE2ZWh4UzNuSHRGRHVhS1U2NGFxQjEwS25QT0t6OUYrUjkxVmtXWFlyZWcyeFBtYkFGYnduRGt1SjFpWldPdVA2L3JJWW1yVXBHV3NUOXRYNnFJRFZhQUlkZVhQK09UVTdZZGJsQXNXNGt5KzU4UVkwT2QvWjVVR0NOMGZ3a1VnK1Z2d2xiUzZQc3dtT3pWYWZmNW9QTkYvaytCV3Q1dktJeWovYWR0Y3BxT0hsV29TT1NhUXdFT2hnMU15cjRqSzVFOW9YRzdHQkVjUjlNOEZSZ2hnN2M3UTZrb2NLTVVTbmd0VkczT1cwOUhidDdnQlVrL1ZLMTFRMUxlVC9qN0dyOWxJTXFxMS9aRVdxeW5UQ1FTOURXS2tOd0NZYkpWeDg2U0ZVS0ZDVHhzUVM2cFY3MUZPdDMzYjZvNEZQNk92elpmTHoxa0E3UElmWnNNcUFTZkphZHdnVXlmMFBSVkdsMzdEMVY4QlhLUHZnQlNOeGZiN1N0cmlvNDhnM2wrSnJOU3c1Q2xIdGhTNnhIN2lxZjMvNWZWcjFhcmN3TjdQcVcvMEtNNnhIQlJ1ZHJNT21xRkU0NFBjVnRhMFgvZ3RFTnRUYis4SWVFc2dmc1pIZmFQdU1WV25Ya0dJYVA3RHJ0Zzl3Y2NrSllDeTVDOUNlbng4eTF5OWJ6S2ExQmVOdXMzT00vUGVya1RBWTRWTnVMRUxrN01xbjFRMXEvNElaRGhhTGN5dE1KeExGaUp0dE85VG53MWZ2QzBoSlVYdUFtb0xvME1uaTVVZXU3bVF3OFBoTmlQQzlpUE96Y0I2bGw1MlNBMUNLWlJwd3RqSTBueGNpempOMCtabTJOSGR3NkxsRTEwbkdLWllBdXV0dHdDL3lGRVRIUWZkNmRiN2ZFeGdFQi9MemZLQzAvWE8rT3AwK1g5QlEwTU4rRzhjYnR0R2JUNEhxcS9CQWRhSTZhWGFPcU5GejY0cms0eVRBYkV2QkpBalVpa2lLZ0dKRC9oMktXRUtXMzlPTEFjamJVajFReXpneUlGd1BKU1dUSE83MHg4RXlVTHJ6S0VSUVo2YkRVS2w5WGlIcXZsZlJUVlBRMzErR3h0Q3dJTnl0VGh2SW1YUzFWV3NLVlVhT3lJRjhjKzlCTlhITG9pUU1pU2t3eXd0NW5pVFVUUDRiSHNWWGUvU2srbjJvZjRLcGdsRTFGOGI4Ukh4VjJ1UUhSY2RIUlRaeFo2UTdJbXBXcWpNQnJ3ekNJalA2KzVLMzljOUdBcHRsTWRiUnpxOFphSk9UK01JaVRjcmc1ZFZ5cjRzbUd1aUs1aTE4aS9wczFmdFY5M1dlK0tQdC9kbFlqaFV4WHh5dzRBaytPblBQMUk5TUdpRHo4Y3JhYzBPOEtsMy9XcFRYSHZwRmFCaVVuWmZWYzVFRGdwcmZHbjE4SnFPaEQ4ekZ0Z25IRmRwK2g2Q05RVTJ0WllWakV5dkloZzJJL0JINFlwNWtTN3MwOXE4b21Ob2F3SFBzcUUxS1JZSmg0T1JxREQya1NYaUcrY2VWU2hjcDZ2eWU5emNEUStKZWY4cEdEb0JibkJQbEVWVENocjVZTC96bFlrSjJYYVk3WmpnVnlEWlk0WkxuYWZHejE1OEU5aHRiQVRBcGhpbmNKZUdKUytsYUd4eU9qUmx2dk5kZ2Q4djN1d2dyUEczdktscUxHTWNzdlZFUlVXdXl0Qk80MjI0L3NFTk5WY2pEZHZLVVhVb3dRci9UNEFORk84RDRTc043dExaRmd2UWM1Vy9JTytmbFZtMjk2R0JYOWRsZVN2TzBYZVBCYTB5Q3QzMHdXK0wzTDI2TWpaU1Vma0NPTmpKY0I2Myt4UkRZVEFUN21EZjN6TGZUdW82Yk9UbmxvWXRxWXowTU5YcUdEMGV3dEVsZU5OQUI2bXh5N1R0TVpYMXMwdWw4bENkV0ZxNkNtcEZQb2ZoU0RqUitLbGhxY25veHVTUXdBTTRCK3RNazVTMDZSWkZNTWZOUS9ROWZ1NXZrL0pJcTdBcU8vNm5OK2pBWFVBUDZMYk9Cb0Fhby9ndXFhZkUwSXliVG4zblY1V0dua1QrbzRMa0k4VjBRWnFONE1ZMXRWc0J0ZjdpL0drcnhEb1pub2FEbVB4MHAzNm5GYVVKWkdQMWRZTVBKdUdYcFU1TVhHR1VOWGcvaHdsTXBrOUxwd2VkVW1LeVJLdEVybzBCTVhrKzNNY0w4Tm1IcjVYNzE3RmZUTm5VdUNuSkZ0aG9qNGdObWszTTRpTmZuRFQ0KzA0SzhwWjR2eUNkSzA1dW5aSWxKTy85cG5zOWN2eGw1M1MzU0g2eHJDZ2NmUEJPeFh6SHRMZE90cjlUSFppVVdYOExjVkloWitTMG1qWHYwb3B4OWVJbk13QTNyNDZBU256Q1BybXZsYzlqaFNQa0Nma0NJZ3A4QTZueFQ1UnhnZkFjeUtvTUdXWThDZEZVT25GRTdtU0YzLy93aWRtY29KaVBvd0oxSEtGWjdseGF0WUhsUVYvZGlhOUh1aWF6Z0hZQjgvTCtqekpGRjlpRHV3bXF2WGM1SFZyREFJK0JoVjdGQkgvM09ja2xCZHJQTitYSVpIQmhsZVA3dTlUMGp3eU9uMVhUNzdvbWFpQzRkdy9UZTljbzBSTHc3NHpSclUyVm9IMUFIWTYzeTFnb1RSR2NtcEkwdDQ3ZVFlZ0JXZ1lyR3dhVDZ4WTJLdnpIWDF4WHQvUzJpeER5UjFKOVpKdTdveFQ3bEtrRytRSGJCN2IxZXFUL1RUbWZtSjZzeGxDMnFKUlRlcVhTNVp1TlZNQUZwamhXemFERzN1SjBlMldrSUNXVlo3WHgvRlN1d25aSVFxTytrMTRkQmhrM0o5b0FrSjNGelIrVWo1WisxdENUdE1yeGptaWx5RXl3Vms5dmpwVzZoMnJHS2RwMGlib1hrblJiNEIvNVBYdjVqajJxb3dPWjdBYnJsQ0pyRm9CVVJVV2NZTVZhOTRiYllFZUhtTkZpS0RhUEJIYUZKSGFta1lnckh5ZklxNFJSeWxMaEo0b04yVTgwSTRrc29jODAxTTZWU2tNakRKdkwxemVHblIyb283OUR6V2toS2ovdWQyQjVOcWRlZ0xmb09sVFhOb3VZQnZUSC9nTFRrTVBrSm5rVEZMR1l4NytPN1hoeTRzd1hyRG9OTW5zV3RYZmEzMjBCYmZuWTVINXF2WDB4TzQwaW5LMlhLaVNtT3NWRFNwZnJuWGNUM3luZEZUcjFNUkEva25tZTI2cnREZ3lJMVdlTllObnFoZWlWckVGd2FCWVp4K21rMzg3Y1ZuN0UrOHhiNkJ2NUVoN3VWSXRDamlmRS9oc3RDR1dLQlg4SmdRaFJSV2JQNmc0VzBMTFo5bHJ5S0wrVDhYaVFHYUxNT3MrRDZHTG1UTGpIY3lhYjV1d245WkgrR0g1SWtqaWM0eEZWOTdqcndDMlQ2U1Q1enpCMjRhVVIyTTVXRVhDbXF6RUk1RG05QW9RY2lXQzkyYUlwTlltZW1pTEE0TE9HeTczUHVzL29nS09JVVlBZ1RpaW5NdUxkN3hVOTdYcUlWc2Q2ZHZBZTI2TVdJcndzUDFvZndPVTBnNEswc3hsaWxPbTgwY3pUYU5zak9TTHB6YTdLT0RKbEJNV3JiempZc1lNc2hiU0NJaklpQTJDNE92QlZUWC94WVQvWG01eStKV1J6Tzg1S3RpM2p0Y3ZHa2M4bFFqUUk4QWRNbjlURkJhamtEL2xtSGkzOEJPZmtST0lXVUY1QUFRdkhqL0JkeERMS2FIdVBCZFR0SmwvcjdDUG1rYnNUVkc0NHEzOTlUWStYcWtpcnRzMnhwRmR2Qm52a25weCs0UTNzRFd4OENsN3Y5eTlQeFdGa005NFpJTFZraHZPVU9zVjNZN0dpWE9xUDZOVkdXd0dnVmo2Mko5VEVzRFNXbFBXSllySmxadHNlbUlGSmVoUXBMUEgxU2VSVGhONzcvb1B3YjdDY21jZzNabmhjQm1hNGVhY2s2aGRjMHNjalZBUkFWUXI1NGk2MjIxak1zT2RDRHhzUmVna0IyR2Q5Y25wdG9nRXZESk4zNFkycWEzejJXZVpMQ2JSZTkxVnd3dmY0OUNGd2JUcDdBKzFTTTdHSFIxWFZpNDBHQlZjc3k1TDA0dko5QWxZMU1ONU9WMGc0WWVjamhxYStMYU96cjBWTnlJci96enBxdk12YUhMako5VlFmR1ltRG9USW85ZFJOaWhSTDErbFgyclIvdXBmeVVaMVNBWWJIaVNCdTFHbGJQT3NpZzRiak9QTVQrVU9JcFlZKy9PVEJsb044TXVnN1BJMG1KRXVkZlZ0QTIrcjNZSUI2SW1yWGViV3ZpdjRSTkQ1cEVLdGkyUG5EWWZJMnZWWGhtbGhGNExuYnk4ZWFLdzFtMTZxa3BTbS9CdkRDbHVwN3E2ZzdhR1h0eHFTTUFuYTROb2tXdWpOcU9SRW5lcmpvTm1LZVIzanN6bkQ4TmdtTmZxVGxQaUVyVkNLdU5Nb0RFZHlhN21zOXkzS3FGMXRpUW9zRmYvaFVRdFV0OSszNzZtSlNmSi9sWUw0WjJFZGZrUjQxQnladkt2N1c2TnFuRktoMERJQVJxQmRzU0hOdU9IblF4bWpmQjQ5bEJ3c01tcGpSRHMzd2NadmNFT0ZPZmNsVEUzMlVKelNIUTR0MTFCNjJIdjZOVjBnYzN3K3AxNHVjNENnNTBKWVpTV1I1TDAxc3NzNDRMWXFuL1BiVzI1VXBjcXByT0tyWkZzQUU5bXJzWmdOeFdlNlBCNUVmQnZVdE9ZbEFkc1BtZWNLZGNuSmVqZUZ4eE0zenBtTjlFd2ZMaFA5VUt6VXE1TE1oS0l4ZklDT2krWG9HdEhOM01oSXBYWkZsNzIwd3pVV05jRE5LalA4djVwYlR1bm5kQzRDMml0Z29DR3lOUXFYVkM0RjJUeFZiV01oTnhhYzltUG42WDRwUmo1aHZMQlpwQkhiR1ZCYzk1R1M0N3NRejVoOFpPaGxEeFJwZTJ0R3l6N2lSSHR6ZDhTZnNHVUd5RzVvY2pZc2JqY3lPTEhjMWdwNXV4QU9nMHNqQmtmd1dla3Z3cCsydjdBQm1rMU5JY1czVWlBcEsvRFpHYjEvd0JZV3A1ZEt1Rm14UjM4enlRVWZweHRxUzFRUVVGaFdjOWFpSjlNL1prenlYdzMwdnYrQU5xd2IrNmM4ZC93bmZzS1J5L2htVUg5bDZBQkxrc3JRcC9pV0RlbVRsWXRsN1VjM21iUE5FdENiR2JaSVEyOWhEazZOM001aTdPdVhIbm52aUdPS05rWHcrVXFwZUMyKzR3MUZEcFlOMkttSENjYXBjamgxOWJ2cVRZOUk5d2dqcVk0L21TUEFsZzd5d3hyK2wydUgvTUxSZmNDbDBnY3BKVUF1cjQyb2FYR2pxbmxNK2NObVpjbWJJSFZneDFkWjVTT1BUdFY1cTdjRklodmR6cENtK2xBOWVaWC9WY25SZC9ZMkNTT0dsakhtRUtYSzV1QitsWkZCc3AzVjVTa0RybEtpSjUwdWs5aVZIUHF5My8zanRId1lZalQxSmFhdVluT1NRd3pQU3d2b2JtVkhLYnVGa0hlZHRzam1MUEJjZUxDWDNCcENnNThmMisvRlJSVHVIVm9keklUdGtPWUtwK2VNRm9wTVVKeUdhcytYRVRSOUZBQzYxaVVyVFhUSVN4WjdxODErOUxQeTA4aVpnaDRNMi9CQXhRSGJaVi8xTTlkd1VydzhraWNzOEdpUHBKYWRObFdUemJRZ2RmZm9FdTQ0ZXF0QmZYL2tXOGdSSWVhYW9aQlplVmdKR2xMZFEzWklocCswbkRzM3MzUUlNOUVnbkdRTkxHUm1FTUhDNlFOVEhhVnZxNGJqM2FtTHpPUGtFSmpLeThHTXpCU1Zxb09oN1FDZ0pZQTlpWnhoMnBySis2Z3NPTlZzbnZaMnR2Z2hJdm9SRUZubFZ1VjRHcG50dG9SdFplbTROOVZyTC9lTkZqUkhsbVA0VFByZmMveG5RN2JHZ0daMjRwdEo4UlN5bGVmcDI5Q1FpemJVelkzeXFkN3liY2VpQ3QyZHlPQlhRdFMwRFdZL3hxNFZIY051Z2RvcFVHeWFIY1YwMjFZU2tDRSsxQmpydnV6Wnhwb0FRelJYWnVyNGRHdnlPN3RTNzdwUXk4MXo4bkp6UTlha1pSa05jWVE4UzR0UVZpdnNIdlZlYStpNTBGTDg5Z041NXROWVlHcHFKV3ZVVWRMc2pEVnlnRklGdjFvWXpBT3RQMTdmZXlZYWlRQjRncndraEhLR1E5QkxOaTh6eFdGOEV6aGFiVE1MTGV5YVcrUkpIcWFuZmtYL0krOU5TV2ZhTUMwY3JqOExmOUpCazdHaHZGNTFtTjFzSDEvejhGTWJPMXVRTXNGRE9DZkxFVjdqdVhNSkRQUHM1TWZCMnFWRHYvbm1uWThTQzV5MVIyOXBYR3V5aFkydytjQ2ZMM3BRSHpFNmZyYVJudDVDSXNYMkV2YWN6WHcwZXBzMVJ1QkV4b2NVbm00LzdIT0RtaGQ3VXo5NmRnSzlPZkVQcXZBeHp1YUpsK0ZHemY3NWN0NnkvQ05ja0FCNGcwa1dtL3VQL3NKNGpZN1czbER5UWRISE5TbnJienpIS1MvakgvRi9NZTZVUzBxc1I5T2p2MGljSms3M3JCSUlhNXBkdTNJbW91WnF4TW1xNTN5bEtCcHBJK1hmOTZzc3JiTWptNVpRbDQ1bnVwdkhYTHQ3VlhScUh2N1hMZW5heEVKcW51VHIvOGF0UnRReUpsbEp1TWU0YWk5Ulh6N21XZmlWc21Nb0tBK2J0Y3NDdHBiSG1ZakZIOEhMd0pRV0pESlhvL1hQaG5vWlRGQXdvYzNXUjMwTERkYjJlQVN3cElDM3VQNkZxSlJCRml6SWdGcWlQdGYzYit3NlVUbzFPZXFrZDEzaG1nYmZzWVJKaUdVZ2l1RXd3TjA0RVA4TnNUTTM0cDRVVGNDQXFiRTBWbUY5Z2xKTy9sejNmZEJpdWF3SGpFSTUreTc2K3pRdFVYRDlONFhEZ2Qvck5WNm84RDVFZTdsL0xQTFY1cXN3RkFWeEc5OWFocE5WdXZsVDNzRVZRbGhKaVIzbEliUGhFWklVL09lQmZ6Vy8vOCtCbEJiL2lhcG1VTkhQWlBHUFRnWjBFSGx1SzRRV3YwdVY4SUlKaktDeTZ0S25EUi9BUjlhZEVyOVc3aHJXSDlSVUlWR3pxT2l3RkgvSEx1VjVBb2N3V0tSWFJ6a1U5Rm91VXpkS1hROEp6ZE14dUF6SmZyd1hLbUluL2ZveFUwRHhsNlJmeUVZQ1hxS0dBa3VIaVFjOVBDRlEzWmIyYjBUbEp6T0tRUnF6WmxacVAzTmNjR1M0RitUekh5V3dMVGxta1dkekdScGlObnZKOHNCK0V5a2lEZVRIaXJQbWNIYVQ3eUEzMlhQaiszMGdyNDVIWVV6MEJkT2oxOWVpbDBqdFlJVWZIRVkxaTdCNnZ2R2tBM2xsMTc1bURtZHIwdXFUZFBTTjNITXpWVm5VaWtoUThuV0JZdnBDUHFvb3paUk9OQmNOenFpUitHVSsrdmc5czgwZUh1dDR5cjl6L1JYM1FtUUxMVXlaREdybG56eEI3NHBNSG15N29zTm5TVnkxM1d2c1c4dDAyMGNSQWtLZ2UvSTVGcU5aZFpiZ3hXRDNMY0Zza3lmYUdMT0ovc1pNVHhEMlVUb1d6Rk5yTlppc01TcmpJUWJDT3NHMW5xZEo2TndPOWtaVlhpN3VnUjZ2VjVXU0MrNWMyQWxEaW01ajBYZFpFL1VYbGV0a1liZGxJSDJrNVlpL1NTMituSktaNjUycVJCSlpsandnOHhiSFlUT2xBS2xNYWQ2Unk4L0prZkdKOWozNjZmNTNYRzFteFdTRGlsQ2hlR3V4cStrYWRjUk10UG5Xb0xzdnJVa2lHb2czb0tZWG5WME41c0xrSzVGWThEYXBvSUk5aWNEWXZsOGRmTUpVRWJPTEpnWk5NZFE0cWhIQWdQVWJOVlNjYTJWSGd2TDViVXNZRWc4NmpwdE5LRFlFRXdyWnNMSGxXVHZYRDNFejF4QjM1WUJYUEhKN2trbTNRS09hNUhEdXpYM2tJQy9GOGd3aVg3K3JFKzhqa1ZiUVQ0L0NLUVpxZ085SkNzc2xaKzgyRVNua25TSGpOZW9HVnlxMXpSbDNNd2V3NG56dTRla3VRNXlyQzdxbWtzVEl5SjBYNDZJOXBjME5RUEp4WTRoSE9BVkhCYmRYZmpsYWRmanA2c1Q3RDJEc2tYdlJ3PT0iLCJtYWMiOiI2OTA2NDkxNDRiNjljNDU1MjBlNTUzOTA5NTZlYTAzZWZjOGE2MDlmMTI5NDBhNGUzN2FiY2NlZWFjNGRkYWYxIiwidGFnIjoiIn0= \ No newline at end of file +eyJpdiI6IlBsbENyOGN2em81MEVWa05EbUFJS1E9PSIsInZhbHVlIjoiVEFHaVExVUQrSjlYSjlCZVp6eHVONCsyWVdvZkdoM3g2RXhZREV6WENodjVaYjZDeW9lbjQyc3RvejlCNDdERXljbkFVL3NHTlZTM3VoZE1tWERreW5xdXZYQ2tkcHpHT0gwRjVEaWE3TmErUDJvMHp3amdQZ3o5ZmQ3RzhURjcyWnJHMzR1bElCMktKUzN0elphNnZTY2ZkRHhBL2VVaWppMnk1UkR3MVBPYWttSXZmYUdHdWlhbkdnZGdGQ01LbHFWeklwYklITVZOUDVIWE56dkpmSnR4U2ZDQVlZYTRiZ1FoYmlZK1NZMHZLeDJtcjYwQnBpREU2OHNISCs0MEZXRWl1Z3laSkN6dEpiQnI2blFZS3pjNE14VzRBYTVUc3l5SEpNenl4b0NBQVJidngrRTJXRWFCUXhyWkh4YlhrdjZ4dUt1UStFYm5qcjdDaGlpTGZzNU91THkwd1pxczY1dWdiWDcyTEhzK1NMekFCVnlWRDNOZHhaQ21tNGxOVk9CcmljQ0JkcDFudDRrYzgrREpXQzZXSnpGbUFaMWdYQWp3d25aSTc4ZGM4UjFwUXh1OFAzbHA2RHNxc3ZBbEpVTVM2MmRrVFVIUHZzRXJIeTFsYUpMS0FoaXl3VTJnSkcrZlB5MlF0cjN4anhWZlZwalJ2OENxODkwU0tjUkVXRzRuOHVVMCt1eWsxbGlRZFU1R2c1WkxWSXJWN2x6c3hUS2tjcHo2dHY2YU9MWHcvcE9mWWlSZHJhTzYxUDVRbjN1UjJjc2NXREFxeDlFOTdFSFhib1MvcEx5MVRKS0E3VWNhdlpsT2M5U3ZhZUoxNEM1a0ptcGZrR0VJWmxGUmhHMjh0VGlLVEhwU253eUQ4NUlHY2RVSDdud2taV1BnbkdLUG03QnhoT1VDYm92V2J4ai9rNXdqNWgzYVJyOG5SejhFUEpIM2J4R0NrMTUvUXJFRzh4NWh0aDBWL1pyOU96UFlJUE1ONFlSTFd2RmE2d0QyS2MzN2tuYU1FbkErNEJQUzhiOGhOTHlldU9VMXVNYlpNU01HeDNXVVVBeS9VQ05taTdYdCtwMWJvZVJ1aDk1RkNuVHR6V01VNERZQ3FIZGNYaGFvbWJMUE1iVjJJcDdEZ0RvekNLWERmSWliQkhJYkd1YjdVazlubWJXdEQ1b0EwWktxSGNXWFVOWDdiYlNPYVlQUzZtWTVUbDF5bjM1aFQxZTdyTkl3QkFJL0k5cUE5SXhUbEJOUlBYd3pyVVRRUFFVV1FRWjhnWFJWM25tS1pmcUR4SVloV1dwdC9IaEl6T0xXTUQvaXM1dUVnVjd1alkrYmNZM2NDT0ZOUHE5aFRTaENOKzdzaXlJOUdKbzFMbjJPVzd6VS9mTWZkVlkwUmFHVW5XRG9CQTFHL3hidEJHRCtUSCtsbGVyQmVFRXd4ZjhKM3Q5ZGxnODA4RWRwRlRUczRMamNMMVY4Vkd5MkN4K0hQNWk3Tm5Rdm9yN0J1WHJZcVNIdUtTOXlrN1BIV3VQZnp3djArRUxSWDVMUUJwS2k1K1ZTN2UrOVg3VzBXTjJzL3lTdVVsdWJwbnFQeDZpSWFmRVhqRTNvZklaVURFSi82L2drYnZTOGJZT1lYbXN0cFlGMTFnYk5saVpuMno3aFZCbUw2aWQ1Zmk5V1prTlY5NmM2My9YZXp5UVBodk95dTB2ZGNreTY2eG9idnhGOCtrNGozTVBRbWhuNG0wV1JFbzhPWlFHOTV5WEN1dDA4eTJjMk1PcDhrcUNtaVgxMkFLdXJrSFNlVmpsS04rODF6R2Z6RzJyLzR3K1pSUHo5a3BUTXBjbWl2N3BOUHpVcHh3SmMxb2o5MVlxU1VoV3B1a2ZmV3RqNXk5d0NpTXB6ZithSFQraml4VnE5T093dHZrdzVjTjkrNmc0YSthZGcyZnEzYnJBNm9Qd0x2bG1rRndhd3hienprMk4vK2M5b3lzcVZpY25KSTFGbnlManVJUXZKbWVUNHJKS0JEUlFUOXZMZnRUYWU3a1ZIcldxZUtwTFIwOUJqanM1RDlOaVhRN2RQK25NZG96UmxvcFNnL3liNnczQWw2K0VFQU5OWUt5Y3BkanhwbUIzZXFsVTBacVpRZTFFa3V4ZzJBRDMvZE1qL1BGeDBrUUg3KzBtOGVLUWlDdjJoZllzdUdtNk1GVWRqUDN5dTlHZGlONnlaNXhaUDV4YnRod3VMcGI2R1haU2FXek4wcXYxNzgzQXo1MkQ1M3dSWEpiMXh4YVAwZ0x3a05mODhZQnE3Q1ZucGV3UUpzYzFqUkdFbUh6ODlSNzJ3N0laVUYrQ1dUOENQNUNEbGQ4NFVmMzEyakJ5aTc1V0NpdGRKaC9iRmc2R25YYnVOUDZjc095WnQzbTdubVFkTmxnd1pwRVhCMDczQnMvbWZxZytwOVY2bzdUWVdkanRqUGs1MnA2bWZmREludHJxTlFVbi9uUS8zQ0lRb3BoMWV4ZVUxQkY2aTVZSHU5NXd2c2xZMkJHajBNanRxWU5FOG5MamV6MkRiYjRVRnlZVExhazJmM2pvVVhKYkFNdFBzMkUzQlZ6KzRZcFdpUEZBNGJNNG51djRyV1E2OHp2MlF1ZEw0UWZpSE9PVDdSNXdkaUUvUzEvMmIxMU1GaHBuUW5vSXZRSFp6Nkw3TWVqS1llK0N3RldLdVFTa0M4MXc4bVBFbklML29teG4zcjJSZU5ncjU2U1NVS1R2aHN1b0RaOXlXUGZFUHFkUStyWGFrSGFUUjVHcW5MTVFKOFpMT1BqMUNxR1ZSVVJrcUFxMkEvTXJLNkFqaDA3MG5ua09oUmMvNjJtRDRWUWxRQnk1bmZYTHZsYTVnaXJKVnkzbmovRDJ0T2RsN0Q5VWRndy81bEwwbEw1K2U5cmFESGkyRXFjbDBFRHc1ZVkrTC90b1hQR1ZsOGVGbUczRi9MR29CS25pNlVaeFBjM2htdEhJLzlmcFpYTkZ0RklscUNkYTR5YWdPUElicnhFOFYydndKUFJZaStvWWowU2pad2dZV21NamRqcmtyNGhGcUJOMUpjN0p4TzllY01vTldLcXNGTHpESk9USC9VL0VQVkRlSXJQZWRWVnFLa1BJSDRmVVRDSkwyOHhPM3JOMytjeWhWeTBjelg3aWhwV01LK1RzejVpQld2cjVibERxNDBIbUl4MEx2dzBVRElmSUxLdk9mVVV1YjJIZTdtdnVieVh6Uit0aGNRdDNNNHd1NzVJMG5PM0wxNXJGTWlaeE0zNXZBVzJvUXhyaXNBY1JndFdUeCtQSXNUNFhmN05jR1Fhbkcxa3lnMzE1RGVKMXYzM1VEN1ZBcC9GcThjNHd5RlFaVzZGQit6Ty9SMlAyZld2cnFHaVNMbFBTMkIvWFdTVkMyU0s4MnhSaXpWNFNRUmNzdVFocmJtaUtUMW0wNlMvZjdkdkVKNk96bzNnSm5OYTJzWWdXeFVpSGtKaWxmMWVKc0FWbUd1RHdsY3REUk1sYUdmNTRoME9KMGhwYm1GQlowSUF3Z0RmY2dNemFsdlJxTGpYUi9SWUhjNmwySFJDWHN2UFZRY1N2MGhuSE1pbERlUkNxTXVBSzJRWFFIR0RuTFBlOFAzbjNScEdLeDBHMnMzVGN5NThwYkpQTXo1N3VWMG03ajV5VTNBY09mKzlYRGZuWktGUElkNUwzeGZKRjBiQytpSzZvSzhMY2p2dUk0MHdnSVR1dWFmMWQ2MXlEUjlGeVJaVEFCU2xOeHNYbkV5RVNHNmJibFJTcGdaT0hlWWtGZDBrQXZUTmFvRmlBaWJlMTB1blI4SG1yNW1oNEJXNlJ1KzV5eGVpT0M1RmRZcmlCbU5IUUtCbFNqS0hRYUdDbXNVV3NoeXFab2VvanVrMDBIcE1JemZ3WUFsRGpJRys0clZYQURndStXUGNiZGdVNTQwbUpyQWtSdG9BanpwVFEwR0NXVEh0N0syem01cnVHM250MDBGTVhKbGdJVmJGQzNOZzlnMkt3RWVvS3JwMEFKMWQxRkRjY0hIYTJwbktLM2JhMXN3ak9qTDNpUjlBVkZjMUxPT1BpTDVqcExQbU9WUHRhMG9yNmdJbk9MMHQ3VlBYTnR0VVFHZ1pWdUp1VHdRblJ2bEtqS2xsNEhEc2RZMXhTdk1GMSt3YmFvemhnMC84Vmp3YllRNGxib29SQUtzbW1kc3lpd1lwOXhlczhxRDdpaDk5RGVjcFhUajJITkZYdGp2eTE3Z0F6U1RORHJVaGx3NUxjVE4zNFFFM0p0YXhxTEZJcHV4amxHTEN4a1orNjFGQWxLK3QrZVk4a2xweUFaVHJuaWdBaS9Ic1N3WWovWlVVL2I4MkU2c2YzMjBnYkVFTVV1RWlJRzZid1BOOWNGZXY0U3VWcTBwTmhhTmhIYyt1WE1adUtEcjIrbktVWllleU9vNEU3RHpzV1M2TXBTOUtXZEE2a1Y3MmtwNTZCOWt1a1MwNkx0USt3Q0tkbkp3ODJNdTRQWG41TnhUa3hGVXJaWHYyb2Z0d3l4dG95K0p4M3BjWDlyanN4MzZ4L0F4T2hsM1RNUThCZm9aRkdCWGxOdytQOTFkR1hoTy9YU2ltalZ1aGVXeElXeXlPYm9RR0hqbGdmWXAzaEJ2ZnBTWjlUeEJ5YmxISEZGemErdkUzcHlaVGVLU1dzaHBhNFdDMjMvVjRJR056MTVoOGt2anl5OUJvWWhta2t6RGNNL3hzNDVoeUQvOXA3N29EQUxoY1RCN0grMDJGREVFckxNWnhaOHdnS1BtZTU1dktvRmVENXdHWk9BSlNPaXZMa1ZTNU1zb1EzZ1MycitiTEJGWHpkZDlBRmdzams2a0ZlbUpiaXZrQ2E0dWpNaE84UlYyeENzS3RlWkVKQ1JhVDRHK3E3MmpOaGxzVWZBbE5QbWpZbHpvTDFEbmczbnE2T0pGc2xlOEh4d2VqMUdYZGoxcm1lM0Z0RUg2RTBhRkJFQ1NlZm5qdGxDL0UvRVljUlhuOFZXU0JkMThrYzdFOHZ1ZkpDWmg2Y2tZOW54dDU4MDdneFR2aWhJSDZ1WGNac3J4OFRnaHdhTzVQT0ltS2RQclpUdGJ2clB6QnpqS1NtcE8yWkQ2QXZ5QmZZUG9IY1h2N1pPTzRZRWV5NGprd0JQR3M4NEgrRDNJUmtqZlNSYUwxeEU3clV6MStod2I5N1hSanU2NkhwRUFEVGhycTVvakQ5bEQzWWVaQUZzeXJzS0tLaitoRnBUOUplNXlDYTByQ285ZXRiZHpZdjlRcW1DVnZuc1pLVW5WelNRbjFscFlzc1l0dHJIRmE0eFE0cWs5c0xQYlBLcWk5MzNhNlA4MkZaYTF3aktPZThlOFBQam4zTjFMZlltNnVwQXN5cThMUDlqdkFRdFBTWm1iQThmVjVTV1hRVG4zRkkrU1JFcEk4cHF3Wjc1WTFqRGY4R3c4ekVHem11WFVCOXF6NXhRRnJBejd5bXVXU29zZXhVWGtpejZmRENlZHBYK2k0T1Vsd2xtK3FCM1JDeGd1WmhFYnNldnp1cER2eitGNlE2QmpZS0lrb2xjNVZ6MnNtMUZXTW5BV2dsSEs0aFFRYmcvc2VqZ0xodGE4cVpvOGZMUTBkMW45S0R3SzI3SzM1TmtVd25ueVlvclI0QW13MnFEdzRxSmVaOUMzVVRSa1VUSEVKbTZaSisvQ0dURjloT1F6MGljekxVWHhBc1IvU2grUkMwbXltWW5TdTlWOFdMa0JwK1lkR1hmNjVVaEVHMFN1cDBnanVMaDQrTVJGS2tTUHNTR2VGSTZzdiszN1hmRUFoSU1rUVdIZTdkYkNjNzVVcytWT1RBd25ZbW1lcFNsWDBQOVMxdkZyWi92TVhvb24yYmxYZHoyTk1PaEpBVXV3UXNhUnMrTi83Qi9qMlB2WExPU3BZSUFwQlJlZnByUFpwaFpSVG1ZWURiWWtOWjRPQ1c2U1h4a3FxUmxkUzJydmRBKzh2ODBHVDdVV1h5RGdlSjFIL1JBd3FScVJWVkR2djNxbWMvMGRvQzhCQVdPOVBtSHgwdU5aS1RKY1RTcmYyTkhpTWh5VUtpVWl0RnY1dWhwZXBCYitwN2NSWitpdWpRWFptM0d2cHBESFVMZFh1cmFOMTZMS3JOMjY4VmJBN0lWYmZDQXRCRXU1dHluUTZqVC9vb0dVNVc2MzZKeWlyL2tIOTdvYklKOEJOZE5OUE9ENC9BU0pvOGlFUDNyWk1kbmF5bEY1MTV0ZXJXTW81N1lkb1RKa1NiZ3NBeDVRRHpYdTIxZlBkSGdOR0pkQXhkR2c0QzEvY3lub20zYW5jK0NDbm85ci9qNTdYdXNKL0pzMXdOb3pvZThYcFQ1NDM2UmtGV2VENFc0SEtubmVzTFpsWHd1eHFZSEZYWFU4QWpOeWZFZHF6MVIxeXdNaGozRjRmRWVsOWdzZllCSG1wM1FwMjRLd1k0R3VJNERPbU9YQkFFU1gzbUZ5cTljaUw3VE5BZlljM29UYWpBa1REN0ZSTDBCUWN4a0huRHgwR1RoRE1sSzZqUmRzZ2VGVjloWFRIMGpCdVNpQ2xBVW5aTUFsYkRqOVBHWVVDa2pydDVFdlRLTGxXWHpoZ0YxSWU3bDdWa0ppUnRhWXExNnFxbXl4aDZVZkhNRXRjRlE3QUZYU0JaVkU4OU9RM1hBT290bnJSVytrb2xhR0lKZFFhZ3o0clV1TFRqbTFaWG1FVFF5TmxUd1QxSW5nYUlEV1o4R0RLSjFvMEdyeUVUVHlqb0oyNXRuYlhYOFRYczE4NzNvMzkwZURBR1dkSHhVdnh1Zkk3ZXFvTzZDSUh4Tlk2Tks2Smx5SjF1ejRiWFViM3RTOTJSYnVPVkxPN3lIM1NVTkhzQVlKNXBpRVlabW5oSHAvT21zK2p6WmNnWTBZN29OdnRwWkhCZVVoNDZmbE84bkRyS1JxMXllbVpkV24yTWZGeTZYVFBkTUJXQ1cwa3QvYm94Wk4yRFU4K1k4blVwdnYxY0VEaHE4eWpINGlta3N3SkdXT3NhQWZKeFd2Rmdnem0yUUIrUW1mYzVZR2xoWkcvcUxCd05xWnRQQlhwaVFOcFY3amEyWXluQmd0eGVhNE1rSHAzeWt6VU5zcUVNSHg1QXdqdjhEclJJNndwU1FZRERyclB1ODhkWitESUdCWFhUMVpEUFgwZlBPclBiZS9wa1pjSE5YS1hNSTREQlJGUTl5YXdLekZGL3lNRTRlLzJneldaR0NSQXlQRSs1ZjMxRUN3aEVBOVcyTG1tcnFmamN1OEo2NTRIVkJLZzUrclV0MjZGdUlxMWpzM3pMQ1gvZkVmSFhhZWpzdTlWMlN6OWY3VXFEcUh5ZFJQSnMyYnNZWTNvZEVxSVRDWUROZ21tV2JNdlF0V2ZTbmVwS1lVRy9DakFaNGRPRGRNM3V1cUdWRFhSZE1qeHBzTVNCNGRzVHpXTnI2TXV6ZEJXSnNmZXhOOXRMem5vbHNsbkJTZExYNXNnT0czSVBVSXZNZHVxRjcyNFBTZWhYSHBHME9BNlRCZXhMT3hNem1nbFRSUUNmdzlQWEJUa2lKdFFuOGtVMGhPZDZhbU5Ydy9jZ2R4RkZJRkhMNFpnTzVzZVhESWNmZ2xTU01JV2srMWszSU4vcEd0TXNwZVdVZnREak5EMzQyRnBQTnd0emtBN0F1My91V1JSSGk2UmpXSjh0MDJQaTJtaWIrK2E3S2Q2Z1BiNnVLYkQxNEFUa2NuRFJaN1hOcHZrQnVPR0FIdXg2OG5ESU1jZUw1TVFMMVRyZFZUQTA1dlhGUHVUSzBPVFJVL2wrQjNJZ0QrQUhYNkVHaE94bzFIbGRSTXRzTHZOT1dTSGxGajJpWmM3Q215YngyTE1acDhSWENRKy9nV2xGa3E2MW9mVithVUp0dUwzc2ZlamduNC9OWXdnWE9yanoyOXpWUy9IS2VZdnY5S1RPS0lZYS9EY2hEeVNYaU1PMHA4dlY1Y3VJZ3crcjNKcXBkMXlhRG81VDR1a3kxbklyNUJCbi9ZZlY4VTlkWWQ5N2N6VDZURHBsUC9KK2RZUEtxZ29scXNzTS9jaUJqYzZOYjYvS0JvU0h5VkxuN3NlYXRpVU9PR3UrS3pBc2FUa3pOU041b2Y2YW8zVHVKRDJoS0g1d0ZaT0IrVDRuYU1Db0UwcWhuL1ZhZ3ROQzdmUGNPbnErMlNOVVY5T2QxcFlJMFRYODZ0eEZDcitIMkJyQjU3OEN4SXlCN29SZUhKQloxMjZ1aWxHT2tPV1pZY0h0Vit5ekhKREp6Njc4eWVENFJoWUdRRmJ1czh3cXY1NkFoR09TNzJoOURuM3dSbDBWSDVQbXM1MWFVUDhON1d3SWx0WlBQQWxEcGZGa0VpK3VnTWFaV3JpVkNxK1o5OUpTd2h3by8wSVNURVg5Ynk0MEh4ZEFpdTBDN0JYb1JQYk1kajhxUHFPM2x0ZDNBV2VjNGR6QVhyVXNsTm96ZGZXTXppdEVVdUVjVy8xWU1ZWEtIS0RObXMrZmFHckVEN2ZwSGhZSHZJYjh0TmNCNWRSemtrLyt5SVhzK0xJblFVOFlMVDVidmxwdktrNGhidW00REo2dnA1eWxZeEt5N2JvZzJoQVo0a2ZKT0Y5T0FuMTh5QUpNOEE2WndTWFdMV1hkMHRVVFd2NHJaMFpxeG9lWVBQVEV4NTA1N1BKR1FaY1ArRVlTTng4Tlc0Q3kxNVNkVTFGVTlubDR1aFRnUXBtb2ZhSk05WUc4b2lyRzFVeVJubkF3Tm92R2dEREJjdDZxOUVaVExjLzg1aG1JeWluTW9SWWgxNnQrazY4dDVQRUxuZ2U2a0FyN1F2UUh3TXYvMWJEWExxYzRpUUlBaFN3eWR0dlU0RjRmZDkrQWpYZFlBT0NlSWZ2MmVmdzhBZHZONnRCRmZRNi9MbEtKQjFOejNpZ0ZnVzRtZ1lFNTY0a0FmYVM0RXJMVG1QS3VxQzRTSzUyclJmdWNDNlJSQUNwc2FteURFb2p6WDRJSEx6aWpnaWUwTWVsakZYQzR1TytLbmpUT2Y5Y0c2OXFJQ2hkVGVGcjQzVURtYzl6bEE1S2RiZUxIT2hYTk00dW5ZQU1hbThhbzdNb01pQkNKY3RJTC91Rkk4c3JwOFpqYmQ5Q2RQOVRzY0hHUWxvY1pHVVRRUXd3UFJQMzJpeFlRRmVHd0dLK010UzBrQndLd2gyOGE1MU5rcjM2QjE4OXJES3Y2VElnVEVZNGE0TFFlVUZ4VVd1Tkx0cEYxUmhoN3hyZGhvR2U3RGtBN0NjQzZJTklMd29qek95R1crL0tZMGQzeitYS3o2Q1B6RU9Mclp5YVhzeGdKc25TLzEvcUFOQjhQUlZ0ZGpiSVNreGJJTVI5NjBNdUtBYmJFU2tvU1RQTXNVNXBteFhzd1pzVU9yUFF2UjE2Z2tMb25rZnVncENPOE1qemxhWkV2ekF2VHJXcGtTUVFwTnJYUUZqYXJ2V0RpZ2dKVzlTaXJ5R1ZpWkhrR1JGUEV4SXJjWHZka0N5R0tjcGhxOGJ2NWg3QjV2VUtpZTN1OGVuNUdCQnUwSk5oVHYrcUNySDVrN1VwQUpJQ0ErMCsvWlhhMHhCbWxuUzVDdWUvYTQ0bFRwdG5kZEpQdFN0Vmg1a1FTcUdXVDhDWUpIdmg5LzFVMERHRkZXdVlrZENiSzVtMC95ZnlDaXQ4a3RxNWhDZ05NRWFNbVpuRi9tMDVwdzQyTXFGRkt2MzBXZk1KbFBySmZYQ1dPc0xndENlVFpCVjZmdWlNL0VwQ0c5Z1Vab0c5VmE2TjFYMHBnZjNCbEg5N2lRbE42S2xIREtocUFGZm9NaW9sdytBR1QvRm1JcWZ6elVSay81QjJYYmhiNWJYMFdOTnZlNFMyMHYyaDNTd2IzczM1azJ2K2ZneFBTTlF4ZGc3d2ExZ2NIZXVIaENRWC8zcDEvQUNHQnBvR0s3QjV1Vm1UTE5Gb0xob0JLa1hkSGZhbFhYU0Y2VUd6MXhUck1uTElRUE9pazh3V0FBMy8rZ1YrUFdPeFRob1hhNTl4L2s0NUlZS1g4ZWVOY0E4RTUrWE91dkE0WFRBMVNKY0J4ZHJDeHBkeGVBN1FnNGVhUnYwd2s5QjNpcWlVZENjOTU5MnlDOGxsdjRwM0ZoM3Z5UmVBQ0g3OUh5a2tjcHhsQmx1S0lBRXRuV25XNFBjM0NCSitrdm9DY2ZRM2dpbXEvSVEvdUEyRFFUUmNhR2hYWUNvOTEwWEcxZWFyMU1EL05qbWxSZG5rS3VERDdrUDhyRk9OMkNyRTYvS0x4aGg3aE02bDBKekhGLzdObGNkM3ZmQWtDNHBOQnNpQnoxZ2lyOSt2amdJeXFGZkFCV2xvSFlacFR1SysyUDJzMmlYVjJ0R2NFcy90dHhjMGl3OGkrVzBlb2xvNG5KMDJmdGVWTVV4VHR0NTBvNUxnUlE4aTNmeFdGemxsZFBOK293WmVwelNKOElpMmhKYzB4VXEvZWxybHF5d3B4dTRkdENKMXhUcWRvd25OVkRSdmlvblhUcGU1c1ExejErZXVRU0l0WWFhL1VFRHRJRFg3bkN4dWVrbURHR3J4UVhtajZiVVhHTFRObDM1b0Evbi9ZczJzYTk5UTMvc2duYzBLekEyWlFTY01jTXhQazhoVWdDeUxYY0VrYytzd1JuNnlpaFhnUVk3OVNpaFpSa3d1bDRvR3ZIdGVHWkk5RDlGaHh1SC9UKytIWnZ3QkhUY3Vob2J6M3BVOUZMWEtzM0lqNENlb05Wc2lVVVhMV3NJMDNkTVFGRXpGckw5Sm5oOU9mVS82ekhPQWNIQUYrWEtraGlMQUJrK0R5NVlrdXp3bUluRXZZbjdzb2JvNUxSblFsL1ZpVWptYXJ1UGFGakhQZWl1Wk9zc09aQ0l3U01iTmdmSnVNclZaNFlNUXJhL21Qc2RaNVRFbEVOSkxsRDdwWnBSc05hamp2R29SNXF3ZHFicDErUFdUcCtQazBiNnZ2Y2w0NHRlZUFmazFWVkdmSjFkOEc1TThtVjdYeVF4L09UZU9mNHk4WEJoViswWlFFMzdFWHhaY3BUU05FMWw3RWtHMkNxUzVoR0RiN3BFSFpZbzlmdkV0WTRhaVQ0dHhQMHBjdGsvZXBOMDhveWN6QXRYM1lkNnVkM0U2L0JROEhQNHJuZnRQbXN5dytuMXNLWWR1YTJ4dFd1NVFPbkFBdGhDU3ZPU2t6bmtWeG84UVdHeDZCSEJxdlpSY3l3VHBtVGlrTnJsYlNFWmVuRElLZkR1YmRGUjh2Rms1ZEdFL2ljTG56cXduQTlTaU84THVTMjNmazBueTRFbXNxSjJXUDhGR3RLNE9ybm9HcjVzN1pwZFBXTm1DRFBybGZWNDh2QkdYVnZFa01SUGpzR2FvNm9WbUl4WWlBNksvd1M5Vk8xUlIzK2x2eVlPbnovOEtPTXN2d2drVEpkNnNnYTFsQ3Z2U3VMS1dOK2g4NlNGQzhKYjMyYlFKZmxHOUVRMTdlamlCMlZ3WHlIOXV5UzBCTXM3SUdZWDgralp0MGFCWXdjcDVsUDhGdnVVOVdZWkdxcThQdVBVa3pVMXdrZzNNYWtNRXpoTThyZEp1bXJLcmpLTG1DdkplRzFaNGJBcTNkdTQ5NUYydTkyNVp6Q0w1cHZtQjVaMG91dW9WSmRaa1dPSG9kUmQ1djFnRE93LzVmd3NHRXpXZkxYblIrOWdVU1V4bll5dGhMdEV5Y3hVM1hDeWEraVFQZVJxRTNVVWlLdjZSc253Y3FySU0xS2ZtMTEraHczeUNURHl4MFZIZHgxMk1ZQ0VlM3R1ZTRmT0dEYTZjSDJoSGxiVCs1WnBOL1B0QXl0ODlFVS9BT2t1b0Y5LzJpcDQ2UjhPcC9RU2IvVk9WUzhjanZZeEk5T2FRQ2xWU2FkelR6cjgyU3NSVy9GRWtKQXQwSTFKMGhBTitUTTlWL0pVL3l1TmdMNzRCa040TFZrOGt0cTlyMGRtbnRoRmhFajU5bmNWZU1CL0VQc1lCeHA3Q213WCtGZXZIcWc4eXNnWVg0RDJZaEloSFpxclB2T0FaTjVNY1BXWjJMZDJ0ZXJvbUlKaXVLUEZKbWVJb3c1NmcxZm9MRi9mM0s2YXNtM0FhRjhMTXZQZXhtOHk2M2FGSzZTQkVxMFB0dzJGcko1Z1orQlorM2IwajRSNnVuYnI1emNwa0Y5NTdQSEFTT1Y1c3pxM3dqRHlNL1dHLzNRZnBjVHBiUWVzaVBqNXo2endmSW00NFZzYzRwRzh1MzJUbjI5ZmEvNmgzUmZtZ2dWK0xjZnc5TnBIb2p6ck1KWGNwczZ2cHJyZXZVenRERnVZZVFtb2V3K0xTZkc3d2VmZlovaVh1a3ZhcVVsYnFTaVhyTUxOU3F2Y0Fma1FGL21GdVRYSDZXdEEzQzNIQkFFZ3BJRU13PT0iLCJtYWMiOiI3Y2MxMmQwNTk0ZjU2ZWJmYjgxNmRmZGFjOTUxMGQyZTZhNTE0MzMwMDgxZTkyOWY0ZTljMjFiNmI5ZjRjZTg3IiwidGFnIjoiIn0= \ No newline at end of file diff --git a/tests/Feature/PaymentLink/PaymentLinkTest.php b/tests/Feature/PaymentLink/PaymentLinkTest.php index 9695b0d57e9f..de5755c177c8 100644 --- a/tests/Feature/PaymentLink/PaymentLinkTest.php +++ b/tests/Feature/PaymentLink/PaymentLinkTest.php @@ -9,7 +9,7 @@ * @license https://www.elastic.co/licensing/elastic-license */ -namespace Tests\Feature; +namespace Tests\Feature\PaymentLink; use Tests\TestCase; use App\Models\Invoice;