mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-05 11:44:35 -04:00
Trial Flow:
This commit is contained in:
parent
242accde6f
commit
bba3c79553
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\ClientPortal;
|
namespace App\Http\Controllers\ClientPortal;
|
||||||
|
|
||||||
|
use App\Factory\RecurringInvoiceFactory;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ClientPortal\Uploads\StoreUploadRequest;
|
use App\Http\Requests\ClientPortal\Uploads\StoreUploadRequest;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
@ -19,9 +20,11 @@ use App\Models\Account;
|
|||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Models\Subscription;
|
use App\Models\Subscription;
|
||||||
|
use App\Repositories\SubscriptionRepository;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||||
@ -76,10 +79,14 @@ class NinjaPlanController extends Controller
|
|||||||
|
|
||||||
$data['gateway'] = $gateway;
|
$data['gateway'] = $gateway;
|
||||||
|
|
||||||
$gateway_driver = $gateway->driver()->init();
|
$gateway_driver = $gateway->driver(auth()->guard('contact')->user()->client)->init();
|
||||||
|
|
||||||
|
$customer = $gateway_driver->findOrCreateCustomer();
|
||||||
|
|
||||||
$setupIntent = \Stripe\SetupIntent::create([
|
$setupIntent = \Stripe\SetupIntent::create([
|
||||||
'payment_method_types' => ['card'],
|
'payment_method_types' => ['card'],
|
||||||
|
'usage' => 'off_session',
|
||||||
|
'customer' => $customer->id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$data['intent'] = $setupIntent;
|
$data['intent'] = $setupIntent;
|
||||||
@ -91,6 +98,82 @@ class NinjaPlanController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function trial_confirmation(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$client = auth()->guard('contact')->user()->client;
|
||||||
|
$client->fill($request->all());
|
||||||
|
$client->save();
|
||||||
|
|
||||||
|
//store payment method
|
||||||
|
|
||||||
|
$gateway = CompanyGateway::where('gateway_key', 'd14dd26a37cecc30fdd65700bfb55b23')->first();
|
||||||
|
$gateway_driver = $gateway->driver(auth()->guard('contact')->user()->client)->init();
|
||||||
|
|
||||||
|
$stripe_response = json_decode($request->input('gateway_response'));
|
||||||
|
$customer = $gateway_driver->findOrCreateCustomer();
|
||||||
|
|
||||||
|
$gateway_driver->attach($stripe_response->payment_method, $customer);
|
||||||
|
$method = $gateway_driver->getStripePaymentMethod($stripe_response->payment_method);
|
||||||
|
|
||||||
|
$this->storePaymentMethod($method, $request->payment_method_id, $customer);
|
||||||
|
|
||||||
|
$payment_meta = new \stdClass;
|
||||||
|
$payment_meta->exp_month = (string) $method->card->exp_month;
|
||||||
|
$payment_meta->exp_year = (string) $method->card->exp_year;
|
||||||
|
$payment_meta->brand = (string) $method->card->brand;
|
||||||
|
$payment_meta->last4 = (string) $method->card->last4;
|
||||||
|
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'payment_meta' => $payment_meta,
|
||||||
|
'token' => $method->id,
|
||||||
|
'payment_method_id' => GatewayType::CREDIT_CARD,
|
||||||
|
];
|
||||||
|
|
||||||
|
$gateway_driver->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]);
|
||||||
|
|
||||||
|
//set free trial
|
||||||
|
$account = auth()->guard('contact')->user()->company->account;
|
||||||
|
$account->trial_started = now();
|
||||||
|
$account->trial_plan = 'pro';
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
//create recurring invoice
|
||||||
|
$subscription_repo = new SubscriptionRepository();
|
||||||
|
$subscription = Subscription::find(6);
|
||||||
|
|
||||||
|
$recurring_invoice = RecurringInvoiceFactory::create($subscription->company_id, $subscription->user_id);
|
||||||
|
$recurring_invoice->client_id = $client->id;
|
||||||
|
$recurring_invoice->line_items = $subscription_repo->generateLineItems($subscription, true, false);
|
||||||
|
$recurring_invoice->subscription_id = $subscription->id;
|
||||||
|
$recurring_invoice->frequency_id = $subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY;
|
||||||
|
$recurring_invoice->date = now()->addDays(14);
|
||||||
|
$recurring_invoice->remaining_cycles = -1;
|
||||||
|
$recurring_invoice->auto_bill = $client->getSetting('auto_bill');
|
||||||
|
$recurring_invoice->auto_bill_enabled = $this->setAutoBillFlag($recurring_invoice->auto_bill);
|
||||||
|
$recurring_invoice->due_date_days = 'terms';
|
||||||
|
$recurring_invoice->next_send_date = now()->addDays(14)->format('Y-m-d');
|
||||||
|
$recurring_invoice->next_send_date = $recurring_invoice->nextSendDate();
|
||||||
|
|
||||||
|
$recurring_invoice->save();
|
||||||
|
$recurring_invoice->service()->start();
|
||||||
|
|
||||||
|
return redirect('/');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function setAutoBillFlag($auto_bill)
|
||||||
|
{
|
||||||
|
if ($auto_bill == 'always' || $auto_bill == 'optout') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function plan()
|
public function plan()
|
||||||
{
|
{
|
||||||
return $this->trial();
|
return $this->trial();
|
||||||
|
@ -84,8 +84,8 @@ class CreateAccount
|
|||||||
{
|
{
|
||||||
$sp794f3f->hosted_client_count = config('ninja.quotas.free.clients');
|
$sp794f3f->hosted_client_count = config('ninja.quotas.free.clients');
|
||||||
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
||||||
$sp794f3f->trial_started = now();
|
// $sp794f3f->trial_started = now();
|
||||||
$sp794f3f->trial_plan = 'pro';
|
// $sp794f3f->trial_plan = 'pro';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 overflow-hidden">
|
<div class="w-1/2 overflow-hidden">
|
||||||
|
|
||||||
<form>
|
<form id="card-form" action="{{ route('client.trial.response') }}" method="post">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="gateway_response">
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
<div class="form-group mb-2">
|
<div class="form-group mb-2">
|
||||||
<input type="text" class="form-control block
|
<input type="text" class="form-control block
|
||||||
w-full
|
w-full
|
||||||
@ -48,7 +52,7 @@
|
|||||||
transition
|
transition
|
||||||
ease-in-out
|
ease-in-out
|
||||||
m-0
|
m-0
|
||||||
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="address1"
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="name"
|
||||||
placeholder="{{ ctrans('texts.name') }}"
|
placeholder="{{ ctrans('texts.name') }}"
|
||||||
name="name"
|
name="name"
|
||||||
value="{{$client->present()->name()}}">
|
value="{{$client->present()->name()}}">
|
||||||
@ -68,7 +72,7 @@
|
|||||||
transition
|
transition
|
||||||
ease-in-out
|
ease-in-out
|
||||||
m-0
|
m-0
|
||||||
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="exampleInput91"
|
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" id="address1"
|
||||||
placeholder="{{ ctrans('texts.address1') }}"
|
placeholder="{{ ctrans('texts.address1') }}"
|
||||||
name="address1"
|
name="address1"
|
||||||
value="{{$client->address1}}">
|
value="{{$client->address1}}">
|
||||||
@ -163,9 +167,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group mb-2">
|
<div class="form-group mb-2">
|
||||||
<select name="countries" id="country" class="form-select w-full py-2 text-gray-700">
|
<select name="country" id="country" class="form-select w-full py-2 text-gray-700">
|
||||||
@foreach($countries as $country)
|
@foreach($countries as $country)
|
||||||
<option value="{{ $client->country->iso_3166_2 }}">{{ $client->country->iso_3166_2 }} ({{ $client->country->name }})</option>
|
<option value="{{ $client->country->id }}">{{ $client->country->iso_3166_2 }} ({{ $client->country->name }})</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -213,21 +217,69 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var stripe = Stripe('{{ $gateway->getPublishableKey()}}');
|
var stripe = Stripe('{{ $gateway->getPublishableKey()}}');
|
||||||
|
var client_secret = '{{ $intent->client_secret }}';
|
||||||
|
|
||||||
var elements = stripe.elements({
|
var elements = stripe.elements({
|
||||||
clientSecret: '{{ $intent->client_secret }}',
|
clientSecret: client_secret,
|
||||||
});
|
});
|
||||||
|
|
||||||
var cardElement = elements.create('card', {
|
var cardElement = elements.create('card', {
|
||||||
value: {
|
value: {
|
||||||
postalCode: document.querySelector('meta[name=client-postal-code]').content,
|
postalCode: document.querySelector('input[name=postal_code]').content,
|
||||||
name: document.querySelector('meta[name=client-name').content
|
name: document.querySelector('input[name=name]').content
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cardElement.mount('#card-element');
|
cardElement.mount('#card-element');
|
||||||
|
|
||||||
|
const form = document.getElementById('card-form');
|
||||||
|
|
||||||
|
var e = document.getElementById("country");
|
||||||
|
var country_value = e.options[e.selectedIndex].value;
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById('pay-now')
|
||||||
|
.addEventListener('click', () => {
|
||||||
|
|
||||||
|
let payNowButton = document.getElementById('pay-now');
|
||||||
|
payNowButton = payNowButton;
|
||||||
|
payNowButton.disabled = true;
|
||||||
|
payNowButton.querySelector('svg').classList.remove('hidden');
|
||||||
|
payNowButton.querySelector('span').classList.add('hidden');
|
||||||
|
|
||||||
|
stripe.handleCardSetup(this.client_secret, cardElement, {
|
||||||
|
payment_method_data: {
|
||||||
|
billing_details: {
|
||||||
|
name: document.querySelector('input[name=name]').content,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.error) {
|
||||||
|
|
||||||
|
let errors = document.getElementById('errors');
|
||||||
|
let payNowButton = document.getElementById('pay-now');
|
||||||
|
|
||||||
|
errors.textContent = '';
|
||||||
|
errors.textContent = result.error.message;
|
||||||
|
errors.hidden = false;
|
||||||
|
|
||||||
|
payNowButton.disabled = false;
|
||||||
|
payNowButton.querySelector('svg').classList.add('hidden');
|
||||||
|
payNowButton.querySelector('span').classList.remove('hidden');
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector(
|
||||||
|
'input[name="gateway_response"]'
|
||||||
|
).value = JSON.stringify(result.setupIntent);
|
||||||
|
|
||||||
|
document.getElementById('card-form').submit();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
@ -28,6 +28,7 @@ Route::get('documents/{document_hash}', 'ClientPortal\DocumentController@publicD
|
|||||||
Route::get('error', 'ClientPortal\ContactHashLoginController@errorPage')->name('client.error');
|
Route::get('error', 'ClientPortal\ContactHashLoginController@errorPage')->name('client.error');
|
||||||
Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['domain_db','contact_key_login']);
|
Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['domain_db','contact_key_login']);
|
||||||
Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['domain_db']);
|
Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['domain_db']);
|
||||||
|
Route::post('client/ninja/trial_confirmation', 'ClientPortal\NinjaPlanController@trial_confirmation')->name('client.trial.response')->middleware(['domain_db']);
|
||||||
|
|
||||||
Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||||
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||||
|
Loading…
x
Reference in New Issue
Block a user