diff --git a/VERSION.txt b/VERSION.txt index a7e0a988addf..12d56fd94bff 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.3.81 \ No newline at end of file +5.3.82 \ No newline at end of file diff --git a/app/Console/Commands/TypeCheck.php b/app/Console/Commands/TypeCheck.php new file mode 100644 index 000000000000..108800e7c0b2 --- /dev/null +++ b/app/Console/Commands/TypeCheck.php @@ -0,0 +1,162 @@ +option('all')) + { + if (! config('ninja.db.multi_db_enabled')) { + $this->checkAll(); + } else { + + foreach (MultiDB::$dbs as $db) + { + MultiDB::setDB($db); + + $this->checkAll(); + } + + MultiDB::setDB($current_db); + + } + + } + + if($this->option('client_id')) + { + $client = MultiDB::findAndSetDbByClientId($this->option('client_id')); + + if($client) + $this->checkClient($client); + else + $this->logMessage(date('Y-m-d h:i:s').' Could not find this client'); + + } + + if($this->option('company_id')) + { + $company = MultiDB::findAndSetDbByCompanyId($this->option('company_id')); + + + if($company) + $this->checkCompany($company); + else + $this->logMessage(date('Y-m-d h:i:s').' Could not find this company'); + } + + } + + + private function checkClient($client) + { + $this->logMessage(date('Y-m-d h:i:s').' Checking Client => ' . $client->present()->name(). " " . $client->id); + + + $entity_settings = $this->checkSettingType($client->settings); + $entity_settings->md5 = md5(time()); + $client->settings = $entity_settings; + $client->save(); + + } + + private function checkCompany($company) + { + $this->logMessage(date('Y-m-d h:i:s').' Checking Company => ' . $company->present()->name(). " " . $company->id); + + $company->saveSettings((array)$company->settings, $company); + + } + + private function checkAll() + { + + $this->logMessage(date('Y-m-d h:i:s').' Checking all clients and companies.'); + + Client::cursor()->each( function ($client) { + $this->logMessage("Checking client {$client->id}"); + $entity_settings = $this->checkSettingType($client->settings); + $entity_settings->md5 = md5(time()); + $client->settings = $entity_settings; + $client->save(); + + }); + + Company::cursor()->each( function ($company) { + $this->logMessage("Checking company {$company->id}"); + $company->saveSettings($company->settings, $company); + + }); + + + } + + private function logMessage($str) + { + $str = date('Y-m-d h:i:s').' '.$str; + $this->info($str); + $this->log .= $str."\n"; + } +} + diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index c3d8039546e4..51ad55d86ab7 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -27,6 +27,7 @@ use App\Http\Requests\Invoice\StoreInvoiceRequest; use App\Http\Requests\Invoice\UpdateInvoiceRequest; use App\Http\Requests\Invoice\UploadInvoiceRequest; use App\Jobs\Entity\EmailEntity; +use App\Jobs\Invoice\BulkInvoiceJob; use App\Jobs\Invoice\StoreInvoice; use App\Jobs\Invoice\ZipInvoices; use App\Jobs\Ninja\TransactionLog; @@ -747,23 +748,14 @@ class InvoiceController extends BaseController case 'email': //check query parameter for email_type and set the template else use calculateTemplate + if (request()->has('email_type') && property_exists($invoice->company->settings, request()->input('email_type'))) { $this->reminder_template = $invoice->client->getSetting(request()->input('email_type')); } else { $this->reminder_template = $invoice->calculateTemplate('invoice'); } - //touch reminder1,2,3_sent + last_sent here if the email is a reminder. - //$invoice->service()->touchReminder($this->reminder_template)->deletePdf()->save(); - $invoice->service()->touchReminder($this->reminder_template)->markSent()->save(); - - $invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($invoice) { - EmailEntity::dispatch($invitation, $invoice->company, $this->reminder_template)->delay(now()->addSeconds(30)); - }); - - if ($invoice->invitations->count() >= 1) { - $invoice->entityEmailEvent($invoice->invitations->first(), 'invoice', $this->reminder_template); - } + BulkInvoiceJob::dispatch($invoice, $this->reminder_template); if (! $bulk) { return response()->json(['message' => 'email sent'], 200); diff --git a/app/Http/Requests/Account/CreateAccountRequest.php b/app/Http/Requests/Account/CreateAccountRequest.php index 75d3d05a026c..dc95f1ef6a6c 100644 --- a/app/Http/Requests/Account/CreateAccountRequest.php +++ b/app/Http/Requests/Account/CreateAccountRequest.php @@ -36,7 +36,7 @@ class CreateAccountRequest extends Request return [ 'first_name' => 'string|max:100', 'last_name' => 'string:max:100', - 'password' => 'required|string|min:6', + 'password' => 'required|string|min:6|max:1000', // 'email' => 'bail|required|email:rfc,dns', // 'email' => new NewUniqueUserRule(), 'email' => ['required', 'email:rfc,dns', new NewUniqueUserRule], diff --git a/app/Http/Requests/Client/StoreClientRequest.php b/app/Http/Requests/Client/StoreClientRequest.php index 06693fff25f9..b641c4c025ac 100644 --- a/app/Http/Requests/Client/StoreClientRequest.php +++ b/app/Http/Requests/Client/StoreClientRequest.php @@ -36,7 +36,8 @@ class StoreClientRequest extends Request } public function rules() - {nlog($this->input); + { + if ($this->input('documents') && is_array($this->input('documents'))) { $documents = count($this->input('documents')); diff --git a/app/Http/Requests/Login/LoginRequest.php b/app/Http/Requests/Login/LoginRequest.php index bb8db25bd0a5..7b731d5102a3 100644 --- a/app/Http/Requests/Login/LoginRequest.php +++ b/app/Http/Requests/Login/LoginRequest.php @@ -36,7 +36,7 @@ class LoginRequest extends Request { return [ 'email' => 'required', - 'password' => 'required', + 'password' => 'required|max:1000', ]; } diff --git a/app/Jobs/Invoice/BulkInvoiceJob.php b/app/Jobs/Invoice/BulkInvoiceJob.php new file mode 100644 index 000000000000..ff42dc722e61 --- /dev/null +++ b/app/Jobs/Invoice/BulkInvoiceJob.php @@ -0,0 +1,71 @@ +invoice = $invoice; + $this->reminder_template = $reminder_template; + } + + /** + * Execute the job. + * + * + * @return void + */ + public function handle() + { + + $this->invoice->service()->touchReminder($this->reminder_template)->markSent()->save(); + + $this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) { + EmailEntity::dispatch($invitation, $this->invoice->company, $this->reminder_template)->delay(now()->addSeconds(5)); + }); + + if ($this->invoice->invitations->count() >= 1) { + $this->invoice->entityEmailEvent($this->invoice->invitations->first(), 'invoice', $this->reminder_template); + } + + } + +} diff --git a/app/Libraries/MultiDB.php b/app/Libraries/MultiDB.php index 7250e9f81fae..eee061cb5902 100644 --- a/app/Libraries/MultiDB.php +++ b/app/Libraries/MultiDB.php @@ -284,6 +284,22 @@ class MultiDB return false; } + public static function findAndSetDbByCompanyId($company_id) :?Company + { + $current_db = config('database.default'); + + foreach (self::$dbs as $db) { + if ($company = Company::on($db)->where('id', $company_id)->first()) { + self::setDb($db); + return $company; + } + } + + self::setDB($current_db); + + return false; + } + public static function findAndSetDbByAccountKey($account_key) :bool { $current_db = config('database.default'); @@ -332,6 +348,22 @@ class MultiDB return false; } + public static function findAndSetDbByClientId($client_id) :?Client + { + $current_db = config('database.default'); + + foreach (self::$dbs as $db) { + if ($client = Client::on($db)->where('id', $client_id)->first()) { + self::setDb($db); + return $client; + } + } + + self::setDB($current_db); + + return false; + } + public static function findAndSetDbByDomain($query_array) { diff --git a/app/PaymentDrivers/GoCardlessPaymentDriver.php b/app/PaymentDrivers/GoCardlessPaymentDriver.php index c9cdaef99e98..562416cc2838 100644 --- a/app/PaymentDrivers/GoCardlessPaymentDriver.php +++ b/app/PaymentDrivers/GoCardlessPaymentDriver.php @@ -234,6 +234,9 @@ class GoCardlessPaymentDriver extends BaseDriver $this->init(); + nlog("GoCardless Event"); + nlog($request->all()); + if(!is_array($request->events) || !is_object($request->events)){ diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php index 920f72e27a09..17cfdf5e1437 100644 --- a/app/Services/Invoice/MarkPaid.php +++ b/app/Services/Invoice/MarkPaid.php @@ -18,6 +18,7 @@ use App\Jobs\Invoice\InvoiceWorkflowSettings; use App\Jobs\Ninja\TransactionLog; use App\Jobs\Payment\EmailPayment; use App\Libraries\Currency\Conversion\CurrencyApi; +use App\Models\Client; use App\Models\Invoice; use App\Models\Payment; use App\Models\TransactionEvent; @@ -99,10 +100,15 @@ class MarkPaid extends AbstractService $payment->ledger() ->updatePaymentBalance($payment->amount * -1); - $this->invoice->client->fresh(); - $this->invoice->client->paid_to_date += $payment->amount; - $this->invoice->client->balance += $payment->amount * -1; - $this->invoice->client->push(); + \DB::connection(config('database.default'))->transaction(function () use($payment){ + + /* Get the last record for the client and set the current balance*/ + $client = Client::where('id', $this->invoice->client_id)->lockForUpdate()->first(); + $client->paid_to_date += $payment->amount; + $client->balance += $payment->amount * -1; + $client->save(); + + }, 1); $this->invoice = $this->invoice ->service() diff --git a/app/Services/Invoice/MarkSent.php b/app/Services/Invoice/MarkSent.php index 292521ea5a7f..886888cd77ed 100644 --- a/app/Services/Invoice/MarkSent.php +++ b/app/Services/Invoice/MarkSent.php @@ -57,16 +57,21 @@ class MarkSent extends AbstractService ->service() ->applyNumber() ->setDueDate() - // ->deletePdf() //08-01-2022 - ->touchPdf() //08-01-2022 + ->touchPdf() ->setReminder() ->save(); /*Adjust client balance*/ - $this->client->fresh(); - $this->client->balance += $adjustment; - $this->client->save(); + + \DB::connection(config('database.default'))->transaction(function () use($adjustment){ + + /* Get the last record for the client and set the current balance*/ + $client = Client::where('id', $this->client->id)->lockForUpdate()->first(); + $client->balance += $adjustment; + $client->save(); + + }, 1); $this->invoice->markInvitationsSent(); diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 87e650b9696f..f43741acea06 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -225,10 +225,13 @@ class Design extends BaseDesign public function entityDetails(): array { if ($this->type === 'statement') { + + $s_date = $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale()); + return [ ['element' => 'tr', 'properties' => [], 'elements' => [ ['element' => 'th', 'properties' => [], 'content' => ctrans('texts.statement_date')], - ['element' => 'th', 'properties' => [], 'content' => $this->options['end_date'] ?? ''], + ['element' => 'th', 'properties' => [], 'content' => $s_date ?? ''], ]], ['element' => 'tr', 'properties' => [], 'elements' => [ ['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'], diff --git a/app/Utils/Traits/ClientGroupSettingsSaver.php b/app/Utils/Traits/ClientGroupSettingsSaver.php index 663b17394a2f..0957c70e9dfe 100644 --- a/app/Utils/Traits/ClientGroupSettingsSaver.php +++ b/app/Utils/Traits/ClientGroupSettingsSaver.php @@ -176,7 +176,9 @@ trait ClientGroupSettingsSaver if (! property_exists($settings, $key)) { continue; } elseif ($this->checkAttribute($value, $settings->{$key})) { - if (substr($key, -3) == '_id') { + if (substr($key, -3) == '_id'|| + ($key == 'payment_terms' && property_exists($settings, 'payment_terms') && strlen($settings->{$key}) >= 1) || + ($key == 'valid_until' && property_exists($settings, 'valid_until') && strlen($settings->{$key}) >= 1)) { settype($settings->{$key}, 'string'); } else { settype($settings->{$key}, $value); diff --git a/app/Utils/Traits/CompanySettingsSaver.php b/app/Utils/Traits/CompanySettingsSaver.php index d2b370bd9d31..e210c2ab0dda 100644 --- a/app/Utils/Traits/CompanySettingsSaver.php +++ b/app/Utils/Traits/CompanySettingsSaver.php @@ -63,8 +63,19 @@ trait CompanySettingsSaver { //this pass will handle any null values that are in the translations foreach ($settings->translations as $key => $value) { - if (is_null($settings->translations[$key])) { - $settings->translations[$key] = ''; + + if(is_array($settings->translations)) + { + if (is_null($settings->translations[$key])) { + $settings->translations[$key] = ''; + } + } + elseif(is_object($settings->translations)){ + + if (is_null($settings->translations->{$key})) { + $settings->translations->{$key} = ''; + } + } } diff --git a/config/ninja.php b/config/ninja.php index 5cd221c4039e..10f6f4404b78 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.3.81', - 'app_tag' => '5.3.81', + 'app_version' => '5.3.82', + 'app_tag' => '5.3.82', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), diff --git a/database/migrations/2022_04_22_115838_client_settings_parse_for_types.php b/database/migrations/2022_04_22_115838_client_settings_parse_for_types.php new file mode 100644 index 000000000000..6612ff12a959 --- /dev/null +++ b/database/migrations/2022_04_22_115838_client_settings_parse_for_types.php @@ -0,0 +1,47 @@ +each( function ($client) { + $entity_settings = $this->checkSettingType($client->settings); + $entity_settings->md5 = md5(time()); + $client->settings = $entity_settings; + $client->save(); + + }); + + + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/resources/views/index/index.blade.php b/resources/views/index/index.blade.php index c794eddecf2c..99a10c3303b9 100644 --- a/resources/views/index/index.blade.php +++ b/resources/views/index/index.blade.php @@ -152,7 +152,6 @@ -
diff --git a/tests/Feature/PaymentTest.php b/tests/Feature/PaymentTest.php index 5299cdbf8eec..7c4be819c05a 100644 --- a/tests/Feature/PaymentTest.php +++ b/tests/Feature/PaymentTest.php @@ -1426,7 +1426,7 @@ class PaymentTest extends TestCase $this->assertEquals(10, $this->invoice->balance); - $this->assertEquals(10, $this->invoice->client->balance); + $this->assertEquals(10, $this->invoice->client->fresh()->balance); $this->invoice->service()->markPaid()->save(); diff --git a/tests/Integration/CompanyLedgerTest.php b/tests/Integration/CompanyLedgerTest.php index 01d87f9fce9c..2a9a7f1788da 100644 --- a/tests/Integration/CompanyLedgerTest.php +++ b/tests/Integration/CompanyLedgerTest.php @@ -187,7 +187,7 @@ class CompanyLedgerTest extends TestCase $invoice_ledger = $invoice->company_ledger->sortByDesc('id')->first(); - $this->assertEquals($invoice_ledger->balance, $invoice->client->balance); + $this->assertEquals($invoice_ledger->balance, $this->client->balance); $this->assertEquals($invoice->client->paid_to_date, 0); /* Test adding another invoice */ @@ -203,10 +203,10 @@ class CompanyLedgerTest extends TestCase $invoice->service()->markSent()->save(); //client balance should = 20 - $this->assertEquals($invoice->client->balance, 20); + $this->assertEquals($this->client->fresh()->balance, 20); $invoice_ledger = $invoice->company_ledger->sortByDesc('id')->first(); - $this->assertEquals($invoice_ledger->balance, $invoice->client->balance); + $this->assertEquals($invoice_ledger->balance, $this->client->fresh()->balance); $this->assertEquals($invoice->client->paid_to_date, 0); /* Test making a payment */