function Callback_confirm_recur($client_id, $gateway, $subscription, $params) { $CI =& get_instance(); // retrieve charge data $CI->load->model('charge_data_model'); $data = $CI->charge_data_model->Get('r' . $subscription['id']); // this gets complex below, so we'll track the general success of this process // with a simple boolean variable $process_status = FALSE; $url = $this->GetAPIUrl($gateway); // regardless of it's a single or recurring charge at PayPal, we need to retrieve the token $post = array(); $post['method'] = 'GetExpressCheckoutDetails'; $post['token'] = $params['token']; $post['version'] = '95.0'; $post['user'] = $gateway['user']; $post['pwd'] = $gateway['pwd']; $post['signature'] = $gateway['signature']; $response = $this->Process($url, $post); if ($this->debug) { $this->log_it('PayPal Express Callback Confirm Recur Params: ', $post); $this->log_it('PayPal Express Charge Callback Confirm Response: ', $response); } if (isset($response['TOKEN']) and $response['TOKEN'] == $params['token']) { // tokens match. this is a legitimate PayPal request // do we need a first charge? if (date('Y-m-d', strtotime($subscription['start_date'])) == date('Y-m-d', strtotime($subscription['date_created']))) { $CI->load->model('charge_model'); // get the first charge amount (it may be different) $first_charge_amount = isset($data['first_charge']) ? $data['first_charge'] : $subscription['amount']; $first_charge_amount = (double) $first_charge_amount; if (!empty($first_charge_amount)) { $customer_id = isset($subscription['customer']['id']) ? $subscription['customer']['id'] : FALSE; $order_id = $CI->charge_model->CreateNewOrder($client_id, $gateway['gateway_id'], $first_charge_amount, array(), $subscription['id'], $customer_id); // yes, the first charge is today $post = $response; // most of the data is from here unset($post['NOTE']); $post['METHOD'] = 'DoExpressCheckoutPayment'; $post['TOKEN'] = $response['TOKEN']; $post['PAYMENTACTION'] = 'Sale'; $post['version'] = '95.0'; $post['user'] = $gateway['user']; $post['pwd'] = $gateway['pwd']; $post['signature'] = $gateway['signature']; $response_charge = $this->Process($url, $post); if ($this->debug) { $this->log_it('PayPal Express Callback Confirm Recur - First Charge Params: ', $post); $this->log_it('PayPal Express Callback Confirm Recur - First Charge Response: ', $response_charge); } if (!isset($response_charge) or $response_charge['PAYMENTINFO_0_PAYMENTSTATUS'] != 'Completed' and $response_charge['PAYMENTINFO_0_PAYMENTSTATUS'] != 'Pending' and $response_charge['PAYMENTINFO_0_PAYMENTSTATUS'] != 'Processed') { die('Your initial PayPal payment failed. <a href="' . $data['cancel_url'] . '">Go back to merchant</a>.'); } else { // create today's order // we assume it's good because the profile is OK $CI->load->model('order_authorization_model'); // we may not have the transaction ID if it's Pending $response_charge['PAYMENTINFO_0_TRANSACTIONID'] = isset($response_charge['PAYMENTINFO_0_TRANSACTIONID']) ? $response_charge['PAYMENTINFO_0_TRANSACTIONID'] : 'pending_payment'; $CI->order_authorization_model->SaveAuthorization($order_id, $response_charge['PAYMENTINFO_0_TRANSACTIONID']); $CI->charge_model->SetStatus($order_id, 1); } // we'll also adjust the profile start date $adjusted_start_date = TRUE; $subscription['start_date'] = date('Y-m-d', strtotime($subscription['start_date']) + 60 * 60 * 24 * $subscription['interval']); } } // if this was sent to PayPal as a recurring payment, we'll create the profile here if ($data['paypal_charge_type'] == 'subscription') { // continue with creating payment profile $post = $response; // most of the data is from here unset($post['NOTE']); // If we're keeping charges on the same day every month, // we need to calculate the proper interval, but only // if the interval is evenly divided by 30 if ($this->same_day_every_month === true && $subscription['interval'] % 30 === 0) { $interval = $subscription['interval'] / 30; } else { $interval = $subscription['interval']; } $post['METHOD'] = 'CreateRecurringPaymentsProfile'; $post['VERSION'] = '95.0'; $post['user'] = $gateway['user']; $post['pwd'] = $gateway['pwd']; $post['signature'] = $gateway['signature']; $post['TOKEN'] = $response['TOKEN']; $post['DESC'] = $data['profile_description']; $post['PROFILESTARTDATE'] = date('c', strtotime($subscription['start_date'])); $post['BILLINGPERIOD'] = $this->same_day_every_month === true ? 'Month' : 'Day'; $post['BILLINGFREQUENCY'] = $interval; $post['AMT'] = $subscription['amount']; $response_sub = $this->Process($url, $post); if ($this->debug) { $this->log_it('PayPal Express Create Payment Profile Params: ', $post); $this->log_it('PayPal Express Create Payment Profile Response: ', $response_sub); } if (isset($response_sub['PROFILEID'])) { // success! $CI->recurring_model->SaveApiCustomerReference($subscription['id'], $response_sub['PROFILEID']); $process_status = TRUE; } } else { // we know we are good because the first charge was executed before and, if it failed // we'd have die()'d above $process_status = TRUE; } if ($process_status === TRUE) { // success! $order_id = isset($order_id) ? $order_id : FALSE; $CI->recurring_model->SetActive($client_id, $subscription['id']); // Update the end_date if necessary due to same_day_every_month if ($this->same_day_every_month == true && $subscription['interval'] % 30 === 0) { $end_date = strtotime('+' . $subscription['number_occurrences'] . ' month'); $CI->db->where('subscription_id', $subscription['id']); $CI->db->update('subscriptions', array('end_date' => date('Y-m-d', $end_date))); } // trip it - were golden! TriggerTrip('new_recurring', $client_id, $order_id, $subscription['id']); // trip a recurring charge? if ($order_id) { TriggerTrip('recurring_charge', $client_id, $order_id, $subscription['id']); } if (!empty($coupon_id)) { // track coupon $CI->load->model('coupon_model'); $CI->coupon_model->add_usage($coupon_id, $subscription_id, $order_id, $customer_id); } // redirect back to user's site header('Location: ' . $data['return_url']); die; } else { die('Error completing payment (subscription profile error).'); } } }
function SubscriptionMaintenance($key) { if ($this->config->item('cron_key') != $key) { echo 'Invalid key.'; if ($this->debug) { $this->log_it('Invalid Key for SubscriptionMaintenance cronjob: ' . $key); } return FALSE; } if ($this->debug) { $this->log_it('Starting SubscriptionMaintenance Cron'); } $this->load->model('recurring_model'); $this->load->model('gateway_model'); $this->load->library('email'); // Run PayPal fixes if ($this->run_paypal_fix()) { $this->load->library('paypal_fix'); $this->paypal_fix->run_fix(); $this->db->update('version', array('paypal_fix_ran' => date('Y-m-d H:i:s'))); } // Expire subscription if the end date is today or before $cancelled = array(); $subscriptions = $this->recurring_model->GetAllSubscriptionsForExpiring(); if ($subscriptions) { foreach ($subscriptions as $subscription) { // cancel the subscription $response = $this->recurring_model->CancelRecurring($subscription['client_id'], $subscription['subscription_id'], TRUE); if ($response) { $trip_trigger = TRUE; if (!empty($subscription['renewed'])) { // let's verify this subscription is active $renewing_sub = $this->recurring_model->GetSubscriptionDetails($subscription['client_id'], $subscription['renewed']); if ($renewing_sub['active'] == '1') { $trip_trigger = FALSE; } } if ($trip_trigger == TRUE) { // not being renewed, send expiration notice TriggerTrip('recurring_expire', $subscription['client_id'], FALSE, $subscription['subscription_id']); } $cancelled[] = $subscription['subscription_id']; } } } // get all the subscriptions with a next_charge date of today for the next charge $today = date('Y-m-d'); $subscriptions = $this->recurring_model->GetAllSubscriptionsForCharging($today); $charge_success = array(); $charge_failure = array(); if ($subscriptions) { foreach ($subscriptions as $subscription) { // Try and make the charge $response = $this->gateway_model->ChargeRecurring($subscription['client_id'], $subscription); if ($response) { $charge_success[] = $subscription['subscription_id']; } else { $charge_failure[] = $subscription['subscription_id']; } } } // Check for emails to send // Get all the recurring charge emails to send in one week $sent_emails['recurring_autorecur_in_week'] = array(); $next_week = mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')); $charges = $this->recurring_model->GetChargesByDate($next_week); if ($charges) { foreach ($charges as $charge) { if (TriggerTrip('recurring_autorecur_in_week', $charge['client_id'], false, $charge['subscription_id'])) { $sent_emails['recurring_autorecur_in_week'][] = $charge['subscription_id']; } } } // Get all the recurring charge emails to send in one month $sent_emails['recurring_autorecur_in_month'] = array(); $next_month = mktime(0, 0, 0, date('m') + 1, date('d'), date('Y')); $charges = $this->recurring_model->GetChargesByDate($next_month); if ($charges) { foreach ($charges as $charge) { if (TriggerTrip('recurring_autorecur_in_month', $charge['client_id'], false, $charge['subscription_id'])) { $sent_emails['recurring_autorecur_in_month'][] = $charge['subscription_id']; } } } // Get all the recurring expiration emails to send in one week $sent_emails['recurring_expiring_in_week'] = array(); $charges = $this->recurring_model->GetChargesByExpiryDate($next_week); if ($charges) { foreach ($charges as $charge) { $trip_trigger = TRUE; if (!empty($charge['renewed'])) { // let's verify this subscription is active $renewing_sub = $this->recurring_model->GetSubscriptionDetails($charge['client_id'], $charge['renewed']); if ($renewing_sub['active'] == '1') { $trip_trigger = FALSE; } } if ($trip_trigger == TRUE) { if (TriggerTrip('recurring_expiring_in_week', $charge['client_id'], false, $charge['subscription_id'])) { $sent_emails['recurring_expiring_in_week'][] = $charge['subscription_id']; } } } } // Get all the recurring expiration emails to send in one month $sent_emails['recurring_expiring_in_month'] = array(); $charges = $this->recurring_model->GetChargesByExpiryDate($next_month); if ($charges) { foreach ($charges as $charge) { $trip_trigger = TRUE; if (!empty($charge['renewed'])) { // let's verify this subscription is active $renewing_sub = $this->recurring_model->GetSubscriptionDetails($charge['client_id'], $charge['renewed']); if ($renewing_sub['active'] == '1') { $trip_trigger = FALSE; } } if ($trip_trigger == TRUE) { if (TriggerTrip('recurring_expiring_in_month', $charge['client_id'], false, $charge['subscription_id'])) { $sent_emails['recurring_expiring_in_month'][] = $charge['subscription_id']; } } } } $charge_success = count($charge_success); $charge_failure = count($charge_failure); $cancelled = count($cancelled); $autorecur_week = count($sent_emails['recurring_autorecur_in_week']); $autorecur_month = count($sent_emails['recurring_autorecur_in_month']); $expire_week = count($sent_emails['recurring_expiring_in_week']); $expire_month = count($sent_emails['recurring_expiring_in_month']); $response = $charge_success . " Successful Charges. \n"; $response .= $charge_failure . " Failed Charges. \n"; $response .= $cancelled . " Expired Subscriptions. \n"; $response .= $autorecur_week . " Weekly Charge Reminders Sent. \n"; $response .= $autorecur_month . " Monthly Charge Reminders Sent. \n"; $response .= $expire_week . " Weekly Expiration Reminders Sent. \n"; $response .= $expire_month . " Monthly Expiration Reminders Sent. \n"; echo $response; $this->save_cron_date($key, 'cron_last_run_subs'); if ($this->debug) { $this->log_it('Finished SubscriptionMaintenance Cron'); } die; }
function Callback_confirm_recur($client_id, $gateway, $subscription, $params) { $CI =& get_instance(); $CI->load->model('charge_data_model'); $data = $CI->charge_data_model->Get('r' . $subscription['id']); $url = $this->GetAPIUrl($gateway); $order_id = $CI->charge_model->CreateNewOrder($client_id, $gateway['gateway_id'], $subscription['amount'], array(), $subscription['id'], $customer_id); $CI->load->model('order_authorization_model'); $CI->order_authorization_model->SaveAuthorization($order_id, 'n/a'); $CI->charge_model->SetStatus($order_id, 1); $CI->recurring_model->SetActive($client_id, $subscription['id']); // trip it - were golden! TriggerTrip('new_recurring', $client_id, $order_id, $subscription['id']); TriggerTrip('recurring_charge', $client_id, $order_id, $subscription['id']); // redirect back to user's site header('Location: ' . $data['return_url']); die; }
public function Callback_recurring_installment_stopped($client_id, $gateway, $subscription, $params) { // Mark the subscription as inactive $this->CI->load->model('recurring_model'); $this->CI->recurring_model->MakeInactive($subscription['id']); $this->CI->recurring_model->CancelRecurring($client_id, $subscription['id'], TRUE); TriggerTrip('recurring_fail', $client_id, FALSE, $subscription['id']); }
function SaveNewCustomer($client_id, $first_name, $last_name, $company = '', $internal_id = '', $address_1 = '', $address_2 = '', $city = '', $state = '', $postal_code = '', $country_id = '', $phone = '', $email = '') { $insert_data = array('client_id' => $client_id, 'first_name' => $first_name, 'last_name' => $last_name, 'company' => $company, 'internal_id' => $internal_id, 'address_1' => $address_1, 'address_2' => $address_2, 'city' => $city, 'state' => $state, 'postal_code' => $postal_code, 'country' => $country_id, 'phone' => $phone, 'email' => $email, 'active' => '1', 'date_created' => date('Y-m-d, H:i:s')); $this->db->insert('customers', $insert_data); $customer_id = $this->db->insert_id(); TriggerTrip('new_customer', $client_id, false, false, $customer_id); return $customer_id; }
/** * Process a credit card recurring charge * * Processes a credit card CHARGE transaction for a recurring subscription using the gateway_id to use the proper client gateway. * Returns an array response from the appropriate payment library. * * The gateway may return a 'next_charge' == YYYY-MM-DD in their response array, thus specifying the date of the next charge * and not relying on OG's date calculator. * * @param int $client_id The Client ID * @param array $params The subscription array, from GetSubscription, for the recurring charge * * @return mixed Array with response_code and response_text */ function ChargeRecurring($client_id, $params) { $CI =& get_instance(); $gateway_id = $params['gateway_id']; // Get the gateway info to load the proper library $gateway = $this->GetGatewayDetails($client_id, $gateway_id); if (!$gateway or $gateway['enabled'] == '0') { return FALSE; } // get the credit card last four digits $params['credit_card'] = array(); $params['credit_card']['card_num'] = $params['card_last_four']; // Create a new order $CI->load->model('charge_model'); $order_id = $CI->charge_model->CreateNewOrder($client_id, $params['gateway_id'], $params['amount'], $params['credit_card'], $params['subscription_id'], $params['customer_id']); if ($params['amount'] > 0) { // Load the proper library $gateway_name = $gateway['name']; $this->load->library('payment/' . $gateway_name); // send to gateway for charging // gateway responds with: // success as TRUE or FALSE // reason (error if success == FALSE) // next_charge (if standard next_charge won't apply) $response = $this->{$gateway_name}->AutoRecurringCharge($client_id, $order_id, $gateway, $params); } else { $response = array(); $response['success'] = TRUE; } $CI->load->model('recurring_model'); if ($response['success'] == TRUE) { // save the last_charge and next_charge $last_charge = date('Y-m-d'); if (!isset($response['next_charge'])) { $next_charge = $CI->recurring_model->GetNextChargeDate($params['subscription_id'], $params['next_charge']); } else { $next_charge = $response['next_charge']; } $CI->recurring_model->SetChargeDates($params['subscription_id'], $last_charge, $next_charge); $CI->charge_model->SetStatus($order_id, 1); TriggerTrip('recurring_charge', $client_id, $order_id, $params['subscription_id']); } else { $response = FALSE; // Check the number of failures allowed $num_allowed = $this->config->item('recurring_charge_failures_allowed'); $failures = $params['number_charge_failures']; $CI->charge_model->SetStatus($order_id, 0); $failures++; $CI->recurring_model->AddFailure($params['subscription_id'], $failures); if ($failures >= $num_allowed) { $CI->recurring_model->CancelRecurring($client_id, $params['subscription_id'], TRUE); TriggerTrip('recurring_fail', $client_id, FALSE, $params['subscription_id']); } } return $response; }
function CancelRecurring($client_id, $recurring_id, $not_user_cancellation = FALSE) { // Get the subscription information $subscription = $this->GetSubscriptionDetails($client_id, $recurring_id); // Get the gateway info to load the proper library $CI =& get_instance(); $CI->load->model('gateway_model'); $gateway = $CI->gateway_model->GetGatewayDetails($client_id, $subscription['gateway_id']); if ((double) $subscription['amount'] > 0) { $gateway_name = $subscription['name']; $this->load->library('payment/' . $gateway_name); $cancelled = $this->{$gateway_name}->CancelRecurring($client_id, $subscription, $gateway); } else { $cancelled = TRUE; } $this->MakeInactive($recurring_id); if ($not_user_cancellation == FALSE) { TriggerTrip('recurring_cancel', $client_id, FALSE, $recurring_id); } if ($cancelled) { return TRUE; } else { return FALSE; } }
public function Callback_confirm($client_id, $gateway, $charge, $params) { $post = array('MD' => $params['MD'], 'PARes' => $params['PaRes']); $post_url = $this->GetAPIUrl($gateway, '3d'); $response = $this->Process($charge['id'], $post_url, $post); $VPSTxId = isset($response['VPSTxId']) ? $response['VPSTxId'] : false; $TxAuthNo = isset($response['TxAuthNo']) ? $response['TxAuthNo'] : false; $SecurityKey = isset($response['SecurityKey']) ? $response['SecurityKey'] : false; $this->ci->load->model('charge_data_model'); $data = $this->ci->charge_data_model->Get($charge['id']); if ($this->debug) { $this->log_it('Callback_confirm data', $data); $this->log_it('Callback_confirm charge', $charge); $this->log_it('Callback_confirm Params', $params); $this->log_it('Callback_Confirm Response', $response); } // A successful transaction if ($response['Status'] == 'OK' || $response['Status'] == 'AUTHENTICATED' && $response['3DSecureStatus'] == 'OK') { /* Recurring Charge */ if (isset($charge['type']) && $charge['type'] == 'recurring_charge' || isset($charge['type']) && $charge['type'] == 'recurring_repeat') { // Do we have a recurring id passed in the $charge var? $subscription_id = $charge['recurring_id']; // We need to find our subscription id by backtracing based // on the charge id. $query = $this->ci->db->where('order_data_value', $charge['id'])->get('order_data'); if (isset($subscription_id) || $query->num_rows() > 0) { if (empty($subscription_id)) { $subscription_id = str_replace('r', '', $query->row()->order_id); } $this->ci->charge_model->SetStatus($charge['id'], 1); // Since we didn't get to save these for REPEATS earlier, we'll save them now // these authorizations were saved during $this->Process() $this->ci->load->model('recurring_model'); $this->ci->recurring_model->SaveApiCustomerReference($subscription_id, $VPSTxId); $this->ci->recurring_model->SaveApiPaymentReference($subscription_id, $charge['id'] . '|' . $TxAuthNo); $this->ci->recurring_model->SaveApiAuthNumber($subscription_id, $SecurityKey); // Set the subscription to active $this->ci->load->model('recurring_model'); $this->ci->recurring_model->SetActive($client_id, $subscription_id); $response_array = array('charge_id' => $charge['id'], 'recurring_id' => $subscription_id); $response = $this->ci->response->TransactionResponse(100, $response_array); } } /* Single Charge */ // save authorization (transaction id #) $this->ci->load->model('order_authorization_model'); $this->ci->order_authorization_model->SaveAuthorization($charge['id'], $VPSTxId, $TxAuthNo); $this->ci->charge_model->SetStatus($charge['id'], 1); TriggerTrip('charge', $client_id, $charge['id']); // Save our SecurityKey so that we can do refunds... if (isset($SecurityKey) && !empty($SecurityKey)) { $this->ci->charge_data_model->Save($charge['id'], 'token', $params['Token']); } $coupon_id = (isset($charge['coupon']) and isset($charge['coupon']['coupon_id'])) ? $charge['coupon']['coupon_id'] : null; if (!empty($coupon_id)) { // track coupon $this->ci->load->model('coupon_model'); $this->ci->coupon_model->add_usage($coupon_id, FALSE, $charge['id'], $customer_id); } // redirect back to user's site header('Location: ' . $data['return_url']); die; } else { $this->ci->load->model('charge_model'); $this->ci->charge_model->SetStatus($charge['id'], 0); // Make sure to show an error here since we won't know anywhere else. $this->ci->load->library('session'); $this->ci->load->model('cp/notices'); $this->ci->notices->SetError('Charge failed: ' . $response['StatusDetail']); // redirect back to user's site header('Location: ' . $data['cancel_url']); die; } }
/** * Record Subscription Payment * * This is a hidden API call used for Membrr to record payments for subscriptions manually * when extending an expiry date. * * @param int $recurring_id * @param string $amount * * @return int $charge_id */ function RecordSubscriptionpayment($client_id, $params) { if (!isset($params['recurring_id']) or !isset($params['amount'])) { die($this->response->Error(1004)); } $this->load->model('recurring_model'); $subscription = $this->recurring_model->GetRecurring($client_id, $params['recurring_id']); // get gateway_id from previous subscription payments, else make it 0 $result = $this->db->select('gateway_id')->where('subscription_id', $params['recurring_id'])->limit(1)->get('subscriptions'); if ($result->num_rows() > 0) { $gateway_id = $result->row()->gateway_id; } else { $gateway_id = 0; } // record payment $this->load->model('charge_model'); $charge_id = $this->charge_model->CreateNewOrder($client_id, $gateway_id, (double) $params['amount'], FALSE, $subscription['id'], $subscription['customer']['id']); if (empty($charge_id)) { return array('error' => 'Unable to create order.'); } else { $this->charge_model->SetStatus($charge_id, 1); TriggerTrip('recurring_charge', $client_id, $charge_id, $subscription['id']); // extend next_charge and end_date $start = $subscription['next_charge_date']; $next_charge = date('Y-m-d', strtotime($start . ' + ' . $subscription['interval'] . ' days')); // if the end_date is less than the next charge date, we'll push it back 2 intervals if (strtotime($subscription['end_date']) < strtotime($next_charge)) { $end_date = date('Y-m-d', strtotime($start . ' + ' . $subscription['interval'] * 2 . ' days')); } else { $end_date = date('Y-m-d', strtotime($subscription['end_date'])); } $update = array('next_charge' => $next_charge, 'end_date' => $end_date); // update locally $this->db->update('subscriptions', array('next_charge' => $next_charge, 'end_date' => $end_date), array('subscription_id' => $subscription['id'])); // return return array('charge_id' => $charge_id, 'next_charge' => $next_charge, 'end_date' => $end_date); } }