/** * Subscribe * * This is the heart of the Membrr engine, an essentially a wrapper for OpenGateway's Recur API Call. * * @param int $plan_id * @param int $member_id * @param array $credit_card * @param array $customer * @param string/boolean $end_date * @param float/boolean $first_charge * @param float/boolean $recurring_charge * @param string/boolean $cancel_url * @param string/boolean $return_url * @param int/boolean $gateway_id * @param int/boolean $renew_subscription * @param string $coupon * * @return array Response from OpenGateway */ function Subscribe($plan_id, $member_id, $credit_card, $customer, $end_date = FALSE, $first_charge = FALSE, $recurring_charge = FALSE, $cancel_url = '', $return_url = '', $gateway_id = FALSE, $renew_subscription = FALSE, $coupon = FALSE) { $plan = $this->GetPlan($plan_id); // calculate initial charge if ($plan['initial_charge'] != $plan['price'] and $first_charge === FALSE) { $first_charge = $plan['initial_charge']; } $config = $this->GetConfig(); if (!class_exists('Opengateway')) { require dirname(__FILE__) . '/opengateway.php'; } $connect_url = $config['api_url'] . '/api'; $recur = new Recur(); $recur->Authenticate($config['api_id'], $config['secret_key'], $connect_url); // use existing customer_id if we can $opengateway = new OpenGateway(); $opengateway->Authenticate($config['api_id'], $config['secret_key'], $connect_url); $opengateway->SetMethod('GetCustomers'); $opengateway->Param('internal_id', $member_id); $response = $opengateway->Process(); if ($response['total_results'] > 0) { // there is already a customer record here $customer = !isset($response['customers']['customer'][0]) ? $response['customers']['customer'] : $response['customers']['customer'][0]; $recur->UseCustomer($customer['id']); } else { // no customer records, yet $recur->Param('internal_id', $member_id, 'customer'); // let's try to auto-generate a name based if there isn't one there if (empty($customer['first_name']) and empty($customer['last_name'])) { // do we have a credit card name to generate from? if (isset($credit_card['name']) and !empty($credit_card['name'])) { $names = explode(' ', $credit_card['name']); $customer['first_name'] = $names[0]; $customer['last_name'] = end($names); } } $recur->Customer($customer['first_name'], $customer['last_name'], $customer['company'], $customer['address'], $customer['address_2'], $customer['city'], $customer['region'], $customer['country'], $customer['postal_code'], $customer['phone'], $customer['email']); } // coupon? if ($coupon != FALSE) { // may be using PayPal, so we should store this $this->EE->functions->set_cookie('membrr_coupon', $coupon, 86400); $recur->Coupon($coupon); } // end date? if ($end_date != FALSE) { $recur->Param('end_date', $end_date, 'recur'); } // if different first charge? if ($first_charge !== FALSE) { $recur->Amount($first_charge); } else { $recur->Amount($plan['price']); } // if different recurring rate? if ($recurring_charge != FALSE) { $recur->Param('amount', $recurring_charge, 'recur'); } // are we renewing an existing subscription? if (!empty($renew_subscription)) { // is sub active? $old_sub = $this->GetSubscription($renew_subscription); if ($old_sub['active'] == '1') { $recur->Param('renew', $renew_subscription); if ($plan['renewal_extend_from_end'] === TRUE) { // we will delay the start of the new subscription until the end of this one $old_sub = $this->GetSubscription($renew_subscription); // calculate real end date $old_end_date = $this->_calculate_end_date($old_sub['end_date'], $old_sub['next_charge_date'], $old_sub['date_created']); // convert to timestamp for calcs $old_end_date = strtotime($old_end_date); // postpone the start date of this new subscription from that end_date $difference_in_days = ($old_end_date - time()) / (60 * 60 * 24); $recur->Param('start_date', date('Y-m-d', $old_end_date), 'recur'); $plan['free_trial'] = $difference_in_days; } else { // this plan will cancel immediately // let's make CancelSubscription do this $this->EE->db->update('exp_membrr_subscriptions', array('next_charge_date' => '0000-00-00', 'end_date' => date('Y-m-d H:i:s')), array('recurring_id' => $old_sub['id'])); } } } $recur->UsePlan($plan['api_id']); $security = empty($credit_card['security_code']) ? FALSE : $credit_card['security_code']; if ($credit_card and !empty($credit_card) and isset($credit_card['number']) and !empty($credit_card['number'])) { $recur->CreditCard($credit_card['name'], $credit_card['number'], $credit_card['expiry_month'], $credit_card['expiry_year'], $security); } // specify the gateway? // from arguments first: if (!empty($gateway_id)) { $recur->Param('gateway_id', $gateway_id); } elseif (!empty($plan['gateway'])) { $recur->Param('gateway_id', $plan['gateway']); } elseif (!empty($config['gateway'])) { $recur->Param('gateway_id', $config['gateway']); } // add IP address to request // get true IP if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $current_ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $current_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $current_ip = $_SERVER['REMOTE_ADDR']; } $recur->Param('customer_ip_address', $current_ip); // if they are using PayPal, we need the following parameters if (empty($return_url)) { $this->EE->db->select('action_id'); $this->EE->db->where('class', 'Membrr'); $this->EE->db->where('method', 'post_notify'); $result = $this->EE->db->get('exp_actions'); $action_id = $result->row_array(); $action_id = $action_id['action_id']; $return_url = $this->EE->functions->create_url('?ACT=' . $action_id . '&member=' . $member_id . '&plan_id=' . $plan_id, 0); // if we are renewing, we will append this to the $return_url so that we can cancel old subscriptions // and update channel entries to the new recurring_id for external gateways like PayPal EC if (!empty($renew_subscription)) { $return_url .= '&renew_recurring_id=' . $renew_subscription; } // sometimes, with query strings, we get index.php?/?ACT=26... $return_url = str_replace('?/?', '?', $return_url); } $recur->Param('return_url', htmlspecialchars($return_url)); if (empty($cancel_url)) { $cancel_url = $this->EE->functions->fetch_current_uri(); } $recur->Param('cancel_url', htmlspecialchars($cancel_url)); // call "membrr_pre_subscribe" hook with: $recur, $member_id, $plan_id, $recurring_charge, $first_charge, $end_date if ($this->EE->extensions->active_hook('membrr_pre_subscribe') == TRUE) { $this->EE->extensions->call('membrr_pre_subscribe', $recur, $member_id, $plan_id, $recurring_charge, $first_charge, $end_date); if ($this->EE->extensions->end_script === TRUE) { return FALSE; } } $response = $recur->Charge(); if (isset($response['response_code']) and $response['response_code'] == '100') { // success! // calculate payment amount $recur_payment = $response['recur_amount']; $payment = $response['amount']; $free_trial = $response['free_trial']; $start_date = $response['start_date']; // calculate end date if ($end_date != FALSE) { // we must also account for their signup time $time_created = date('H:i:s'); $end_date = date('Y-m-d', strtotime($end_date)) . ' ' . $time_created; } elseif ($end_date == FALSE) { if ($plan['occurrences'] == '0') { // unlimited occurrences $end_date = '0000-00-00 00:00:00'; } else { $time_to_calculate_end = time(); if (!empty($renew_subscription)) { $subscription = $this->GetSubscription($renew_subscription); $old_end_date = $this->_calculate_end_date($subscription['end_date'], $subscription['next_charge_date'], $subscription['date_created']); $time_to_calculate_end = strtotime($old_end_date); // we don't want to take on the end dates from previously expired subscriptions if ($time_to_calculate_end < time()) { $time_to_calculate_end = time(); } } $end_date = date('Y-m-d H:i:s', $time_to_calculate_end + $free_trial * 86400 + $plan['occurrences'] * $plan['interval'] * 86400); } } // calculate next charge date if (!empty($free_trial)) { $next_charge_date = time() + $free_trial * 86400; } elseif (!empty($start_date) and strtotime($start_date) > time() + 84600) { $next_charge_date = strtotime($start_date); } else { if ($this->same_day_every_month == TRUE and $plan['interval'] % 30 === 0) { $months = $plan['interval'] / 30; $plural = $months > 1 ? 's' : ''; $next_charge_date = strtotime('today + ' . $months . ' month' . $plural); } else { $next_charge_date = strtotime('today + ' . $plan['interval'] . ' days'); } } if ((date('Y-m-d', $next_charge_date) == date('Y-m-d', strtotime($end_date)) or $next_charge_date > strtotime($end_date)) and $end_date != '0000-00-00 00:00:00') { $next_charge_date = '0000-00-00'; } else { $next_charge_date = date('Y-m-d', $next_charge_date); } $this->RecordSubscription($response['recurring_id'], $member_id, $plan_id, $next_charge_date, $end_date, $recur_payment, $coupon, $credit_card); if (empty($free_trial) and isset($response['charge_id'])) { // create payment record $this->RecordPayment($response['recurring_id'], $response['charge_id'], $payment); } // perform renewing subscription maintenance if (!empty($renew_subscription)) { $this->RenewalMaintenance($renew_subscription, $response['recurring_id']); } } return $response; }
/** * Post Charge */ function post() { $this->load->library('opengateway'); if ($this->input->post('recurring') == '0') { $charge = new Charge(); } else { $charge = new Recur(); } $api_url = site_url('api'); $api_url = $this->config->item('ssl_active') == TRUE ? str_replace('http://', 'https://', $api_url) : $api_url; $charge->Authenticate($this->user->Get('api_id'), $this->user->Get('secret_key'), site_url('api')); $charge->Amount($this->input->post('amount')); // coupon if ($this->input->post('coupon')) { $charge->Coupon($this->input->post('coupon')); } if ($this->input->post('cc_number')) { $charge->CreditCard($this->input->post('cc_name'), $this->input->post('cc_number'), $this->input->post('cc_expiry_month'), $this->input->post('cc_expiry_year'), $this->input->post('cc_security')); } if ($this->input->post('recurring') == '1') { $charge->UsePlan($this->input->post('recurring_plan')); } elseif ($this->input->post('recurring') == '2') { $free_trial = $this->input->post('free_trial'); $free_trial = empty($free_trial) ? FALSE : $free_trial; $occurrences = $this->input->post('recurring_end') == 'occurrences' ? $this->input->post('occurrences') : FALSE; $start_date = $this->input->post('start_date_year') . '-' . $this->input->post('start_date_month') . '-' . $this->input->post('start_date_day'); $end_date = $this->input->post('end_date_year') . '-' . $this->input->post('end_date_month') . '-' . $this->input->post('end_date_day'); $end_date = $this->input->post('recurring_end') == 'date' ? $end_date : FALSE; $charge->Schedule($this->input->post('interval'), $free_trial, $occurrences, $start_date, $end_date); } if ($this->input->post('customer_id') != '') { $charge->UseCustomer($this->input->post('customer_id')); } else { $first_name = $this->input->post('first_name') == 'First Name' ? '' : $this->input->post('first_name'); $last_name = $this->input->post('last_name') == 'Last Name' ? '' : $this->input->post('last_name'); $email = $this->input->post('email') == '*****@*****.**' ? '' : $this->input->post('email'); $state = ($this->input->post('country') == 'US' or $this->input->post('country') == 'CA') ? $this->input->post('state_select') : $this->input->post('state'); if (!empty($first_name) and !empty($last_name)) { $charge->Customer($first_name, $last_name, $this->input->post('company'), $this->input->post('address_1'), $this->input->post('address_2'), $this->input->post('city'), $state, $this->input->post('country'), $this->input->post('postal_code'), $this->input->post('phone'), $email); } } if ($this->input->post('gateway_type') == 'specify') { $charge->UseGateway($this->input->post('gateway')); } // set return URL if ($this->input->post('recurring') == '0') { $charge->Param('return_url', site_url('transactions/latest_charge')); } else { $charge->Param('return_url', site_url('transactions/latest_recur')); } $charge->Param('cancel_url', site_url('transactions/create')); $response = $charge->Charge(); if (!is_array($response) or isset($response['error'])) { $this->notices->SetError($this->lang->line('transaction_error') . $response['error_text'] . ' (#' . $response['error'] . ')'); } elseif (isset($response['response_code']) and $response['response_code'] == '2') { $this->notices->SetError($this->lang->line('transaction_error') . $response['response_text'] . '. ' . $response['reason'] . ' (#' . $response['response_code'] . ')'); } else { $this->notices->SetNotice($this->lang->line('transaction_ok')); } if (isset($response['recurring_id'])) { $redirect = site_url('transactions/recurring/' . $response['recurring_id']); } elseif (isset($response['charge_id'])) { $redirect = site_url('transactions/charge/' . $response['charge_id']); } else { $redirect = site_url('transactions/create'); } redirect($redirect); return TRUE; }