From f0ad4175aa340f9e3395d4c3b4e451fc48bf1486 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 11 Mar 2024 13:35:16 +1100 Subject: [PATCH] Fixes for required client invoice + SMTP transport --- .../Transformer/Csv/InvoiceTransformer.php | 8 +- app/Jobs/Mail/NinjaMailerJob.php | 47 +++- app/Livewire/RequiredClientInfo.php | 225 ++++++++++++++---- app/Services/Email/Email.php | 42 +++- app/Utils/Number.php | 2 +- .../livewire/required-client-info.blade.php | 6 +- .../ninja2020/layout/payments.blade.php | 2 +- tests/Unit/NumberTest.php | 5 +- 8 files changed, 274 insertions(+), 63 deletions(-) diff --git a/app/Import/Transformer/Csv/InvoiceTransformer.php b/app/Import/Transformer/Csv/InvoiceTransformer.php index 38980311eae1..5dbced3ca7e8 100644 --- a/app/Import/Transformer/Csv/InvoiceTransformer.php +++ b/app/Import/Transformer/Csv/InvoiceTransformer.php @@ -98,19 +98,19 @@ class InvoiceTransformer extends BaseTransformer $invoice_data, 'invoice.partial_due_date' ), - 'custom_surcharge1' => $this->getString( + 'custom_surcharge1' => $this->getFloat( $invoice_data, 'invoice.custom_surcharge1' ), - 'custom_surcharge2' => $this->getString( + 'custom_surcharge2' => $this->getFloat( $invoice_data, 'invoice.custom_surcharge2' ), - 'custom_surcharge3' => $this->getString( + 'custom_surcharge3' => $this->getFloat( $invoice_data, 'invoice.custom_surcharge3' ), - 'custom_surcharge4' => $this->getString( + 'custom_surcharge4' => $this->getFloat( $invoice_data, 'invoice.custom_surcharge4' ), diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index 7932c01ec79c..6e54dc7d5db2 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -324,7 +324,10 @@ class NinjaMailerJob implements ShouldQueue $this->mailer = 'mailgun'; $this->setMailgunMailer(); return $this; - + case 'smtp': + $this->mailer = 'smtp'; + $this->configureSmtpMailer(); + return $this; default: break; } @@ -336,6 +339,48 @@ class NinjaMailerJob implements ShouldQueue return $this; } + private function configureSmtpMailer(): void + { + + $company = $this->company; + + $smtp_host = $company->smtp_host; + $smtp_port = $company->smtp_port; + $smtp_username = $company->smtp_username; + $smtp_password = $company->smtp_password; + $smtp_encryption = $company->smtp_encryption ?? 'tls'; + $smtp_local_domain = strlen($company->smtp_local_domain) > 2 ? $company->smtp_local_domain : null; + $smtp_verify_peer = $company->smtp_verify_peer ?? true; + + config([ + 'mail.mailers.smtp' => [ + 'transport' => 'smtp', + 'host' => $smtp_host, + 'port' => $smtp_port, + 'username' => $smtp_username, + 'password' => $smtp_password, + 'encryption' => $smtp_encryption, + 'local_domain' => $smtp_local_domain, + 'verify_peer' => $smtp_verify_peer, + 'timeout' => 30, + ], + ]); + + 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 { + $email_from_name = $this->company->present()->name(); + } + + $user = $this->resolveSendingUser(); + $sending_email = (isset($this->nmo->settings->custom_sending_email) && stripos($this->nmo->settings->custom_sending_email, "@")) ? $this->nmo->settings->custom_sending_email : $user->email; + + $this->nmo + ->mailable + ->from($sending_email, $email_from_name); + + } + /** * Allows configuration of multiple mailers * per company for use by self hosted users diff --git a/app/Livewire/RequiredClientInfo.php b/app/Livewire/RequiredClientInfo.php index a4595b771ef2..fdb117de2801 100644 --- a/app/Livewire/RequiredClientInfo.php +++ b/app/Livewire/RequiredClientInfo.php @@ -12,15 +12,17 @@ namespace App\Livewire; +use App\Models\Client; +use App\Models\Invoice; +use Livewire\Component; use App\Libraries\MultiDB; +use Illuminate\Support\Str; use App\Models\ClientContact; use App\Models\CompanyGateway; -use App\Models\Invoice; use App\Utils\Traits\MakesHash; +use Livewire\Attributes\Computed; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Validator; -use Illuminate\Support\Str; -use Livewire\Component; class RequiredClientInfo extends Component { @@ -31,10 +33,7 @@ class RequiredClientInfo extends Component */ public $show_terms = false; - /** - * @var array - */ - public $invoice; + public $invoice_terms; /** * @var bool @@ -49,18 +48,40 @@ class RequiredClientInfo extends Component /** * @var ClientContact */ - public $contact; + public $contact_id; /** * @var \App\Models\Client */ - public $client; + public $client_id; /** * @var array */ public $countries; + + public $client_name; + public $contact_first_name; + public $contact_last_name; + public $contact_email; + public $client_phone; + public $client_address_line_1; + public $client_city; + public $client_state; + public $client_country_id; + public $client_postal_code; + public $client_shipping_address_line_1; + public $client_shipping_city; + public $client_shipping_state; + public $client_shipping_postal_code; + public $client_shipping_country_id; + public $client_custom_value1; + public $client_custom_value2; + public $client_custom_value3; + public $client_custom_value4; + + /** * Mappings for updating the database. Left side is mapping from gateway, * right side is column in database. @@ -113,50 +134,96 @@ class RequiredClientInfo extends Component ]; protected $rules = [ - 'client.address1' => '', - 'client.address2' => '', - 'client.city' => '', - 'client.state' => '', - 'client.postal_code' => '', - 'client.country_id' => '', - 'client.shipping_address1' => '', - 'client.shipping_address2' => '', - 'client.shipping_city' => '', - 'client.shipping_state' => '', - 'client.shipping_postal_code' => '', - 'client.shipping_country_id' => '', - 'contact.first_name' => '', - 'contact.last_name' => '', - 'contact.email' => '', - 'client.name' => '', - 'client.website' => '', - 'client.phone' => '', - 'client.custom_value1' => '', - 'client.custom_value2' => '', - 'client.custom_value3' => '', - 'client.custom_value4' => '', + // 'client.address1' => '', + // 'client.address2' => '', + // 'client.city' => '', + // 'client.state' => '', + // 'client.postal_code' => '', + // 'client.country_id' => '', + // 'client.shipping_address1' => '', + // 'client.shipping_address2' => '', + // 'client.shipping_city' => '', + // 'client.shipping_state' => '', + // 'client.shipping_postal_code' => '', + // 'client.shipping_country_id' => '', + // 'contact.first_name' => '', + // 'contact.last_name' => '', + // 'contact.email' => '', + // 'client.name' => '', + // 'client.website' => '', + // 'client.phone' => '', + // 'client.custom_value1' => '', + // 'client.custom_value2' => '', + // 'client.custom_value3' => '', + // 'client.custom_value4' => '', + 'client_name' => '', + 'client_website' => '', + 'client_phone' => '', + 'client_address_line_1' => '', + 'client_address_line_2' => '', + 'client_city' => '', + 'client_state' => '', + 'client_postal_code' => '', + 'client_country_id' => '', + 'client_shipping_address_line_1' => '', + 'client_shipping_address_line_2' => '', + 'client_shipping_city' => '', + 'client_shipping_state' => '', + 'client_shipping_postal_code' => '', + 'client_shipping_country_id' => '', + 'client_custom_value1' => '', + 'client_custom_value2' => '', + 'client_custom_value3' => '', + 'client_custom_value4' => '', + 'contact_first_name' => '', + 'contact_last_name' => '', + 'contact_email' => '', ]; public $show_form = false; - public $company; + public $company_id; public $company_gateway_id; + public $db; + public function mount() { - MultiDB::setDb($this->company->db); + MultiDB::setDb($this->db); + $contact = ClientContact::withTrashed()->find($this->contact_id); + $company = $contact->company; - $this->client = $this->contact->client; + $this->client_name = $contact->client->name; + $this->contact_first_name = $contact->first_name; + $this->contact_last_name = $contact->last_name; + $this->contact_email = $contact->email; + $this->client_phone = $contact->client->phone; + $this->client_address_line_1 = $contact->client->address1; + $this->client_city = $contact->client->city ; + $this->client_state = $contact->client->state; + $this->client_country_id = $contact->client->country_id; + $this->client_postal_code = $contact->client->postal_code; + $this->client_shipping_address_line_1 = $contact->client->shipping_address1; + $this->client_shipping_city = $contact->client->shipping_city; + $this->client_shipping_state = $contact->client->shipping_state; + $this->client_shipping_postal_code = $contact->client->shipping_postal_code; + $this->client_shipping_country_id = $contact->client->shipping_country_id; + $this->client_custom_value1 = $contact->client->custom_value1; + $this->client_custom_value2 = $contact->client->custom_value2; + $this->client_custom_value3 = $contact->client->custom_value3; + $this->client_custom_value4 = $contact->client->custom_value4; - if ($this->company->settings->show_accept_invoice_terms && request()->query('hash')) { + // $this->client = $this->contact->client; + + if ($company->settings->show_accept_invoice_terms && request()->query('hash')) { $this->show_terms = true; $this->terms_accepted = false; $this->show_form = true; $hash = Cache::get(request()->input('hash')); - $this->invoice = Invoice::find($this->decodePrimaryKey($hash['invoice_id'])); + $this->invoice_terms = Invoice::find($this->decodePrimaryKey($hash['invoice_id']))->terms; } count($this->fields) > 0 || $this->show_terms @@ -164,6 +231,24 @@ class RequiredClientInfo extends Component : $this->show_form = false; } + #[Computed] + public function contact() + { + + MultiDB::setDb($this->db); + return ClientContact::withTrashed()->find($this->contact_id); + + } + + #[Computed] + public function client() + { + + MultiDB::setDb($this->db); + return ClientContact::withTrashed()->find($this->contact_id)->client; + + } + public function toggleTermsAccepted() { $this->terms_accepted = !$this->terms_accepted; @@ -171,6 +256,10 @@ class RequiredClientInfo extends Component public function handleSubmit(array $data): bool { + + MultiDB::setDb($this->db); + $contact = ClientContact::withTrashed()->find($this->contact_id); + $rules = []; collect($this->fields)->map(function ($field) use (&$rules) { @@ -192,7 +281,7 @@ class RequiredClientInfo extends Component if ($this->updateClientDetails($data)) { $this->dispatch( 'passed-required-fields-check', - client_postal_code: $this->contact->client->postal_code + client_postal_code: $contact->client->postal_code ); //if stripe is enabled, we want to update the customer at this point. @@ -209,6 +298,11 @@ class RequiredClientInfo extends Component $client = []; $contact = []; + + MultiDB::setDb($this->db); + $_contact = ClientContact::withTrashed()->find($this->contact_id); + + foreach ($data as $field => $value) { if (Str::startsWith($field, 'client_')) { $client[$this->mappings[$field]] = $value; @@ -219,20 +313,43 @@ class RequiredClientInfo extends Component } } - $contact_update = $this->contact + +$_contact->first_name = $this->contact_first_name; +$_contact->last_name = $this->contact_last_name; +$_contact->client->name = $this->client_name; +$_contact->email = $this->contact_email; +$_contact->client->phone = $this->client_phone; +$_contact->client->address1 = $this->client_address_line_1; +$_contact->client->city = $this->client_city; +$_contact->client->state = $this->client_state; +$_contact->client->country_id = $this->client_country_id; +$_contact->client->postal_code = $this->client_postal_code; +$_contact->client->shipping_address1 = $this->client_shipping_address_line_1; +$_contact->client->shipping_city = $this->client_shipping_city; +$_contact->client->shipping_state = $this->client_shipping_state; +$_contact->client->shipping_postal_code = $this->client_shipping_postal_code; +$_contact->client->shipping_country_id = $this->client_shipping_country_id; +$_contact->client->custom_value1 = $this->client_custom_value1; +$_contact->client->custom_value2 = $this->client_custom_value2; +$_contact->client->custom_value3 = $this->client_custom_value3; +$_contact->client->custom_value4 = $this->client_custom_value4; +$_contact->push(); + + + $contact_update = $_contact ->fill($contact) ->push(); - $client_update = $this->contact->client + $client_update = $_contact->client ->fill($client) ->push(); - if ($contact_update && $client_update) { + if ($_contact) { /** @var \App\Models\CompanyGateway $cg */ $cg = CompanyGateway::find($this->company_gateway_id); if ($cg && $cg->update_details) { - $payment_gateway = $cg->driver($this->client)->init(); + $payment_gateway = $cg->driver($_contact->client)->init(); if (method_exists($payment_gateway, "updateCustomer")) { $payment_gateway->updateCustomer(); @@ -247,11 +364,15 @@ class RequiredClientInfo extends Component public function checkFields() { + + MultiDB::setDb($this->db); + $_contact = ClientContact::withTrashed()->find($this->contact_id); + foreach ($this->fields as $index => $field) { $_field = $this->mappings[$field['name']]; if (Str::startsWith($field['name'], 'client_')) { - if (empty($this->contact->client->{$_field}) || is_null($this->contact->client->{$_field}) || in_array($_field, $this->client_address_array)) { + if (empty($_contact->client->{$_field}) || is_null($_contact->client->{$_field}) || in_array($_field, $this->client_address_array)) { $this->show_form = true; } else { $this->fields[$index]['filled'] = true; @@ -259,7 +380,7 @@ class RequiredClientInfo extends Component } if (Str::startsWith($field['name'], 'contact_')) { - if (empty($this->contact->{$_field}) || is_null($this->contact->{$_field}) || str_contains($this->contact->{$_field}, '@example.com')) { + if (empty($_contact->{$_field}) || is_null($_contact->{$_field}) || str_contains($_contact->{$_field}, '@example.com')) { $this->show_form = true; } else { $this->fields[$index]['filled'] = true; @@ -289,19 +410,23 @@ class RequiredClientInfo extends Component public function handleCopyBilling(): void { + + MultiDB::setDb($this->db); + $_contact = ClientContact::withTrashed()->find($this->contact_id); + $this->dispatch( 'update-shipping-data', - client_shipping_address_line_1: $this->contact->client->address1, - client_shipping_address_line_2: $this->contact->client->address2, - client_shipping_city: $this->contact->client->city, - client_shipping_state: $this->contact->client->state, - client_shipping_postal_code: $this->contact->client->postal_code, - client_shipping_country_id: $this->contact->client->country_id, + client_shipping_address_line_1: $_contact->client->address1, + client_shipping_address_line_2: $_contact->client->address2, + client_shipping_city: $_contact->client->city, + client_shipping_state: $_contact->client->state, + client_shipping_postal_code: $_contact->client->postal_code, + client_shipping_country_id: $_contact->client->country_id, ); } public function render() { - return render('components.livewire.required-client-info'); + return render('components.livewire.required-client-infox'); } } diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php index d0e2da2d39d8..80cc5b0e9a40 100644 --- a/app/Services/Email/Email.php +++ b/app/Services/Email/Email.php @@ -549,7 +549,10 @@ class Email implements ShouldQueue $this->mailer = 'mailgun'; $this->setMailgunMailer(); return $this; - + case 'smtp': + $this->mailer = 'smtp'; + $this->configureSmtpMailer(); + return $this; default: $this->mailer = config('mail.default'); return $this; @@ -562,6 +565,43 @@ class Email implements ShouldQueue return $this; } + private function configureSmtpMailer(): void + { + + $company = $this->company; + + $smtp_host = $company->smtp_host; + $smtp_port = $company->smtp_port; + $smtp_username = $company->smtp_username; + $smtp_password = $company->smtp_password; + $smtp_encryption = $company->smtp_encryption ?? 'tls'; + $smtp_local_domain = strlen($company->smtp_local_domain) > 2 ? $company->smtp_local_domain : null; + $smtp_verify_peer = $company->smtp_verify_peer ?? true; + + config([ + 'mail.mailers.smtp' => [ + 'transport' => 'smtp', + 'host' => $smtp_host, + 'port' => $smtp_port, + 'username' => $smtp_username, + 'password' => $smtp_password, + 'encryption' => $smtp_encryption, + 'local_domain' => $smtp_local_domain, + 'verify_peer' => $smtp_verify_peer, + 'timeout' => 30, + ], + ]); + + $user = $this->resolveSendingUser(); + + $sending_email = (isset($this->email_object->settings->custom_sending_email) && stripos($this->email_object->settings->custom_sending_email, "@")) ? $this->email_object->settings->custom_sending_email : $user->email; + $sending_user = (isset($this->email_object->settings->email_from_name) && strlen($this->email_object->settings->email_from_name) > 2) ? $this->email_object->settings->email_from_name : $user->name(); + + $this->mailable + ->from($sending_email, $sending_user); + + } + /** * Allows configuration of multiple mailers * per company for use by self hosted users diff --git a/app/Utils/Number.php b/app/Utils/Number.php index 53e030093c2c..cf7c0130ec3a 100644 --- a/app/Utils/Number.php +++ b/app/Utils/Number.php @@ -181,7 +181,7 @@ class Number return (float) $value; } - //comma first = traditional thousan separator + //comma first = traditional thousand separator $value = str_replace(',', '', $value); return (float)$value; diff --git a/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php b/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php index ba6e6ac7175c..bda902de7424 100644 --- a/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php +++ b/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php @@ -15,7 +15,7 @@ @if(!array_key_exists('filled', $field)) @component('portal.ninja2020.components.general.card-element', ['title' => $field['label']]) @if($field['name'] == 'client_country_id' || $field['name'] == 'client_shipping_country_id') - @foreach($countries as $country) @@ -25,7 +25,7 @@ @endforeach @else - + @endif @if(session()->has('validation_errors') && array_key_exists($field['name'], session('validation_errors'))) @@ -85,7 +85,7 @@

- {!! nl2br($invoice->terms) !!} + {!! nl2br($invoice_terms) !!}

diff --git a/resources/views/portal/ninja2020/layout/payments.blade.php b/resources/views/portal/ninja2020/layout/payments.blade.php index ec8c52479595..5c5177d0dacb 100644 --- a/resources/views/portal/ninja2020/layout/payments.blade.php +++ b/resources/views/portal/ninja2020/layout/payments.blade.php @@ -11,7 +11,7 @@ @endpush @section('body') - @livewire('required-client-info', ['fields' => method_exists($gateway, 'getClientRequiredFields') ? $gateway->getClientRequiredFields() : [], 'contact' => auth()->guard('contact')->user(), 'countries' => $countries, 'company' => $company, 'company_gateway_id' => $gateway->company_gateway ? $gateway->company_gateway->id : $gateway->id]) + @livewire('required-client-info', ['db' => $company->db, 'fields' => method_exists($gateway, 'getClientRequiredFields') ? $gateway->getClientRequiredFields() : [], 'contact_id' => auth()->guard('contact')->user()->id, 'countries' => $countries, 'company_id' => $company->id, 'company_gateway_id' => $gateway->company_gateway ? $gateway->company_gateway->id : $gateway->id])
diff --git a/tests/Unit/NumberTest.php b/tests/Unit/NumberTest.php index 538a48e338e4..82b7ae8ba530 100644 --- a/tests/Unit/NumberTest.php +++ b/tests/Unit/NumberTest.php @@ -55,13 +55,14 @@ class NumberTest extends TestCase "1000.02" =>"1'000,02 EUR", "1000.02" =>"1 000.02$", "1000.02" =>"1,000.02$", - "1000.02" =>"1.000,02 EURO" + "1000.02" =>"1.000,02 EURO", + "9.975" => "9.975" ]; foreach($floatvals as $key => $value) { - $this->assertEquals($key, Number::parseFloat($value)); + // $this->assertEquals($key, Number::parseFloat2($value)); }