mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
commit
f02ee29a47
@ -92,6 +92,20 @@ class ExpenseFilters extends QueryFilters
|
|||||||
return $this->builder;
|
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
|
* Filters the list based on the status
|
||||||
|
@ -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.
|
* Sorts the list based on $sort.
|
||||||
*
|
*
|
||||||
|
@ -49,7 +49,7 @@ class InvoiceSum
|
|||||||
/**
|
/**
|
||||||
* Constructs the object with Invoice and Settings object.
|
* 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)
|
public function __construct($invoice)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,7 @@ class InvoiceSumInclusive
|
|||||||
/**
|
/**
|
||||||
* Constructs the object with Invoice and Settings object.
|
* 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)
|
public function __construct($invoice)
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,7 @@ use Illuminate\Support\Facades\Cache;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class BillingPortalPurchasev2 extends Component
|
class BillingPortalPurchasev2 extends Component
|
||||||
@ -97,7 +98,6 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
*/
|
*/
|
||||||
public $payment_method_id;
|
public $payment_method_id;
|
||||||
|
|
||||||
private $user_coupon;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of steps that frontend form follows.
|
* List of steps that frontend form follows.
|
||||||
@ -188,12 +188,19 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
public $optional_recurring_products;
|
public $optional_recurring_products;
|
||||||
public $optional_products;
|
public $optional_products;
|
||||||
public $total;
|
public $total;
|
||||||
|
public $discount;
|
||||||
|
public $sub_total;
|
||||||
|
public $authenticated = false;
|
||||||
|
public $otp;
|
||||||
|
public $login;
|
||||||
|
public $value;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
$this->quantity = 1;
|
$this->discount = 0;
|
||||||
|
$this->sub_total = 0;
|
||||||
|
|
||||||
$this->data = [];
|
$this->data = [];
|
||||||
|
|
||||||
@ -212,17 +219,71 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
$this->optional_recurring_products = $this->subscription->service()->optional_recurring_products();
|
$this->optional_recurring_products = $this->subscription->service()->optional_recurring_products();
|
||||||
$this->optional_products = $this->subscription->service()->optional_products();
|
$this->optional_products = $this->subscription->service()->optional_products();
|
||||||
|
|
||||||
// $this->buildBundle();
|
|
||||||
$this->bundle = collect();
|
$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()
|
public function buildBundle()
|
||||||
{
|
{
|
||||||
$this->bundle = collect();
|
$this->bundle = collect();
|
||||||
|
|
||||||
$data = $this->data;
|
$data = $this->data;
|
||||||
|
|
||||||
|
/* Recurring products can have a variable quantity */
|
||||||
foreach($this->recurring_products as $key => $p)
|
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),
|
'price' => Number::formatMoney($total, $this->subscription->company).' / '. RecurringInvoice::frequencyForKey($this->subscription->frequency_id),
|
||||||
'total' => $total,
|
'total' => $total,
|
||||||
'qty' => $qty,
|
'qty' => $qty,
|
||||||
'is_recurring' => true
|
'is_recurring' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* One time products can only have a single quantity */
|
||||||
foreach($this->products as $key => $p)
|
foreach($this->products as $key => $p)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -251,10 +313,13 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
'qty' => $qty,
|
'qty' => $qty,
|
||||||
'is_recurring' => false
|
'is_recurring' => false
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->data as $key => $value)
|
foreach($this->data as $key => $value)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/* Optional recurring products can have a variable quantity */
|
||||||
if(isset($this->data[$key]['optional_recurring_qty']))
|
if(isset($this->data[$key]['optional_recurring_qty']))
|
||||||
{
|
{
|
||||||
$p = $this->optional_recurring_products->first(function ($v,$k) use($key){
|
$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']))
|
if(isset($this->data[$key]['optional_qty']))
|
||||||
{
|
{
|
||||||
$p = $this->optional_products->first(function ($v,$k) use($key){
|
$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;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatedData()
|
private function createClientContact()
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public function updating($prop)
|
$company = $this->subscription->company;
|
||||||
{
|
$user = $this->subscription->user;
|
||||||
// $this->resetValidation($prop);
|
$user->setCompany($company);
|
||||||
// $this->resetErrorBag($prop);
|
|
||||||
}
|
$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)
|
public function updated($propertyName)
|
||||||
{
|
{
|
||||||
$x = $this->validateOnly($propertyName, $this->rules(), [], $this->attributes());
|
if(in_array($propertyName, ['login','email']))
|
||||||
|
return;
|
||||||
|
|
||||||
// // $validatedData = $this->validate();
|
|
||||||
$this->buildBundle();
|
$this->buildBundle();
|
||||||
|
|
||||||
// $order_validator = Validator::make($this->all(), $this->rules(), [], $this->attributes());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$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;
|
return $rules;
|
||||||
@ -343,9 +435,6 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
public function attributes()
|
public function attributes()
|
||||||
{
|
{
|
||||||
$attributes = [
|
$attributes = [
|
||||||
'data.*.recurring_qty' => 'recurring_qty',
|
|
||||||
'data.*.optional_recurring_qty' => 'optional_recurring_qty',
|
|
||||||
'data.*.optional_qty' => 'optional_qty',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return $attributes;
|
return $attributes;
|
||||||
@ -390,6 +479,9 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a blank client. Used for new customers purchasing.
|
* Create a blank client. Used for new customers purchasing.
|
||||||
*
|
*
|
||||||
@ -526,7 +618,7 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
]],
|
]],
|
||||||
'user_input_promo_code' => $this->coupon,
|
'user_input_promo_code' => $this->coupon,
|
||||||
'coupon' => empty($this->subscription->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);
|
$is_eligible = $this->subscription->service()->isEligible($this->contact);
|
||||||
@ -588,7 +680,6 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return $this->subscription->service()->handleNoPaymentRequired([
|
return $this->subscription->service()->handleNoPaymentRequired([
|
||||||
'email' => $this->email ?? $this->contact->email,
|
'email' => $this->email ?? $this->contact->email,
|
||||||
'quantity' => $this->quantity,
|
'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()
|
public function passwordlessLogin()
|
||||||
{
|
{
|
||||||
$this->passwordless_login_btn = true;
|
$this->passwordless_login_btn = true;
|
||||||
@ -681,10 +723,10 @@ class BillingPortalPurchasev2 extends Component
|
|||||||
return render('components.livewire.billing-portal-purchasev2');
|
return render('components.livewire.billing-portal-purchasev2');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function changeData()
|
// public function changeData()
|
||||||
{
|
// {
|
||||||
|
|
||||||
nlog($this->data);
|
// nlog($this->data);
|
||||||
|
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\RecurringInvoices;
|
namespace App\Http\Livewire\RecurringInvoices;
|
||||||
|
|
||||||
|
use App\Models\Invoice;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class UpdateAutoBilling extends Component
|
class UpdateAutoBilling extends Component
|
||||||
@ -24,6 +25,12 @@ class UpdateAutoBilling extends Component
|
|||||||
if ($this->invoice->auto_bill == 'optin' || $this->invoice->auto_bill == 'optout') {
|
if ($this->invoice->auto_bill == 'optin' || $this->invoice->auto_bill == 'optout') {
|
||||||
$this->invoice->auto_bill_enabled = ! $this->invoice->auto_bill_enabled;
|
$this->invoice->auto_bill_enabled = ! $this->invoice->auto_bill_enabled;
|
||||||
$this->invoice->saveQuietly();
|
$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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,8 @@ class Csv extends BaseImport implements ImportInterface
|
|||||||
$this->transformer = new BankTransformer($this->company);
|
$this->transformer = new BankTransformer($this->company);
|
||||||
$bank_transaction_count = $this->ingest($data, $entity_type);
|
$bank_transaction_count = $this->ingest($data, $entity_type);
|
||||||
$this->entity_count['bank_transactions'] = $bank_transaction_count;
|
$this->entity_count['bank_transactions'] = $bank_transaction_count;
|
||||||
|
|
||||||
|
nlog("bank matching co id = {$this->company->id}");
|
||||||
|
|
||||||
BankMatchingService::dispatchSync($this->company->id, $this->company->db);
|
BankMatchingService::dispatchSync($this->company->id, $this->company->db);
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ class PaymentType extends StaticModel
|
|||||||
const INSTANT_BANK_PAY = 45;
|
const INSTANT_BANK_PAY = 45;
|
||||||
const FPX = 46;
|
const FPX = 46;
|
||||||
const KLARNA = 47;
|
const KLARNA = 47;
|
||||||
|
const Interac_E_Transfer = 48;
|
||||||
|
|
||||||
public static function parseCardType($cardName)
|
public static function parseCardType($cardName)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +52,8 @@ class CreditCard
|
|||||||
{
|
{
|
||||||
$amount = $this->mollie->convertToMollieAmount((float) $this->mollie->payment_hash->data->amount_with_fee);
|
$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
|
$this->mollie->payment_hash
|
||||||
->withData('gateway_type_id', GatewayType::CREDIT_CARD)
|
->withData('gateway_type_id', GatewayType::CREDIT_CARD)
|
||||||
->withData('client_id', $this->mollie->client->id);
|
->withData('client_id', $this->mollie->client->id);
|
||||||
@ -68,7 +70,7 @@ class CreditCard
|
|||||||
'mandateId' => $request->token,
|
'mandateId' => $request->token,
|
||||||
'customerId' => $cgt->gateway_customer_reference,
|
'customerId' => $cgt->gateway_customer_reference,
|
||||||
'sequenceType' => 'recurring',
|
'sequenceType' => 'recurring',
|
||||||
'description' => \sprintf('Hash: %s', $this->mollie->payment_hash->hash),
|
'description' => $description,
|
||||||
'webhookUrl' => $this->mollie->company_gateway->webhookUrl(),
|
'webhookUrl' => $this->mollie->company_gateway->webhookUrl(),
|
||||||
'idempotencyKey' => uniqid("st",true),
|
'idempotencyKey' => uniqid("st",true),
|
||||||
'metadata' => [
|
'metadata' => [
|
||||||
@ -91,7 +93,11 @@ class CreditCard
|
|||||||
if ($payment->status === 'open') {
|
if ($payment->status === 'open') {
|
||||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
$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) {
|
} catch (\Exception $e) {
|
||||||
return $this->processUnsuccessfulPayment($e);
|
return $this->processUnsuccessfulPayment($e);
|
||||||
@ -104,7 +110,7 @@ class CreditCard
|
|||||||
'currency' => $this->mollie->client->currency()->code,
|
'currency' => $this->mollie->client->currency()->code,
|
||||||
'value' => $amount,
|
'value' => $amount,
|
||||||
],
|
],
|
||||||
'description' => \sprintf('Hash: %s', $this->mollie->payment_hash->hash),
|
'description' => $description,
|
||||||
'redirectUrl' => route('mollie.3ds_redirect', [
|
'redirectUrl' => route('mollie.3ds_redirect', [
|
||||||
'company_key' => $this->mollie->client->company->company_key,
|
'company_key' => $this->mollie->client->company->company_key,
|
||||||
'company_gateway_id' => $this->mollie->company_gateway->hashed_id,
|
'company_gateway_id' => $this->mollie->company_gateway->hashed_id,
|
||||||
@ -151,7 +157,13 @@ class CreditCard
|
|||||||
if ($payment->status === 'open') {
|
if ($payment->status === 'open') {
|
||||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
$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) {
|
} catch (\Exception $e) {
|
||||||
$this->processUnsuccessfulPayment($e);
|
$this->processUnsuccessfulPayment($e);
|
||||||
|
@ -173,9 +173,9 @@ class ACH
|
|||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($invoice) {
|
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 {
|
} 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();
|
->first();
|
||||||
|
|
||||||
if ($invoice) {
|
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 {
|
} 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') {
|
if (substr($cgt->token, 0, 2) === 'pm') {
|
||||||
@ -455,9 +455,9 @@ class ACH
|
|||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($invoice) {
|
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 {
|
} 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') {
|
if (substr($source->token, 0, 2) === 'pm') {
|
||||||
|
@ -63,9 +63,9 @@ class Charge
|
|||||||
$invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
|
$invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
|
||||||
|
|
||||||
if ($invoice) {
|
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 {
|
} 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();
|
$this->stripe->init();
|
||||||
|
@ -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()}";
|
// $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(',');
|
$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 = [
|
$payment_intent_data = [
|
||||||
'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
|
'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
|
||||||
|
@ -53,9 +53,9 @@ class Klarna
|
|||||||
$invoice_numbers = collect($data['invoices'])->pluck('invoice_number');
|
$invoice_numbers = collect($data['invoices'])->pluck('invoice_number');
|
||||||
|
|
||||||
if ($invoice_numbers->count() > 0) {
|
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 {
|
} 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([
|
$intent = \Stripe\PaymentIntent::create([
|
||||||
|
@ -98,7 +98,7 @@ class StripePaymentDriver extends BaseDriver
|
|||||||
GatewayType::BECS => BECS::class,
|
GatewayType::BECS => BECS::class,
|
||||||
GatewayType::ACSS => ACSS::class,
|
GatewayType::ACSS => ACSS::class,
|
||||||
GatewayType::FPX => FPX::class,
|
GatewayType::FPX => FPX::class,
|
||||||
GatewayType::KLARNA => KLARNA::class,
|
GatewayType::KLARNA => Klarna::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE;
|
const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE;
|
||||||
|
@ -37,6 +37,8 @@ class BankMatchingService implements ShouldQueue
|
|||||||
|
|
||||||
protected $db;
|
protected $db;
|
||||||
|
|
||||||
|
protected $middleware_key;
|
||||||
|
|
||||||
public function __construct($company_id, $db)
|
public function __construct($company_id, $db)
|
||||||
{
|
{
|
||||||
$this->company_id = $company_id;
|
$this->company_id = $company_id;
|
||||||
|
@ -44,8 +44,6 @@ class ProcessBankRules extends AbstractService
|
|||||||
private function matchCredit()
|
private function matchCredit()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->credit_rules = $this->bank_transaction->company->credit_rules();
|
|
||||||
|
|
||||||
$this->invoices = Invoice::where('company_id', $this->bank_transaction->company_id)
|
$this->invoices = Invoice::where('company_id', $this->bank_transaction->company_id)
|
||||||
->whereIn('status_id', [1,2,3])
|
->whereIn('status_id', [1,2,3])
|
||||||
->where('is_deleted', 0)
|
->where('is_deleted', 0)
|
||||||
@ -65,6 +63,8 @@ class ProcessBankRules extends AbstractService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->credit_rules = $this->bank_transaction->company->credit_rules();
|
||||||
|
|
||||||
//stub for credit rules
|
//stub for credit rules
|
||||||
foreach($this->credit_rules as $rule)
|
foreach($this->credit_rules as $rule)
|
||||||
{
|
{
|
||||||
@ -81,11 +81,16 @@ class ProcessBankRules extends AbstractService
|
|||||||
|
|
||||||
$this->categories = collect(Cache::get('bank_categories'));
|
$this->categories = collect(Cache::get('bank_categories'));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach($this->debit_rules as $bank_transaction_rule)
|
foreach($this->debit_rules as $bank_transaction_rule)
|
||||||
{
|
{
|
||||||
|
|
||||||
$matches = 0;
|
$matches = 0;
|
||||||
|
|
||||||
|
if(!is_array($bank_transaction_rule['rules']))
|
||||||
|
continue;
|
||||||
|
|
||||||
foreach($bank_transaction_rule['rules'] as $rule)
|
foreach($bank_transaction_rule['rules'] as $rule)
|
||||||
{
|
{
|
||||||
$rule_count = count($bank_transaction_rule['rules']);
|
$rule_count = count($bank_transaction_rule['rules']);
|
||||||
|
@ -145,8 +145,6 @@ class UpdateReminder extends AbstractService
|
|||||||
$reminder_date = $this->addTimeInterval($this->invoice->last_sent_date, (int) $this->settings->endless_reminder_frequency_id);
|
$reminder_date = $this->addTimeInterval($this->invoice->last_sent_date, (int) $this->settings->endless_reminder_frequency_id);
|
||||||
|
|
||||||
if ($reminder_date) {
|
if ($reminder_date) {
|
||||||
// $reminder_date->addSeconds($offset);
|
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date))) {
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date))) {
|
||||||
$date_collection->push($reminder_date);
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
@ -285,6 +285,9 @@ class HtmlEngine
|
|||||||
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
|
$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['$balance_due'] = $data['$balance_due'];
|
||||||
$data['$outstanding'] = &$data['$balance_due'];
|
$data['$outstanding'] = &$data['$balance_due'];
|
||||||
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
||||||
|
@ -21,9 +21,11 @@ class PDF extends FPDI
|
|||||||
{
|
{
|
||||||
$this->SetXY(0, -5);
|
$this->SetXY(0, -5);
|
||||||
$this->SetFont('Arial', 'I', 9);
|
$this->SetFont('Arial', 'I', 9);
|
||||||
|
|
||||||
$this->SetTextColor(135, 135, 135);
|
$this->SetTextColor(135, 135, 135);
|
||||||
|
|
||||||
$trans = ctrans('texts.pdf_page_info', ['current' => $this->PageNo(), 'total' => '{nb}']);
|
$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);
|
$this->Cell(0, 5, $trans, 0, 0, $this->text_alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,21 +14,37 @@ return new class extends Migration {
|
|||||||
*/
|
*/
|
||||||
public function up()
|
public function up()
|
||||||
{
|
{
|
||||||
Schema::table('payment_types', function (Blueprint $table) {
|
$pt = PaymentType::find(47);
|
||||||
$type = new PaymentType();
|
|
||||||
|
|
||||||
|
if(!$pt)
|
||||||
|
{
|
||||||
|
$type = new PaymentType();
|
||||||
$type->id = 47;
|
$type->id = 47;
|
||||||
$type->name = 'Klarna';
|
$type->name = 'Klarna';
|
||||||
$type->gateway_type_id = GatewayType::KLARNA;
|
$type->gateway_type_id = GatewayType::KLARNA;
|
||||||
|
|
||||||
$type->save();
|
$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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,5 +17,6 @@ return new class extends Migration
|
|||||||
$table->string('matomo_url',191)->nullable();
|
$table->string('matomo_url',191)->nullable();
|
||||||
$table->bigInteger('matomo_id')->nullable();
|
$table->bigInteger('matomo_id')->nullable();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -254,8 +254,8 @@ $LANG = array(
|
|||||||
'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
|
'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_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
|
||||||
'notification_invoice_viewed' => 'The following client :client viewed 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_payment_text' => 'Invoice :invoicenumber for :amount for client :client',
|
||||||
'stripe_paymenttext_without_invoice' => 'Payment with no invoice for amount :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:',
|
'reset_password' => 'You can reset your account password by clicking the following button:',
|
||||||
'secure_payment' => 'Secure Payment',
|
'secure_payment' => 'Secure Payment',
|
||||||
'card_number' => 'Card Number',
|
'card_number' => 'Card Number',
|
||||||
@ -4778,7 +4778,7 @@ $LANG = array(
|
|||||||
'invoice_task_project' => 'Invoice Task Project',
|
'invoice_task_project' => 'Invoice Task Project',
|
||||||
'invoice_task_project_help' => 'Add the project to the invoice line items',
|
'invoice_task_project_help' => 'Add the project to the invoice line items',
|
||||||
'bulk_action' => 'Bulk Action',
|
'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',
|
'transaction' => 'Transaction',
|
||||||
'disable_2fa' => 'Disable 2FA',
|
'disable_2fa' => 'Disable 2FA',
|
||||||
'change_number' => 'Change Number',
|
'change_number' => 'Change Number',
|
||||||
@ -4891,7 +4891,11 @@ $LANG = array(
|
|||||||
'restored_transaction_rule' => 'Successfully restored transaction rule',
|
'restored_transaction_rule' => 'Successfully restored transaction rule',
|
||||||
'search_transaction_rule' => 'Search Transaction Rule',
|
'search_transaction_rule' => 'Search Transaction Rule',
|
||||||
'search_transaction_rules' => 'Search Transaction Rules',
|
'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;
|
return $LANG;
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
@if(!empty($subscription->recurring_product_ids))
|
@if(!empty($subscription->recurring_product_ids))
|
||||||
@foreach($recurring_products as $index => $product)
|
@foreach($recurring_products as $index => $product)
|
||||||
<li class="flex py-6">
|
<li class="flex py-6">
|
||||||
@if(false)
|
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL))
|
||||||
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
|
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
|
||||||
<img src="https://tailwindui.com/img/ecommerce-images/shopping-cart-page-04-product-01.jpg" alt="Salmon orange fabric pouch with match zipper, gray zipper pull, and adjustable hip belt." class="h-full w-full object-cover object-center">
|
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center">
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="ml-0 flex flex-1 flex-col">
|
<div class="ml-0 flex flex-1 flex-col">
|
||||||
@ -34,8 +34,15 @@
|
|||||||
<p class="text-gray-500 w-full"></p>
|
<p class="text-gray-500 w-full"></p>
|
||||||
<div class="flex place-content-end">
|
<div class="flex place-content-end">
|
||||||
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
||||||
<input wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" type="text" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0"/>
|
|
||||||
|
<select wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm">
|
||||||
|
<option value="1" selected="selected">1</option>
|
||||||
|
@for ($i = 2; $i <= $subscription->max_seats_limit; $i++)
|
||||||
|
<option value="{{$i}}">{{$i}}</option>
|
||||||
|
@endfor
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@error("data.{$index}.recurring_qty")
|
@error("data.{$index}.recurring_qty")
|
||||||
@ -52,9 +59,9 @@
|
|||||||
@if(!empty($subscription->product_ids))
|
@if(!empty($subscription->product_ids))
|
||||||
@foreach($products as $product)
|
@foreach($products as $product)
|
||||||
<li class="flex py-6">
|
<li class="flex py-6">
|
||||||
@if(false)
|
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL))
|
||||||
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
|
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
|
||||||
<img src="https://tailwindui.com/img/ecommerce-images/shopping-cart-page-04-product-01.jpg" alt="Salmon orange fabric pouch with match zipper, gray zipper pull, and adjustable hip belt." class="h-full w-full object-cover object-center">
|
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center">
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="ml-0 flex flex-1 flex-col">
|
<div class="ml-0 flex flex-1 flex-col">
|
||||||
@ -79,10 +86,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if(!empty($subscription->optional_recurring_product_ids) || !empty($subscription->optional_product_ids))
|
||||||
<div class="w-full p-4 md:max-w-3xl">
|
<div class="w-full p-4 md:max-w-3xl">
|
||||||
<h2 class="text-2xl font-normal text-left border-b-4">Optional products</h2>
|
<h2 class="text-2xl font-normal text-left border-b-4">Optional products</h2>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
<div class="w-full px-4 md:max-w-3xl">
|
<div class="w-full px-4 md:max-w-3xl">
|
||||||
|
|
||||||
<!-- Optional Recurring Products-->
|
<!-- Optional Recurring Products-->
|
||||||
@ -90,33 +98,41 @@
|
|||||||
@if(!empty($subscription->optional_recurring_product_ids))
|
@if(!empty($subscription->optional_recurring_product_ids))
|
||||||
@foreach($optional_recurring_products as $index => $product)
|
@foreach($optional_recurring_products as $index => $product)
|
||||||
<li class="flex py-6">
|
<li class="flex py-6">
|
||||||
@if(false)
|
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL))
|
||||||
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
|
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
|
||||||
<img src="https://tailwindui.com/img/ecommerce-images/shopping-cart-page-04-product-01.jpg" alt="Salmon orange fabric pouch with match zipper, gray zipper pull, and adjustable hip belt." class="h-full w-full object-cover object-center">
|
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center">
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="ml-0 flex flex-1 flex-col">
|
<div class="ml-0 flex flex-1 flex-col">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-base font-medium text-gray-900">
|
<div class="flex justify-between text-base font-medium text-gray-900">
|
||||||
<h3>{!! nl2br($product->notes) !!}</h3>
|
<h3>{!! nl2br($product->notes) !!}</h3>
|
||||||
<p class="ml-0">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }} </p>
|
<p class="ml-0">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }} </p>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-1 text-sm text-gray-500"></p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex content-end text-sm mt-1">
|
<div class="flex justify-between text-sm mt-1">
|
||||||
<p class="text-gray-500 w-full"></p>
|
@if(is_numeric($product->custom_value2))
|
||||||
|
<p class="text-gray-500 w-3/4"></p>
|
||||||
<div class="flex place-content-end">
|
<div class="flex place-content-end">
|
||||||
|
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
|
||||||
|
<p class="w-full text-sm font-light text-red-500 text-right mr-2 mt-2">Out of stock</p>
|
||||||
|
@else
|
||||||
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
||||||
<input wire:model.debounce.300ms="data.{{ $index }}.optional_recurring_qty" type="text" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0"/>
|
@endif
|
||||||
|
<select wire:model.debounce.300ms="data.{{ $index }}.optional_recurring_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm"
|
||||||
|
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
|
||||||
|
disabled
|
||||||
|
@endif
|
||||||
|
>
|
||||||
|
<option value="0" selected="selected">0</option>
|
||||||
|
@for ($i = 1; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity,$product->custom_value2) : $product->custom_value2); $i++)
|
||||||
|
<option value="{{$i}}">{{$i}}</option>
|
||||||
|
@endfor
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@error("data.{$index}.optional_recurring_qty")
|
|
||||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
|
||||||
<span class="block sm:inline">{{ $message }} </span>
|
|
||||||
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -124,11 +140,11 @@
|
|||||||
@if(!empty($subscription->optional_product_ids))
|
@if(!empty($subscription->optional_product_ids))
|
||||||
@foreach($optional_products as $index => $product)
|
@foreach($optional_products as $index => $product)
|
||||||
<li class="flex py-6">
|
<li class="flex py-6">
|
||||||
@if(false)
|
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL))
|
||||||
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
|
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
|
||||||
<img src="https://tailwindui.com/img/ecommerce-images/shopping-cart-page-04-product-01.jpg" alt="Salmon orange fabric pouch with match zipper, gray zipper pull, and adjustable hip belt." class="h-full w-full object-cover object-center">
|
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center">
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="ml-0 flex flex-1 flex-col">
|
<div class="ml-0 flex flex-1 flex-col">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-base font-medium text-gray-900">
|
<div class="flex justify-between text-base font-medium text-gray-900">
|
||||||
@ -137,19 +153,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="mt-1 text-sm text-gray-500"></p>
|
<p class="mt-1 text-sm text-gray-500"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex content-end text-sm mt-1">
|
<div class="flex justify-between text-sm mt-1">
|
||||||
<p class="text-gray-500 w-full"></p>
|
@if(is_numeric($product->custom_value2))
|
||||||
|
<p class="text-gray-500 w-3/4"></p>
|
||||||
<div class="flex place-content-end">
|
<div class="flex place-content-end">
|
||||||
|
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
|
||||||
|
<p class="w-full text-sm font-light text-red-500 text-right mr-2 mt-2">Out of stock</p>
|
||||||
|
@else
|
||||||
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
||||||
<input type="text" wire:model.debounce.300ms="data.{{ $index }}.optional_qty" class="w-1/4 rounded-md border-gray-300 shadow-sm sm:text-sm text-center" placeholder="0">
|
@endif
|
||||||
|
<select wire:model.debounce.300ms="data.{{ $index }}.optional_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm">
|
||||||
|
<option value="0" selected="selected">0</option>
|
||||||
|
@for ($i = 1; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity,$product->custom_value2) : $product->custom_value2); $i++)
|
||||||
|
<option value="{{$i}}">{{$i}}</option>
|
||||||
|
@endfor
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@error("data.{$index}.optional_qty")
|
|
||||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
|
||||||
<span class="block sm:inline">{{ $message }} </span>
|
|
||||||
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
|
|
||||||
</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -173,33 +195,142 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
@if(!empty($subscription->promo_code) && !$subscription->trial_enabled)
|
@if(!empty($subscription->promo_code) && !$subscription->trial_enabled)
|
||||||
<form wire:submit.prevent="handleCoupon" class="">
|
<form wire:submit.prevent="handleCoupon" class="">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="mt-2">
|
<div class="mt-4">
|
||||||
<label for="email" class="block text-sm font-medium text-white">{{ ctrans('texts.promo_code') }}</label>
|
<label for="coupon" class="block text-sm font-medium text-white">{{ ctrans('texts.promo_code') }}</label>
|
||||||
<div class="mt-1 flex rounded-md shadow-sm">
|
<div class="mt-1 flex rounded-md shadow-sm">
|
||||||
<div class="relative flex flex-grow items-stretch focus-within:z-10">
|
<div class="relative flex flex-grow items-stretch focus-within:z-10">
|
||||||
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
||||||
|
</div>
|
||||||
|
<input type="text" wire:model.defer="coupon" class="block w-full rounded-none rounded-l-md border-gray-300 pl-2 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm text-gray-700" placeholder="">
|
||||||
|
</div>
|
||||||
|
<button class="relative -ml-px inline-flex items-center space-x-2 rounded-r-md border border-gray-300 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||||
|
|
||||||
|
<span>{{ ctrans('texts.apply') }}</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" wire:model.debounce.300ms="coupon" class="block w-full rounded-none rounded-l-md border-gray-300 pl-10 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" placeholder="">
|
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="relative -ml-px inline-flex items-center space-x-2 rounded-r-md border border-gray-300 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
</form>
|
||||||
|
|
||||||
<span>{{ ctrans('texts.apply') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="border-t-2 border-gray-200 border-opacity-50 mt-8">
|
<div class="border-t-2 border-gray-200 border-opacity-50 mt-4">
|
||||||
<div class="flex font-semibold justify-between py-6 text-sm uppercase">
|
@if($discount)
|
||||||
<span>{{ ctrans('texts.total') }}</span>
|
<div class="flex font-semibold justify-between py-1 text-sm uppercase">
|
||||||
<span>{{ $total }}</span>
|
<span>{{ ctrans('texts.subtotal') }}</span>
|
||||||
</div>
|
<span>{{ $sub_total }}</span>
|
||||||
<button class="bg-white font-semibold hover:bg-gray-600 py-3 text-sm text-blue-500 uppercase w-full">Checkout</button>
|
</div>
|
||||||
|
<div class="flex font-semibold justify-between py-1 text-sm uppercase">
|
||||||
|
<span>{{ ctrans('texts.discount') }}</span>
|
||||||
|
<span>{{ $discount }}</span>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="flex font-semibold justify-between py-1 text-sm uppercase border-t-2">
|
||||||
|
<span>{{ ctrans('texts.total') }}</span>
|
||||||
|
<span>{{ $total }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($authenticated)
|
||||||
|
<button class="bg-white font-semibold hover:bg-gray-600 py-3 text-sm text-blue-500 uppercase w-full">Checkout</button>
|
||||||
|
@else
|
||||||
|
<form wire:submit.prevent="handleEmail" class="">
|
||||||
|
@csrf
|
||||||
|
<div class="mt-4">
|
||||||
|
<label for="email" class="block text-sm font-medium text-white">{{ ctrans('texts.email') }}</label>
|
||||||
|
<div class="mt-1 flex rounded-md shadow-sm">
|
||||||
|
<div class="relative flex flex-grow items-stretch focus-within:z-10">
|
||||||
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
||||||
|
</div>
|
||||||
|
<input type="text" wire:model.defer="email" class="block w-full rounded-none rounded-l-md border-gray-300 pl-2 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm text-gray-700" placeholder="">
|
||||||
|
</div>
|
||||||
|
<button class="relative -ml-px inline-flex items-center space-x-2 rounded-r-md border border-gray-300 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||||
|
|
||||||
|
<span>{{ ctrans('texts.login') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
@error("email")
|
||||||
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
||||||
|
<span class="block sm:inline">{{ $message }} </span>
|
||||||
|
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($email && !$errors->has('email'))
|
||||||
|
<div class="py-6 px-6 w-80 border mx-auto text-center my-6">
|
||||||
|
<form wire:submit.prevent="handleLogin" class="" x-data="otpForm()">
|
||||||
|
<p class="mb-4">{{ ctrans('texts.otp_code_message')}}</p>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<template x-for="(input, index) in length" :key="index">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
maxlength="1"
|
||||||
|
class="border border-gray-500 w-10 h-10 text-center text-gray-700"
|
||||||
|
:x-ref="index"
|
||||||
|
x-on:input="handleInput($event)"
|
||||||
|
x-on:paste="handlePaste($event)"
|
||||||
|
x-on:keydown.backspace="$event.target.value || handleBackspace($event.target.getAttribute('x-ref'))"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
@error("login")
|
||||||
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
||||||
|
<span class="block sm:inline">{{ $message }} </span>
|
||||||
|
<span class="absolute top-0 bottom-0 right-0 px-4 py-3">
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<script>
|
||||||
|
function otpForm() {
|
||||||
|
return {
|
||||||
|
length: 6,
|
||||||
|
login: "",
|
||||||
|
|
||||||
|
handleInput(e) {
|
||||||
|
const input = e.target;
|
||||||
|
|
||||||
|
this.login = Array.from(Array(this.length), (element, i) => {
|
||||||
|
return this.$refs[i].value || "";
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
if (input.nextElementSibling && input.value) {
|
||||||
|
input.nextElementSibling.focus();
|
||||||
|
input.nextElementSibling.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.login.length == 6){
|
||||||
|
this.$wire.handleLogin(this.login);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePaste(e) {
|
||||||
|
const paste = e.clipboardData.getData('text');
|
||||||
|
this.value = paste;
|
||||||
|
|
||||||
|
const inputs = Array.from(Array(this.length));
|
||||||
|
|
||||||
|
inputs.forEach((element, i) => {
|
||||||
|
this.$refs[i].value = paste[i] || '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBackspace(e) {
|
||||||
|
const previous = parseInt(e, 10) - 1;
|
||||||
|
this.$refs[previous] && this.$refs[previous].focus();
|
||||||
|
this.$wire.loginValidation();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
@extends('portal.ninja2020.layout.clean')
|
||||||
|
@section('meta_title', 'Mollie')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="grid lg:grid-cols-3">
|
||||||
|
<div class="hidden lg:block col-span-1 bg-red-100 h-screen">
|
||||||
|
<img src="{{ asset('images/client-portal-new-image.jpg') }}"
|
||||||
|
class="w-full h-screen object-cover"
|
||||||
|
alt="Background image">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-2 h-screen flex">
|
||||||
|
<div class="m-auto md:w-1/2 lg:w-1/4 flex flex-col items-center">
|
||||||
|
<span class="flex items-center text-2xl">
|
||||||
|
{{ ctrans('texts.payment_error_code',['code' => 500]) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<a class="button-link text-sm mt-2" href="{{ url(request()->getSchemeAndHttpHost() . '/client') }}">
|
||||||
|
{{ ctrans('texts.back_to', ['url' => parse_url(request()->getHttpHost())['host'] ?? request()->getHttpHost()]) }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
|
@ -66,8 +66,6 @@
|
|||||||
<script src="{{ asset('vendor/alpinejs@2.8.2/alpine.js') }}" defer></script>
|
<script src="{{ asset('vendor/alpinejs@2.8.2/alpine.js') }}" defer></script>
|
||||||
|
|
||||||
<!-- Fonts -->
|
<!-- Fonts -->
|
||||||
{{-- <link rel="dns-prefetch" href="https://fonts.gstatic.com"> --}}
|
|
||||||
{{-- <link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet" type="text/css" defer> --}}
|
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: 'Open Sans';
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<!-- Error: {{ session('error') }} -->
|
<!-- Error: {{ session('error') }} -->
|
||||||
@if (isset($company) && $company->matomo_url && $company->matomo_id)
|
@if (isset($company) && $company->matomo_url && $company->matomo_id)
|
||||||
<script>
|
<script>
|
||||||
var _paq = window._paq = window._paq || [];
|
var _paq = window._paq = window._paq || [];
|
||||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
@ -66,9 +66,6 @@
|
|||||||
<script src="{{ asset('vendor/alpinejs@2.8.2/alpine.js') }}" defer></script>
|
<script src="{{ asset('vendor/alpinejs@2.8.2/alpine.js') }}" defer></script>
|
||||||
|
|
||||||
<!-- Fonts -->
|
<!-- Fonts -->
|
||||||
{{-- <link rel="dns-prefetch" href="https://fonts.gstatic.com">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet" type="text/css" defer>
|
|
||||||
--}}
|
|
||||||
<style>
|
<style>
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: 'Open Sans';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user