Merge pull request #5853 from beganovich/v5-2805-tracking-campaign-source

(v5) Passing campaign data into payment flow
This commit is contained in:
Benjamin Beganović 2021-06-01 16:32:34 +02:00 committed by GitHub
commit c61a94f2d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 81 deletions

View File

@ -162,6 +162,13 @@ class BillingPortalPurchase extends Component
*/ */
public $passwordless_login_btn = false; public $passwordless_login_btn = false;
/**
* Campaign reference.
*
* @var string|null
*/
public $campaign;
public function mount() public function mount()
{ {
$this->price = $this->subscription->price; $this->price = $this->subscription->price;
@ -182,8 +189,8 @@ class BillingPortalPurchase extends Component
$this->validate(); $this->validate();
$contact = ClientContact::where('email', $this->email) $contact = ClientContact::where('email', $this->email)
->where('company_id', $this->subscription->company_id) ->where('company_id', $this->subscription->company_id)
->first(); ->first();
if ($contact && $this->steps['existing_user'] === false) { if ($contact && $this->steps['existing_user'] === false) {
return $this->steps['existing_user'] = true; return $this->steps['existing_user'] = true;
@ -272,8 +279,8 @@ class BillingPortalPurchase extends Component
return $this; return $this;
} }
if((int)$this->subscription->price == 0) if ((int)$this->subscription->price == 0)
$this->steps['payment_required'] = false; $this->steps['payment_required'] = false;
else else
$this->steps['fetched_payment_methods'] = true; $this->steps['fetched_payment_methods'] = true;
@ -332,7 +339,7 @@ class BillingPortalPurchase extends Component
$is_eligible = $this->subscription->service()->isEligible($this->contact); $is_eligible = $this->subscription->service()->isEligible($this->contact);
if ($is_eligible['exception']['message'] != 'Success') { if (is_array($is_eligible) && $is_eligible['exception']['message'] != 'Success') {
$this->steps['not_eligible'] = true; $this->steps['not_eligible'] = true;
$this->steps['not_eligible_message'] = $is_eligible['exception']['message']; $this->steps['not_eligible_message'] = $is_eligible['exception']['message'];
$this->steps['show_loading_bar'] = false; $this->steps['show_loading_bar'] = false;
@ -341,13 +348,13 @@ class BillingPortalPurchase extends Component
} }
Cache::put($this->hash, [ Cache::put($this->hash, [
'subscription_id' => $this->subscription->id, 'subscription_id' => $this->subscription->id,
'email' => $this->email ?? $this->contact->email, 'email' => $this->email ?? $this->contact->email,
'client_id' => $this->contact->client->id, 'client_id' => $this->contact->client->id,
'invoice_id' => $this->invoice->id, 'invoice_id' => $this->invoice->id,
'context' => 'purchase', 'context' => 'purchase',
now()->addMinutes(60)] 'campaign' => $this->campaign,
); ], now()->addMinutes(60));
$this->emit('beforePaymentEventsCompleted'); $this->emit('beforePaymentEventsCompleted');
} }
@ -370,7 +377,7 @@ class BillingPortalPurchase extends Component
public function handlePaymentNotRequired() public function handlePaymentNotRequired()
{ {
$is_eligible = $this->subscription->service()->isEligible($this->contact); $is_eligible = $this->subscription->service()->isEligible($this->contact);
if ($is_eligible['status_code'] != 200) { if ($is_eligible['status_code'] != 200) {
$this->steps['not_eligible'] = true; $this->steps['not_eligible'] = true;

View File

@ -244,6 +244,10 @@ class BaseDriver extends AbstractPaymentDriver
if (property_exists($this->payment_hash->data, 'billing_context')) { if (property_exists($this->payment_hash->data, 'billing_context')) {
$billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id); $billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id);
// To access campaign hash => $this->payment_hash->data->billing_context->campaign;
// To access campaign data => Cache::get(CAMPAIGN_HASH)
// To access utm data => session()->get('utm-' . CAMPAIGN_HASH);
(new SubscriptionService($billing_subscription))->completePurchase($this->payment_hash); (new SubscriptionService($billing_subscription))->completePurchase($this->payment_hash);
} }

View File

@ -52,8 +52,8 @@ class SubscriptionService
$this->subscription = $subscription; $this->subscription = $subscription;
} }
/* /*
Performs the initial purchase of a Performs the initial purchase of a
one time or recurring product one time or recurring product
*/ */
public function completePurchase(PaymentHash $payment_hash) public function completePurchase(PaymentHash $payment_hash)
@ -184,13 +184,13 @@ class SubscriptionService
/** /**
* Returns an upgrade price when moving between plans * Returns an upgrade price when moving between plans
* *
* However we only allow people to move between plans * However we only allow people to move between plans
* if their account is in good standing. * if their account is in good standing.
* *
* @param RecurringInvoice $recurring_invoice * @param RecurringInvoice $recurring_invoice
* @param Subscription $target * @param Subscription $target
* *
* @return float * @return float
*/ */
public function calculateUpgradePrice(RecurringInvoice $recurring_invoice, Subscription $target) :?float public function calculateUpgradePrice(RecurringInvoice $recurring_invoice, Subscription $target) :?float
{ {
@ -210,7 +210,7 @@ class SubscriptionService
->where('client_id', $recurring_invoice->client_id) ->where('client_id', $recurring_invoice->client_id)
->where('is_deleted', 0) ->where('is_deleted', 0)
->orderBy('id', 'desc') ->orderBy('id', 'desc')
->first(); ->first();
if ($outstanding->count() == 0){ if ($outstanding->count() == 0){
//nothing outstanding //nothing outstanding
@ -232,15 +232,15 @@ class SubscriptionService
/** /**
* We refund unused days left. * We refund unused days left.
* *
* @param Invoice $invoice * @param Invoice $invoice
* @return float * @return float
*/ */
private function calculateProRataRefund($invoice) :float private function calculateProRataRefund($invoice) :float
{ {
if(!$this->invoice->date) if(!$this->invoice->date)
return 0; return 0;
$start_date = Carbon::parse($invoice->date); $start_date = Carbon::parse($invoice->date);
$current_date = now(); $current_date = now();
@ -259,9 +259,9 @@ class SubscriptionService
* Returns refundable set of line items * Returns refundable set of line items
* transformed for direct injection into * transformed for direct injection into
* the invoice * the invoice
* *
* @param Invoice $invoice * @param Invoice $invoice
* @return array * @return array
*/ */
private function calculateProRataRefundItems($invoice, $is_credit = false) :array private function calculateProRataRefundItems($invoice, $is_credit = false) :array
{ {
@ -285,14 +285,14 @@ class SubscriptionService
if($item->product_key != ctrans('texts.refund')) if($item->product_key != ctrans('texts.refund'))
{ {
$item->cost = ($item->cost*$ratio*$multiplier); $item->cost = ($item->cost*$ratio*$multiplier);
$item->product_key = ctrans('texts.refund'); $item->product_key = ctrans('texts.refund');
$item->notes = ctrans('texts.refund') . ": ". $item->notes; $item->notes = ctrans('texts.refund') . ": ". $item->notes;
$line_items[] = $item; $line_items[] = $item;
} }
} }
@ -302,13 +302,13 @@ class SubscriptionService
/** /**
* We only charge for the used days * We only charge for the used days
* *
* @param Invoice $invoice * @param Invoice $invoice
* @return float * @return float
*/ */
private function calculateProRataCharge($invoice) :float private function calculateProRataCharge($invoice) :float
{ {
$start_date = Carbon::parse($invoice->date); $start_date = Carbon::parse($invoice->date);
$current_date = now(); $current_date = now();
@ -320,7 +320,7 @@ class SubscriptionService
nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency}"); nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency}");
$pro_rata_charge = round(($days_to_charge/$days_in_frequency) * $invoice->amount ,2); $pro_rata_charge = round(($days_to_charge/$days_in_frequency) * $invoice->amount ,2);
nlog("pro rata charge = {$pro_rata_charge}"); nlog("pro rata charge = {$pro_rata_charge}");
return $pro_rata_charge; return $pro_rata_charge;
@ -329,15 +329,15 @@ class SubscriptionService
/** /**
* When downgrading, we may need to create * When downgrading, we may need to create
* a credit * a credit
* *
* @param array $data * @param array $data
*/ */
public function createChangePlanCredit($data) public function createChangePlanCredit($data)
{ {
$recurring_invoice = $data['recurring_invoice']; $recurring_invoice = $data['recurring_invoice'];
$old_subscription = $data['subscription']; $old_subscription = $data['subscription'];
$target_subscription = $data['target']; $target_subscription = $data['target'];
$pro_rata_charge_amount = 0; $pro_rata_charge_amount = 0;
$pro_rata_refund_amount = 0; $pro_rata_refund_amount = 0;
@ -346,9 +346,9 @@ class SubscriptionService
->where('is_deleted', 0) ->where('is_deleted', 0)
->withTrashed() ->withTrashed()
->orderBy('id', 'desc') ->orderBy('id', 'desc')
->first(); ->first();
if($last_invoice->balance > 0) if($last_invoice->balance > 0)
{ {
$pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription); $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription);
nlog("pro rata charge = {$pro_rata_charge_amount}"); nlog("pro rata charge = {$pro_rata_charge_amount}");
@ -364,7 +364,7 @@ class SubscriptionService
nlog("total payable = {$total_payable}"); nlog("total payable = {$total_payable}");
$credit = $this->createCredit($last_invoice, $target_subscription); $credit = $this->createCredit($last_invoice, $target_subscription);
$new_recurring_invoice = $this->createNewRecurringInvoice($recurring_invoice); $new_recurring_invoice = $this->createNewRecurringInvoice($recurring_invoice);
$context = [ $context = [
@ -386,9 +386,9 @@ class SubscriptionService
/** /**
* When changing plans, we need to generate a pro rata invoice * When changing plans, we need to generate a pro rata invoice
* *
* @param array $data * @param array $data
* @return Invoice * @return Invoice
*/ */
public function createChangePlanInvoice($data) public function createChangePlanInvoice($data)
{ {
@ -404,9 +404,9 @@ class SubscriptionService
->where('is_deleted', 0) ->where('is_deleted', 0)
->withTrashed() ->withTrashed()
->orderBy('id', 'desc') ->orderBy('id', 'desc')
->first(); ->first();
if($last_invoice->balance > 0) if($last_invoice->balance > 0)
{ {
$pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription); $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription);
nlog("pro rata charge = {$pro_rata_charge_amount}"); nlog("pro rata charge = {$pro_rata_charge_amount}");
@ -424,10 +424,10 @@ class SubscriptionService
} }
/** /**
* Response from payment service on * Response from payment service on
* return from a plan change * return from a plan change
* *
* @param PaymentHash $payment_hash * @param PaymentHash $payment_hash
*/ */
private function handlePlanChange($payment_hash) private function handlePlanChange($payment_hash)
{ {
@ -457,9 +457,9 @@ class SubscriptionService
/** /**
* Creates a new recurring invoice when changing * Creates a new recurring invoice when changing
* plans * plans
* *
* @param RecurringInvoice $old_recurring_invoice * @param RecurringInvoice $old_recurring_invoice
* @return RecurringInvoice * @return RecurringInvoice
*/ */
private function createNewRecurringInvoice($old_recurring_invoice) :RecurringInvoice private function createNewRecurringInvoice($old_recurring_invoice) :RecurringInvoice
{ {
@ -512,10 +512,10 @@ class SubscriptionService
/** /**
* Creates a credit note if the plan change requires * Creates a credit note if the plan change requires
* *
* @param Invoice $last_invoice * @param Invoice $last_invoice
* @param Subscription $target * @param Subscription $target
* @return Credit * @return Credit
*/ */
private function createCredit($last_invoice, $target) private function createCredit($last_invoice, $target)
{ {
@ -544,10 +544,10 @@ class SubscriptionService
/** /**
* When changing plans we need to generate a pro rata * When changing plans we need to generate a pro rata
* invoice which takes into account any credits. * invoice which takes into account any credits.
* *
* @param Invoice $last_invoice * @param Invoice $last_invoice
* @param Subscription $target * @param Subscription $target
* @return Invoice * @return Invoice
*/ */
private function proRataInvoice($last_invoice, $target) private function proRataInvoice($last_invoice, $target)
{ {
@ -576,9 +576,9 @@ class SubscriptionService
/** /**
* Generates the first invoice when a subscription is purchased * Generates the first invoice when a subscription is purchased
* *
* @param array $data * @param array $data
* @return Invoice * @return Invoice
*/ */
public function createInvoice($data): ?\App\Models\Invoice public function createInvoice($data): ?\App\Models\Invoice
{ {
@ -603,9 +603,9 @@ class SubscriptionService
/** /**
* Generates a recurring invoice based on * Generates a recurring invoice based on
* the specifications of the subscription * the specifications of the subscription
* *
* @param int $client_id The Client Id * @param int $client_id The Client Id
* @return RecurringInvoice * @return RecurringInvoice
*/ */
public function convertInvoiceToRecurring($client_id) :RecurringInvoice public function convertInvoiceToRecurring($client_id) :RecurringInvoice
{ {
@ -626,12 +626,11 @@ class SubscriptionService
/** /**
* Hit a 3rd party API if defined in the subscription * Hit a 3rd party API if defined in the subscription
* *
* @param array $context * @param array $context
*/ */
public function triggerWebhook($context) public function triggerWebhook($context)
{ {
/* If no webhooks have been set, then just return gracefully */ if (empty($this->subscription->webhook_configuration['post_purchase_url']) || empty($this->subscription->webhook_configuration['post_purchase_rest_method'])) {
if(!array_key_exists('post_purchase_url', $this->subscription->webhook_configuration) || !array_key_exists('post_purchase_rest_method', $this->subscription->webhook_configuration)) {
return true; return true;
} }
@ -667,7 +666,7 @@ class SubscriptionService
SystemLog::CATEGORY_WEBHOOK, SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_RESPONSE, SystemLog::EVENT_WEBHOOK_RESPONSE,
SystemLog::TYPE_WEBHOOK_RESPONSE, SystemLog::TYPE_WEBHOOK_RESPONSE,
$client, $client,
$client->company, $client->company,
); );
@ -718,9 +717,9 @@ class SubscriptionService
/** /**
* Handle the cancellation of a subscription * Handle the cancellation of a subscription
* *
* @param RecurringInvoice $recurring_invoice * @param RecurringInvoice $recurring_invoice
* *
*/ */
public function handleCancellation(RecurringInvoice $recurring_invoice) public function handleCancellation(RecurringInvoice $recurring_invoice)
{ {
@ -730,7 +729,7 @@ class SubscriptionService
->where('client_id', $recurring_invoice->client_id) ->where('client_id', $recurring_invoice->client_id)
->where('is_deleted', 0) ->where('is_deleted', 0)
->orderBy('id', 'desc') ->orderBy('id', 'desc')
->first(); ->first();
$invoice_start_date = Carbon::parse($outstanding_invoice->date); $invoice_start_date = Carbon::parse($outstanding_invoice->date);
$refund_end_date = $invoice_start_date->addSeconds($this->subscription->refund_period); $refund_end_date = $invoice_start_date->addSeconds($this->subscription->refund_period);
@ -807,15 +806,15 @@ class SubscriptionService
default: default:
return 0; return 0;
} }
} }
/** /**
* 'email' => $this->email ?? $this->contact->email, * 'email' => $this->email ?? $this->contact->email,
* 'quantity' => $this->quantity, * 'quantity' => $this->quantity,
* 'contact_id' => $this->contact->id, * 'contact_id' => $this->contact->id,
*/ */
public function handleNoPaymentRequired(array $data) public function handleNoPaymentRequired(array $data)
{ {
@ -827,7 +826,7 @@ class SubscriptionService
// Hit the redirect // Hit the redirect
return $this->handleRedirect($context['redirect_url']); return $this->handleRedirect($context['redirect_url']);
} }
/** /**
@ -840,5 +839,5 @@ class SubscriptionService
return redirect($this->subscription->webhook_configuration['return_url']); return redirect($this->subscription->webhook_configuration['return_url']);
return redirect($default_redirect); return redirect($default_redirect);
} }
} }

View File

@ -2,7 +2,7 @@
@section('meta_title', ctrans('texts.purchase')) @section('meta_title', ctrans('texts.purchase'))
@section('body') @section('body')
@livewire('billing-portal-purchase', ['subscription' => $subscription, 'contact' => auth('contact')->user(), 'hash' => $hash, 'request_data' => $request_data]) @livewire('billing-portal-purchase', ['subscription' => $subscription, 'contact' => auth('contact')->user(), 'hash' => $hash, 'request_data' => $request_data, 'campaign' => request()->query('campaign') ?? null])
@stop @stop
@push('footer') @push('footer')