| Server IP : 103.161.17.216 / Your IP : 216.73.216.1 Web Server : nginx/1.18.0 System : Linux tipsysaigoncharming 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 User : www-data ( 33) PHP Version : 7.4.3-4ubuntu2.29 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/app.houseland.info/application/controllers/ |
Upload File : |
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Subscription extends ClientsController
{
public function __construct()
{
parent::__construct();
$this->load->model('subscriptions_model');
$this->load->library('stripe_subscriptions');
$this->load->library('stripe_core');
}
public function index($hash = '')
{
$subscription = $this->subscriptions_model->get_by_hash($hash);
if (!$hash || !$subscription) {
show_404();
}
$language = load_client_language($subscription->clientid);
$data['locale'] = get_locale_key($language);
$data['publishableKey'] = $this->stripe_subscriptions->get_publishable_key();
$plan = $this->stripe_subscriptions->get_plan($subscription->stripe_plan_id);
check_stripe_subscription_environment($subscription);
if (!empty($subscription->stripe_subscription_id) && !empty($data['publishableKey'])) {
$data['stripeSubscription'] = $this->stripe_subscriptions->get_subscription([
'id' => $subscription->stripe_subscription_id,
'expand' => ['latest_invoice'],
]);
if ($this->input->get('complete')) {
redirect($data['stripeSubscription']->latest_invoice->hosted_invoice_url);
}
}
$upcomingInvoice = new stdClass();
$upcomingInvoice->default_tax_rates = null;
$upcomingInvoice->total = $plan->amount * $subscription->quantity;
$upcomingInvoice->subtotal = $upcomingInvoice->total;
$total = $upcomingInvoice->total;
if (!empty($subscription->tax_percent) || !empty($subscription->tax_percent_2)) {
$totalTax = 0;
$upcomingInvoice->default_tax_rates = [];
if (!empty($subscription->tax_percent)) {
$tax1 = new stdClass();
$tax1->percentage = $subscription->tax_percent;
$tax1->display_name = $subscription->tax_name;
$upcomingInvoice->default_tax_rates[] = $tax1;
$totalTax += $upcomingInvoice->total * ($subscription->tax_percent / 100);
}
if (!empty($subscription->tax_percent_2)) {
$tax2 = new stdClass();
$tax2->percentage = $subscription->tax_percent_2;
$tax2->display_name = $subscription->tax_name_2;
$upcomingInvoice->default_tax_rates[] = $tax2;
$totalTax += $upcomingInvoice->total * ($subscription->tax_percent_2 / 100);
}
$upcomingInvoice->total += $totalTax;
}
$data['total'] = $upcomingInvoice->total;
$product = $this->stripe_subscriptions->get_product($plan->product);
$upcomingInvoice->lines = new stdClass();
$upcomingInvoice->lines->data = [];
$upcomingInvoice->lines->data[] = [
'description' => $this->lineProductDescription($product, $plan, $subscription->currency_name),
'amount' => $plan->amount * $subscription->quantity,
'quantity' => $subscription->quantity,
];
$this->disableNavigation();
$this->disableSubMenu();
$data['child_invoices'] = $this->subscriptions_model->get_child_invoices($subscription->id);
$data['invoice'] = subscription_invoice_preview_data($subscription, $upcomingInvoice);
$this->app_scripts->theme('sticky-js', 'assets/plugins/sticky/sticky.js');
$data['plan'] = $plan;
$data['subscription'] = $subscription;
$data['title'] = $subscription->name;
$data['hash'] = $hash;
$data['bodyclass'] = 'subscriptionhtml';
$this->data($data);
$this->view('subscriptionhtml');
$this->layout();
}
public function subscribe($subscription_hash)
{
$subscription = $this->subscriptions_model->get_by_hash($subscription_hash);
if (!$subscription) {
show_404();
}
$stripe_customer_id = $subscription->stripe_customer_id;
$cancelUrl = site_url('subscription/' . $subscription_hash);
$customerExistsButWithoutPaymentMethod = false;
if (!empty($stripe_customer_id)) {
// Check if the stripe customer actually have default payment method
// Perhaps the stripe_id is saved via regular invoice payments where
// the payment method is not stored
$customer = $this->stripe_core->get_customer($stripe_customer_id);
if (!empty($customer->invoice_settings->default_payment_method)) {
$this->create_subscription($subscription, $stripe_customer_id);
} else {
$customerExistsButWithoutPaymentMethod = true;
}
}
$sessionData = [
'payment_method_types' => ['card'],
'mode' => 'setup',
'success_url' => site_url('subscription/complete_setup/' . $subscription->hash . '?session_id={CHECKOUT_SESSION_ID}'),
'cancel_url' => $cancelUrl,
'setup_intent_data' => [
'description' => $subscription->name,
],
];
if ($customerExistsButWithoutPaymentMethod) {
$sessionData['client_reference_id'] = $stripe_customer_id;
}
if (is_client_logged_in()) {
$contact = $this->clients_model->get_contact(get_contact_user_id());
if ($contact->email) {
$sessionData['customer_email'] = $contact->email;
}
}
$sessionData = hooks()->apply_filters('stripe_subscription_session_data', $sessionData, $subscription_hash);
try {
$session = $this->stripe_core->create_session($sessionData);
} catch (Exception $e) {
set_alert('warning', $e->getMessage());
redirect($cancelUrl);
}
redirect_to_stripe_checkout($session->id);
}
/**
* After collection payments for future subscriptions
*
* @return mixed
*/
public function complete_setup($hash)
{
$subscription = $this->subscriptions_model->get_by_hash($hash);
if (!$subscription) {
show_404();
}
try {
$session = $this->stripe_core->retrieve_session([
'id' => $this->input->get('session_id'),
'expand' => ['setup_intent.payment_method'],
]);
$payment_method = $session->setup_intent->payment_method;
$client = $this->clients_model->get($subscription->clientid);
$customerPayload = [
'email' => $payment_method->billing_details->email,
'name' => $payment_method->billing_details->name,
'description' => $subscription->company,
// https://stripe.com/docs/india-accept-international-payments
'address' => [
'line1' => $client->billing_street,
'postal_code' => $client->billing_zip,
'city' => $client->billing_zip,
'state' => $client->billing_state,
'country' => get_country($client->billing_country)->iso2 ?? null,
],
];
if ($session->client_reference_id) {
$customer = $this->stripe_core->get_customer($session->client_reference_id);
// Update the existing customer with the new provided email and name
// this can happen if customer previously paid only invoice and it was saved in database
// but without payment method, now becase above client_reference_id is passed
// so we can determine here the customer
$customer = $this->stripe_core->update_customer($session->client_reference_id, $customerPayload);
} else {
$customer = $this->stripe_subscriptions->create_customer($customerPayload);
}
$payment_method->attach(['customer' => $customer->id]);
$this->stripe_core->update_customer($customer->id, [
'invoice_settings' => [
'default_payment_method' => $payment_method->id,
],
]);
$this->create_subscription($subscription, $customer->id);
} catch (Exception $e) {
set_alert('warning', $e->getMessage());
}
redirect(site_url('subscription/' . $hash));
}
protected function create_subscription($subscription, $customer_id)
{
try {
$params = [];
if (!empty($subscription->stripe_tax_id) || !empty($subscription->stripe_tax_id_2)) {
$params['default_tax_rates'] = [];
if (!empty($subscription->stripe_tax_id)) {
$params['default_tax_rates'][] = $subscription->stripe_tax_id;
}
if (!empty($subscription->stripe_tax_id_2)) {
$params['default_tax_rates'][] = $subscription->stripe_tax_id_2;
}
}
$params['metadata'] = [
'pcrm-subscription-hash' => $subscription->hash,
// Indicated the the customer was on session,
// see requires action event
'customer-on-session' => true,
];
$params['items'] = [
[
'plan' => $subscription->stripe_plan_id,
],
];
$params['expand'] = ['latest_invoice.payment_intent'];
if (!empty($subscription->date)) {
if ($subscription->date > date('Y-m-d')) {
// is future
$params['billing_cycle_anchor'] = strtotime($subscription->date);
// https://stripe.com/docs/billing/subscriptions/billing-cycle#new-subscriptions
$params['prorate'] = false;
}
}
$params['off_session'] = true;
if ($subscription->quantity > 1) {
$params['items'][0]['quantity'] = $subscription->quantity;
}
$stripeSubscription = $this->stripe_subscriptions->subscribe($customer_id, $params);
// https://stripe.com/docs/billing/subscriptions/payment#signup-3b
if ($stripeSubscription->status === 'incomplete') {
if ($stripeSubscription->latest_invoice->payment_intent->status === 'requires_action') {
$this->subscriptions_model->update($subscription->id, [
'status' => $stripeSubscription->status,
'stripe_subscription_id' => $stripeSubscription->id,
]);
redirect($stripeSubscription->latest_invoice->hosted_invoice_url);
}
} elseif ($stripeSubscription->status === 'active') {
// In case the webhook is slower, update the stripe_subscription_id so the user won't see
// the subscribe button again
$this->subscriptions_model->update($subscription->id, ['stripe_subscription_id' => $stripeSubscription->id]);
set_alert('success', _l('customer_successfully_subscribed_to_subscription', $subscription->name));
}
} catch (Exception $e) {
set_alert('warning', $e->getMessage());
}
redirect(site_url('subscription/' . $subscription->hash));
}
/**
* After stripe checkout succcess
* Used only to display success message to the customer
*
* @param string $invoice_id The invoice id the payment is made to
* @param strgin $invoice_hash invoice hash
*
* @return mixed
*/
public function success($hash)
{
$subscription = $this->subscriptions_model->get_by_hash($hash);
set_alert('success', _l('customer_successfully_subscribed_to_subscription', $subscription->name));
send_email_customer_subscribed_to_subscription_to_staff($subscription);
redirect(site_url('subscription/' . $hash));
}
protected function lineProductDescription($product, $plan, $currency)
{
$intervals = ['day', 'week', 'month', 'year'];
$interval = $plan->interval;
foreach ($intervals as $stripeInterval) {
if ($plan->interval === $stripeInterval && $plan->interval_count === 1) {
$interval = _l($stripeInterval);
} elseif ($plan->interval === $stripeInterval && $plan->interval_count > 1) {
$interval = _l('frequency_every', $plan->interval_count . ' ' . _l($stripeInterval . 's'));
}
}
$productName = (!empty($plan->nickname) ? $plan->nickname : $product->name);
return $productName . ' (' . app_format_money(strcasecmp($plan->currency, 'JPY') == 0 ?
$plan->amount :
$plan->amount / 100, strtoupper($currency)) . ' / ' . $interval . ')';
}
}