Subscriptions v2
This commit is contained in:
parent
82ec5a655b
commit
d2ea53b0a4
|
|
@ -41,6 +41,25 @@ class SubscriptionPurchaseController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function upgrade(Subscription $subscription, Request $request)
|
||||||
|
{
|
||||||
|
/* Make sure the contact is logged into the correct company for this subscription */
|
||||||
|
if (auth()->guard('contact')->user() && auth()->guard('contact')->user()->company_id != $subscription->company_id) {
|
||||||
|
auth()->guard('contact')->logout();
|
||||||
|
$request->session()->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('locale')) {
|
||||||
|
$this->setLocale($request->query('locale'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('billing-portal.purchasev2', [
|
||||||
|
'subscription' => $subscription,
|
||||||
|
'hash' => Str::uuid()->toString(),
|
||||||
|
'request_data' => $request->all(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set locale for incoming request.
|
* Set locale for incoming request.
|
||||||
*
|
*
|
||||||
|
|
@ -56,4 +75,7 @@ class SubscriptionPurchaseController extends Controller
|
||||||
App::setLocale($record->locale);
|
App::setLocale($record->locale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,528 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
|
use App\Factory\ClientFactory;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Mail\ContactPasswordlessLogin;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Subscription;
|
||||||
|
use App\Repositories\ClientContactRepository;
|
||||||
|
use App\Repositories\ClientRepository;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use App\DataMapper\ClientSettings;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class BillingPortalPurchasev2 extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Random hash generated by backend to handle the tracking of state.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top level text on the left side of billing page.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $heading_text;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* E-mail address model for user input.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Password model for user input.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of subscription.
|
||||||
|
*
|
||||||
|
* @var Subscription
|
||||||
|
*/
|
||||||
|
public $subscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of client contact.
|
||||||
|
*
|
||||||
|
* @var null|ClientContact
|
||||||
|
*/
|
||||||
|
public $contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rules for validating the form.
|
||||||
|
*
|
||||||
|
* @var \string[][]
|
||||||
|
*/
|
||||||
|
protected $rules = [
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id for CompanyGateway record.
|
||||||
|
*
|
||||||
|
* @var string|integer
|
||||||
|
*/
|
||||||
|
public $company_gateway_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id for GatewayType.
|
||||||
|
*
|
||||||
|
* @var string|integer
|
||||||
|
*/
|
||||||
|
public $payment_method_id;
|
||||||
|
|
||||||
|
private $user_coupon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of steps that frontend form follows.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $steps = [
|
||||||
|
'passed_email' => false,
|
||||||
|
'existing_user' => false,
|
||||||
|
'fetched_payment_methods' => false,
|
||||||
|
'fetched_client' => false,
|
||||||
|
'show_start_trial' => false,
|
||||||
|
'passwordless_login_sent' => false,
|
||||||
|
'started_payment' => false,
|
||||||
|
'discount_applied' => false,
|
||||||
|
'show_loading_bar' => false,
|
||||||
|
'not_eligible' => null,
|
||||||
|
'not_eligible_message' => null,
|
||||||
|
'payment_required' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of payment methods fetched from client.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $methods = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of \App\Models\Invoice
|
||||||
|
*
|
||||||
|
* @var Invoice
|
||||||
|
*/
|
||||||
|
public $invoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coupon model for user input
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $coupon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quantity for seats
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $quantity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First-hit request data (queries, locales...).
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $request_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disabled state of passwordless login button.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $passwordless_login_btn = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of company.
|
||||||
|
*
|
||||||
|
* @var Company
|
||||||
|
*/
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Campaign reference.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $campaign;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
$this->quantity = 1;
|
||||||
|
|
||||||
|
$this->price = $this->subscription->price;
|
||||||
|
|
||||||
|
if (request()->query('coupon')) {
|
||||||
|
$this->coupon = request()->query('coupon');
|
||||||
|
$this->handleCoupon();
|
||||||
|
}
|
||||||
|
elseif(strlen($this->subscription->promo_code) == 0 && $this->subscription->promo_discount > 0){
|
||||||
|
$this->price = $this->subscription->promo_price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle user authentication
|
||||||
|
*
|
||||||
|
* @return $this|bool|void
|
||||||
|
*/
|
||||||
|
public function authenticate()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$contact = ClientContact::where('email', $this->email)
|
||||||
|
->where('company_id', $this->subscription->company_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($contact && $this->steps['existing_user'] === false) {
|
||||||
|
return $this->steps['existing_user'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($contact && $this->steps['existing_user']) {
|
||||||
|
$attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password, 'company_id' => $this->subscription->company_id]);
|
||||||
|
|
||||||
|
return $attempt
|
||||||
|
? $this->getPaymentMethods($contact)
|
||||||
|
: session()->flash('message', 'These credentials do not match our records.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->steps['existing_user'] = false;
|
||||||
|
|
||||||
|
$contact = $this->createBlankClient();
|
||||||
|
|
||||||
|
if ($contact && $contact instanceof ClientContact) {
|
||||||
|
$this->getPaymentMethods($contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a blank client. Used for new customers purchasing.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @throws \Laracasts\Presenter\Exceptions\PresenterException
|
||||||
|
*/
|
||||||
|
protected function createBlankClient()
|
||||||
|
{
|
||||||
|
$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(),
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($this->request_data as $field => $value) {
|
||||||
|
if (in_array($field, Client::$subscriptions_fillable)) {
|
||||||
|
$data[$field] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($field, ClientContact::$subscription_fillable)) {
|
||||||
|
$data['contacts'][0][$field] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nlog($this->subscription->group_settings->settings);
|
||||||
|
// nlog($this->subscription->group_settings->settings->currency_id);
|
||||||
|
|
||||||
|
if(array_key_exists('currency_id', $this->request_data)) {
|
||||||
|
|
||||||
|
$currency = Cache::get('currencies')->filter(function ($item){
|
||||||
|
return $item->id == $this->request_data['currency_id'];
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if($currency)
|
||||||
|
$data['settings']->currency_id = $currency->id;
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif($this->subscription->group_settings && property_exists($this->subscription->group_settings->settings, 'currency_id')) {
|
||||||
|
|
||||||
|
$currency = Cache::get('currencies')->filter(function ($item){
|
||||||
|
return $item->id == $this->subscription->group_settings->settings->currency_id;
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if($currency)
|
||||||
|
$data['settings']->currency_id = $currency->id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('locale', $this->request_data)) {
|
||||||
|
$request = $this->request_data;
|
||||||
|
|
||||||
|
$record = Cache::get('languages')->filter(function ($item) use ($request) {
|
||||||
|
return $item->locale == $request['locale'];
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($record) {
|
||||||
|
$data['settings']['language_id'] = (string)$record->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $client_repo->save($data, ClientFactory::create($company->id, $user->id));
|
||||||
|
|
||||||
|
return $client->fresh()->contacts->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetching payment methods from the client.
|
||||||
|
*
|
||||||
|
* @param ClientContact $contact
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function getPaymentMethods(ClientContact $contact): self
|
||||||
|
{
|
||||||
|
Auth::guard('contact')->loginUsingId($contact->id, true);
|
||||||
|
|
||||||
|
$this->contact = $contact;
|
||||||
|
|
||||||
|
if ($this->subscription->trial_enabled) {
|
||||||
|
$this->heading_text = ctrans('texts.plan_trial');
|
||||||
|
$this->steps['show_start_trial'] = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)$this->price == 0)
|
||||||
|
$this->steps['payment_required'] = false;
|
||||||
|
else
|
||||||
|
$this->steps['fetched_payment_methods'] = true;
|
||||||
|
|
||||||
|
$this->methods = $contact->client->service()->getPaymentMethods($this->price);
|
||||||
|
|
||||||
|
$this->heading_text = ctrans('texts.payment_methods');
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middle method between selecting payment method &
|
||||||
|
* submitting the from to the backend.
|
||||||
|
*
|
||||||
|
* @param $company_gateway_id
|
||||||
|
* @param $gateway_type_id
|
||||||
|
*/
|
||||||
|
public function handleMethodSelectingEvent($company_gateway_id, $gateway_type_id)
|
||||||
|
{
|
||||||
|
$this->company_gateway_id = $company_gateway_id;
|
||||||
|
$this->payment_method_id = $gateway_type_id;
|
||||||
|
|
||||||
|
$this->handleBeforePaymentEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to handle events before payments.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handleBeforePaymentEvents()
|
||||||
|
{
|
||||||
|
$this->steps['started_payment'] = true;
|
||||||
|
$this->steps['show_loading_bar'] = true;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->contact->client->id,
|
||||||
|
'date' => now()->format('Y-m-d'),
|
||||||
|
'invitations' => [[
|
||||||
|
'key' => '',
|
||||||
|
'client_contact_id' => $this->contact->hashed_id,
|
||||||
|
]],
|
||||||
|
'user_input_promo_code' => $this->coupon,
|
||||||
|
'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon,
|
||||||
|
'quantity' => $this->quantity,
|
||||||
|
];
|
||||||
|
|
||||||
|
$is_eligible = $this->subscription->service()->isEligible($this->contact);
|
||||||
|
|
||||||
|
if (is_array($is_eligible) && $is_eligible['message'] != 'Success') {
|
||||||
|
$this->steps['not_eligible'] = true;
|
||||||
|
$this->steps['not_eligible_message'] = $is_eligible['message'];
|
||||||
|
$this->steps['show_loading_bar'] = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->invoice = $this->subscription
|
||||||
|
->service()
|
||||||
|
->createInvoice($data, $this->quantity)
|
||||||
|
->service()
|
||||||
|
->markSent()
|
||||||
|
->fillDefaults()
|
||||||
|
->adjustInventory()
|
||||||
|
->save();
|
||||||
|
|
||||||
|
Cache::put($this->hash, [
|
||||||
|
'subscription_id' => $this->subscription->id,
|
||||||
|
'email' => $this->email ?? $this->contact->email,
|
||||||
|
'client_id' => $this->contact->client->id,
|
||||||
|
'invoice_id' => $this->invoice->id,
|
||||||
|
'context' => 'purchase',
|
||||||
|
'campaign' => $this->campaign,
|
||||||
|
], now()->addMinutes(60));
|
||||||
|
|
||||||
|
$this->emit('beforePaymentEventsCompleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy method for starting the trial.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
|
*/
|
||||||
|
public function handleTrial()
|
||||||
|
{
|
||||||
|
return $this->subscription->service()->startTrial([
|
||||||
|
'email' => $this->email ?? $this->contact->email,
|
||||||
|
'quantity' => $this->quantity,
|
||||||
|
'contact_id' => $this->contact->id,
|
||||||
|
'client_id' => $this->contact->client->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handlePaymentNotRequired()
|
||||||
|
{
|
||||||
|
|
||||||
|
$is_eligible = $this->subscription->service()->isEligible($this->contact);
|
||||||
|
|
||||||
|
if ($is_eligible['status_code'] != 200) {
|
||||||
|
$this->steps['not_eligible'] = true;
|
||||||
|
$this->steps['not_eligible_message'] = $is_eligible['message'];
|
||||||
|
$this->steps['show_loading_bar'] = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $this->subscription->service()->handleNoPaymentRequired([
|
||||||
|
'email' => $this->email ?? $this->contact->email,
|
||||||
|
'quantity' => $this->quantity,
|
||||||
|
'contact_id' => $this->contact->id,
|
||||||
|
'client_id' => $this->contact->client->id,
|
||||||
|
'coupon' => $this->coupon,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
$contact = ClientContact::query()
|
||||||
|
->where('email', $this->email)
|
||||||
|
->where('company_id', $this->subscription->company_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$mailer = new NinjaMailerObject();
|
||||||
|
$mailer->mailable = new ContactPasswordlessLogin($this->email, $this->subscription->company, (string)route('client.subscription.purchase', $this->subscription->hashed_id) . '?coupon=' . $this->coupon);
|
||||||
|
$mailer->company = $this->subscription->company;
|
||||||
|
$mailer->settings = $this->subscription->company->settings;
|
||||||
|
$mailer->to_user = $contact;
|
||||||
|
|
||||||
|
NinjaMailerJob::dispatch($mailer);
|
||||||
|
|
||||||
|
$this->steps['passwordless_login_sent'] = true;
|
||||||
|
$this->passwordless_login_btn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
if (array_key_exists('email', $this->request_data)) {
|
||||||
|
$this->email = $this->request_data['email'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->contact instanceof ClientContact) {
|
||||||
|
$this->getPaymentMethods($this->contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
return render('components.livewire.billing-portal-purchasev2');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,7 @@ class GenerateSmsRequest extends Request
|
||||||
*/
|
*/
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{
|
||||||
return auth()->user()->isAdmin();
|
return auth()->user();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/compat-data": "7.15.0",
|
"@babel/compat-data": "7.15.0",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
"laravel-mix-purgecss": "^6.0.0",
|
"laravel-mix-purgecss": "^6.0.0",
|
||||||
"vue-template-compiler": "^2.6.14"
|
"vue-template-compiler": "^2.6.14"
|
||||||
}
|
}
|
||||||
|
|
@ -1682,6 +1683,15 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/aspect-ratio": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@trysound/sax": {
|
"node_modules/@trysound/sax": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
||||||
|
|
@ -10285,6 +10295,13 @@
|
||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@tailwindcss/aspect-ratio": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@trysound/sax": {
|
"@trysound/sax": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/compat-data": "7.15.0",
|
"@babel/compat-data": "7.15.0",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
|
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||||
"laravel-mix-purgecss": "^6.0.0",
|
"laravel-mix-purgecss": "^6.0.0",
|
||||||
"vue-template-compiler": "^2.6.14"
|
"vue-template-compiler": "^2.6.14"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"/js/app.js": "/js/app.js?id=384185bf9d293949134d09b890c81369",
|
"/js/app.js": "/js/app.js?id=19300612c6880925e8043b61e8d49632",
|
||||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=9fb77e87fe0f85a367050e08f79ec9df",
|
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=9fb77e87fe0f85a367050e08f79ec9df",
|
||||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=803182f668c39d631ca5c55437876da4",
|
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=803182f668c39d631ca5c55437876da4",
|
||||||
"/js/clients/payments/forte-credit-card-payment.js": "/js/clients/payments/forte-credit-card-payment.js?id=6e9f466c5504d3753f9b4ffc6f947095",
|
"/js/clients/payments/forte-credit-card-payment.js": "/js/clients/payments/forte-credit-card-payment.js?id=6e9f466c5504d3753f9b4ffc6f947095",
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=6fb63bae43d077b5061f4dadfe8dffc8",
|
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=6fb63bae43d077b5061f4dadfe8dffc8",
|
||||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=cdc76607aaf0b47a5a4e554e4177713d",
|
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=cdc76607aaf0b47a5a4e554e4177713d",
|
||||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=809de47258a681f0ffebe787dd6a9a93",
|
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=809de47258a681f0ffebe787dd6a9a93",
|
||||||
"/js/setup/setup.js": "/js/setup/setup.js?id=87367cce4927b42a92defdbae7a64711",
|
"/js/setup/setup.js": "/js/setup/setup.js?id=27560b012f166f8b9417ced2188aab70",
|
||||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314fb8357e5be63b",
|
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314fb8357e5be63b",
|
||||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=be5307abc990bb44f2f92628103b1d98",
|
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=be5307abc990bb44f2f92628103b1d98",
|
||||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12ca45acddacd72",
|
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12ca45acddacd72",
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=3d53d2f7d0291d9f92cf7414dd2d351c",
|
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=3d53d2f7d0291d9f92cf7414dd2d351c",
|
||||||
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js?id=db71055862995fd6ae21becfc587a3de",
|
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js?id=db71055862995fd6ae21becfc587a3de",
|
||||||
"/js/clients/payments/stripe-fpx.js": "/js/clients/payments/stripe-fpx.js?id=914a6846ad1e5584635e7430fef76875",
|
"/js/clients/payments/stripe-fpx.js": "/js/clients/payments/stripe-fpx.js?id=914a6846ad1e5584635e7430fef76875",
|
||||||
"/css/app.css": "/css/app.css?id=6bafb560444b3b12f8d1ce59bd7fd703",
|
"/css/app.css": "/css/app.css?id=134313385d8e842c1589a0c057b0a112",
|
||||||
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ada60afcedcb7c",
|
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ada60afcedcb7c",
|
||||||
"/vendor/clipboard.min.js": "/vendor/clipboard.min.js?id=15f52a1ee547f2bdd46e56747332ca2d"
|
"/vendor/clipboard.min.js": "/vendor/clipboard.min.js?id=15f52a1ee547f2bdd46e56747332ca2d"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
@extends('portal.ninja2020.layout.clean')
|
||||||
|
@section('meta_title', ctrans('texts.purchase'))
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
@livewire('billing-portal-purchasev2', ['subscription' => $subscription, 'company' => $subscription->company, 'contact' => auth()->guard('contact')->user(), 'hash' => $hash, 'request_data' => $request_data, 'campaign' => request()->query('campaign') ?? null])
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@push('footer')
|
||||||
|
<script>
|
||||||
|
function updateGatewayFields(companyGatewayId, paymentMethodId) {
|
||||||
|
document.getElementById('company_gateway_id').value = companyGatewayId;
|
||||||
|
document.getElementById('payment_method_id').value = paymentMethodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Livewire.on('beforePaymentEventsCompleted', () => document.getElementById('payment-method-form').submit());
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-12">
|
||||||
|
|
||||||
|
<div class="col-span-12 xl:col-span-8 bg-gray-50 flex flex-col max-h-100px">
|
||||||
|
<div class="w-full p-8 md:max-w-3xl">
|
||||||
|
|
||||||
|
<img class="object-scale-down" style="max-height: 100px;"src="{{ $subscription->company->present()->logo }}" alt="{{ $subscription->company->present()->name }}">
|
||||||
|
|
||||||
|
<h1 id="billing-page-company-logo" class="text-3xl font-bold tracking-wide mt-6">
|
||||||
|
{{ $subscription->name }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-12 xl:col-span-4 bg-blue-500 flex flex-col item-center">
|
||||||
|
<div class="w-full p-4 md:max-w-3xl">
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-12 border-4 border-gray-600">
|
||||||
|
|
||||||
|
<div class="col-span-12 xl:col-span-8 bg-gray-50 flex flex-col">
|
||||||
|
<div class="w-full p-8 md:max-w-3xl">
|
||||||
|
|
||||||
|
product block
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-12 xl:col-span-4 bg-blue-500 flex flex-col item-center">
|
||||||
|
<div class="w-full p-4 md:max-w-3xl">
|
||||||
|
|
||||||
|
customer form block
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -115,6 +115,8 @@ Route::post('payments/process/response', [App\Http\Controllers\ClientPortal\Paym
|
||||||
Route::get('payments/process/response', [App\Http\Controllers\ClientPortal\PaymentController::class, 'response'])->name('client.payments.response.get')->middleware(['locale', 'domain_db', 'verify_hash']);
|
Route::get('payments/process/response', [App\Http\Controllers\ClientPortal\PaymentController::class, 'response'])->name('client.payments.response.get')->middleware(['locale', 'domain_db', 'verify_hash']);
|
||||||
|
|
||||||
Route::get('client/subscriptions/{subscription}/purchase', [App\Http\Controllers\ClientPortal\SubscriptionPurchaseController::class, 'index'])->name('client.subscription.purchase')->middleware('domain_db');
|
Route::get('client/subscriptions/{subscription}/purchase', [App\Http\Controllers\ClientPortal\SubscriptionPurchaseController::class, 'index'])->name('client.subscription.purchase')->middleware('domain_db');
|
||||||
|
Route::get('client/subscriptions/{subscription}/purchase/v2', [App\Http\Controllers\ClientPortal\SubscriptionPurchaseController::class, 'upgrade'])->name('client.subscription.upgrade')->middleware('domain_db');
|
||||||
|
|
||||||
|
|
||||||
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||||
/*Invitation catches*/
|
/*Invitation catches*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue