diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index d7e10ac0f4f1..657680140a69 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -92,6 +92,20 @@ class ExpenseFilters extends QueryFilters return $this->builder; } + /** + * Returns a list of expenses that can be matched to bank transactions + */ + public function match_transactions($value = '') + { + + if($value == 'true') + { + return $this->builder->where('is_deleted',0)->whereNull('transaction_id'); + } + + return $this->builder; + } + /** * Filters the list based on the status diff --git a/app/Filters/PaymentFilters.php b/app/Filters/PaymentFilters.php index 823cb9fcf741..e09c49e35557 100644 --- a/app/Filters/PaymentFilters.php +++ b/app/Filters/PaymentFilters.php @@ -81,6 +81,20 @@ class PaymentFilters extends QueryFilters }); } + /** + * Returns a list of payments that can be matched to bank transactions + */ + public function match_transactions($value = '') + { + + if($value == 'true') + { + return $this->builder->where('is_deleted',0)->whereNull('transaction_id'); + } + + return $this->builder; + } + /** * Sorts the list based on $sort. * diff --git a/app/Helpers/Invoice/InvoiceSum.php b/app/Helpers/Invoice/InvoiceSum.php index b1c170a26736..5d981f597edf 100644 --- a/app/Helpers/Invoice/InvoiceSum.php +++ b/app/Helpers/Invoice/InvoiceSum.php @@ -49,7 +49,7 @@ class InvoiceSum /** * Constructs the object with Invoice and Settings object. * - * @param Invoice $invoice The invoice + * @param \App\Models\RecurringInvoice|\App\Models\Quote|\App\Models\Credit|\App\Models\PurchaseOrder|\App\Models\Invoice $invoice The entity */ public function __construct($invoice) { diff --git a/app/Helpers/Invoice/InvoiceSumInclusive.php b/app/Helpers/Invoice/InvoiceSumInclusive.php index ad38f2754691..c540f825bc01 100644 --- a/app/Helpers/Invoice/InvoiceSumInclusive.php +++ b/app/Helpers/Invoice/InvoiceSumInclusive.php @@ -46,7 +46,7 @@ class InvoiceSumInclusive /** * Constructs the object with Invoice and Settings object. * - * @param Invoice $invoice The invoice + * @param \App\Models\RecurringInvoice|\App\Models\Quote|\App\Models\Credit|\App\Models\PurchaseOrder|\App\Models\Invoice $invoice The entity */ public function __construct($invoice) { diff --git a/app/Http/Livewire/BillingPortalPurchasev2.php b/app/Http/Livewire/BillingPortalPurchasev2.php index dd8e89b7a447..35933f13d043 100644 --- a/app/Http/Livewire/BillingPortalPurchasev2.php +++ b/app/Http/Livewire/BillingPortalPurchasev2.php @@ -31,6 +31,7 @@ use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; +use Illuminate\Validation\Rule; use Livewire\Component; class BillingPortalPurchasev2 extends Component @@ -97,7 +98,6 @@ class BillingPortalPurchasev2 extends Component */ public $payment_method_id; - private $user_coupon; /** * List of steps that frontend form follows. @@ -188,12 +188,19 @@ class BillingPortalPurchasev2 extends Component public $optional_recurring_products; public $optional_products; public $total; + public $discount; + public $sub_total; + public $authenticated = false; + public $otp; + public $login; + public $value; public function mount() { MultiDB::setDb($this->company->db); - $this->quantity = 1; + $this->discount = 0; + $this->sub_total = 0; $this->data = []; @@ -212,17 +219,71 @@ class BillingPortalPurchasev2 extends Component $this->optional_recurring_products = $this->subscription->service()->optional_recurring_products(); $this->optional_products = $this->subscription->service()->optional_products(); - // $this->buildBundle(); $this->bundle = collect(); } + public function loginValidation() + { + $this->resetErrorBag('login'); + $this->resetValidation('login'); + } + + public function handleLogin() + { + + $code = Cache::get("subscriptions:otp:{$this->email}"); + + $this->validateOnly('login', ['login' => ['required',Rule::in([$code])]], ['login' => ctrans('texts.invalid_code')]); + + $contact = ClientContact::where('email', $this->email)->first(); + + if($contact){ + Auth::guard('contact')->loginUsingId($contact->id, true); + $this->contact = $contact; + } + else { + + } + + + } + + public function handleEmail() + { + $this->validateOnly('email', ['email' => 'required|bail|email:rfc']); + + $rand = rand(100000,999999); + + $email_hash = "subscriptions:otp:{$this->email}"; + + Cache::put($email_hash, $rand, 120); + + } + + /** + * Handle a coupon being entered into the checkout + */ + public function handleCoupon() + { + + if($this->coupon == $this->subscription->promo_code) + $this->buildBundle(); + else + $this->discount = 0; + + } + + /** + * Build the bundle in the checkout + */ public function buildBundle() { $this->bundle = collect(); $data = $this->data; + /* Recurring products can have a variable quantity */ foreach($this->recurring_products as $key => $p) { @@ -234,10 +295,11 @@ class BillingPortalPurchasev2 extends Component 'price' => Number::formatMoney($total, $this->subscription->company).' / '. RecurringInvoice::frequencyForKey($this->subscription->frequency_id), 'total' => $total, 'qty' => $qty, - 'is_recurring' => true + 'is_recurring' => true, ]); } + /* One time products can only have a single quantity */ foreach($this->products as $key => $p) { @@ -251,10 +313,13 @@ class BillingPortalPurchasev2 extends Component 'qty' => $qty, 'is_recurring' => false ]); + } foreach($this->data as $key => $value) { + + /* Optional recurring products can have a variable quantity */ if(isset($this->data[$key]['optional_recurring_qty'])) { $p = $this->optional_recurring_products->first(function ($v,$k) use($key){ @@ -278,6 +343,7 @@ class BillingPortalPurchasev2 extends Component } + /* Optional products can have a variable quantity */ if(isset($this->data[$key]['optional_qty'])) { $p = $this->optional_products->first(function ($v,$k) use($key){ @@ -300,41 +366,67 @@ class BillingPortalPurchasev2 extends Component } - } - $this->total = Number::formatMoney($this->bundle->sum('total'), $this->subscription->company); + $this->sub_total = Number::formatMoney($this->bundle->sum('total'), $this->subscription->company); + $this->total = $this->sub_total; + + if($this->coupon == $this->subscription->promo_code) + { + + if($this->subscription->is_amount_discount) + $discount = $this->subscription->promo_discount; + else + $discount = round($this->bundle->sum('total') * ($this->subscription->promo_discount / 100), 2); + + $this->discount = Number::formatMoney($discount, $this->subscription->company); + + $this->total = Number::formatMoney(($this->bundle->sum('total') - $discount), $this->subscription->company); + + } + return $this; } - public function updatedData() + private function createClientContact() { - } - public function updating($prop) - { - // $this->resetValidation($prop); - // $this->resetErrorBag($prop); - } + $company = $this->subscription->company; + $user = $this->subscription->user; + $user->setCompany($company); + + $client_repo = new ClientRepository(new ClientContactRepository()); + $data = [ + 'name' => '', + 'contacts' => [ + ['email' => $this->email], + ], + 'client_hash' => Str::random(40), + 'settings' => ClientSettings::defaults(), + ]; + + $client = $client_repo->save($data, ClientFactory::create($company->id, $user->id)); + + $this->contact = $client->fresh()->contacts()->first(); + Auth::guard('contact')->loginUsingId($this->contact->id, true); + + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public function updated($propertyName) { - $x = $this->validateOnly($propertyName, $this->rules(), [], $this->attributes()); + if(in_array($propertyName, ['login','email'])) + return; - // // $validatedData = $this->validate(); $this->buildBundle(); - // $order_validator = Validator::make($this->all(), $this->rules(), [], $this->attributes()); - } public function rules() { $rules = [ - 'data.*.recurring_qty' => 'numeric|between:0,1000', - 'data.*.optional_recurring_qty' => 'numeric|between:0,1000', - 'data.*.optional_qty' => 'numeric|between:0,1000', ]; return $rules; @@ -343,9 +435,6 @@ class BillingPortalPurchasev2 extends Component public function attributes() { $attributes = [ - 'data.*.recurring_qty' => 'recurring_qty', - 'data.*.optional_recurring_qty' => 'optional_recurring_qty', - 'data.*.optional_qty' => 'optional_qty', ]; return $attributes; @@ -390,6 +479,9 @@ class BillingPortalPurchasev2 extends Component } } + + + /** * Create a blank client. Used for new customers purchasing. * @@ -526,7 +618,7 @@ class BillingPortalPurchasev2 extends Component ]], 'user_input_promo_code' => $this->coupon, 'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon, - 'quantity' => $this->quantity, + // 'quantity' => $this->quantity, ]; $is_eligible = $this->subscription->service()->isEligible($this->contact); @@ -588,7 +680,6 @@ class BillingPortalPurchasev2 extends Component return; } - return $this->subscription->service()->handleNoPaymentRequired([ 'email' => $this->email ?? $this->contact->email, 'quantity' => $this->quantity, @@ -598,55 +689,6 @@ class BillingPortalPurchasev2 extends Component ]); } - /** - * Update quantity property. - * - * @param string $option - * @return int - */ - public function updateQuantity(string $option): int - { - $this->handleCoupon(); - - if ($this->quantity == 1 && $option == 'decrement') { - $this->price = $this->price * 1; - return $this->quantity; - } - - if ($this->quantity > $this->subscription->max_seats_limit && $option == 'increment') { - $this->price = $this->price * $this->subscription->max_seats_limit; - return $this->quantity; - } - - if ($option == 'increment') { - $this->quantity++; - $this->price = $this->price * $this->quantity; - return $this->quantity; - } - - $this->quantity--; - $this->price = $this->price * $this->quantity; - - return $this->quantity; - } - - public function handleCoupon() - { - - if($this->steps['discount_applied']){ - $this->price = $this->subscription->promo_price; - return; - } - - if ($this->coupon == $this->subscription->promo_code) { - $this->price = $this->subscription->promo_price; - $this->quantity = 1; - $this->steps['discount_applied'] = true; - } - else - $this->price = $this->subscription->price; - } - public function passwordlessLogin() { $this->passwordless_login_btn = true; @@ -681,10 +723,10 @@ class BillingPortalPurchasev2 extends Component return render('components.livewire.billing-portal-purchasev2'); } - public function changeData() - { + // public function changeData() + // { - nlog($this->data); + // nlog($this->data); - } + // } } diff --git a/app/Http/Livewire/RecurringInvoices/UpdateAutoBilling.php b/app/Http/Livewire/RecurringInvoices/UpdateAutoBilling.php index 8170fbf12d66..548521dddfc6 100644 --- a/app/Http/Livewire/RecurringInvoices/UpdateAutoBilling.php +++ b/app/Http/Livewire/RecurringInvoices/UpdateAutoBilling.php @@ -12,6 +12,7 @@ namespace App\Http\Livewire\RecurringInvoices; +use App\Models\Invoice; use Livewire\Component; class UpdateAutoBilling extends Component @@ -24,6 +25,12 @@ class UpdateAutoBilling extends Component if ($this->invoice->auto_bill == 'optin' || $this->invoice->auto_bill == 'optout') { $this->invoice->auto_bill_enabled = ! $this->invoice->auto_bill_enabled; $this->invoice->saveQuietly(); + + Invoice::where('recurring_id', $this->invoice->id) + ->whereIn('status_id', [2,3]) + ->where('is_deleted',0) + ->where('balance', '>', 0) + ->update(['auto_bill_enabled' => $this->invoice->auto_bill_enabled]); } } diff --git a/app/Import/Providers/Csv.php b/app/Import/Providers/Csv.php index ecc1f15dce7e..4da3dad96184 100644 --- a/app/Import/Providers/Csv.php +++ b/app/Import/Providers/Csv.php @@ -107,6 +107,8 @@ class Csv extends BaseImport implements ImportInterface $this->transformer = new BankTransformer($this->company); $bank_transaction_count = $this->ingest($data, $entity_type); $this->entity_count['bank_transactions'] = $bank_transaction_count; + + nlog("bank matching co id = {$this->company->id}"); BankMatchingService::dispatchSync($this->company->id, $this->company->db); diff --git a/app/Models/PaymentType.php b/app/Models/PaymentType.php index 21b165014c65..5459a83774a8 100644 --- a/app/Models/PaymentType.php +++ b/app/Models/PaymentType.php @@ -56,6 +56,7 @@ class PaymentType extends StaticModel const INSTANT_BANK_PAY = 45; const FPX = 46; const KLARNA = 47; + const Interac_E_Transfer = 48; public static function parseCardType($cardName) { diff --git a/app/PaymentDrivers/Mollie/CreditCard.php b/app/PaymentDrivers/Mollie/CreditCard.php index 8268f80f638d..601aafe1f27e 100644 --- a/app/PaymentDrivers/Mollie/CreditCard.php +++ b/app/PaymentDrivers/Mollie/CreditCard.php @@ -52,6 +52,8 @@ class CreditCard { $amount = $this->mollie->convertToMollieAmount((float) $this->mollie->payment_hash->data->amount_with_fee); + $description = sprintf('%s: %s', ctrans('texts.invoices'), \implode(', ', collect($this->mollie->payment_hash->invoices())->pluck('invoice_number')->toArray())); + $this->mollie->payment_hash ->withData('gateway_type_id', GatewayType::CREDIT_CARD) ->withData('client_id', $this->mollie->client->id); @@ -68,7 +70,7 @@ class CreditCard 'mandateId' => $request->token, 'customerId' => $cgt->gateway_customer_reference, 'sequenceType' => 'recurring', - 'description' => \sprintf('Hash: %s', $this->mollie->payment_hash->hash), + 'description' => $description, 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), 'idempotencyKey' => uniqid("st",true), 'metadata' => [ @@ -91,7 +93,11 @@ class CreditCard if ($payment->status === 'open') { $this->mollie->payment_hash->withData('payment_id', $payment->id); - return redirect($payment->getCheckoutUrl()); + if(!$payment->getCheckoutUrl()) + return render('gateways.mollie.mollie_placeholder'); + else + return redirect()->away($payment->getCheckoutUrl()); + } } catch (\Exception $e) { return $this->processUnsuccessfulPayment($e); @@ -104,7 +110,7 @@ class CreditCard 'currency' => $this->mollie->client->currency()->code, 'value' => $amount, ], - 'description' => \sprintf('Hash: %s', $this->mollie->payment_hash->hash), + 'description' => $description, 'redirectUrl' => route('mollie.3ds_redirect', [ 'company_key' => $this->mollie->client->company->company_key, 'company_gateway_id' => $this->mollie->company_gateway->hashed_id, @@ -151,7 +157,13 @@ class CreditCard if ($payment->status === 'open') { $this->mollie->payment_hash->withData('payment_id', $payment->id); - return redirect($payment->getCheckoutUrl()); + nlog("Mollie"); + nlog($payment); + + if(!$payment->getCheckoutUrl()) + return render('gateways.mollie.mollie_placeholder'); + else + return redirect()->away($payment->getCheckoutUrl()); } } catch (\Exception $e) { $this->processUnsuccessfulPayment($e); diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index 5a5d893dfeb0..eccdc0b70494 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -173,9 +173,9 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('texts.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } @@ -211,9 +211,9 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('texts.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } if (substr($cgt->token, 0, 2) === 'pm') { @@ -455,9 +455,9 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('texts.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } if (substr($source->token, 0, 2) === 'pm') { diff --git a/app/PaymentDrivers/Stripe/Charge.php b/app/PaymentDrivers/Stripe/Charge.php index b0e5f1a17ce9..f023580f661c 100644 --- a/app/PaymentDrivers/Stripe/Charge.php +++ b/app/PaymentDrivers/Stripe/Charge.php @@ -63,9 +63,9 @@ class Charge $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); if ($invoice) { - $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('texts.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } $this->stripe->init(); diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index e9bba8bd26e9..fb2f4e6b901d 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -63,7 +63,7 @@ class CreditCard // $description = $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')) . " for client {$this->stripe->client->present()->name()}"; $invoice_numbers = collect($data['invoices'])->pluck('invoice_number')->implode(','); - $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($data['total']['amount_with_fee'], $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($data['total']['amount_with_fee'], $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); $payment_intent_data = [ 'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()), diff --git a/app/PaymentDrivers/Stripe/Klarna.php b/app/PaymentDrivers/Stripe/Klarna.php index 718d3f8cfa1a..eb30191b4a44 100644 --- a/app/PaymentDrivers/Stripe/Klarna.php +++ b/app/PaymentDrivers/Stripe/Klarna.php @@ -53,9 +53,9 @@ class Klarna $invoice_numbers = collect($data['invoices'])->pluck('invoice_number'); if ($invoice_numbers->count() > 0) { - $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice_numbers->implode(', '), 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice_numbers->implode(', '), 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('texts.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_payment_text_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } $intent = \Stripe\PaymentIntent::create([ diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index e6fa402b3a00..b44e63ceb755 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -98,7 +98,7 @@ class StripePaymentDriver extends BaseDriver GatewayType::BECS => BECS::class, GatewayType::ACSS => ACSS::class, GatewayType::FPX => FPX::class, - GatewayType::KLARNA => KLARNA::class, + GatewayType::KLARNA => Klarna::class, ]; const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; diff --git a/app/Services/Bank/BankMatchingService.php b/app/Services/Bank/BankMatchingService.php index 8afb84ff6737..00f1e1183c9f 100644 --- a/app/Services/Bank/BankMatchingService.php +++ b/app/Services/Bank/BankMatchingService.php @@ -37,6 +37,8 @@ class BankMatchingService implements ShouldQueue protected $db; + protected $middleware_key; + public function __construct($company_id, $db) { $this->company_id = $company_id; diff --git a/app/Services/Bank/ProcessBankRules.php b/app/Services/Bank/ProcessBankRules.php index 86743bcb366d..99ef98064a02 100644 --- a/app/Services/Bank/ProcessBankRules.php +++ b/app/Services/Bank/ProcessBankRules.php @@ -44,8 +44,6 @@ class ProcessBankRules extends AbstractService private function matchCredit() { - $this->credit_rules = $this->bank_transaction->company->credit_rules(); - $this->invoices = Invoice::where('company_id', $this->bank_transaction->company_id) ->whereIn('status_id', [1,2,3]) ->where('is_deleted', 0) @@ -65,6 +63,8 @@ class ProcessBankRules extends AbstractService return; } + $this->credit_rules = $this->bank_transaction->company->credit_rules(); + //stub for credit rules foreach($this->credit_rules as $rule) { @@ -81,11 +81,16 @@ class ProcessBankRules extends AbstractService $this->categories = collect(Cache::get('bank_categories')); + + foreach($this->debit_rules as $bank_transaction_rule) { $matches = 0; + if(!is_array($bank_transaction_rule['rules'])) + continue; + foreach($bank_transaction_rule['rules'] as $rule) { $rule_count = count($bank_transaction_rule['rules']); diff --git a/app/Services/Invoice/UpdateReminder.php b/app/Services/Invoice/UpdateReminder.php index 40962a7ced78..9e627d33a90c 100644 --- a/app/Services/Invoice/UpdateReminder.php +++ b/app/Services/Invoice/UpdateReminder.php @@ -145,8 +145,6 @@ class UpdateReminder extends AbstractService $reminder_date = $this->addTimeInterval($this->invoice->last_sent_date, (int) $this->settings->endless_reminder_frequency_id); if ($reminder_date) { - // $reminder_date->addSeconds($offset); - if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date))) { $date_collection->push($reminder_date); } diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index a2a98275804e..f1958ef62195 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -285,6 +285,9 @@ class HtmlEngine $data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')]; } + // $data['$amount_in_words'] = ['value' => (new \NumberFormatter($this->client->locale(), \NumberFormatter::SPELLOUT))->format($this->entity->amount), 'label' => '']; + // $data['$balance_in_words'] = ['value' => (new \NumberFormatter($this->client->locale(), \NumberFormatter::SPELLOUT))->format($this->entity->balance), 'label' => '']; + // $data['$balance_due'] = $data['$balance_due']; $data['$outstanding'] = &$data['$balance_due']; $data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')]; diff --git a/app/Utils/Traits/Pdf/PDF.php b/app/Utils/Traits/Pdf/PDF.php index 21f41daf8273..f81407b9f9c0 100644 --- a/app/Utils/Traits/Pdf/PDF.php +++ b/app/Utils/Traits/Pdf/PDF.php @@ -21,9 +21,11 @@ class PDF extends FPDI { $this->SetXY(0, -5); $this->SetFont('Arial', 'I', 9); + $this->SetTextColor(135, 135, 135); $trans = ctrans('texts.pdf_page_info', ['current' => $this->PageNo(), 'total' => '{nb}']); + $trans = iconv('UTF-8', 'ISO-8859-7', $trans); $this->Cell(0, 5, $trans, 0, 0, $this->text_alignment); } diff --git a/database/migrations/2022_05_12_56879_add_stripe_klarna.php b/database/migrations/2022_05_12_56879_add_stripe_klarna.php index 969553634d52..e85e0e733879 100644 --- a/database/migrations/2022_05_12_56879_add_stripe_klarna.php +++ b/database/migrations/2022_05_12_56879_add_stripe_klarna.php @@ -14,21 +14,37 @@ return new class extends Migration { */ public function up() { - Schema::table('payment_types', function (Blueprint $table) { - $type = new PaymentType(); + $pt = PaymentType::find(47); + if(!$pt) + { + $type = new PaymentType(); $type->id = 47; $type->name = 'Klarna'; $type->gateway_type_id = GatewayType::KLARNA; - $type->save(); - }); - $type = new GatewayType(); + } - $type->id = 23; - $type->alias = 'klarna'; - $type->name = 'Klarna'; - $type->save(); + $pt = PaymentType::find(48); + + if(!$pt) + { + $type = new PaymentType(); + $type->id = 48; + $type->name = 'Interac E-Transfer'; + $type->save(); + } + + $gt = GatewayType::find(23); + + if(!$gt) + { + $type = new GatewayType(); + $type->id = 23; + $type->alias = 'klarna'; + $type->name = 'Klarna'; + $type->save(); + } } }; diff --git a/database/migrations/2022_07_12_45766_add_matomo.php b/database/migrations/2022_07_12_45766_add_matomo.php index 5df323980c73..6eb354c2784a 100644 --- a/database/migrations/2022_07_12_45766_add_matomo.php +++ b/database/migrations/2022_07_12_45766_add_matomo.php @@ -17,5 +17,6 @@ return new class extends Migration $table->string('matomo_url',191)->nullable(); $table->bigInteger('matomo_id')->nullable(); }); + } }; \ No newline at end of file diff --git a/lang/en/texts.php b/lang/en/texts.php index 9fc9764b2a61..090ba0f2dde9 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -254,8 +254,8 @@ $LANG = array( 'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.', 'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.', 'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.', - 'stripe_paymenttext' => 'Invoice :invoicenumber for :amount for client :client', - 'stripe_paymenttext_without_invoice' => 'Payment with no invoice for amount :amount for client :client', + 'stripe_payment_text' => 'Invoice :invoicenumber for :amount for client :client', + 'stripe_payment_text_without_invoice' => 'Payment with no invoice for amount :amount for client :client', 'reset_password' => 'You can reset your account password by clicking the following button:', 'secure_payment' => 'Secure Payment', 'card_number' => 'Card Number', @@ -4778,7 +4778,7 @@ $LANG = array( 'invoice_task_project' => 'Invoice Task Project', 'invoice_task_project_help' => 'Add the project to the invoice line items', 'bulk_action' => 'Bulk Action', - 'phone_validation_error' => 'This mobile/cell phone number is not valid, please enter in E.164 format', + 'phone_validation_error' => 'This mobile (cell) phone number is not valid, please enter in E.164 format', 'transaction' => 'Transaction', 'disable_2fa' => 'Disable 2FA', 'change_number' => 'Change Number', @@ -4891,7 +4891,11 @@ $LANG = array( 'restored_transaction_rule' => 'Successfully restored transaction rule', 'search_transaction_rule' => 'Search Transaction Rule', 'search_transaction_rules' => 'Search Transaction Rules', - + 'payment_type_Interac E-Transfer' => 'Interac E-Transfer', + 'delete_bank_account' => 'Delete Bank Account', + 'archive_transaction' => 'Archive Transaction', + 'delete_transaction' => 'Delete Transaction', + 'otp_code_message' => 'Enter the code emailed.' ); return $LANG; diff --git a/resources/views/portal/ninja2020/components/livewire/billing-portal-purchasev2.blade.php b/resources/views/portal/ninja2020/components/livewire/billing-portal-purchasev2.blade.php index 07d2096e3165..c8e5dd7e2d5e 100644 --- a/resources/views/portal/ninja2020/components/livewire/billing-portal-purchasev2.blade.php +++ b/resources/views/portal/ninja2020/components/livewire/billing-portal-purchasev2.blade.php @@ -14,9 +14,9 @@ @if(!empty($subscription->recurring_product_ids)) @foreach($recurring_products as $index => $product)
{{ ctrans('texts.qty') }}
- + +{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }}
Out of stock
+ @else{{ ctrans('texts.qty') }}
- + @endif +Out of stock
+ @else{{ ctrans('texts.qty') }}
- + @endif +