From 972228979678cd33dcd4784bfa7e7b80b802434f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 3 Apr 2022 19:39:55 +1000 Subject: [PATCH 01/19] Fixes for coercing types for react UI --- app/Models/Client.php | 2 ++ app/Repositories/ClientRepository.php | 7 ++++++- app/Utils/Traits/ClientGroupSettingsSaver.php | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/Models/Client.php b/app/Models/Client.php index 48ce8d6c8c..2d6a0d915d 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -22,6 +22,7 @@ use App\Models\Quote; use App\Models\Task; use App\Services\Client\ClientService; use App\Utils\Traits\AppSetup; +use App\Utils\Traits\ClientGroupSettingsSaver; use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; @@ -40,6 +41,7 @@ class Client extends BaseModel implements HasLocalePreference use Filterable; use GeneratesCounter; use AppSetup; + use ClientGroupSettingsSaver; protected $presenter = ClientPresenter::class; diff --git a/app/Repositories/ClientRepository.php b/app/Repositories/ClientRepository.php index 8aec2c5604..a48a8bec49 100644 --- a/app/Repositories/ClientRepository.php +++ b/app/Repositories/ClientRepository.php @@ -14,6 +14,7 @@ namespace App\Repositories; use App\Factory\ClientFactory; use App\Models\Client; use App\Models\Company; +use App\Utils\Traits\ClientGroupSettingsSaver; use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\SavesDocuments; @@ -61,10 +62,14 @@ class ClientRepository extends BaseRepository $client->fill($data); + + if (array_key_exists('settings', $data)) { + $client->saveSettings($data['settings'], $client); + } + if(!$client->country_id){ $company = Company::find($client->company_id); $client->country_id = $company->settings->country_id; - } $client->save(); diff --git a/app/Utils/Traits/ClientGroupSettingsSaver.php b/app/Utils/Traits/ClientGroupSettingsSaver.php index 2172469f19..a7dabe4f20 100644 --- a/app/Utils/Traits/ClientGroupSettingsSaver.php +++ b/app/Utils/Traits/ClientGroupSettingsSaver.php @@ -104,6 +104,11 @@ trait ClientGroupSettingsSaver } foreach ($casts as $key => $value) { + + if($value == 'float' && property_exists($settings, $key)){ + $settings->{$key} = floatval($settings->{$key}); + } + if (in_array($key, CompanySettings::$string_casts)) { $value = 'string'; @@ -160,6 +165,10 @@ trait ClientGroupSettingsSaver foreach ($casts as $key => $value) { + if($value == 'float' && property_exists($settings, $key)){ + $settings->{$key} = floatval($settings->{$key}); + } + /*Separate loop if it is a _id field which is an integer cast as a string*/ if (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') { $value = 'integer'; From c3330b6777df7bff7e4d742a1f7c8d4e3d89e040 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 4 Apr 2022 13:00:11 +1000 Subject: [PATCH 02/19] Reduce queries for Invoice POST --- app/Http/Controllers/InvoiceController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index bbd80dca48..c3d8039546 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -215,7 +215,7 @@ class InvoiceController extends BaseController public function store(StoreInvoiceRequest $request) { - $client = Client::find($request->input('client_id')); + // $client = Client::find($request->input('client_id')); $invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id)); From fa2019661d5662f09b09a7d8ffa2678973a85c60 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 5 Apr 2022 05:23:39 +1000 Subject: [PATCH 03/19] Fixes for regression --- app/Services/Payment/UpdateInvoicePayment.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index a55f65fb70..b516441000 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -73,6 +73,10 @@ class UpdateInvoicePayment /*Improve performance here - 26-01-2022 - also change the order of events for invoice first*/ //caution what if we amount paid was less than partial - we wipe it! + $invoice->balance -= $paid_amount; + $invoice->paid_to_date += $paid_amount; + $invoice->save(); + $invoice = $invoice->service() ->clearPartial() // ->updateBalance($paid_amount * -1) @@ -80,10 +84,6 @@ class UpdateInvoicePayment ->updateStatus() ->touchPdf() ->save(); - - $invoice->balance -= $paid_amount; - $invoice->paid_to_date += $paid_amount; - $invoice->save(); $invoice->service() ->workFlow() From 7d62cd5e50aae47b109a744afc4df6ca20a06339 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 5 Apr 2022 09:52:10 +1000 Subject: [PATCH 04/19] Set correct order of session middleware --- app/Http/Controllers/ClientPortal/InvitationController.php | 2 +- app/Http/Kernel.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/ClientPortal/InvitationController.php b/app/Http/Controllers/ClientPortal/InvitationController.php index 7c22fe41f8..dc1a3cd21a 100644 --- a/app/Http/Controllers/ClientPortal/InvitationController.php +++ b/app/Http/Controllers/ClientPortal/InvitationController.php @@ -210,7 +210,7 @@ class InvitationController extends Controller public function paymentRouter(string $contact_key, string $payment_id) { - $contact = ClientContact::where('contact_key', $contact_key)->firstOrFail(); + $contact = ClientContact::withTrashed()->where('contact_key', $contact_key)->firstOrFail(); $payment = Payment::find($this->decodePrimaryKey($payment_id)); if($payment->client_id != $contact->client_id) diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 515d5f0df5..7cd6458ed8 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -170,6 +170,8 @@ class Kernel extends HttpKernel protected $middlewarePriority = [ + EncryptCookies::class, + StartSession::class, SessionDomains::class, Cors::class, SetDomainNameDb::class, From 4efec42670dc0d360eb28db8920fbb58db841bd7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 5 Apr 2022 13:54:10 +1000 Subject: [PATCH 05/19] Fixes for contact key login --- app/Factory/RecurringInvoiceFactory.php | 2 +- app/Http/Middleware/ContactKeyLogin.php | 14 + app/Repositories/PaymentRepository.php | 10 +- resources/lang/en/texts.php | 21 +- resources/lang/et/texts.php | 420 ++++++++++++------------ 5 files changed, 252 insertions(+), 215 deletions(-) diff --git a/app/Factory/RecurringInvoiceFactory.php b/app/Factory/RecurringInvoiceFactory.php index 7658938a8d..80691807a4 100644 --- a/app/Factory/RecurringInvoiceFactory.php +++ b/app/Factory/RecurringInvoiceFactory.php @@ -48,7 +48,7 @@ class RecurringInvoiceFactory $invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; $invoice->last_sent_date = null; $invoice->next_send_date = null; - $invoice->remaining_cycles = 0; + $invoice->remaining_cycles = -1; $invoice->paid_to_date = 0; return $invoice; diff --git a/app/Http/Middleware/ContactKeyLogin.php b/app/Http/Middleware/ContactKeyLogin.php index 9891236cfb..129cd54c6c 100644 --- a/app/Http/Middleware/ContactKeyLogin.php +++ b/app/Http/Middleware/ContactKeyLogin.php @@ -122,6 +122,20 @@ class ContactKeyLogin return redirect($this->setRedirectPath()); } + }elseif ($request->segment(3)) { + if ($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()) { + if(empty($client_contact->email)) { + $client_contact->email = Str::random(6) . "@example.com"; $client_contact->save(); + } + + auth()->guard('contact')->loginUsingId($client_contact->id, true); + + if ($request->query('next')) { + return redirect($request->query('next')); + } + + return redirect($this->setRedirectPath()); + } } //28-02-2022 middleware should not allow this to progress as we should have redirected by this stage. abort(404, "Unable to authenticate."); diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php index fa02bec8e0..f623574ebd 100644 --- a/app/Repositories/PaymentRepository.php +++ b/app/Repositories/PaymentRepository.php @@ -49,15 +49,7 @@ class PaymentRepository extends BaseRepository { */ public function save(array $data, Payment $payment): ?Payment { - // if ($payment->amount >= 0) { - // return $this->applyPayment($data, $payment); - // } - - - return $this->applyPayment($data, $payment); - - - return $payment; + return $this->applyPayment($data, $payment); } /** diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index e4db031e75..acf2834c54 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4542,7 +4542,26 @@ $LANG = array( 'gmail_credentials_invalid_body' => 'Your GMail credentials are not correct, please log into the administrator portal and navigate to Settings > User Details and disconnect and reconnect your GMail account. We will send you this notification daily until this issue is resolved', 'notification_invoice_sent' => 'Invoice Sent', 'total_columns' => 'Total Fields', - + 'view_task' => 'View Task', + 'cancel_invoice' => 'Cancel', + 'changed_status' => 'Successfully changed task status', + 'change_status' => 'Change Status', + 'enable_touch_events' => 'Enable Touch Events', + 'enable_touch_events_help' => 'Support drag events to scroll', + 'after_saving' => 'After Saving', + 'view_record' => 'View Record', + 'enable_email_markdown' => 'Enable Email Markdown', + 'enable_email_markdown_help' => 'Use visual markdown editor for emails', + 'enable_pdf_markdown' => 'Enable PDF Markdown', + 'json_help' => 'Note: JSON files generated by the v4 app are not supported', + 'release_notes' => 'Release Notes', + 'upgrade_to_view_reports' => 'Upgrade your plan to view reports', + 'started_tasks' => 'Successfully started :value tasks', + 'stopped_tasks' => 'Successfully stopped :value tasks', + 'approved_quote' => 'Successfully apporved quote', + 'approved_quotes' => 'Successfully :value approved quotes', + 'client_website' => 'Client Website', + 'invalid_time' => 'Invalid Time', ); return $LANG; diff --git a/resources/lang/et/texts.php b/resources/lang/et/texts.php index 070e02aa2b..eeec97ab1e 100644 --- a/resources/lang/et/texts.php +++ b/resources/lang/et/texts.php @@ -68,10 +68,10 @@ $LANG = array( 'tax_rates' => 'Maksumäärad', 'rate' => 'Määr', 'settings' => 'Seaded', - 'enable_invoice_tax' => 'Luba määramine', + 'enable_invoice_tax' => 'Lubage arve maksu määramine', 'enable_line_item_tax' => 'Luba täpsustamine', 'dashboard' => 'Töölaud', - 'dashboard_totals_in_all_currencies_help' => 'Märkus. Lisage :link nimega ":Nimi", et kuvada kogusummad põhivluutat kasutades.', + 'dashboard_totals_in_all_currencies_help' => 'Märkus. Lisage :link nimega ":name", et kuvada kogusummad põhivluutat kasutades.', 'clients' => 'Kliendid', 'invoices' => 'Arved', 'payments' => 'Maksed', @@ -207,9 +207,9 @@ $LANG = array( 'confirmation_required' => 'Palun kinnitage oma meiliaadress, :link kinnitusmeili uuesti saatmiseks.', 'updated_client' => 'Kliendi värskendamine õnnestus', 'archived_client' => 'Kliendi arhiivimine õnnestus', - 'archived_clients' => ':kogus klienti on edukalt arhiveeritud', + 'archived_clients' => ':count klienti on edukalt arhiveeritud', 'deleted_client' => 'Kliendi kustutamine õnnestus', - 'deleted_clients' => ':kogus klienti on edukalt kustutatud', + 'deleted_clients' => ':count klienti on edukalt kustutatud', 'updated_invoice' => 'Arve edukalt uuendatud', 'created_invoice' => 'Arve edukalt loodud', 'cloned_invoice' => 'Arve edukalt kloonitud', @@ -220,24 +220,24 @@ $LANG = array( 'deleted_invoice' => 'Arve edukalt kustutatud', 'deleted_invoices' => ':count arvet edukalt kustutatud', 'created_payment' => 'Makse loomine õnnestus', - 'created_payments' => ':kogus makse(t) on edukalt loodud', + 'created_payments' => ':count makse(t) on edukalt loodud', 'archived_payment' => 'Makse arhiivimine õnnestus', - 'archived_payments' => ':kogus makset on edukalt arhiveeritud', + 'archived_payments' => ':count makset on edukalt arhiveeritud', 'deleted_payment' => 'Makse kustutamine õnnestus', - 'deleted_payments' => ':kogus makset on edukalt kustutatud', + 'deleted_payments' => ':count makset on edukalt kustutatud', 'applied_payment' => 'Makse rakendamine õnnestus', 'created_credit' => 'Ettemaksu loomine õnnestus', 'archived_credit' => 'Ettemaksu arhiveerimine õnnestus', - 'archived_credits' => ':kogus ettemakset on edukalt arhiveeritud', + 'archived_credits' => ':count ettemakset on edukalt arhiveeritud', 'deleted_credit' => 'Ettemaksu kustutamine õnnestus', - 'deleted_credits' => ':kogus ettemakset on edukalt kustutatud', + 'deleted_credits' => ':count ettemakset on edukalt kustutatud', 'imported_file' => 'Fail edukalt imporditud', 'updated_vendor' => 'Tarnija värskendamine õnnestus', 'created_vendor' => 'Tarnija loomine õnnestus', 'archived_vendor' => 'Tarnija arhiivimine õnnestus', - 'archived_vendors' => ':kogus tarnijaid on edukalt arhiveeritud', + 'archived_vendors' => ':count tarnijaid on edukalt arhiveeritud', 'deleted_vendor' => 'Tarnija edukalt kustutatud', - 'deleted_vendors' => ':kogus tarnijad on edukalt kustutatud', + 'deleted_vendors' => ':count tarnijad on edukalt kustutatud', 'confirmation_subject' => 'Konto kinnitus', 'confirmation_header' => 'Konto Kinnitus', 'confirmation_message' => 'Oma konto kinnitamiseks minge allolevale lingile.', @@ -252,9 +252,9 @@ $LANG = array( 'notification_invoice_paid_subject' => 'Arve :invoice tasutud :client poolt', 'notification_invoice_sent_subject' => 'Arve :invoice saadeti kliendile :client', 'notification_invoice_viewed_subject' => 'Arvet :invoice vaadati :client poolt', - 'notification_invoice_paid' => 'Klient :klient tegi makse summas :summa arvele :arve.', - 'notification_invoice_sent' => 'Antud kliendile :klient saadeti meili teel arve :arve summas :summa.', - 'notification_invoice_viewed' => 'Antud klient :klient vaatas arvet :arve summas :summa.', + 'notification_invoice_paid' => 'Klient :clienttegi makse summas :amount arvele :invoice.', + 'notification_invoice_sent' => 'Antud kliendile :client saadeti meili teel arve :arve summas :amount.', + 'notification_invoice_viewed' => 'Antud klient :client vaatas arvet :invoice summas :amount.', 'reset_password' => 'Saate oma konto parooli lähtestada, klõpsates järgmist nuppu:', 'secure_payment' => 'Turvaline Makse', 'card_number' => 'Kaardi Number', @@ -263,7 +263,7 @@ $LANG = array( 'cvv' => 'CVV', 'logout' => 'Logi Välja', 'sign_up_to_save' => 'Registreeruge oma töö salvestamiseks', - 'agree_to_terms' => 'Nõustun :tingimustega', + 'agree_to_terms' => 'Nõustun :terms', 'terms_of_service' => 'Teenuse Tingimused', 'email_taken' => 'E-posti aadress on juba registreeritud', 'working' => 'Töötleb', @@ -332,17 +332,17 @@ $LANG = array( 'cloned_quote' => 'Pakkumus edukalt kloonitud', 'emailed_quote' => 'Hinnapakkumise saatmine õnnestus', 'archived_quote' => 'Hinnapakkumine edukalt arhiivitud', - 'archived_quotes' => ':kogus hinnapakkumisi on edukalt arhiveeritud', + 'archived_quotes' => ':count hinnapakkumisi on edukalt arhiveeritud', 'deleted_quote' => 'Hinnapakkmuise kustutamine õnnestus', - 'deleted_quotes' => ':kogus hinnapakkumisi on edukalt kustutatud', + 'deleted_quotes' => ':count hinnapakkumisi on edukalt kustutatud', 'converted_to_invoice' => 'Hinnapakkumus edukalt muudetud arveks', - 'quote_subject' => 'Uus hinnapakkumine :number :kasutaja poolt', + 'quote_subject' => 'Uus hinnapakkumine :number :account poolt', 'quote_message' => 'Nägemaks oma pakkumust summas :amount, klõpsa alloleval lingil.', 'quote_link_message' => 'Et vaadata oma kliendi hinnapakkumist klõpsake allolevat linki:', 'notification_quote_sent_subject' => 'Hinnapakkumus :invoice saadeti kliendile :client', 'notification_quote_viewed_subject' => 'Hinnapakkumust :invoice vaadati :client poolt', - 'notification_quote_sent' => 'Antud kliendile :klient saadeti e-kirjaga hinnapakkumine :arve summas :summa.', - 'notification_quote_viewed' => 'Antud klient :klient vaatas hinnapakkumist :arve summas :summa.', + 'notification_quote_sent' => 'Antud kliendile :client saadeti e-kirjaga hinnapakkumine :invoice summas :amount.', + 'notification_quote_viewed' => 'Antud klient :client vaatas hinnapakkumist :invoice summas :amount.', 'session_expired' => 'Sinu sessioon on aegunud.', 'invoice_fields' => 'Arve Väljad', 'invoice_options' => 'Arve Valikud', @@ -354,7 +354,7 @@ $LANG = array( 'send_invite' => 'Saada Kutse', 'sent_invite' => 'Kutse saadeti edukalt', 'updated_user' => 'Kasutaja värskendamine õnnestus', - 'invitation_message' => 'Teid on kutsunud :kutsuja.', + 'invitation_message' => 'Teid on kutsunud :invitor.', 'register_to_add_user' => 'Kasutaja lisamiseks registreeruge', 'user_state' => 'Maakond', 'edit_user' => 'Muuda Kasutajat', @@ -382,9 +382,9 @@ $LANG = array( 'invoice_issued_to' => 'Arve Saaja', 'invalid_counter' => 'Võimalike konfliktide vältimiseks seadista arve või hinnapakkumuse numbri prefiks.', 'mark_sent' => 'Märgi saadetuks', - 'gateway_help_1' => 'Autorize.neti registreerumiseks : link.', - 'gateway_help_2' => 'Autorize.neti registreerumiseks : link.', - 'gateway_help_17' => 'Oma PayPali API allkirja saamiseks. :link.', + 'gateway_help_1' => 'Autorize.neti registreerumiseks :link.', + 'gateway_help_2' => 'Autorize.neti registreerumiseks :link.', + 'gateway_help_17' => 'Oma PayPali API allkirja saamiseks :link.', 'gateway_help_27' => '2Checkout.com-i registreerumiseks : link. Maksete jälgimise tagamiseks määrake portaalis 2Checkout jaotises Konto > Saidihaldus ümbersuunamise URL-iks :complete_link.', 'gateway_help_60' => 'WePay konto loomiseks :link.', 'more_designs' => 'Rohkem kujundusi', @@ -497,8 +497,8 @@ $LANG = array( 'set_password' => 'Sea Salasõna', 'converted' => 'Teisendatud', 'email_approved' => 'Saada mulle E-kiri, kui pakkumus kinnitatakse', - 'notification_quote_approved_subject' => ':klient kiitis heaks hinnapakkumise :arve', - 'notification_quote_approved' => 'Antud klient :klient kinnitas hinnapakkumise :arve summas :summa.', + 'notification_quote_approved_subject' => ':client kiitis heaks hinnapakkumise :invoice', + 'notification_quote_approved' => 'Antud klient :client kinnitas hinnapakkumise :invoice summas :amount.', 'resend_confirmation' => 'Saada kinnitusmeil uuesti', 'confirmation_resent' => 'Kinnitusmeil saadeti uuesti', 'gateway_help_42' => ':link BitPay kasutajaks registreerumiseks.
Märkus: Kasutage Legacy API võtit, mitte API tokenit.', @@ -656,7 +656,7 @@ $LANG = array( 'recurring_invoice' => 'Perioodiline Arve', 'new_recurring_quote' => 'Uus korduv hinnapakkumine', 'recurring_quote' => 'Korduv hinnapakkumine', - 'recurring_too_soon' => 'Järgmise korduva arve koostamiseks on liiga vara, see on ajastatud kuupäevaks :kuupäev', + 'recurring_too_soon' => 'Järgmise korduva arve koostamiseks on liiga vara, see on ajastatud kuupäevaks :date', 'created_by_invoice' => 'Loodud :invoice', 'primary_user' => 'Peamine Kasutaja', 'help' => 'Abi', @@ -694,12 +694,12 @@ $LANG = array( 'second_reminder' => 'Teine Meeldetuletus', 'third_reminder' => 'Kolmas Meeldetuletus', 'num_days_reminder' => 'Päeva peale maksetähtaega', - 'reminder_subject' => 'Meeldetuletus: Arve :arve :kasutajalt', + 'reminder_subject' => 'Meeldetuletus: Arve :invoice :account', 'reset' => 'Lähtesta', 'invoice_not_found' => 'Soovitud arve pole saadaval', 'referral_program' => 'Referral Program', 'referral_code' => 'Referral URL', - 'last_sent_on' => 'Viimati saadetud: :kuupäev', + 'last_sent_on' => 'Viimati saadetud: :date', 'page_expire' => 'See leht aegub peagi, töö jätkamiseks :click_here', 'upcoming_quotes' => 'Eesseisvad Pakkumused', 'expired_quotes' => 'Aegunud hinnapakkumised', @@ -711,10 +711,10 @@ $LANG = array( 'disable' => 'Keela', 'invoice_quote_number' => 'Arvete ja hinnapakkumiste numbrid', 'invoice_charges' => 'Arve lisatasud', - 'notification_invoice_bounced' => 'Meil ei õnnestunud saata arvet :arve aadressile :kontakt.', - 'notification_invoice_bounced_subject' => 'Arvet :arve ei saa saata', - 'notification_quote_bounced' => 'Meil ei õnnestunud saata hinnapakkumist :arve aadressile :kontakt.', - 'notification_quote_bounced_subject' => 'Hinnapakkumist :arve ei saa saata', + 'notification_invoice_bounced' => 'Meil ei õnnestunud saata arvet :invoice aadressile :contact.', + 'notification_invoice_bounced_subject' => 'Arvet :invoice ei saa saata', + 'notification_quote_bounced' => 'Meil ei õnnestunud saata hinnapakkumist :invoice aadressile :contact.', + 'notification_quote_bounced_subject' => 'Hinnapakkumist :invoiceei saa saata', 'custom_invoice_link' => 'Kohandatud Arve Link', 'total_invoiced' => 'Arveldatud kokku', 'open_balance' => 'Open Balance', @@ -722,7 +722,7 @@ $LANG = array( 'basic_settings' => 'Elementaarsed Seaded', 'pro' => 'Pro', 'gateways' => 'Makselüüsid', - 'next_send_on' => 'Järgmine saatmine: :kuupäev', + 'next_send_on' => 'Järgmine saatmine: :date', 'no_longer_running' => 'This invoice is not scheduled to run', 'general_settings' => 'Üldised Seaded', 'customize' => 'Kohanda', @@ -743,7 +743,7 @@ $LANG = array( 'pattern_help_title' => 'Mustri Abi', 'pattern_help_1' => 'Loo Kohandatud Numeratsioon Kasutades Mustreid', 'pattern_help_2' => 'Saadaolevad muutujad:', - 'pattern_help_3' => 'Näiteks :näide teisendataks väärtuseks :väärtus', + 'pattern_help_3' => 'Näiteks :example teisendataks väärtuseks :value', 'see_options' => 'Vaata valikuid', 'invoice_counter' => 'Arve Loendur', 'quote_counter' => 'Pakkumuse Loendur', @@ -753,53 +753,53 @@ $LANG = array( 'activity_3' => ':user kustutas kliendi :client', 'activity_4' => ':user lõi arve :invoice', 'activity_5' => ':user uuendas arvet :invoice', - 'activity_6' => ':kasutaja saatis arve :arve e-postiga :kliendile :kontaktile', - 'activity_7' => ':kontakt on vaadatud arvet :arve :klient', + 'activity_6' => ':user saatis arve :invoice e-postiga :client :contact', + 'activity_7' => ':contact on vaadatud arvet :invoice :client', 'activity_8' => ':user arhiveeris arve :invoice', 'activity_9' => ':user kustutas arve :invoice', 'activity_10' => ':contact entered payment :payment for :payment_amount on invoice :invoice for :client', - 'activity_11' => ':kasutaja uuendas makset :makse', - 'activity_12' => ':kasutaja arhiveeris makse :makse', - 'activity_13' => ':kasutaja kustutas makse :makse', - 'activity_14' => ':kasutaja sisestas :ettemakse', - 'activity_15' => ':kasutaja värskendas :ettemakse ettemakset', - 'activity_16' => ':kasutaja arhiveeris :ettemakse ettemakse', - 'activity_17' => ':kasutaja kustutas :ettemakse ettemakse', - 'activity_18' => ':kasutaja lõi hinnapkkumise :hinnapakkumine', - 'activity_19' => ':kasutaja uuendas hinnapakkumist :hinnapakkumine', - 'activity_20' => ':kasutaja saatis meiliga hinnapakkumise :hinnapakkumine :kliendile :kontaktile', - 'activity_21' => ':kontakt vaatas hinnapakkumist :hinnapakkumine', - 'activity_22' => ':kasutaja arhiveeris hinnapakkumise :hinnapakkumine', - 'activity_23' => ':kasutaja kustutas hinnapakkumise :hinnapakkumine', - 'activity_24' => ':kasutaja taastas hinnapakkumise :hinnapakkumine', - 'activity_25' => ':kasutaja taastas arve :arve', - 'activity_26' => ':kasutaja taastas kliendi :klient', - 'activity_27' => ':kasutaja taastas makse :makse', - 'activity_28' => ':kasutaja taastas ettemakse :ettemakse', - 'activity_29' => ':kontakt kinnitas hinnapakkumise :hinnapkkumine :kliendile', - 'activity_30' => ':kasutaja lõi tarnija :tarnija', - 'activity_31' => ':kasutaja arhiveeris tarnija :tarnija ', - 'activity_32' => ':kasutaja kustutas tarnija :tarnija ', - 'activity_33' => ':kasutaja taastas tarnija :tarnija', - 'activity_34' => ':kasutaja lõi kulu :kulu', - 'activity_35' => ':kasutaja arhiveeris kulu :kulu', - 'activity_36' => ':kasutaja kustutas kulu :kulu', - 'activity_37' => ':kasutaja taastas kulu :kulu', + 'activity_11' => ':user uuendas makset :payment', + 'activity_12' => ':user arhiveeris makse :payment', + 'activity_13' => ':user kustutas makse :payment', + 'activity_14' => ':user sisestas :credit', + 'activity_15' => ':user värskendas :credit ettemakset', + 'activity_16' => ':user arhiveeris :credit ettemakse', + 'activity_17' => ':user kustutas :credit ettemakse', + 'activity_18' => ':user lõi hinnapkkumise :quote', + 'activity_19' => ':user uuendas hinnapakkumist :quote', + 'activity_20' => ':user saatis meiliga hinnapakkumise :quote :client :contact', + 'activity_21' => ':contact vaatas hinnapakkumist :quote', + 'activity_22' => ':user arhiveeris hinnapakkumise :quote', + 'activity_23' => ':user kustutas hinnapakkumise :quote', + 'activity_24' => ':user taastas hinnapakkumise :quote', + 'activity_25' => ':user taastas arve :invoice', + 'activity_26' => ':user taastas kliendi :client', + 'activity_27' => ':user taastas makse :payment', + 'activity_28' => ':user taastas ettemakse :credit ', + 'activity_29' => ':contact kinnitas hinnapakkumise :quote :client', + 'activity_30' => ':user lõi tarnija :vendor', + 'activity_31' => ':user arhiveeris tarnija :tarnija ', + 'activity_32' => ':user kustutas tarnija :vendor', + 'activity_33' => ':user taastas tarnija :vendor', + 'activity_34' => ':user lõi kulu :expense', + 'activity_35' => ':user arhiveeris kulu :expense', + 'activity_36' => ':user kustutas kulu :expense', + 'activity_37' => ':user taastas kulu :expense', 'activity_42' => ':user lõi ülesande :task', 'activity_43' => ':user uuendas ülesannet :task', 'activity_44' => ':user arhiveeris ülesande :task', 'activity_45' => ':user kustutas ülesande :task', 'activity_46' => ':user taastas ülesande :task', - 'activity_47' => ':kasutaja uuendas kulu :kulu', - 'activity_48' => ':kasutaja uuendas piletit :pilet', - 'activity_49' => ':kasutaja sulges pileti :pilet', - 'activity_50' => ':kasutaja ühendas pileti :pilet', - 'activity_51' => ':kasutaja jagas pileti :pilet', - 'activity_52' => ':kontakt avas pileti :pilet', - 'activity_53' => ':kontakt taasavas pileti :pilet', - 'activity_54' => ':kasutaja taasavas pileti :pilet', - 'activity_55' => ':contact vastas piletile :pilet', - 'activity_56' => ':kasutaja vaatas piletit :pilet', + 'activity_47' => ':user uuendas kulu :expense', + 'activity_48' => ':user uuendas piletit :ticket', + 'activity_49' => ':user sulges pileti :ticket', + 'activity_50' => ':user ühendas pileti :ticket', + 'activity_51' => ':user jagas pileti :ticket', + 'activity_52' => ':contact avas pileti :ticket', + 'activity_53' => ':contact taasavas pileti :ticket', + 'activity_54' => ':user taasavas pileti :ticket', + 'activity_55' => ':contact vastas piletile :ticket', + 'activity_56' => ':user vaatas piletit :ticket', 'payment' => 'Makse', 'system' => 'Süsteem', @@ -842,7 +842,7 @@ $LANG = array( 'user' => 'Kasutaja', 'country' => 'Riik', 'include' => 'Kaasa', - 'logo_too_large' => 'Teie logo suurus on :suurus, parema PDF-i jõudluse tagamiseks soovitame üles laadida alla 200 KB suuruse pildifaili', + 'logo_too_large' => 'Teie logo suurus on :size, parema PDF-i jõudluse tagamiseks soovitame üles laadida alla 200 KB suuruse pildifaili', 'import_freshbooks' => 'Impordi FreshBooksist', 'import_data' => 'Impordi Andmed', 'source' => 'Allikas', @@ -925,7 +925,7 @@ $LANG = array( 'yes' => 'Jah', 'no' => 'Ei', 'should_be_invoiced' => 'Tuleks esitada arve', - 'view_expense' => 'Vaadake kulu # :kulu', + 'view_expense' => 'Vaadake kulu # :expense', 'edit_expense' => 'Muuda kulusid', 'archive_expense' => 'Arhiveeri kulud', 'delete_expense' => 'Kustuta kulud', @@ -959,9 +959,9 @@ $LANG = array( ', 'due' => 'Tähtaeg', - 'next_due_on' => 'Järgmine tähtaeg: :kuupäev', + 'next_due_on' => 'Järgmine tähtaeg: :date', 'use_client_terms' => 'Kasutage kliendi tingimusi', - 'day_of_month' => ':järguline päev kuus', + 'day_of_month' => ':ordinal päev kuus', 'last_day_of_month' => 'Kuu viimane päev', 'day_of_week_after' => ':ordinal :day after', 'sunday' => 'pühapäev', @@ -992,7 +992,7 @@ $LANG = array( 'archived_bank_account' => 'Pangakonto arhiveerimine õnnestus', 'created_bank_account' => 'Pangakonto loomine õnnestus', 'validate_bank_account' => 'Kinnitage pangakonto', - 'bank_password_help' => 'Märkus. Teie parool edastatakse turvaliselt ja seda ei salvestata kunagi meie serveritesse.', + 'bank_password_help' => 'Märkus: Teie parool edastatakse turvaliselt ja seda ei salvestata kunagi meie serveritesse.', 'bank_password_warning' => 'Hoiatus: teie parool võidakse edastada lihttekstina, kaaluge HTTPS-i lubamist.', 'username' => 'Kasutajanimi', 'account_number' => 'Kontonumber', @@ -1032,11 +1032,11 @@ $LANG = array( 'user_email_footer' => 'To adjust your email notification settings please visit :link', 'reset_password_footer' => 'Kui te seda parooli lähtestamist ei taotlenud, saatke meie toele e-kiri: :email', 'limit_users' => 'Vabandust, see ületab kasutajate limiiti :limit', - 'more_designs_self_host_header' => 'Hankige veel 6 arvekujundust vaid $:hinna eest', + 'more_designs_self_host_header' => 'Hankige veel 6 arvekujundust vaid $:price eest', 'old_browser' => 'Palun kasutage :linki', 'newer_browser' => 'uuem brauser', 'white_label_custom_css' => ':link for $:price to enable custom styling and help support our project.', - 'bank_accounts_help' => 'Ühendage pangakonto kulude automaatseks importimiseks ja tarnijate loomiseks. Toetab American Expressi ja :linki.', + 'bank_accounts_help' => 'Ühendage pangakonto kulude automaatseks importimiseks ja tarnijate loomiseks. Toetab American Expressi ja :link.', 'us_banks' => '400+ USA panka', 'pro_plan_remove_logo' => ':link Invoice Ninja logo eemaldamiseks, liitudes Pro-paketiga', @@ -1131,7 +1131,7 @@ $LANG = array( 'invoice_embed_documents_help' => 'Lisage arvele lisatud pildid.', 'document_email_attachment' => 'Lisa dokumendid', 'ubl_email_attachment' => 'Lisa UBL', - 'download_documents' => 'Laadi alla dokumendid (: suurus)', + 'download_documents' => 'Laadi alla dokumendid (:size)', 'documents_from_expenses' => 'Kuludest:', 'dropzone_default_message' => 'Asetage failid või klõpsake üleslaadimiseks', 'dropzone_default_message_disabled' => 'Üleslaadimine keelatud', @@ -1159,8 +1159,8 @@ $LANG = array( 'plan_upgrade' => 'Uuenda', 'plan_change' => 'Muuda Paketti', 'pending_change_to' => 'Changes To', - 'plan_changes_to' => ':plaan :kuupäev', - 'plan_term_changes_to' => ':plaan (:tingimus) kuupäeval :kuupäev', + 'plan_changes_to' => ':plan :date', + 'plan_term_changes_to' => ':plan (:term) kuupäeval :date', 'cancel_plan_change' => 'Katkesta muudatused', 'plan' => 'Pakett', 'expires' => 'Kehtib kuni', @@ -1179,8 +1179,8 @@ $LANG = array( 'plan_term_yearly' => 'Iga-aastaselt', 'plan_term_month' => 'Kuu', 'plan_term_year' => 'Aasta', - 'plan_price_monthly' => '$:price/Kuu', - 'plan_price_yearly' => '$:price/Aasta', + 'plan_price_monthly' => '$:price/Month', + 'plan_price_yearly' => '$:price/Year', 'updated_plan' => 'Uuendatud plaani seaded', 'plan_paid' => 'Term Started', 'plan_started' => 'Plaan alanud', @@ -1218,11 +1218,11 @@ $LANG = array( 'status_completed' => 'Lõpetatud', 'status_failed' => 'Ebaõnnestunud', 'status_partially_refunded' => 'Osaliselt tagastatud', - 'status_partially_refunded_amount' => ':summa tagastatud', + 'status_partially_refunded_amount' => ':amount tagastatud', 'status_refunded' => 'Tagastatud', 'status_voided' => 'Tühistatud', 'refunded_payment' => 'Tagastatud makse', - 'activity_39' => ':kasutaja tühistas :makse_summa makse :makse', + 'activity_39' => ':user tühistas :payment_amount makse :payment', 'activity_40' => ':user refunded :adjustment of a :payment_amount payment :payment', 'card_expiration' => 'Exp: :expires', @@ -1244,7 +1244,7 @@ $LANG = array( 'payment_type_stripe' => 'Stripe', 'ach' => 'ACH', 'enable_ach' => 'Aktsepteerige USA pangaülekandeid', - 'stripe_ach_help' => 'ACH-tugi peab olema lubatud ka :linkis.', + 'stripe_ach_help' => 'ACH-tugi peab olema lubatud ka :link.', 'ach_disabled' => 'Another gateway is already configured for direct debit.', 'plaid' => 'Plaid', @@ -1285,21 +1285,21 @@ $LANG = array( 'use_for_auto_bill' => 'Use For Autobill', 'used_for_auto_bill' => 'Autobill Payment Method', 'payment_method_set_as_default' => 'Set Autobill payment method.', - 'activity_41' => ':makse_summa makse (:makse) ebaõnnestus', + 'activity_41' => ':payment_amount makse (:payment) ebaõnnestus', 'webhook_url' => 'Webhook URL', 'stripe_webhook_help' => 'Peate :link.', 'stripe_webhook_help_link_text' => 'lisage see URL Stripe\'i lõpp-punktina', 'gocardless_webhook_help_link_text' => 'lisage see URL GoCardlessi lõpp-punktina', 'payment_method_error' => 'Teie makseviisi lisamisel ilmnes viga. Palun proovi hiljem uuesti.', - 'notification_invoice_payment_failed_subject' => 'Arve :arve makse ebaõnnestus', - 'notification_invoice_payment_failed' => 'Kliendi :klient poolt tehtud makse arvele :arve ebaõnnestus. Makse on märgitud ebaõnnestunuks ja :summa on lisatud kliendi saldole.', + 'notification_invoice_payment_failed_subject' => 'Arve :invoice makse ebaõnnestus', + 'notification_invoice_payment_failed' => 'Kliendi :client poolt tehtud makse arvele :invoice ebaõnnestus. Makse on märgitud ebaõnnestunuks ja :amount on lisatud kliendi saldole.', 'link_with_plaid' => 'Link Account Instantly with Plaid', 'link_manually' => 'Link käsitsi', 'secured_by_plaid' => 'Secured by Plaid', 'plaid_linked_status' => 'Teie pangakonto aadressil :bank', 'add_payment_method' => 'Lisa makseviis', 'account_holder_type' => 'Konto omaniku tüüp', - 'ach_authorization' => 'Volitan :firmat kasutama minu pangakontot tulevaste maksete tegemiseks ja vajadusel krediteerin oma kontot elektrooniliselt, et parandada vigaseid deebeteid. Mõistan, et võin selle volituse igal ajal tühistada, eemaldades makseviisi või võttes ühendust aadressil :email.', + 'ach_authorization' => 'Volitan :company kasutama minu pangakontot tulevaste maksete tegemiseks ja vajadusel krediteerin oma kontot elektrooniliselt, et parandada vigaseid deebeteid. Mõistan, et võin selle volituse igal ajal tühistada, eemaldades makseviisi või võttes ühendust aadressil :email.', 'ach_authorization_required' => 'Peate ACH tehingutega nõustuma.', 'off' => 'Off', 'opt_in' => 'Opt-in', @@ -1332,7 +1332,7 @@ $LANG = array( 'company_name' => 'Ettevõtte nimi', 'wepay_company_name_help' => 'See kuvatakse kliendi krediitkaardi väljavõtetel.', 'wepay_description_help' => 'Selle konto eesmärk.', - 'wepay_tos_agree' => 'Nõustun :linkiga.', + 'wepay_tos_agree' => 'Nõustun :link.', 'wepay_tos_link_text' => 'WePay teenusetingimused', 'resend_confirmation_email' => 'Saada kinnitusmeil uuesti', 'manage_account' => 'Konto haldamine', @@ -1353,7 +1353,7 @@ $LANG = array( 'original_start_date' => 'Algne alguskuupäev', 'new_start_date' => 'Uus alguskuupäev', 'security' => 'Turvalisus', - 'see_whats_new' => 'Vaadake, mis on v:versioonis uut', + 'see_whats_new' => 'Vaadake, mis on v:versioon uut', 'wait_for_upload' => 'Palun oodake, kuni dokumendi üleslaadimine on lõpule viidud.', 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', 'enable_second_tax_rate' => 'Luba määramine teine ​​maksumäär', @@ -1363,7 +1363,7 @@ $LANG = array( 'import_products' => 'Impordi tooted', 'products_will_create' => 'luuakse tooteid', 'product_key' => 'Toode', - 'created_products' => 'Edukalt loodud/värskendatud: kogus toodet/tooteid', + 'created_products' => 'Edukalt loodud/värskendatud :count toodet/tooteid', 'export_help' => 'Kasuta JSON vormingut kui soovind andmed importida Invoice Ninja-sse.
Fail sisaldab kliente, tooteid, arveid, pakkumusi ja makseid.', 'selfhost_export_help' => '
Soovitame täieliku varukoopia loomiseks kasutada mysqldumpi.', 'JSON_file' => 'JSON Fail', @@ -1386,7 +1386,7 @@ $LANG = array( 'bank_account' => 'Pangakonto', 'payment_processed_through_wepay' => 'ACH-makseid töödeldakse WePay abil.', - 'wepay_payment_tos_agree' => 'Nõustun WePay :tingimuste ja :privaatsuspoliitikaga.', + 'wepay_payment_tos_agree' => 'Nõustun WePay :terms ja :privacy_policy.', 'privacy_policy' => 'Privaatsuspoliitika', 'wepay_payment_tos_agree_required' => 'Peate nõustuma WePay teenusetingimuste ja privaatsuspoliitikaga.', 'ach_email_prompt' => 'Palun sisestage oma e-posti aadress:', @@ -1824,7 +1824,7 @@ $LANG = array( 'updated_expense_category' => 'Kulukategooria värskendamine õnnestus', 'created_expense_category' => 'Kulukategooria loomine õnnestus', 'archived_expense_category' => 'Kulukategooria arhiiveerimine õnnestus', - 'archived_expense_categories' => 'Edukalt arhiveeritud :kogus kulukategooriat', + 'archived_expense_categories' => 'Edukalt arhiveeritud :count kulukategooriat', 'restore_expense_category' => 'Taasta kulukategooria', 'restored_expense_category' => 'Kulukategooria edukalt taastatud', 'apply_taxes' => 'Rakenda maksud', @@ -1844,7 +1844,7 @@ $LANG = array( 'wepay_account_description' => 'Payment gateway for Invoice Ninja', 'payment_error_code' => 'Teie makse [:code] töötlemisel ilmnes viga. Palun proovi hiljem uuesti.', 'standard_fees_apply' => 'Tasu: 2,9%/1,2% [krediitkaart/pangaülekanne] + 0,30 dollarit eduka makse eest.', - 'limit_import_rows' => 'Andmed tuleb importida partiidena :kogus ridade kaupa', + 'limit_import_rows' => 'Andmed tuleb importida partiidena :count ridade kaupa', 'error_title' => 'Midagi läks valesti', 'error_contact_text' => 'Kui soovite abi, saatke meile e-kiri aadressil :mailaddress', 'no_undo' => 'Hoiatus: seda ei saa tagasi võtta.', @@ -1852,7 +1852,7 @@ $LANG = array( 'no_client_selected' => 'Valige klient', 'gateway_config_error' => 'See võib aidata määrata uusi paroole või luua uusi API-võtmeid.', - 'payment_type_on_file' => ':tüüp faili', + 'payment_type_on_file' => ':type faili', 'invoice_for_client' => 'Arve :invoice kliendile :client', 'intent_not_found' => 'Vabandust, ma pole kindel, mida te küsite.', 'intent_not_supported' => 'Vabandust, ma ei saa seda teha.', @@ -1866,7 +1866,7 @@ $LANG = array( 'bot_get_email' => 'Tere! (lehvitus)
Täname Invoice Ninja Boti proovimise eest.
Selle boti kasutamiseks peate looma tasuta konto.
Alustamiseks saatke mulle oma konto meiliaadress.', 'bot_get_code' => 'Aitäh! Saatsin teile turvakoodiga meili.', 'bot_welcome' => 'See on kõik, teie konto on kinnitatud.
', - 'email_not_found' => 'Ma ei leidnud saadaolevat kontot :e-posti jaoks', + 'email_not_found' => 'Ma ei leidnud saadaolevat kontot :email jaoks', 'invalid_code' => 'Kood ei ole õige', 'security_code_email_subject' => 'InvoiceNinja Boti turvakood', 'security_code_email_line1' => 'See on teie Invoice Ninja Boti turvakood.', @@ -1876,7 +1876,7 @@ $LANG = array( 'list_products' => 'Toodete loend', 'include_item_taxes_inline' => 'Include line item taxes in line total', - 'created_quotes' => 'Edukalt loodud :kogus hinnapakkumist', + 'created_quotes' => 'Edukalt loodud :count hinnapakkumist', 'limited_gateways' => 'Note: we support one credit card gateway per company.', 'warning' => 'Hoiatus', @@ -1887,7 +1887,7 @@ $LANG = array( 'update_invoiceninja_unavailable' => 'Invoice Ninja uut versiooni pole saadaval.', 'update_invoiceninja_instructions' => 'Palun installige uus versioon :versioon klõpsates nuppu Uuendage kohe allpool. Pärast seda suunatakse teid juhtpaneelile.', 'update_invoiceninja_update_start' => 'Uuendage kohe', - 'update_invoiceninja_download_start' => 'Laadi alla: versioon', + 'update_invoiceninja_download_start' => 'Laadi alla :version', 'create_new' => 'Loo Uus', 'toggle_navigation' => 'Toggle Navigation', @@ -1938,9 +1938,9 @@ $LANG = array( 'text' => 'Tekst', 'expense_will_create' => 'Kulu luuakse', 'expenses_will_create' => 'Kulud luuakse', - 'created_expenses' => 'Edukalt loodud :kogus kulu(d)', + 'created_expenses' => 'Edukalt loodud :count kulu(d)', - 'translate_app' => 'Aidake meie tõlkeid täiustada :linki abil', + 'translate_app' => 'Aidake meie tõlkeid täiustada :link abil', 'expense_category' => 'Kulu kategooria', 'go_ninja_pro' => 'Mine Ninja Pro!', @@ -1982,42 +1982,10 @@ $LANG = array( 'authorization' => 'Autoriseerimine', 'signed' => 'Allkirjastatud', - // BlueVine - 'bluevine_promo' => 'Get flexible business lines of credit and invoice factoring using BlueVine.', - 'bluevine_modal_label' => 'Registreeruge BlueVine\'iga', - 'bluevine_modal_text' => '

Fast funding for your business. No paperwork.

-
  • Flexible business lines of credit and invoice factoring.
', - 'bluevine_create_account' => 'Loo konto', - 'quote_types' => 'Get a quote for', - 'invoice_factoring' => 'Invoice factoring', - 'line_of_credit' => 'Line of credit', - 'fico_score' => 'Teie FICO skoor', - 'business_inception' => 'Ettevõtte alguskuupäev', - 'average_bank_balance' => 'Keskmine pangakonto saldo', - 'annual_revenue' => 'Aastane tulu', - 'desired_credit_limit_factoring' => 'Desired invoice factoring limit', - 'desired_credit_limit_loc' => 'Desired line of credit limit', - 'desired_credit_limit' => 'Desired credit limit', - 'bluevine_credit_line_type_required' => 'Peate valima vähemalt ühe', - 'bluevine_field_required' => 'See väli on nõutud', - 'bluevine_unexpected_error' => 'Ilmnes ootamatu viga.', - 'bluevine_no_conditional_offer' => 'Enne hinnapakkumise saamist on vaja lisateavet. Klõpsake allpool nuppu Jätka.', - 'bluevine_invoice_factoring' => 'Arve Faktooring', - 'bluevine_conditional_offer' => 'Conditional Offer', - 'bluevine_credit_line_amount' => 'Credit Line', - 'bluevine_advance_rate' => 'Advance Rate', - 'bluevine_weekly_discount_rate' => 'Weekly Discount Rate', - 'bluevine_minimum_fee_rate' => 'Minimumtasu', - 'bluevine_line_of_credit' => 'Line of Credit', - 'bluevine_interest_rate' => 'Interest Rate', - 'bluevine_weekly_draw_rate' => 'Weekly Draw Rate', - 'bluevine_continue' => 'Jätkake BlueVine\'iga', - 'bluevine_completed' => 'BlueVine\'i registreerimine on lõpetatud', - 'vendor_name' => 'Tarnija', 'entity_state' => 'Maakond', 'client_created_at' => 'Loodud', - 'postmark_error' => 'Meili saatmisel Postmark: :linki kaudu ilmnes probleem', + 'postmark_error' => 'Meili saatmisel Postmark: :link kaudu ilmnes probleem', 'project' => 'Projekt', 'projects' => 'Projektid', 'new_project' => 'Uus Projekt', @@ -2082,7 +2050,7 @@ $LANG = array( 'security_confirmation' => 'Teie e-posti aadress on kinnitatud.', 'white_label_expired' => 'Your white label license has expired, please consider renewing it to help support our project.', 'renew_license' => 'Uuenda litsentsi', - 'iphone_app_message' => 'Kaaluge meie :linki allalaadimist', + 'iphone_app_message' => 'Kaaluge meie :link allalaadimist', 'iphone_app' => 'iPhone rakendus', 'android_app' => 'Android rakendus', 'logged_in' => 'Sisse logitud', @@ -2192,8 +2160,8 @@ $LANG = array( 'fee' => 'Fee', 'set_limits_fees' => 'Set :gateway_type Limits/Fees', 'fees_tax_help' => 'Enable line item taxes to set the fee tax rates.', - 'fees_sample' => 'Arve summas :summa viivis oleks :kokku.', - 'discount_sample' => 'Arve summas :summa puhul oleks soodustus :total.', + 'fees_sample' => 'Arve summas :amount viivis oleks :total.', + 'discount_sample' => 'Arve summas :amount puhul oleks soodustus :total.', 'no_fees' => 'No Fees', 'gateway_fees_disclaimer' => 'Warning: not all states/payment gateways allow adding fees, please review local laws/terms of service.', 'percent' => 'Protsent', @@ -2259,7 +2227,7 @@ $LANG = array( 'voice_commands_feedback' => 'We\'re actively working to improve this feature, if there\'s a command you\'d like us to support please email us at :email.', 'payment_type_Venmo' => 'Venmo', 'payment_type_Money Order' => 'Money Order', - 'archived_products' => ':kogus tooted edukalt arhiveeritud', + 'archived_products' => ':count tooted edukalt arhiveeritud', 'recommend_on' => 'Me soovitame võimaldada see seaded.', 'recommend_off' => 'Me soovitame keelata see seaded.', 'notes_auto_billed' => 'Auto-billed', @@ -2351,7 +2319,7 @@ $LANG = array( 'charge_late_fee' => 'Charge Late Fee', 'late_fee_amount' => 'Viivise summa', 'late_fee_percent' => 'Viivise protsent', - 'late_fee_added' => 'Viivis lisati :kuupäev', + 'late_fee_added' => 'Viivis lisati :date', 'download_invoice' => 'Lae Arve Alla', 'download_quote' => 'Lae Pakkumus Alla', 'invoices_are_attached' => 'Teie arve PDF-id on lisatud manusesse.', @@ -2478,7 +2446,7 @@ $LANG = array( 'currency_cuban_peso' => 'Kuuba peeso', - 'review_app_help' => 'Loodame, et teile meeldib rakenduse kasutamine.
Kui kaaluksite :linki, oleksime selle eest väga tänulikud!', + 'review_app_help' => 'Loodame, et teile meeldib rakenduse kasutamine.
Kui kaaluksite :link, oleksime selle eest väga tänulikud!', 'writing_a_review' => 'arvustuse kirjutamine', 'use_english_version' => 'Kasutage kindlasti failide ingliskeelset versiooni.
Väljade sobitamiseks kasutame veerupäiseid.', @@ -2493,7 +2461,7 @@ $LANG = array( 'contact_custom1' => 'Kontakti Esimene Kohandatud', 'contact_custom2' => 'Kontakti Teine Kohandatud', 'currency' => 'Valuuta', - 'ofx_help' => 'Veaotsinguks kontrollige :ofxhome_linki kommentaare ja testige rakendusega :ofxget_link.', + 'ofx_help' => 'Veaotsinguks kontrollige :ofxhome_link kommentaare ja testige rakendusega :ofxget_link.', 'comments' => 'kommentaarid', 'item_product' => 'Item Product', @@ -2509,7 +2477,7 @@ $LANG = array( 'delete_company_help' => 'Jäädavalt kustuta ettevõte kood andmete ja seadistustega.', 'delete_company_message' => 'Hoiatus: see kustutab teie ettevõtte jäädavalt ja seda ei saa tagasi võtta.', - 'applied_discount' => 'Kupong on rakendatud, kava hinda alandatud :allahindlus%.', + 'applied_discount' => 'Kupong on rakendatud, kava hinda alandatud :discount%.', 'applied_free_year' => 'Kupong on rakendatud, teie konto on üheks aastaks üle viidud pro-le.', 'contact_us_help' => 'Kui teatate veast, lisage kõik asjakohased logid saidilt storage/logs/laravel-error.log', @@ -2519,7 +2487,7 @@ $LANG = array( 'customer' => 'Klient', 'customers' => 'Klidendid', 'created_customer' => 'Klient edukalt loodud', - 'created_customers' => 'Edukalt loodud :kogus klienti', + 'created_customers' => 'Edukalt loodud :count klienti', 'purge_details' => 'The data in your company (:account) has been successfully purged.', 'deleted_company' => 'Ettevõtte kustutamine õnnestus', @@ -2598,7 +2566,7 @@ $LANG = array( 'set_phone_for_two_factor' => 'Määrake oma mobiiltelefoni number varukoopia lubamiseks.', 'enabled_two_factor' => 'Kahefaktoriline autentimine edukalt rakendatud', 'add_product' => 'Lisa Toode', - 'email_will_be_sent_on' => 'Märkus: e-kiri saadetakse :kuupäev.', + 'email_will_be_sent_on' => 'Märkus: e-kiri saadetakse :date.', 'invoice_product' => 'Arve toode', 'self_host_login' => 'Self-Host Login', 'set_self_hoat_url' => 'Self-Host URL', @@ -2637,7 +2605,7 @@ $LANG = array( 'invalid_one_time_password' => 'Vigane ühekordne parool', 'apple_pay' => 'Apple/Google Pay', 'enable_apple_pay' => 'Nõustuge Apple Payga ja makske Google\'iga', - 'requires_subdomain' => 'See maksetüüp nõuab :linki.', + 'requires_subdomain' => 'See maksetüüp nõuab :link.', 'subdomain_is_set' => 'subdomain is set', 'verification_file' => 'Kinnitusfail', 'verification_file_missing' => 'Kinnitusfail on vajalik maksete vastuvõtmiseks.', @@ -2691,7 +2659,7 @@ $LANG = array( 'unable_to_delete_primary' => 'Märkus: selle ettevõtte kustutamiseks kustutage esmalt kõik seotud ettevõtted.', 'please_register' => 'Registreerige oma konto', 'processing_request' => 'Taotluse töötlemine', - 'mcrypt_warning' => 'Hoiatus: Mcrypt on aegunud, šifri värskendamiseks käivitage käsk :käsk.', + 'mcrypt_warning' => 'Hoiatus: Mcrypt on aegunud, šifri värskendamiseks käivitage käsk :command .', 'edit_times' => 'Redigeeri aegu', 'inclusive_taxes_help' => 'Include taxes in the cost', 'inclusive_taxes_notice' => 'Seda seadistust ei saa pärast arve koostamist muuta.', @@ -2732,7 +2700,7 @@ $LANG = array( 'tax_amount' => 'Maksud kokku', 'tax_paid' => 'Makstud maksud', 'none' => 'Mitte ühtegi', - 'proposal_message_button' => 'Oma pakkumise vaatamiseks :summas kohta klõpsake alloleval nupul.', + 'proposal_message_button' => 'Oma pakkumise vaatamiseks :amount kohta klõpsake alloleval nupul.', 'proposal' => 'Pakkumine', 'proposals' => 'Pakkumised', 'list_proposals' => 'Loetlege pakkumised', @@ -2744,8 +2712,8 @@ $LANG = array( 'updated_proposal' => 'Ettepanek edukalt uuendatud', 'archived_proposal' => 'Ettepanekud edukalt arhiveeritud ', 'deleted_proposal' => 'Ettepanek edukalt arhiveeritud ', - 'archived_proposals' => ':kogus ettepanekud edukalt arhiveeritud ', - 'deleted_proposals' => ':kogus ettepanekud edukalt arhiveeritud ', + 'archived_proposals' => ':count ettepanekud edukalt arhiveeritud ', + 'deleted_proposals' => ':count ettepanekud edukalt arhiveeritud ', 'restored_proposal' => 'Ettepanek edukalt taastatud', 'restore_proposal' => 'Taasta pakkumine', 'snippet' => 'Snippet', @@ -2776,8 +2744,8 @@ $LANG = array( 'updated_proposal_template' => 'Mall uuendati edukalt', 'archived_proposal_template' => 'Mall arhiveeriti edukalt', 'deleted_proposal_template' => 'Mall arhiveeriti edukalt', - 'archived_proposal_templates' => ':kogus mallide arhiveerimine õnnestus edukalt', - 'deleted_proposal_templates' => ':kogus mallide arhiveerimine õnnestus edukalt', + 'archived_proposal_templates' => ':count mallide arhiveerimine õnnestus edukalt', + 'deleted_proposal_templates' => ':count mallide arhiveerimine õnnestus edukalt', 'restored_proposal_template' => 'Successfully restored template', 'restore_proposal_template' => 'Taasta Mall', 'proposal_category' => 'Kategooria', @@ -2790,8 +2758,8 @@ $LANG = array( 'updated_proposal_category' => 'Kategooria uuendati edukalt', 'archived_proposal_category' => 'Kategooriad arhiveeriti edukalt', 'deleted_proposal_category' => 'Kategooriad arhiveeriti edukalt', - 'archived_proposal_categories' => ':kogus kategooriad arhiveeriti edukalt', - 'deleted_proposal_categories' => ':kogus kategooriad arhiveeriti edukalt', + 'archived_proposal_categories' => ':count kategooriad arhiveeriti edukalt', + 'deleted_proposal_categories' => ':count kategooriad arhiveeriti edukalt', 'restored_proposal_category' => 'Kategooria taastamine õnnestus edukalt', 'restore_proposal_category' => 'Taasta Kategooria', 'delete_status' => 'Kustuta Staatus', @@ -2801,8 +2769,8 @@ $LANG = array( 'create_proposal_category' => 'Loo kategooria', 'clone_proposal_template' => 'Klooni Mall', 'proposal_email' => 'Pakkumise meil', - 'proposal_subject' => 'Uus pakkumine :number :konto lt', - 'proposal_message' => 'Oma pakkumise vaatamiseks :summa kohta klõpsake allolevat linki.', + 'proposal_subject' => 'Uus pakkumine :number :account', + 'proposal_message' => 'Oma pakkumise vaatamiseks :amount kohta klõpsake allolevat linki.', 'emailed_proposal' => 'Ettepanek saadeti meiliga edukalt', 'load_template' => 'Lae Mall', 'no_assets' => 'Pilte pole, lohistage üleslaadimiseks ', @@ -2862,7 +2830,7 @@ $LANG = array( 'allow_approve_expired_quote_help' => 'Lubage klientidel aegunud hinnapakkumisi kinnitada.', 'invoice_workflow' => 'Arve Töövoog', 'quote_workflow' => 'Pakkumuse Töövoog', - 'client_must_be_active' => 'Viga :klient peab olema aktiivne', + 'client_must_be_active' => 'Viga: Klient peab olema aktiivne', 'purge_client' => 'Purge Client', 'purged_client' => 'Successfully purged client', 'purge_client_warning' => 'Kõik seonduvad kirjed (arved, ülesanded, kulud, dokumendid, jne) kustuvad sammuti.', @@ -2875,7 +2843,7 @@ $LANG = array( 'got_it' => 'Sain aru!', 'vendor_will_create' => 'tarnija luuakse', 'vendors_will_create' => 'tarnijad luuakse', - 'created_vendors' => 'Edukalt loodud :kogus tarnija(d)', + 'created_vendors' => 'Edukalt loodud :count tarnija(d)', 'import_vendors' => 'Impordi tarnijad', 'company' => 'Ettevõte', 'client_field' => 'Kliendi Väljad', @@ -2930,7 +2898,7 @@ $LANG = array( 'please_enter_a_product_key' => 'Sisesta Toote kood', 'an_error_occurred' => 'Ilmnes viga', 'overview' => 'Ülevaade', - 'copied_to_clipboard' => 'Kopeeritud :väärtus lõikelauale', + 'copied_to_clipboard' => 'Kopeeritud :value lõikelauale', 'error' => 'Viga', 'could_not_launch' => 'Ei saanud käivitada', 'additional' => 'Lisaks', @@ -2951,7 +2919,7 @@ $LANG = array( 'updated_at' => 'Uuendatud', 'please_enter_an_invoice_number' => 'Palun sisestage arve number', 'please_enter_a_quote_number' => 'Palun sisestage hinnapakkumise number', - 'clients_invoices' => ':kliendi arved', + 'clients_invoices' => ':client\'s arved', 'viewed' => 'Vaadatud', 'approved' => 'Kinnitatud', 'invoice_status_1' => 'Mustand', @@ -3095,22 +3063,22 @@ $LANG = array( 'subject_required' => 'Teema nõutav', 'mobile_refresh_warning' => 'Kui kasutate mobiilirakendust, peate võib-olla tegema täieliku värskenduse.', 'enable_proposals_for_background' => 'Taustapildi üleslaadimiseks :link ettepanekute mooduli lubamiseks.', - 'ticket_assignment' => 'Pilet :pileti_number on määratud :agent \'ile', - 'ticket_contact_reply' => 'Piletit :pileti_number on uuendanud kliendi :kontakt poolt', - 'ticket_new_template_subject' => 'Pilet :pileti_number on loodud.', - 'ticket_updated_template_subject' => 'Pilet :pileti_number on uuendatud.', - 'ticket_closed_template_subject' => 'Pilet :pileti_number on suletud.', - 'ticket_overdue_template_subject' => 'Pilet :pileti_number on nüüd üle tähtaja', + 'ticket_assignment' => 'Pilet :ticket_number on määratud :agent', + 'ticket_contact_reply' => 'Piletit :ticket_number on uuendanud kliendi :contact poolt', + 'ticket_new_template_subject' => 'Pilet :ticket_number on loodud.', + 'ticket_updated_template_subject' => 'Pilet :ticket_number on uuendatud.', + 'ticket_closed_template_subject' => 'Pilet :ticket_number on suletud.', + 'ticket_overdue_template_subject' => 'Pilet :ticket_number on nüüd üle tähtaja', 'merge' => 'Ühendage', 'merged' => 'Ühendatud', 'agent' => 'Agent', 'parent_ticket' => 'Vanem pilet', 'linked_tickets' => 'Lingitud piletid', 'merge_prompt' => 'Sisestage ühendamiseks pileti number', - 'merge_from_to' => 'Pilet #:vana_pilet liideti piletiga #:uus_pilet', - 'merge_closed_ticket_text' => 'Pilet #:vana_pilet suleti ja liideti piletiga #:uus_pilet - :subject', - 'merge_updated_ticket_text' => 'Pilet #:vana_pilet suleti ja liideti sellesse piletisse', - 'merge_placeholder' => 'Ühendage pilet #:pilet järgmiseks piletiks', + 'merge_from_to' => 'Pilet #:old_ticket liideti piletiga #:new_ticket', + 'merge_closed_ticket_text' => 'Pilet #:old_ticket suleti ja liideti piletiga #:new_ticket - :subject', + 'merge_updated_ticket_text' => 'Pilet #:old_ticket suleti ja liideti sellesse piletisse', + 'merge_placeholder' => 'Ühendage pilet #:ticket järgmiseks piletiks', 'select_ticket' => 'Valige Pilet', 'new_internal_ticket' => 'New internal ticket', 'internal_ticket' => 'Internal ticket', @@ -3118,8 +3086,8 @@ $LANG = array( 'allow_inbound_email_tickets_external' => 'Uued piletid meili teel (klient)', 'allow_inbound_email_tickets_external_help' => 'Lubage klientidel e-posti teel uusi pileteid luua', 'include_in_filter' => 'Kaasake filtrisse', - 'custom_client1' => ':VÄÄRTUS', - 'custom_client2' => ':VÄÄRTUS', + 'custom_client1' => ':VALUE', + 'custom_client2' => ':VALUE', 'compare' => 'Võrdlema', 'hosted_login' => 'Hosted Login', 'selfhost_login' => 'Selfhost Login', @@ -3188,7 +3156,7 @@ $LANG = array( 'annual_subscription' => 'Aastane tellimus', 'pro_plan' => 'Pro Plan', 'enterprise_plan' => 'Enterprise Plan', - 'count_users' => ':kogus kasutajaid', + 'count_users' => ':count kasutajaid', 'upgrade' => 'Uuendage', 'please_enter_a_first_name' => 'Palun sisestage eesnimi', 'please_enter_a_last_name' => 'Palun sisestage perekonnanimi', @@ -3356,7 +3324,7 @@ $LANG = array( 'your_message_has_been_received' => 'Saime teie sõnumi kätte ja proovime kiiresti vastata.', 'show_product_details' => 'Kuva toote üksikasjad', 'show_product_details_help' => 'Lisage toote rippmenüüsse kirjeldus ja maksumus', - 'pdf_min_requirements' => 'PDF-i renderdaja nõuab versiooni :versioon', + 'pdf_min_requirements' => 'PDF-i renderdaja nõuab versiooni :version', 'adjust_fee_percent' => 'Reguleerige viivise protsenti', 'configure_settings' => 'Configure Settings', 'about' => 'About', @@ -3415,7 +3383,7 @@ $LANG = array( 'marked_invoice_as_paid' => 'Arve märgiti saadetuks', 'marked_invoices_as_sent' => 'Arved märgiti saadetuks', 'marked_invoices_as_paid' => 'Arved märgiti saadetuks', - 'activity_57' => 'Süsteem ei suutnud arvet :arve meiliga saata', + 'activity_57' => 'Süsteem ei suutnud arvet :invoice meiliga saata', 'custom_value3' => 'Kohandatud väärtus 3', 'custom_value4' => 'Kohandatud väärtus 4', 'email_style_custom' => 'Kohandatud e-posti stiil', @@ -3599,8 +3567,8 @@ $LANG = array( 'reverse' => 'Tühista', 'filtered_by_project' => 'Filtreeritud projekti järgi', 'google_sign_in' => 'Logige sisse Google\'iga', - 'activity_58' => ':kasutaja tühistas arve :arve', - 'activity_59' => ':kasutaja tühistas arve :arve', + 'activity_58' => ':user tühistas arve :invoice', + 'activity_59' => ':user tühistas arve :invoice', 'payment_reconciliation_failure' => 'Reconciliation Failure', 'payment_reconciliation_success' => 'Reconciliation Success', 'gateway_success' => 'Gateway Success', @@ -3621,7 +3589,7 @@ $LANG = array( 'reminder2_sent' => '2. meeldetuletus saadetud', 'reminder3_sent' => '3. meeldetuletus saadetud', 'reminder_last_sent' => 'Viimati saadetud meeldetuletus', - 'pdf_page_info' => 'Lehekülg :praegune :kokku', + 'pdf_page_info' => 'Lehekülg :current :total', 'emailed_credits' => 'Ettemakse on meili teel edukalt saadetud', 'view_in_stripe' => 'Waata Stripe\'is', 'rows_per_page' => 'Ridu lehekülje kohta', @@ -3638,8 +3606,8 @@ $LANG = array( 'company_key' => 'Company Key', 'storefront' => 'Storefront', 'storefront_help' => 'Lubage kolmandate osapoolte rakendustel arveid luua', - 'count_records_selected' => ':kogus valitud kirjeid', - 'count_record_selected' => ':kogus valitud kirje', + 'count_records_selected' => ':count valitud kirjeid', + 'count_record_selected' => ':count valitud kirje', 'client_created' => 'Klient loodud', 'online_payment_email' => 'Online Payment Email', 'manual_payment_email' => 'Manual Payment Email', @@ -3684,7 +3652,7 @@ $LANG = array( 'deleted_webhook' => 'Successfully deleted webhook', 'removed_webhook' => 'Successfully removed webhook', 'restored_webhook' => 'Successfully restored webhook', - 'search_tokens' => 'Otsi :kogus token', + 'search_tokens' => 'Otsi :count token', 'search_token' => 'Otsi 1 Token', 'new_token' => 'Uus Token', 'removed_token' => 'Token on edukalt eemaldatud', @@ -3739,7 +3707,7 @@ $LANG = array( 'gateway_refund_help' => 'Process the refund with the payment gateway', 'due_date_days' => 'Tähtaeg', 'paused' => 'Peatatud', - 'day_count' => 'Päev :kogus', + 'day_count' => 'Päev :count', 'first_day_of_the_month' => 'Kuu esimene päev', 'last_day_of_the_month' => 'Kuu viimane päev', 'use_payment_terms' => 'Kasutage maksetingimusi', @@ -3773,7 +3741,7 @@ $LANG = array( 'removed_task_status' => 'Ülesande olek on edukalt eemaldatud', 'restored_task_status' => 'Ülesande olek on edukalt taastatud', 'search_task_status' => 'Search 1 Task Status', - 'search_task_statuses' => 'Otsi :kogus ülesande olekuid', + 'search_task_statuses' => 'Otsi :count ülesande olekuid', 'show_tasks_table' => 'Show Tasks Table', 'show_tasks_table_help' => 'Always show the tasks section when creating invoices', 'invoice_task_timelog' => 'Invoice Task Timelog', @@ -3812,11 +3780,11 @@ $LANG = array( 'client_phone' => 'Kliendi telefon', 'required_fields' => 'nõutud väljad', 'enabled_modules' => 'Lubatud moodulid', - 'activity_60' => ':kontakt vaatas hinnapakkumist :hinnapakkumine', - 'activity_61' => ':kasutaja uuendas klienti :klient', - 'activity_62' => ':kasutaja uuendas tarnijat :tarnija', - 'activity_63' => ':kasutaja saatis e-kirjaga esimese meeldetuletuse arve kohta :arve aadressile :kontakt', - 'activity_64' => ':kasutaja saatis e-kirjaga teise meeldetuletuse arve kohta :arve aadressile :kontakt', + 'activity_60' => ':contact vaatas hinnapakkumist :quote', + 'activity_61' => ':user uuendas klienti :client', + 'activity_62' => ':user uuendas tarnijat :vendor', + 'activity_63' => ':user saatis e-kirjaga esimese meeldetuletuse arve kohta :invoice aadressile :contact', + 'activity_64' => ':user saatis e-kirjaga teise meeldetuletuse arve kohta :invoice aadressile :contact', 'activity_65' => ':kasutaja saatis e-kirjaga kolmanda meeldetuletuse arve kohta :arve aadressile :kontakt', 'activity_66' => ':user emailed endless reminder for invoice :invoice to :contact', 'expense_category_id' => 'Kulukategooria ID', @@ -3838,8 +3806,8 @@ $LANG = array( 'archived_task_statuses' => ':value ülesannete olekute arhiveerimine õnnestus', 'deleted_task_statuses' => ':value ülesannete olekute kustutamine õnnestus', 'restored_task_statuses' => ':value ülesannete olekute taastamine õnnestus', - 'deleted_expense_categories' => 'Kulude :väärtus kategooriad edukalt kustutatud', - 'restored_expense_categories' => 'Kulude :väärtus kategooriad edukalt taastatud', + 'deleted_expense_categories' => 'Kulude :value kategooriad edukalt kustutatud', + 'restored_expense_categories' => 'Kulude :value kategooriad edukalt taastatud', 'archived_recurring_invoices' => ':value korduvad arved on edukalt arhiveeritud', 'deleted_recurring_invoices' => ':value korduvad arved on edukalt kustutatud', 'restored_recurring_invoices' => ':value korduvad arved on edukalt taastatud', @@ -3954,8 +3922,8 @@ $LANG = array( 'download_timeframe' => 'Kasutage seda linki oma failide allalaadimiseks, link aegub 1 tunni pärast.', 'new_signup' => 'Uus registreerumine', 'new_signup_text' => ':user - :email - on loonud uue konto IP-aadressilt: :ip', - 'notification_payment_paid_subject' => 'Makse tegi :klient', - 'notification_partial_payment_paid_subject' => 'Osalise makse tegi :klient', + 'notification_payment_paid_subject' => 'Makse tegi :client', + 'notification_partial_payment_paid_subject' => 'Osalise makse tegi :client', 'notification_payment_paid' => 'A payment of :amount was made by client :client towards :invoice', 'notification_partial_payment_paid' => 'A partial payment of :amount was made by client :client towards :invoice', 'notification_bot' => 'Notification Bot', @@ -4256,7 +4224,7 @@ $LANG = array( 'activity_103' => ':user deleted recurring invoice :recurring_invoice', 'activity_104' => ':user restored recurring invoice :recurring_invoice', 'new_login_detected' => 'Teie kontol tuvastati uus sisselogimine.', - 'new_login_description' => 'Logisite hiljuti oma Invoice Ninja kontole sisse uuest asukohast või seadmest:

IP: :ip
Aeg: : aeg
E-post: :e-post', + 'new_login_description' => 'Logisite hiljuti oma Invoice Ninja kontole sisse uuest asukohast või seadmest:

IP: :ip
Aeg: : time
E-post: :email', 'download_backup_subject' => 'Teie ettevõtte varukoopia on allalaadimiseks valmis', 'contact_details' => 'Kontaktandmed', 'download_backup_subject' => 'Teie ettevõtte varukoopia on allalaadimiseks valmis', @@ -4273,10 +4241,10 @@ $LANG = array( 'client_email_company_contact_label' => 'Kui teil on küsimusi, võtke meiega ühendust, me oleme siin, et aidata!', 'quote_was_approved_label' => 'Hinnapakkumine kiideti heaks', 'quote_was_approved' => 'Teatame, et pakkumine kiideti heaks.', - 'company_import_failure_subject' => 'Viga importimisel :ettevõte', + 'company_import_failure_subject' => 'Viga importimisel :company', 'company_import_failure_body' => 'Ettevõtte andmete importimisel ilmnes viga, veateade oli järgmine:', 'recurring_invoice_due_date' => 'Tähtaeg', - 'amount_cents' => 'Summa pennides, pennides või sentides', + 'amount_cents' => 'Amount in pennies,pence or cents. ie for $0.10 please enter 10', 'default_payment_method_label' => 'Vaikimisi makseviis', 'default_payment_method' => 'Muutke see oma eelistatud makseviisiks.', 'already_default_payment_method' => 'See on teie eelistatud makseviis.', @@ -4290,14 +4258,14 @@ $LANG = array( 'quotes_with_status_sent_can_be_approved' => 'Kinnitada saab ainult hinnapakkumisi, mille olek on "Saadetud".', 'no_quotes_available_for_download' => 'Hinapakkumist pole võimalik alla laadida', 'copyright' => 'Autoriõigus', - 'user_created_user' => ':kasutaja lõi kasutaja :loodud_kasutaja kell :aeg', + 'user_created_user' => ':user lõi kasutaja :created_user kell :time', 'company_deleted' => 'Ettevõte kustutatud', - 'company_deleted_body' => 'Ettevõte [ :ettevõte] kustutati :user poolt', + 'company_deleted_body' => 'Ettevõte [ :company ] kustutati :user poolt', 'back_to' => 'Tagasi aadressile :url', 'stripe_connect_migration_title' => 'Ühendage oma Stripe\'i konto', 'stripe_connect_migration_desc' => 'Invoice Ninja v5 kasutab Stripe Connecti teie Stripe\'i konto linkimiseks Invoice Ninjaga. See annab teie kontole täiendava turvakihi. Nüüd, kui teie andmed on üle viidud, peate v5-s maksete vastuvõtmiseks lubama Stripe\'i.

Selleks liikuge jaotisse Seaded > Veebimaksed > Lüüside seadistamine. Klõpsake Stripe Connect ja seejärel jaotises Seaded nuppu Setup Gateway. See viib teid Stripe\'i, et autoriseerida Invoice Ninja ja tagastamisel lingitakse teie konto edukalt!', 'email_quota_exceeded_subject' => 'Konto e-posti kvoot on ületatud.', - 'email_quota_exceeded_body' => '24 tunni jooksul olete saatnud :kvoot e-kirju.
Peatasime teie väljaminevad meilid.

Teie meilikvoot lähtestatakse kell 23:00 UTC.', + 'email_quota_exceeded_body' => '24 tunni jooksul olete saatnud :quota e-kirju.
Peatasime teie väljaminevad meilid.

Teie meilikvoot lähtestatakse kell 23:00 UTC.', 'auto_bill_option' => 'Lubage või keelduge selle arve automaatsest tasumisest .', 'lang_Arabic' => 'Araablane', 'lang_Persian' => 'Pärslane', @@ -4332,7 +4300,7 @@ $LANG = array( 'checkout' => 'Kassasse', 'acss' => 'Eelvolitatud deebetmaksed', 'invalid_amount' => 'Vale summa. Ainult arv/kümnendväärtused.', - 'client_payment_failure_body' => 'Arve :arve summas :summa tasumine ebaõnnestus.', + 'client_payment_failure_body' => 'Arve :invoice summas :amount tasumine ebaõnnestus.', 'browser_pay' => 'Google Pay, Apple Pay, Microsoft Pay', 'no_available_methods' => 'Me ei leia teie seadmest ühtegi krediitkaarti. Loe selle kohta lähemalt.', 'gocardless_mandate_not_ready' => 'Maksevolitus pole valmis. Palun proovi hiljem uuesti.', @@ -4432,7 +4400,7 @@ $LANG = array( 'check_status' => 'Kontrolli olekut', 'free_trial' => 'Tasuta prooviversioon', 'free_trial_help' => 'Kõik kontod saavad Pro-paketi kahenädalase prooviperioodi. Kui prooviperiood lõppeb, muutub teie konto automaatselt tasuta paketiks.', - 'free_trial_ends_in_days' => 'Pro-paketi prooviperiood lõpeb :kogus päeva pärast, klõpsake versiooniuuendamiseks.', + 'free_trial_ends_in_days' => 'Pro-paketi prooviperiood lõpeb :count päeva pärast, klõpsake versiooniuuendamiseks.', 'free_trial_ends_today' => 'Täna on Pro-paketi prooviversiooni viimane päev, klõpsake versiooniuuendamiseks.', 'change_email' => 'Muuda meiliaadressi', 'client_portal_domain_hint' => 'Optionally configure a separate client portal domain', @@ -4467,7 +4435,7 @@ $LANG = array( 'ended_all_sessions' => 'Kõik seansid on edukalt lõppenud', 'end_all_sessions' => 'Lõpetage kõik seansid', 'count_session' => '1 seanss', - 'count_sessions' => ':kogus seansse', + 'count_sessions' => ':count seansse', 'invoice_created' => 'Arve loodud', 'quote_created' => 'Hinnapakkumine loodud', 'credit_created' => 'Ettemaks loodud', @@ -4527,6 +4495,50 @@ $LANG = array( 'html_mode_help' => 'Värskenduste eelvaade on kiirem, kuid vähem täpne', 'status_color_theme' => 'Oleku värviteema', 'load_color_theme' => 'Laadige värviteema', + 'lang_Estonian' => 'Estonian', + 'marked_credit_as_paid' => 'Successfully marked credit as paid', + 'marked_credits_as_paid' => 'Successfully marked credits as paid', + 'wait_for_loading' => 'Data loading - please wait for it to complete', + 'wait_for_saving' => 'Data saving - please wait for it to complete', + 'html_preview_warning' => 'Note: changes made here are only previewed, they must be applied in the tabs above to be saved', + 'remaining' => 'Remaining', + 'invoice_paid' => 'Invoice Paid', + 'activity_120' => ':user created recurring expense :recurring_expense', + 'activity_121' => ':user updated recurring expense :recurring_expense', + 'activity_122' => ':user archived recurring expense :recurring_expense', + 'activity_123' => ':user deleted recurring expense :recurring_expense', + 'activity_124' => ':user restored recurring expense :recurring_expense', + 'fpx' => "FPX", + 'to_view_entity_set_password' => 'To view the :entity you need to set password.', + 'unsubscribe' => 'Unsubscribe', + 'unsubscribed' => 'Unsubscribed', + 'unsubscribed_text' => 'You have been removed from notifications for this document', + 'client_shipping_state' => 'Client Shipping State', + 'client_shipping_city' => 'Client Shipping City', + 'client_shipping_postal_code' => 'Client Shipping Postal Code', + 'client_shipping_country' => 'Client Shipping Country', + 'load_pdf' => 'Load PDF', + 'start_free_trial' => 'Start Free Trial', + 'start_free_trial_message' => 'Start your FREE 14 day trial of the pro plan', + 'due_on_receipt' => 'Due on Receipt', + 'is_paid' => 'Is Paid', + 'age_group_paid' => 'Paid', + 'id' => 'Id', + 'convert_to' => 'Convert To', + 'client_currency' => 'Client Currency', + 'company_currency' => 'Company Currency', + 'custom_emails_disabled_help' => 'To prevent spam we require upgrading to a paid account to customize the email', + 'upgrade_to_add_company' => 'Upgrade your plan to add companies', + 'file_saved_in_downloads_folder' => 'The file has been saved in the downloads folder', + 'small' => 'Small', + 'quotes_backup_subject' => 'Your quotes are ready for download', + 'credits_backup_subject' => 'Your credits are ready for download', + 'document_download_subject' => 'Your documents are ready for download', + 'reminder_message' => 'Reminder for invoice :number for :balance', + 'gmail_credentials_invalid_subject' => 'Send with GMail invalid credentials', + 'gmail_credentials_invalid_body' => 'Your GMail credentials are not correct, please log into the administrator portal and navigate to Settings > User Details and disconnect and reconnect your GMail account. We will send you this notification daily until this issue is resolved', + 'notification_invoice_sent' => 'Antud kliendile :client saadeti meili teel arve :arve summas :amount.', + 'total_columns' => 'Total Fields', ); From 4080c47e9b08586eab4df8e3c38f59ee0bc34192 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 5 Apr 2022 20:47:44 +1000 Subject: [PATCH 06/19] Localize timezonen for payment date --- app/Services/Invoice/MarkPaid.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php index 9b29b072a9..920f72e27a 100644 --- a/app/Services/Invoice/MarkPaid.php +++ b/app/Services/Invoice/MarkPaid.php @@ -61,6 +61,9 @@ class MarkPaid extends AbstractService $payment->currency_id = $this->invoice->client->getSetting('currency_id'); $payment->is_manual = true; + if($this->invoice->company->timezone()) + $payment->date = now()->addSeconds($this->invoice->company->timezone()->utc_offset)->format('Y-m-d'); + $payment_type_id = $this->invoice->client->getSetting('payment_type_id'); if((int)$payment_type_id > 0) From 15b18dfc8fe5fbac98a92b78602cd311021390b6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 6 Apr 2022 10:38:01 +1000 Subject: [PATCH 07/19] Entity translations --- app/Jobs/Document/ZipDocuments.php | 9 +- app/Models/Client.php | 4 + app/Models/Company.php | 5 + app/Models/Credit.php | 5 + app/Models/Expense.php | 5 + app/Models/Invoice.php | 5 + app/Models/Payment.php | 4 + app/Models/Product.php | 7 +- app/Models/Project.php | 4 + app/Models/Quote.php | 5 + app/Models/RecurringExpense.php | 5 +- app/Models/RecurringInvoice.php | 5 + app/Models/RecurringQuote.php | 4 + app/Models/Task.php | 7 +- app/Models/User.php | 5 + app/Models/Vendor.php | 5 + tests/Unit/EntityTranslationTest.php | 157 +++++++++++++++++++++++++++ 17 files changed, 236 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/EntityTranslationTest.php diff --git a/app/Jobs/Document/ZipDocuments.php b/app/Jobs/Document/ZipDocuments.php index 12312acb20..4ff689e971 100644 --- a/app/Jobs/Document/ZipDocuments.php +++ b/app/Jobs/Document/ZipDocuments.php @@ -88,7 +88,7 @@ class ZipDocuments implements ShouldQueue foreach ($documents as $document) { - $zipFile->addFromString($document->name, $document->getFile()); + $zipFile->addFromString($this->buildFileName($document), $document->getFile()); } @@ -112,7 +112,12 @@ class ZipDocuments implements ShouldQueue $zipFile->close(); } - } + + private function buildFileName($document) :string + { + $filename = $document->name; + + } } diff --git a/app/Models/Client.php b/app/Models/Client.php index 2d6a0d915d..19133814d6 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -712,4 +712,8 @@ class Client extends BaseModel implements HasLocalePreference ]; } + public function translate_entity() + { + return ctrans('texts.client'); + } } diff --git a/app/Models/Company.php b/app/Models/Company.php index 24e1ff98f2..35739589ae 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -549,4 +549,9 @@ class Company extends BaseModel return $data; } + + public function translate_entity() + { + return ctrans('texts.company'); + } } diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 310041dbef..191b4dbcbb 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -314,4 +314,9 @@ class Credit extends BaseModel 'credit_status' => $credit->status_id ?: 1, ]; } + + public function translate_entity() + { + return ctrans('texts.credit'); + } } diff --git a/app/Models/Expense.php b/app/Models/Expense.php index d9a09f6c2c..27f1273113 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -101,4 +101,9 @@ class Expense extends BaseModel { return $this->belongsTo(Client::class); } + + public function translate_entity() + { + return ctrans('texts.expense'); + } } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 30d4128cd3..5a028981c5 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -560,4 +560,9 @@ class Invoice extends BaseModel 'invoice_status' => $invoice->status_id ?: 1, ]; } + + public function translate_entity() + { + return ctrans('texts.invoice'); + } } diff --git a/app/Models/Payment.php b/app/Models/Payment.php index 584fef3765..4709439694 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -337,4 +337,8 @@ class Payment extends BaseModel ]; } + public function translate_entity() + { + return ctrans('texts.payment'); + } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 01b1852633..19f3d2be7e 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -64,4 +64,9 @@ class Product extends BaseModel { return $this->morphMany(Document::class, 'documentable'); } -} + + public function translate_entity() + { + return ctrans('texts.product'); + } +} \ No newline at end of file diff --git a/app/Models/Project.php b/app/Models/Project.php index daf67ad2d1..694a44c8dc 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -78,4 +78,8 @@ class Project extends BaseModel return $this->hasMany(Task::class); } + public function translate_entity() + { + return ctrans('texts.project'); + } } diff --git a/app/Models/Quote.php b/app/Models/Quote.php index 7dd4af6e16..a0a9c8b099 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -311,4 +311,9 @@ class Quote extends BaseModel { return $this->calc()->getTotal(); } + + public function translate_entity() + { + return ctrans('texts.quote'); + } } diff --git a/app/Models/RecurringExpense.php b/app/Models/RecurringExpense.php index b886fac713..aca56970e4 100644 --- a/app/Models/RecurringExpense.php +++ b/app/Models/RecurringExpense.php @@ -239,5 +239,8 @@ class RecurringExpense extends BaseModel } } - + public function translate_entity() + { + return ctrans('texts.recurring_expense'); + } } diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index b600c8c65b..7b83d1c22a 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -505,4 +505,9 @@ class RecurringInvoice extends BaseModel { return $this->belongsTo(Subscription::class); } + + public function translate_entity() + { + return ctrans('texts.recurring_invoice'); + } } diff --git a/app/Models/RecurringQuote.php b/app/Models/RecurringQuote.php index b6a685a3a2..a35b911453 100644 --- a/app/Models/RecurringQuote.php +++ b/app/Models/RecurringQuote.php @@ -488,5 +488,9 @@ class RecurringQuote extends BaseModel return new RecurringService($this); } + public function translate_entity() + { + return ctrans('texts.recurring_quote'); + } } diff --git a/app/Models/Task.php b/app/Models/Task.php index 96d169d965..b4e1073220 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -147,4 +147,9 @@ class Task extends BaseModel return round($duration); } -} + + public function translate_entity() + { + return ctrans('texts.task'); + } +} \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index 7288f94a7e..16a8091090 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -449,4 +449,9 @@ class User extends Authenticatable implements MustVerifyEmail { return new UserService($this); } + + public function translate_entity() + { + return ctrans('texts.user'); + } } diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index b7505d680a..7cc03366a3 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -104,4 +104,9 @@ class Vendor extends BaseModel { return $this->belongsTo(User::class)->withTrashed(); } + + public function translate_entity() + { + return ctrans('texts.vendor'); + } } diff --git a/tests/Unit/EntityTranslationTest.php b/tests/Unit/EntityTranslationTest.php new file mode 100644 index 0000000000..9eaec378a5 --- /dev/null +++ b/tests/Unit/EntityTranslationTest.php @@ -0,0 +1,157 @@ +faker = \Faker\Factory::create(); + } + + public function testTranslations() + { + $account = Account::factory()->create([ + 'hosted_client_count' => 1000, + 'hosted_company_count' => 1000 + ]); + + + $company = Company::factory()->create([ + 'account_id' => $account->id, + ]); + + $u = User::factory()->create([ + 'email' => $this->faker->email, + 'account_id' => $account->id + ]); + + $client = Client::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id + ]); + + $credit = Credit::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $expense = Expense::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $invoice = Invoice::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $payment = Payment::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $product = Product::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + ]); + + $project = Project::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $quote = Quote::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $recurring_expense = RecurringExpense::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $recurring_invoice = RecurringInvoice::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $recurring_quote = RecurringQuote::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $task = Task::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + 'client_id' => $client->id, + ]); + + $vendor = Vendor::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $u->id, + ]); + + $this->assertEquals(ctrans('texts.user'), $u->translate_entity()); + $this->assertEquals(ctrans('texts.company'), $company->translate_entity()); + $this->assertEquals(ctrans('texts.client'), $client->translate_entity()); + $this->assertEquals(ctrans('texts.credit'), $credit->translate_entity()); + $this->assertEquals(ctrans('texts.expense'), $expense->translate_entity()); + $this->assertEquals(ctrans('texts.invoice'), $invoice->translate_entity()); + $this->assertEquals(ctrans('texts.payment'), $payment->translate_entity()); + $this->assertEquals(ctrans('texts.product'), $product->translate_entity()); + $this->assertEquals(ctrans('texts.project'), $project->translate_entity()); + $this->assertEquals(ctrans('texts.quote'), $quote->translate_entity()); + $this->assertEquals(ctrans('texts.recurring_expense'), $recurring_expense->translate_entity()); + $this->assertEquals(ctrans('texts.recurring_invoice'), $recurring_invoice->translate_entity()); + $this->assertEquals(ctrans('texts.recurring_quote'), $recurring_quote->translate_entity()); + $this->assertEquals(ctrans('texts.task'), $task->translate_entity()); + $this->assertEquals(ctrans('texts.vendor'), $vendor->translate_entity()); + } + +} From 16b219dbb953a4e3988c43a4b1aa8b1146223c45 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 6 Apr 2022 12:22:13 +1000 Subject: [PATCH 08/19] Link converted quote to invoice --- app/Jobs/Document/ZipDocuments.php | 19 ++++++++++++++++++- app/Models/Document.php | 5 +++++ .../portal/ninja2020/quotes/show.blade.php | 13 +++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app/Jobs/Document/ZipDocuments.php b/app/Jobs/Document/ZipDocuments.php index 4ff689e971..810c9c2359 100644 --- a/app/Jobs/Document/ZipDocuments.php +++ b/app/Jobs/Document/ZipDocuments.php @@ -21,19 +21,23 @@ use App\Mail\DownloadInvoices; use App\Models\Company; use App\Models\Document; use App\Models\User; +use App\Utils\Ninja; use App\Utils\TempFile; +use App\Utils\Traits\MakesDates; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Storage; use ZipArchive; class ZipDocuments implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesDates; public $document_ids; @@ -77,6 +81,11 @@ class ZipDocuments implements ShouldQueue { MultiDB::setDb($this->company->db); + App::setLocale($this->company->locale()); + App::forgetInstance('translator'); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + # create new zip object $zipFile = new \PhpZip\ZipFile(); $file_name = date('Y-m-d').'_'.str_replace(' ', '_', trans('texts.documents')).'.zip'; @@ -119,5 +128,13 @@ class ZipDocuments implements ShouldQueue { $filename = $document->name; + $date = $this->formatDate(Carbon::createFromTimestamp($document->created_at), 'Y-m-d'); + + $number = "_"; + + if(isset($document->documentable->number)) + $number = "_".$document->documentable->number; + + return "{$date}_{$document->documentable->translate_entity()}{$number}_{$filename}"; } } diff --git a/app/Models/Document.php b/app/Models/Document.php index a6ff0fba4c..7ebf62c77a 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -140,4 +140,9 @@ class Document extends BaseModel { return Storage::get($this->url); } + + public function translate_entity() + { + return ctrans('texts.document'); + } } diff --git a/resources/views/portal/ninja2020/quotes/show.blade.php b/resources/views/portal/ninja2020/quotes/show.blade.php index 71dfa0553f..4330e5ff1b 100644 --- a/resources/views/portal/ninja2020/quotes/show.blade.php +++ b/resources/views/portal/ninja2020/quotes/show.blade.php @@ -44,7 +44,19 @@ @endif + + + + + + @if($quote->invoice_id) + + @endif @@ -71,6 +83,7 @@ + @else
From cba199cd67f59d81c75cac239dce5dde94c7fe59 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 6 Apr 2022 14:43:14 +1000 Subject: [PATCH 09/19] Coerce types for authorize payment error --- app/PaymentDrivers/Authorize/AuthorizeCreditCard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php index 98906f81d2..fe361592dd 100644 --- a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php +++ b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php @@ -257,7 +257,7 @@ class AuthorizeCreditCard $description = "There was an error processing the payment"; if ($response && $response->getErrors() != null) { - $code = $response->getErrors()[0]->getErrorCode(); + $code = (int)$response->getErrors()[0]->getErrorCode(); $description = $response->getErrors()[0]->getErrorText(); } From 59e032f88357c244855777eef0b608d66e86a239 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 6 Apr 2022 14:52:07 +1000 Subject: [PATCH 10/19] Handle user not present in completePurchase method of subscriptions --- app/Services/Subscription/SubscriptionService.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 9899e94f22..04e2541df9 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -121,7 +121,10 @@ class SubscriptionService //execute any webhooks $this->triggerWebhook($context); - $this->handleRedirect('/client/invoices/'.$this->encodePrimaryKey($payment_hash->fee_invoice_id)); + /* 06-04-2022 */ + /* We may not be in a state where the user is present */ + if(auth()->guard('contact')) + $this->handleRedirect('/client/invoices/'.$this->encodePrimaryKey($payment_hash->fee_invoice_id)); } } From 4210d11fc19b64be308e2fe3073a03445699747f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 6 Apr 2022 20:14:54 +1000 Subject: [PATCH 11/19] Reports --- .../Reports/ClientReportController.php | 91 +++++++++++++++++++ app/Models/Client.php | 6 -- routes/api.php | 3 + 3 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 app/Http/Controllers/Reports/ClientReportController.php diff --git a/app/Http/Controllers/Reports/ClientReportController.php b/app/Http/Controllers/Reports/ClientReportController.php new file mode 100644 index 0000000000..f009e16b09 --- /dev/null +++ b/app/Http/Controllers/Reports/ClientReportController.php @@ -0,0 +1,91 @@ +json(['message' => 'Processing'], 200); + $company = auth()->user()->company(); + + $header = ['first name', 'last name', 'email']; + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($header); + + $records = []; + + //insert all the records + // $this->csv->insertAll($records); + + + Client::with('contacts')->where('company_id') + ->where('is_deleted',0) + ->cursor() + + echo $this->csv->toString(); + + + } + + + +} diff --git a/app/Models/Client.php b/app/Models/Client.php index 19133814d6..9133fc951e 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -89,12 +89,6 @@ class Client extends BaseModel implements HasLocalePreference 'gateway_tokens', 'documents', 'contacts.company', - // 'currency', - // 'primary_contact', - // 'country', - // 'contacts', - // 'shipping_country', - // 'company', ]; protected $casts = [ diff --git a/routes/api.php b/routes/api.php index 2ae7c343f9..385cdd98aa 100644 --- a/routes/api.php +++ b/routes/api.php @@ -154,6 +154,9 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale Route::post('refresh', 'Auth\LoginController@refresh'); + Route::post('reports/clients', 'Reports\ClientReportController'); + + Route::get('scheduler', 'SchedulerController@index'); Route::post('support/messages/send', 'Support\Messages\SendingController'); From 7174939fe07345e85d58eaebc1541c52df0859cc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 07:07:59 +1000 Subject: [PATCH 12/19] Fixes for translation of task statuses --- .../Reports/ClientReportController.php | 22 ++++++++++++++++--- .../Company/CreateCompanyTaskStatuses.php | 5 +++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Reports/ClientReportController.php b/app/Http/Controllers/Reports/ClientReportController.php index f009e16b09..a1e9c98e23 100644 --- a/app/Http/Controllers/Reports/ClientReportController.php +++ b/app/Http/Controllers/Reports/ClientReportController.php @@ -13,6 +13,7 @@ namespace App\Http\Controllers\Reports; use App\Http\Controllers\BaseController; use App\Http\Requests\Report\ClientReportRequest; +use App\Models\Client; use App\Utils\Traits\MakesHash; use Illuminate\Http\Response; use League\Csv\Writer; @@ -21,7 +22,17 @@ class ClientReportController extends BaseController { use MakesHash; - public Writer $csv; + private Writer $csv; + + private array $keys; + + /* + [ + 'client', + 'contacts', + '' + ] + */ public function __construct() { @@ -64,7 +75,8 @@ class ClientReportController extends BaseController $company = auth()->user()->company(); $header = ['first name', 'last name', 'email']; - + $this->keys = $request->input('keys'); + //load the CSV document from a string $this->csv = Writer::createFromString(); @@ -76,10 +88,14 @@ class ClientReportController extends BaseController //insert all the records // $this->csv->insertAll($records); - Client::with('contacts')->where('company_id') ->where('is_deleted',0) ->cursor() + ->each(function ($client){ + + // $row = + + }); echo $this->csv->toString(); diff --git a/app/Jobs/Company/CreateCompanyTaskStatuses.php b/app/Jobs/Company/CreateCompanyTaskStatuses.php index 2c07dbf6cf..6e5b3bd7bb 100644 --- a/app/Jobs/Company/CreateCompanyTaskStatuses.php +++ b/app/Jobs/Company/CreateCompanyTaskStatuses.php @@ -15,6 +15,7 @@ use App\Libraries\MultiDB; use App\Models\TaskStatus; use App\Utils\Traits\MakesHash; use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Support\Facades\App; class CreateCompanyTaskStatuses { @@ -51,6 +52,10 @@ class CreateCompanyTaskStatuses if(TaskStatus::where('company_id', $this->company->id)->count() > 0) return; + App::forgetInstance('translator'); + $t = app('translator'); + App::setLocale($this->company->locale()); + $task_statuses = [ ['name' => ctrans('texts.backlog'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 1], ['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], From 912d0aebc585447bd94978ee3d0f682ef41eeff0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 08:52:10 +1000 Subject: [PATCH 13/19] Do not send notifications to archived/deleted users --- app/Listeners/Invoice/InvoiceCreatedNotification.php | 2 +- app/Utils/Traits/Notifications/UserNotifies.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Listeners/Invoice/InvoiceCreatedNotification.php b/app/Listeners/Invoice/InvoiceCreatedNotification.php index 4f6d117f81..f85200d5aa 100644 --- a/app/Listeners/Invoice/InvoiceCreatedNotification.php +++ b/app/Listeners/Invoice/InvoiceCreatedNotification.php @@ -64,7 +64,7 @@ class InvoiceCreatedNotification implements ShouldQueue /* Returns an array of notification methods */ $methods = $this->findUserNotificationTypes($invoice->invitations()->first(), $company_user, 'invoice', ['all_notifications', 'invoice_created', 'invoice_created_all']); /* If one of the methods is email then we fire the EntitySentMailer */ - // if (($key = array_search('mail', $methods))) { + if (($key = array_search('mail', $methods)) !== false) { unset($methods[$key]); diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 5b8d312c84..f5d8f63adc 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -32,7 +32,7 @@ trait UserNotifies $notifiable_methods = []; $notifications = $company_user->notifications; - if ($company_user->company->is_disabled && is_array($notifications->email)) { + if ($company_user->company->is_disabled && is_array($notifications->email) || $company_user->trashed() || $company_user->user->trashed()) { return []; } @@ -56,7 +56,7 @@ trait UserNotifies $notifiable_methods = []; $notifications = $company_user->notifications; - if ($company_user->company->is_disabled || ! $notifications) { + if ($company_user->company->is_disabled || ! $notifications || $company_user->trashed() || $company_user->user->trashed()) { return []; } @@ -125,7 +125,7 @@ trait UserNotifies public function findCompanyUserNotificationType($company_user, $required_permissions) :array { - if ($company_user->company->is_disabled) { + if ($company_user->company->is_disabled || $company_user->trashed() || $company_user->user->trashed()) { return []; } From 17b1119466e1ea137e2878c2ef239b9590eabbc9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 09:06:02 +1000 Subject: [PATCH 14/19] Allow draft credits to be used in payments --- app/Http/ValidationRules/ValidCreditsPresentRule.php | 5 ++--- app/Repositories/PaymentRepository.php | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/ValidationRules/ValidCreditsPresentRule.php b/app/Http/ValidationRules/ValidCreditsPresentRule.php index 5cb77a680e..ac62328aed 100644 --- a/app/Http/ValidationRules/ValidCreditsPresentRule.php +++ b/app/Http/ValidationRules/ValidCreditsPresentRule.php @@ -46,10 +46,9 @@ class ValidCreditsPresentRule implements Rule if (request()->input('credits') && is_array(request()->input('credits'))) { $credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id'))) - ->where('balance', '>', 0) - ->get(); + ->count(); - return $credit_collection->count() == count(request()->input('credits')); + return $credit_collection == count(request()->input('credits')); } return true; diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php index f623574ebd..651737fd83 100644 --- a/app/Repositories/PaymentRepository.php +++ b/app/Repositories/PaymentRepository.php @@ -156,6 +156,7 @@ class PaymentRepository extends BaseRepository { $credit = Credit::withTrashed()->find($this->decodePrimaryKey($paid_credit['credit_id'])); if ($credit) { + $credit = $credit->service()->markSent()->save(); ApplyCreditPayment::dispatchNow($credit, $payment, $paid_credit['amount'], $credit->company); } } From f8e60546fb9188f5391209ac69513b1d80f6417c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 12:17:02 +1000 Subject: [PATCH 15/19] Client Reports --- app/Export/CSV/ClientExport.php | 180 ++++++++++++++++++ .../Reports/ClientReportController.php | 43 +---- .../Requests/Report/ClientReportRequest.php | 27 +++ 3 files changed, 210 insertions(+), 40 deletions(-) create mode 100644 app/Export/CSV/ClientExport.php create mode 100644 app/Http/Requests/Report/ClientReportRequest.php diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php new file mode 100644 index 0000000000..3abb7e92db --- /dev/null +++ b/app/Export/CSV/ClientExport.php @@ -0,0 +1,180 @@ + 'client.address1', + 'address2' => 'client.address2', + 'balance' => 'client.balance', + 'city' => 'client.city', + 'country' => 'client.country_id', + 'credit_balance' => 'client.credit_balance', + 'custom_value1' => 'client.custom_value1', + 'custom_value2' => 'client.custom_value2', + 'custom_value3' => 'client.custom_value3', + 'custom_value4' => 'client.custom_value4', + 'id_number' => 'client.id_number', + 'industry' => 'client.industry_id', + 'last_login' => 'client.last_login', + 'name' => 'client.name', + 'number' => 'client.number', + 'paid_to_date' => 'client.paid_to_date', + 'phone' => 'client.phone', + 'postal_code' => 'client.postal_code', + 'private_notes' => 'client.private_notes', + 'public_notes' => 'client.public_notes', + 'shipping_address1' => 'client.shipping_address1', + 'shipping_address2' => 'client.shipping_address2', + 'shipping_city' => 'client.shipping_city', + 'shipping_country' => 'client.shipping_country_id', + 'shipping_postal_code' => 'client.shipping_postal_code', + 'shipping_state' => 'client.shipping_state', + 'state' => 'client.state', + 'vat_number' => 'client.vat_number', + 'website' => 'client.website', + 'currency' => 'client.currency', + 'first_name' => 'contact.first_name', + 'last_name' => 'contact.last_name', + 'phone' => 'contact.phone', + 'contact_custom_value1' => 'contact.custom_value1', + 'contact_custom_value2' => 'contact.custom_value2', + 'contact_custom_value3' => 'contact.custom_value3', + 'contact_custom_value4' => 'contact.custom_value4', + 'email' => 'contact.email', + ]; + + private array $decorate_keys = [ + 'client.country_id', + 'client.shipping_country_id', + 'client.currency', + 'client.industry', + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->client_transformer = new ClientTransformer(); + $this->contact_transformer = new ClientContactTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Client::with('contacts')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($client){ + + $this->csv->insertOne($this->buildRow($client)); + + }); + + + echo $this->csv->toString(); + + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(Client $client) :array + { + + $transformed_contact = false; + + $transformed_client = $this->client_transformer->transform($client); + + if($contact = $client->contacts()->first()) + $transformed_contact = $this->contact_transformer->transform($contact); + + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $parts = explode(".",$key); + $entity[$parts[1]] = ""; + + if($parts[0] == 'client') { + $entity[$parts[1]] = $transformed_client[$parts[1]]; + } + elseif($parts[0] == 'contact') { + $entity[$parts[1]] = $transformed_contact[$parts[1]]; + } + + } + + return $this->decorateAdvancedFields($client, $entity); + + } + + private function decorateAdvancedFields(Client $client, array $entity) :array + { + + if(array_key_exists('country_id', $entity)) + $entity['country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : ""; + + if(array_key_exists('shipping_country_id', $entity)) + $entity['shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : ""; + + if(array_key_exists('currency', $entity)) + $entity['currency'] = $client->currency()->code; + + if(array_key_exists('industry_id', $entity)) + $entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : ""; + + return $entity; + } + +} diff --git a/app/Http/Controllers/Reports/ClientReportController.php b/app/Http/Controllers/Reports/ClientReportController.php index a1e9c98e23..804cbce47d 100644 --- a/app/Http/Controllers/Reports/ClientReportController.php +++ b/app/Http/Controllers/Reports/ClientReportController.php @@ -11,29 +11,17 @@ namespace App\Http\Controllers\Reports; +use App\Export\CSV\ClientExport; use App\Http\Controllers\BaseController; use App\Http\Requests\Report\ClientReportRequest; use App\Models\Client; use App\Utils\Traits\MakesHash; use Illuminate\Http\Response; -use League\Csv\Writer; class ClientReportController extends BaseController { use MakesHash; - private Writer $csv; - - private array $keys; - - /* - [ - 'client', - 'contacts', - '' - ] - */ - public function __construct() { parent::__construct(); @@ -72,34 +60,9 @@ class ClientReportController extends BaseController // expect a list of visible fields, or use the default // return response()->json(['message' => 'Processing'], 200); - $company = auth()->user()->company(); - - $header = ['first name', 'last name', 'email']; - $this->keys = $request->input('keys'); - - //load the CSV document from a string - $this->csv = Writer::createFromString(); - - //insert the header - $this->csv->insertOne($header); - - $records = []; - - //insert all the records - // $this->csv->insertAll($records); - - Client::with('contacts')->where('company_id') - ->where('is_deleted',0) - ->cursor() - ->each(function ($client){ - - // $row = - - }); - - echo $this->csv->toString(); - + $export = new ClientExport(auth()->user()->company(), $request->input('keys')); + $csv = $export->run(); } diff --git a/app/Http/Requests/Report/ClientReportRequest.php b/app/Http/Requests/Report/ClientReportRequest.php new file mode 100644 index 0000000000..5fa2e16ec9 --- /dev/null +++ b/app/Http/Requests/Report/ClientReportRequest.php @@ -0,0 +1,27 @@ +user()->isAdmin(); + } +} From ee6f2012f6ed40a1139fa25569aa8885a7915a9e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 14:47:05 +1000 Subject: [PATCH 16/19] prevent double gateway fee removal --- app/Services/Invoice/AutoBillInvoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/Invoice/AutoBillInvoice.php b/app/Services/Invoice/AutoBillInvoice.php index 26ea686c07..7649d86c69 100644 --- a/app/Services/Invoice/AutoBillInvoice.php +++ b/app/Services/Invoice/AutoBillInvoice.php @@ -125,7 +125,7 @@ class AutoBillInvoice extends AbstractService } catch(\Exception $e){ nlog("payment NOT captured for ". $this->invoice->number . " with error " . $e->getMessage()); - $this->invoice->service()->removeUnpaidGatewayFees(); + // $this->invoice->service()->removeUnpaidGatewayFees(); } if($payment){ From 4f10dcd9139f70c291955b169ec131f0f0b835cd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 17:40:59 +1000 Subject: [PATCH 17/19] Improve invoice number generation when race conditions encountered --- app/Jobs/Quote/ApplyQuoteNumber.php | 85 ------------------- app/Services/Credit/ApplyNumber.php | 37 +++++++- app/Services/Invoice/ApplyNumber.php | 38 ++++++++- app/Services/Invoice/ApplyRecurringNumber.php | 40 ++++++++- app/Services/Payment/ApplyNumber.php | 35 +++++++- app/Services/Quote/ApplyNumber.php | 39 ++++++++- app/Services/Recurring/ApplyNumber.php | 35 +++++++- 7 files changed, 214 insertions(+), 95 deletions(-) delete mode 100644 app/Jobs/Quote/ApplyQuoteNumber.php diff --git a/app/Jobs/Quote/ApplyQuoteNumber.php b/app/Jobs/Quote/ApplyQuoteNumber.php deleted file mode 100644 index a046e5f623..0000000000 --- a/app/Jobs/Quote/ApplyQuoteNumber.php +++ /dev/null @@ -1,85 +0,0 @@ -quote = $quote; - - $this->settings = $settings; - - $this->company = $company; - } - - /** - * Execute the job. - * - * - * @return Quote - */ - public function handle() - { - MultiDB::setDB($this->company->db); - - //return early - if ($this->quote->number != '') { - return $this->quote; - } - - switch ($this->settings->quote_number_applied) { - case 'when_saved': - $this->quote->number = $this->getNextQuoteNumber($this->quote->client, $this->quote); - break; - case 'when_sent': - if ($this->quote->status_id == Quote::STATUS_SENT) { - $this->quote->number = $this->getNextQuoteNumber($this->quote->client, $this->quote); - } - break; - - default: - // code... - break; - } - - $this->quote->save(); - - return $this->quote; - } -} diff --git a/app/Services/Credit/ApplyNumber.php b/app/Services/Credit/ApplyNumber.php index 8bb1909521..bfc474f7cd 100644 --- a/app/Services/Credit/ApplyNumber.php +++ b/app/Services/Credit/ApplyNumber.php @@ -15,6 +15,7 @@ use App\Models\Client; use App\Models\Credit; use App\Services\AbstractService; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Database\QueryException; class ApplyNumber extends AbstractService { @@ -24,6 +25,8 @@ class ApplyNumber extends AbstractService private $credit; + private bool $completed = true; + public function __construct(Client $client, Credit $credit) { $this->client = $client; @@ -37,8 +40,40 @@ class ApplyNumber extends AbstractService return $this->credit; } - $this->credit->number = $this->getNextCreditNumber($this->client, $this->credit); + $this->trySaving(); + // $this->credit->number = $this->getNextCreditNumber($this->client, $this->credit); return $this->credit; } + + + private function trySaving() + { + + $x=1; + + do{ + + try{ + + $this->credit->number = $this->getNextCreditNumber($this->client, $this->credit); + $this->credit->saveQuietly(); + + $this->completed = false; + + + } + catch(QueryException $e){ + + $x++; + + if($x>10) + $this->completed = false; + } + + } + while($this->completed); + + } + } diff --git a/app/Services/Invoice/ApplyNumber.php b/app/Services/Invoice/ApplyNumber.php index 786051fb18..333566a82d 100644 --- a/app/Services/Invoice/ApplyNumber.php +++ b/app/Services/Invoice/ApplyNumber.php @@ -15,6 +15,7 @@ use App\Models\Client; use App\Models\Invoice; use App\Services\AbstractService; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Database\QueryException; class ApplyNumber extends AbstractService { @@ -24,6 +25,8 @@ class ApplyNumber extends AbstractService private $invoice; + private $completed = true; + public function __construct(Client $client, Invoice $invoice) { $this->client = $client; @@ -39,11 +42,13 @@ class ApplyNumber extends AbstractService switch ($this->client->getSetting('counter_number_applied')) { case 'when_saved': - $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); + $this->trySaving(); + // $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); break; case 'when_sent': if ($this->invoice->status_id == Invoice::STATUS_SENT) { - $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); + $this->trySaving(); + // $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); } break; @@ -53,4 +58,33 @@ class ApplyNumber extends AbstractService return $this->invoice; } + + private function trySaving() + { + + $x=1; + + do{ + + try{ + + $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id); + $this->invoice->saveQuietly(); + + $this->completed = false; + + + } + catch(QueryException $e){ + + $x++; + + if($x>10) + $this->completed = false; + } + + } + while($this->completed); + + } } diff --git a/app/Services/Invoice/ApplyRecurringNumber.php b/app/Services/Invoice/ApplyRecurringNumber.php index 1c26e7f60b..c93817e6f3 100644 --- a/app/Services/Invoice/ApplyRecurringNumber.php +++ b/app/Services/Invoice/ApplyRecurringNumber.php @@ -15,6 +15,7 @@ use App\Models\Client; use App\Models\Invoice; use App\Services\AbstractService; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Database\QueryException; class ApplyRecurringNumber extends AbstractService { @@ -24,6 +25,8 @@ class ApplyRecurringNumber extends AbstractService private $invoice; + private bool $completed = true; + public function __construct(Client $client, Invoice $invoice) { $this->client = $client; @@ -39,11 +42,13 @@ class ApplyRecurringNumber extends AbstractService switch ($this->client->getSetting('counter_number_applied')) { case 'when_saved': - $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); + $this->trySaving(); + //$this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); break; case 'when_sent': if ($this->invoice->status_id == Invoice::STATUS_SENT) { - $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); + $this->trySaving(); + // $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); } break; @@ -54,4 +59,33 @@ class ApplyRecurringNumber extends AbstractService return $this->invoice; } -} + + private function trySaving() + { + + $x=1; + + do{ + + try{ + + $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client, $this->invoice); + $this->invoice->saveQuietly(); + + $this->completed = false; + + + } + catch(QueryException $e){ + + $x++; + + if($x>10) + $this->completed = false; + } + + } + while($this->completed); + + } +} \ No newline at end of file diff --git a/app/Services/Payment/ApplyNumber.php b/app/Services/Payment/ApplyNumber.php index 2f773dcb02..34604843bd 100644 --- a/app/Services/Payment/ApplyNumber.php +++ b/app/Services/Payment/ApplyNumber.php @@ -14,6 +14,7 @@ namespace App\Services\Payment; use App\Models\Payment; use App\Services\AbstractService; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Database\QueryException; class ApplyNumber extends AbstractService { @@ -21,6 +22,8 @@ class ApplyNumber extends AbstractService private $payment; + private bool $completed = true; + public function __construct(Payment $payment) { $this->client = $payment->client; @@ -34,8 +37,38 @@ class ApplyNumber extends AbstractService return $this->payment; } - $this->payment->number = $this->getNextPaymentNumber($this->client, $this->payment); + $this->trySaving(); + // $this->payment->number = $this->getNextPaymentNumber($this->client, $this->payment); return $this->payment; } + + private function trySaving() + { + + $x=1; + + do{ + + try{ + + $this->payment->number = $this->getNextPaymentNumber($this->client, $this->payment); + $this->payment->saveQuietly(); + + $this->completed = false; + + + } + catch(QueryException $e){ + + $x++; + + if($x>10) + $this->completed = false; + } + + } + while($this->completed); + + } } diff --git a/app/Services/Quote/ApplyNumber.php b/app/Services/Quote/ApplyNumber.php index d7a8a0055a..1b9b77b98a 100644 --- a/app/Services/Quote/ApplyNumber.php +++ b/app/Services/Quote/ApplyNumber.php @@ -13,6 +13,7 @@ namespace App\Services\Quote; use App\Models\Quote; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Database\QueryException; class ApplyNumber { @@ -20,6 +21,8 @@ class ApplyNumber private $client; + private bool $completed = true; + public function __construct($client) { $this->client = $client; @@ -33,11 +36,13 @@ class ApplyNumber switch ($this->client->getSetting('counter_number_applied')) { case 'when_saved': - $quote->number = $this->getNextQuoteNumber($this->client, $quote); + $quote = $this->trySaving($quote); + // $quote->number = $this->getNextQuoteNumber($this->client, $quote); break; case 'when_sent': if ($quote->status_id == Quote::STATUS_SENT) { - $quote->number = $this->getNextQuoteNumber($this->client, $quote); + $quote = $this->trySaving($quote); + // $quote->number = $this->getNextQuoteNumber($this->client, $quote); } break; @@ -48,4 +53,34 @@ class ApplyNumber return $quote; } + + private function trySaving($quote) + { + + $x=1; + + do{ + + try{ + + $quote->number = $this->getNextQuoteNumber($this->client, $quote); + $quote->saveQuietly(); + + $this->completed = false; + + + } + catch(QueryException $e){ + + $x++; + + if($x>10) + $this->completed = false; + } + + } + while($this->completed); + + return $quote; + } } diff --git a/app/Services/Recurring/ApplyNumber.php b/app/Services/Recurring/ApplyNumber.php index 1e95c6d47a..4fab238f8b 100644 --- a/app/Services/Recurring/ApplyNumber.php +++ b/app/Services/Recurring/ApplyNumber.php @@ -14,6 +14,7 @@ namespace App\Services\Recurring; use App\Models\Client; use App\Services\AbstractService; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Database\QueryException; class ApplyNumber extends AbstractService { @@ -23,6 +24,8 @@ class ApplyNumber extends AbstractService private $recurring_entity; + private bool $completed = true; + public function __construct(Client $client, $recurring_entity) { $this->client = $client; @@ -36,8 +39,38 @@ class ApplyNumber extends AbstractService if ($this->recurring_entity->number != '') return $this->recurring_entity; - $this->recurring_entity->number = $this->getNextRecurringInvoiceNumber($this->client, $this->recurring_entity); + $this->trySaving(); + //$this->recurring_entity->number = $this->getNextRecurringInvoiceNumber($this->client, $this->recurring_entity); return $this->recurring_entity; } + + private function trySaving() + { + + $x=1; + + do{ + + try{ + + $this->recurring_entity->number = $this->getNextRecurringInvoiceNumber($this->client, $this->recurring_entity); + $this->recurring_entity->saveQuietly(); + + $this->completed = false; + + + } + catch(QueryException $e){ + + $x++; + + if($x>10) + $this->completed = false; + } + + } + while($this->completed); + + } } From a8eedc27a999713eb2f9e78b857fad5f97c76a28 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 20:08:30 +1000 Subject: [PATCH 18/19] Update client details in Stripe during a transaction --- app/Jobs/Util/Import.php | 4 ++- app/PaymentDrivers/StripePaymentDriver.php | 40 ++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index d30948bc3b..aa5ebffa04 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -568,7 +568,9 @@ class Import implements ShouldQueue unset($modified['id']); unset($modified['password']); //cant import passwords. unset($modified['confirmation_code']); //cant import passwords. - + unset($modified['oauth_user_id']); + unset($modified['oauth_provider_id']); + $user = $user_repository->save($modified, $this->fetchUser($resource['email']), true, true); $user->email_verified_at = now(); // $user->confirmation_code = ''; diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index f693459e7a..cc4a769be1 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -443,8 +443,11 @@ class StripePaymentDriver extends BaseDriver "starting_after" => null ],$this->stripe_connect_auth); - if(count($searchResults) == 1) - return $searchResults->data[0]; + if(count($searchResults) == 1){ + $customer = $searchResults->data[0]; + $this->updateStripeCustomer($customer); + return $customer; + } //Else create a new record $data['name'] = $this->client->present()->name(); @@ -454,6 +457,13 @@ class StripePaymentDriver extends BaseDriver $data['email'] = $this->client->present()->email(); } + $data['address']['line1'] = $this->client->address1; + $data['address']['line2'] = $this->client->address2; + $data['address']['city'] = $this->client->city; + $data['address']['postal_code'] = $this->client->postal_code; + $data['address']['state'] = $this->client->state; + $data['address']['country'] = $this->client->country ? $this->client->country->iso_3166_2 : ""; + $customer = Customer::create($data, $this->stripe_connect_auth); if (!$customer) { @@ -463,6 +473,32 @@ class StripePaymentDriver extends BaseDriver return $customer; } + public function updateStripeCustomer($customer) + { + //Else create a new record + $data['name'] = $this->client->present()->name(); + $data['phone'] = substr($this->client->present()->phone(), 0 , 20); + + if (filter_var($this->client->present()->email(), FILTER_VALIDATE_EMAIL)) { + $data['email'] = $this->client->present()->email(); + } + + $data['address']['line1'] = $this->client->address1; + $data['address']['line2'] = $this->client->address2; + $data['address']['city'] = $this->client->city; + $data['address']['postal_code'] = $this->client->postal_code; + $data['address']['state'] = $this->client->state; + $data['address']['country'] = $this->client->country ? $this->client->country->iso_3166_2 : ""; + + try{ + \Stripe\Customer::update($customer->id, $data, $this->stripe_connect_auth); + } + catch(Exception $e){ + nlog("unable to update clients in Stripe"); + } + + } + public function refund(Payment $payment, $amount, $return_client_response = false) { $this->init(); From ca3440f6424e031fc741aa21229476530c828241 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Apr 2022 20:13:25 +1000 Subject: [PATCH 19/19] v5.3.79 --- VERSION.txt | 2 +- config/ninja.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 80ba0b3252..e003fe334f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.3.78 \ No newline at end of file +5.3.79 \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 89b2ac54fa..b89a23be5b 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.78', - 'app_tag' => '5.3.78', + 'app_version' => '5.3.79', + 'app_tag' => '5.3.79', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''),