From c0ea157ab6ee44bd354bbb75c70c42ae808a0940 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 9 Jul 2023 17:50:30 +1000 Subject: [PATCH 1/4] Adjustments for payments --- app/Jobs/Subscription/CleanStaleInvoiceOrder.php | 4 ++-- app/Services/ClientPortal/InstantPayment.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Jobs/Subscription/CleanStaleInvoiceOrder.php b/app/Jobs/Subscription/CleanStaleInvoiceOrder.php index f872b467f636..b182a8831c1f 100644 --- a/app/Jobs/Subscription/CleanStaleInvoiceOrder.php +++ b/app/Jobs/Subscription/CleanStaleInvoiceOrder.php @@ -56,7 +56,7 @@ class CleanStaleInvoiceOrder implements ShouldQueue Invoice::query() ->withTrashed() ->where('status_id', Invoice::STATUS_SENT) - ->where('created_at', '<', now()->subHours(2)) + ->whereBetween('created_at', [now()->subHours(1), now()->subMinutes(10)]) ->where('balance', '>', 0) ->cursor() ->each(function ($invoice){ @@ -77,7 +77,7 @@ class CleanStaleInvoiceOrder implements ShouldQueue Invoice::query() ->withTrashed() ->where('is_proforma', 1) - ->where('created_at', '<', now()->subHour()) + ->whereBetween('created_at', [now()->subHours(1), now()->subMinutes(10)]) ->cursor() ->each(function ($invoice) use ($repo) { $invoice->is_proforma = false; diff --git a/app/Services/ClientPortal/InstantPayment.php b/app/Services/ClientPortal/InstantPayment.php index 2e5feffd85ea..284e79d93a24 100644 --- a/app/Services/ClientPortal/InstantPayment.php +++ b/app/Services/ClientPortal/InstantPayment.php @@ -190,7 +190,7 @@ class InstantPayment /* Schedule a job to check the gateway fees for this invoice*/ if (Ninja::isHosted()) { - CheckGatewayFee::dispatch($first_invoice->id, $client->company->db)->delay(600); + CheckGatewayFee::dispatch($first_invoice->id, $client->company->db)->delay(800); } if ($gateway) { From dd61b41919221016a698fa18a9a929733b42d709 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 10 Jul 2023 12:55:21 +1000 Subject: [PATCH 2/4] Updates for silent migrations --- app/Http/Controllers/MigrationController.php | 20 ++++++++++++++----- .../ProtectedDownloadController.php | 1 + app/Jobs/Util/Import.php | 15 +++++++++----- app/Jobs/Util/StartMigration.php | 10 +++++++--- app/Repositories/UserRepository.php | 4 ++-- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/app/Http/Controllers/MigrationController.php b/app/Http/Controllers/MigrationController.php index 41f82d9fffb9..57b3044f228e 100644 --- a/app/Http/Controllers/MigrationController.php +++ b/app/Http/Controllers/MigrationController.php @@ -32,6 +32,8 @@ class MigrationController extends BaseController { use DispatchesJobs; + public bool $silent_migration = false; + public function __construct() { parent::__construct(); @@ -260,6 +262,9 @@ class MigrationController extends BaseController { nlog('Starting Migration'); + if($request->has('silent_migration')) + $this->silent_migration = true; + if ($request->companies) { //handle Laravel 5.5 UniHTTP $companies = json_decode($request->companies, 1); @@ -312,7 +317,9 @@ class MigrationController extends BaseController $nmo->company = $user->account->companies()->first(); $nmo->settings = $user->account->companies()->first()->settings; $nmo->to_user = $user; - NinjaMailerJob::dispatch($nmo, true); + + if(!$this->silent_migration) + NinjaMailerJob::dispatch($nmo, true); return; } elseif ($existing_company && $company_count > 10) { @@ -321,7 +328,9 @@ class MigrationController extends BaseController $nmo->company = $user->account->companies()->first(); $nmo->settings = $user->account->companies()->first()->settings; $nmo->to_user = $user; - NinjaMailerJob::dispatch($nmo, true); + + if(!$this->silent_migration) + NinjaMailerJob::dispatch($nmo, true); return; } @@ -341,7 +350,8 @@ class MigrationController extends BaseController $nmo->settings = $user->account->companies()->first(); $nmo->to_user = $user; - NinjaMailerJob::dispatch($nmo, true); + if(!$this->silent_migration) + NinjaMailerJob::dispatch($nmo, true); return response()->json([ '_id' => Str::uuid(), @@ -431,9 +441,9 @@ class MigrationController extends BaseController nlog($migration_file); if (Ninja::isHosted()) { - StartMigration::dispatch($migration_file, $user, $fresh_company)->onQueue('migration'); + StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration)->onQueue('migration'); } else { - StartMigration::dispatch($migration_file, $user, $fresh_company); + StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration); } } diff --git a/app/Http/Controllers/ProtectedDownloadController.php b/app/Http/Controllers/ProtectedDownloadController.php index 452989efda9e..c4c38761b9ab 100644 --- a/app/Http/Controllers/ProtectedDownloadController.php +++ b/app/Http/Controllers/ProtectedDownloadController.php @@ -35,6 +35,7 @@ class ProtectedDownloadController extends BaseController return response()->streamDownload(function () use ($hashed_path) { echo Storage::get($hashed_path); }, basename($hashed_path), []); + } diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index b45f3ead4cfa..e4de8ecc5244 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -165,6 +165,8 @@ class Import implements ShouldQueue public $timeout = 10000000; + public $silent_migration; + // public $backoff = 86430; // public $maxExceptions = 2; @@ -176,12 +178,13 @@ class Import implements ShouldQueue * @param User $user * @param array $resources */ - public function __construct(string $file_path, Company $company, User $user, array $resources = []) + public function __construct(string $file_path, Company $company, User $user, array $resources = [], $silent_migration = false) { $this->file_path = $file_path; $this->company = $company; $this->user = $user; $this->resources = $resources; + $this->silent_migration = $silent_migration; } public function middleware() @@ -263,8 +266,9 @@ class Import implements ShouldQueue $t = app('translator'); $t->replace(Ninja::transformTranslations($this->company->settings)); - Mail::to($this->user->email, $this->user->name()) - ->send(new MigrationCompleted($this->company->id, $this->company->db, implode("
", $check_data))); + if(!$this->silent_migration) + Mail::to($this->user->email, $this->user->name())->send(new MigrationCompleted($this->company->id, $this->company->db, implode("
", $check_data))); + } catch(\Exception $e) { nlog($e->getMessage()); } @@ -641,7 +645,6 @@ class Import implements ShouldQueue $user = $user_repository->save($modified, $this->fetchUser($resource['email']), true, true); $user->email_verified_at = now(); - // $user->confirmation_code = ''; if ($modified['deleted_at']) { $user->deleted_at = now(); @@ -1590,7 +1593,9 @@ class Import implements ShouldQueue $nmo->company = $this->company; $nmo->settings = $this->company->settings; $nmo->to_user = $this->user; - NinjaMailerJob::dispatch($nmo, true); + + if(!$this->silent_migration) + NinjaMailerJob::dispatch($nmo, true); $modified['gateway_key'] = 'd14dd26a47cecc30fdd65700bfb67b34'; } diff --git a/app/Jobs/Util/StartMigration.php b/app/Jobs/Util/StartMigration.php index a76afefb05f3..432b1c1b8be4 100644 --- a/app/Jobs/Util/StartMigration.php +++ b/app/Jobs/Util/StartMigration.php @@ -49,6 +49,8 @@ class StartMigration implements ShouldQueue */ private $company; + private $silent_migration; + /** * Create a new job instance. * @@ -60,11 +62,12 @@ class StartMigration implements ShouldQueue public $timeout = 0; - public function __construct($filepath, User $user, Company $company) + public function __construct($filepath, User $user, Company $company, $silent_migration = false) { $this->filepath = $filepath; $this->user = $user; $this->company = $company; + $this->silent_migration = $silent_migration; } /** @@ -116,7 +119,7 @@ class StartMigration implements ShouldQueue throw new NonExistingMigrationFile('Migration file does not exist, or it is corrupted.'); } - (new Import($file, $this->company, $this->user))->handle(); + (new Import($file, $this->company, $this->user, [], $this->silent_migration))->handle(); Storage::deleteDirectory(public_path("storage/migrations/{$filename}")); @@ -138,7 +141,8 @@ class StartMigration implements ShouldQueue app('sentry')->captureException($e); } - Mail::to($this->user->email, $this->user->name())->send(new MigrationFailed($e, $this->company, $e->getMessage())); + if(!$this->silent_migration) + Mail::to($this->user->email, $this->user->name())->send(new MigrationFailed($e, $this->company, $e->getMessage())); if (Ninja::isHosted()) { $migration_failed = new MigrationFailed($e, $this->company, $e->getMessage()); diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 6b8707d158a9..1e59805c9bc6 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -39,7 +39,7 @@ class UserRepository extends BaseRepository * @param bool $unset_company_user * @return \App\Models\User user Object */ - public function save(array $data, User $user, $unset_company_user = false) + public function save(array $data, User $user, $unset_company_user = false, $is_migrating = false) { $details = $data; @@ -71,7 +71,7 @@ class UserRepository extends BaseRepository $user->password = Hash::make($data['password']); } - if (! $user->confirmation_code) { + if (! $user->confirmation_code && !$is_migrating) { $user->confirmation_code = $this->createDbHash($company->db); } From 7ba8fac6f441af133d7ed2c1c8ed2f932adf4838 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 10 Jul 2023 18:29:24 +1000 Subject: [PATCH 3/4] minor fixes --- app/Jobs/Invoice/BulkInvoiceJob.php | 2 +- app/Jobs/Util/ReminderJob.php | 1 - app/Utils/Helpers.php | 40 ++++++++++++++++++++++++++++- app/Utils/HtmlEngine.php | 16 ++++++------ 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/app/Jobs/Invoice/BulkInvoiceJob.php b/app/Jobs/Invoice/BulkInvoiceJob.php index dfbdb18a7905..be2224d12378 100644 --- a/app/Jobs/Invoice/BulkInvoiceJob.php +++ b/app/Jobs/Invoice/BulkInvoiceJob.php @@ -41,7 +41,7 @@ class BulkInvoiceJob implements ShouldQueue */ public function handle() { //only the reminder should mark the reminder sent field - // $this->invoice->service()->touchReminder($this->reminder_template)->markSent()->save(); + $this->invoice->service()->markSent()->save(); $this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) { diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index 879b759204fd..80f2676d2ab5 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -99,7 +99,6 @@ class ReminderJob implements ShouldQueue $query->where('is_disabled', 0); }) ->with('invitations')->chunk(50, function ($invoices) { - // if ($invoice->refresh() && $invoice->isPayable()) { foreach ($invoices as $invoice) { $this->sendReminderForInvoice($invoice); diff --git a/app/Utils/Helpers.php b/app/Utils/Helpers.php index c3c9ad8a10ba..ef38615696fc 100644 --- a/app/Utils/Helpers.php +++ b/app/Utils/Helpers.php @@ -56,8 +56,35 @@ class Helpers public function formatCustomFieldValue($custom_fields, $field, $value, $entity = null): ?string { $custom_field = ''; + $quote_or_credit_field = false; - if ($custom_fields && property_exists($custom_fields, $field)) { + if($custom_fields && stripos($field, 'quote') !== false && property_exists($custom_fields, $field)) { + $custom_field = $custom_fields->{$field}; + $custom_field_parts = explode('|', $custom_field); + + if (count($custom_field_parts) >= 2) { + $custom_field = $custom_field_parts[1]; + } + + $quote_or_credit_field = true; + + }elseif($custom_fields && stripos($field, 'credit') !== false && property_exists($custom_fields, $field)) { + $custom_field = $custom_fields->{$field}; + $custom_field_parts = explode('|', $custom_field); + + if (count($custom_field_parts) >= 2) { + $custom_field = $custom_field_parts[1]; + } + + $quote_or_credit_field = true; + + }elseif($custom_fields && stripos($field, 'credit') !== false) { + $field = str_replace("credit", "invoice", $field); + }elseif($custom_fields && stripos($field, 'quote') !== false) { + $field = str_replace("quote", "invoice", $field); + } + + if (!$quote_or_credit_field && $custom_fields && property_exists($custom_fields, $field)) { $custom_field = $custom_fields->{$field}; $custom_field_parts = explode('|', $custom_field); @@ -90,6 +117,17 @@ class Helpers */ public function makeCustomField($custom_fields, $field): string { + + if ($custom_fields && property_exists($custom_fields, $field)) { + $custom_field = $custom_fields->{$field}; + + $custom_field_parts = explode('|', $custom_field); + + return $custom_field_parts[0]; + } + + $field = str_replace(["quote","credit"], ["invoice","invoice"], $field); + if ($custom_fields && property_exists($custom_fields, $field)) { $custom_field = $custom_fields->{$field}; diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 7bc3c0acec9d..27451e68d1f6 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -222,10 +222,10 @@ class HtmlEngine $data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')]; $data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: ' ', 'label' => ctrans('texts.quote_date')]; - $data['$quote.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice1')]; - $data['$quote.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')]; - $data['$quote.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')]; - $data['$quote.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice4')]; + $data['$quote.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote1')]; + $data['$quote.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote2')]; + $data['$quote.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote3')]; + $data['$quote.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote4')]; $data['$custom1'] = &$data['$quote.custom1']; $data['$custom2'] = &$data['$quote.custom2']; @@ -266,10 +266,10 @@ class HtmlEngine // $data['$view_link'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')]; $data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: ' ', 'label' => ctrans('texts.credit_date')]; - $data['$credit.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice1')]; - $data['$credit.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')]; - $data['$credit.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')]; - $data['$credit.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice4')]; + $data['$credit.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit1')]; + $data['$credit.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit2')]; + $data['$credit.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit3')]; + $data['$credit.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit4')]; $data['$custom1'] = &$data['$credit.custom1']; $data['$custom2'] = &$data['$credit.custom2']; From 6a2600b7dcf6aa0667ebae68cd8d704a8188b9a3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 10 Jul 2023 18:36:42 +1000 Subject: [PATCH 4/4] Fixes for protected download streams --- app/Http/Controllers/ProtectedDownloadController.php | 7 +------ app/Utils/Helpers.php | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/ProtectedDownloadController.php b/app/Http/Controllers/ProtectedDownloadController.php index c4c38761b9ab..d7277d69f383 100644 --- a/app/Http/Controllers/ProtectedDownloadController.php +++ b/app/Http/Controllers/ProtectedDownloadController.php @@ -30,12 +30,7 @@ class ProtectedDownloadController extends BaseController abort(404, 'File no longer available'); } - UnlinkFile::dispatch(config('filesystems.default'), $hashed_path)->delay(now()->addSeconds(10)); - - return response()->streamDownload(function () use ($hashed_path) { - echo Storage::get($hashed_path); - }, basename($hashed_path), []); - + return response()->download($hashed_path, basename($hashed_path), [])->deleteFileAfterSend(true); } diff --git a/app/Utils/Helpers.php b/app/Utils/Helpers.php index ef38615696fc..6efc82126297 100644 --- a/app/Utils/Helpers.php +++ b/app/Utils/Helpers.php @@ -126,7 +126,7 @@ class Helpers return $custom_field_parts[0]; } - $field = str_replace(["quote","credit"], ["invoice","invoice"], $field); + $field = str_replace(["quote","credit"], ["invoice", "invoice"], $field); if ($custom_fields && property_exists($custom_fields, $field)) { $custom_field = $custom_fields->{$field};