/** * Tells Membership2 Admin to display this form to manage this rule. * * @since 1.0.0 * * @param array $callback (Invalid callback) * @param array $data The data collection. * @return array Correct callback. */ public function handle_render_callback($callback, $data) { $view = MS_Factory::load('MS_Addon_BuddyPress_Rule_View'); $view->data = $data; $callback = array($view, 'to_html'); return $callback; }
/** * Fires only at user creation from admin * Create even to send notification email. * * @since 1.0.2.6 * * @var int $user_id */ public function save_user_create_event($user_id) { if (is_admin()) { $member = MS_Factory::load('MS_Model_Member', $user_id); MS_Model_Event::save_event(MS_Model_Event::TYPE_MS_REGISTERED, $member); } }
/** * Create view output. * * @since 1.0.0 * @return string */ public function to_html() { $list_table = MS_Factory::create('MS_Helper_ListTable_Event'); $list_table->prepare_items(); if (isset($_REQUEST['membership_id'])) { $membership = MS_Factory::load('MS_Model_Membership', $_REQUEST['membership_id']); $title = sprintf(__('%s News', 'membership2'), $membership->get_name_tag()); $url = esc_url_raw(add_query_arg(array('step' => MS_Controller_Membership::STEP_OVERVIEW), remove_query_arg(array('paged', 'order', 'post_mime_type', 'detached', 'orderby', 's')))); $back_link = array('id' => 'back', 'type' => MS_Helper_Html::TYPE_HTML_LINK, 'value' => __('» Back to Overview', 'membership2'), 'url' => $url, 'class' => 'wpmui-field-button button'); } else { $title = __('Membership News', 'membership2'); $back_link = ''; } ob_start(); ?> <div class="wrap ms-wrap ms-membership-news"> <?php MS_Helper_Html::settings_header(array('title' => $title)); MS_Helper_Html::html_element($back_link); $list_table->search_box(); $list_table->views(); ?> <form action="" method="post"> <?php $list_table->display(); ?> </form> </div> <?php $html = ob_get_clean(); echo '' . $html; }
/** * Tells Membership2 Admin to display this form to manage this rule. * * @since 1.0.0 * * @param array $callback (Invalid callback) * @param array $data The data collection. * @return array Correct callback. */ public function handle_render_callback($callback, $data) { $view = MS_Factory::load('MS_Rule_MemberRoles_View'); $view->data = $data; $callback = array($view, 'to_html'); return $callback; }
/** * Initialize the object. * * @since 1.0.0 */ public function after_load() { parent::after_load(); $this->_api = MS_Factory::load('MS_Gateway_Stripe_Api'); // If the gateway is initialized for the first time then copy settings // from the Stripe Single gateway. if (false === $this->test_secret_key) { $single = MS_Factory::load('MS_Gateway_Stripe'); $this->test_secret_key = $single->test_secret_key; $this->secret_key = $single->secret_key; $this->test_publishable_key = $single->test_publishable_key; $this->publishable_key = $single->publishable_key; $this->save(); } $this->id = self::ID; $this->name = __('Stripe Subscriptions Gateway', MS_TEXT_DOMAIN); $this->group = 'Stripe'; $this->manual_payment = false; // Recurring charged automatically $this->pro_rate = true; $this->unsupported_payment_types = array(MS_Model_Membership::PAYMENT_TYPE_PERMANENT, MS_Model_Membership::PAYMENT_TYPE_FINITE, MS_Model_Membership::PAYMENT_TYPE_DATE_RANGE); // Update all payment plans and coupons. $this->add_action('ms_gateway_toggle_stripeplan', 'update_stripe_data'); // Update a single payment plan. $this->add_action('ms_saved_MS_Model_Membership', 'update_stripe_data_membership'); // Update a single coupon. $this->add_action('ms_saved_MS_Addon_Coupon_Model', 'update_stripe_data_coupon'); }
/** * Checks if the current Add-on is enabled * * @since 1.0.0 * @return bool */ public static function is_active() { if (!self::wp_recaptcha_active() && MS_Model_Addon::is_enabled(self::ID)) { $model = MS_Factory::load('MS_Model_Addon'); $model->disable(self::ID); } return MS_Model_Addon::is_enabled(self::ID); }
/** * Returns the singleton instance of the MS_Model_Pages object * * @since 1.0.0 * @return MS_Model_Pages */ public static function get_model() { static $Model = null; if (null === $Model) { $Model = MS_Factory::load('MS_Model_Pages'); } return $Model; }
/** * Initializes the Add-on. Always executed. * * @since 1.0.0 */ public function init() { // Always remove bbpress from MS_Rule_CptGroup_Model. $this->add_filter('ms_rule_cptgroup_model_get_excluded_content', 'exclude_bbpress_cpts'); if (self::is_active()) { $this->add_filter('ms_controller_protection_tabs', 'rule_tabs'); MS_Factory::load('MS_Addon_Bbpress_Rule'); } }
/** * Initialize the Add-On. * * @since 1.0.0 */ public function __construct() { parent::__construct(); self::$model = MS_Factory::load('MS_Model_Addon'); self::$settings = MS_Factory::load('MS_Model_Settings'); $this->add_filter('ms_model_addon_register', 'register'); $this->add_action('ms_model_addon_initialize', 'init_addon'); $this->add_ajax_action($this->ajax_action(), 'ajax_update_settings'); }
/** * Initialize the object. * * @since 1.0.0 * @internal */ public function after_load() { parent::after_load(); $this->_api = MS_Factory::load('MS_Gateway_Stripe_Api'); $this->id = self::ID; $this->name = __('Stripe Single Gateway', 'membership2'); $this->group = 'Stripe'; $this->manual_payment = true; // Recurring billed/paid manually $this->pro_rate = true; }
/** * Initialize the object. * * @since 1.0.0 * @internal */ public function after_load() { parent::after_load(); $this->_api = MS_Factory::load('MS_Gateway_Stripe_Api'); $this->id = self::ID; $this->name = __('Stripe Single Gateway', 'membership2'); $this->group = 'Stripe'; $this->manual_payment = true; // Recurring billed/paid manually $this->pro_rate = true; $this->add_filter('ms_model_pages_get_ms_page_url', 'ms_model_pages_get_ms_page_url_cb', 99, 4); }
/** * Tests the Stripe Subscription gateway * @test */ function stripeplan_subscription() { $gateway = MS_Model_Gateway::factory(MS_Gateway_Stripeplan::ID); $user_id = TData::id('user', 'editor'); $membership_id = TData::id('membership', 'recurring'); $subscription = TData::subscribe($user_id, $membership_id); $controller = MS_Factory::load('MS_Controller_Gateway'); $gateway->update_stripe_data(); $data = array('card' => array('number' => '4242424242424242', 'exp_month' => 12, 'exp_year' => date('Y') + 1, 'cvc' => '314')); $res = M2_Stripe_Token::create($data); $token = $res->id; $form_data = array('_wpnonce' => wp_create_nonce($gateway->id . '_' . $subscription->id), 'gateway' => $gateway->id, 'ms_relationship_id' => $subscription->id, 'step' => 'process_purchase', 'stripeToken' => $token, 'stripeTokenType' => 'card', 'stripeEmail' => '*****@*****.**'); $_POST = $form_data; $_REQUEST = $_POST; // Right now the subscription must have status PENDING $this->assertEquals(MS_Model_Relationship::STATUS_PENDING, $subscription->status); /* * This function processes the purchase and will set the subscription * to active. */ $controller->process_purchase(); // Check the subscription status. $this->assertEquals(MS_Model_Relationship::STATUS_ACTIVE, $subscription->status); $this->assertEquals(1, count($subscription->payments)); // Modify the expiration date to trigger another payment. $today = date('Y-m-d'); $subscription->expire_date = $today; $this->assertEquals($today, $subscription->expire_date); $this->assertEquals(0, $subscription->get_remaining_period()); // Trigger next payment and validate it. $subscription->check_membership_status(); $this->assertEquals(2, count($subscription->payments)); // Modify the expiration date to trigger another payment. $subscription->expire_date = $today; $this->assertEquals($today, $subscription->expire_date); $this->assertEquals(0, $subscription->get_remaining_period()); // Trigger next payment and validate it. // THIS TIME NO PAYMENT SHOULD BE MADE because paycycle_repetitions = 2! $subscription->check_membership_status(); $this->assertEquals(2, count($subscription->payments)); // Also the subscription should be cancelled at stripe now. $customer_id = $subscription->get_member()->get_gateway_profile(MS_Gateway_Stripe_Api::ID, 'customer_id'); $customer = M2_Stripe_Customer::retrieve($customer_id); $invoice = $subscription->get_previous_invoice(); $stripe_sub_id = $invoice->external_id; $stripe_sub = $customer->subscriptions->retrieve($stripe_sub_id); $this->assertEquals('active', $stripe_sub->status); $this->assertTrue($stripe_sub->cancel_at_period_end); // Clean up. $customer->delete(); }
/** * Checks if shared-setup was working. * @test */ function staging_data_is_correct() { $this->assertFalse(empty(TData::id('user', 'admin'))); wp_set_current_user(TData::id('user', 'admin')); $this->assertEquals(get_current_user_id(), TData::id('user', 'admin')); $this->assertFalse(empty(TData::id('user', 'editor'))); $this->assertFalse(empty(TData::id('post', 'sample-page'))); $this->assertEquals('page', get_post_type(TData::id('post', 'sample-page'))); $ms_id = TData::id('membership', 'simple'); $this->assertFalse(empty($ms_id)); $membership = MS_Factory::load('MS_Model_Membership', $ms_id); $this->assertEquals($ms_id, $membership->id); $this->assertEquals(29, $membership->price); }
/** * Prepares a list with field definitions that are required to render the * payment list/global options (i.e. currency and sender name) * * @since 1.0.0 * * @return array */ protected function get_global_payment_fields() { $settings = MS_Factory::load('MS_Model_Settings'); $action = MS_Controller_Settings::AJAX_ACTION_UPDATE_SETTING; $nonce = wp_create_nonce($action); $fields = array('currency' => array('id' => 'currency', 'type' => MS_Helper_Html::INPUT_TYPE_SELECT, 'title' => __('Select payment currency', MS_TEXT_DOMAIN), 'value' => $settings->currency, 'field_options' => $settings->get_currencies(), 'class' => '', 'class' => 'chosen-select', 'data_ms' => array('field' => 'currency')), 'invoice_sender_name' => array('id' => 'invoice_sender_name', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => __('Invoice sender name', MS_TEXT_DOMAIN), 'value' => $settings->invoice_sender_name, 'data_ms' => array('field' => 'invoice_sender_name'))); foreach ($fields as $key => $field) { if (is_array($field['data_ms'])) { $fields[$key]['data_ms']['_wpnonce'] = $nonce; $fields[$key]['data_ms']['action'] = $action; } } return apply_filters('ms_gateway_view_get_global_payment_fields', $fields); }
/** * Check member capability add-on. * @test */ function member_capabilities_rule() { // We only test the addon as an isolated unit. $addon = MS_Factory::load('MS_Rule_MemberCaps_Model'); remove_all_filters('user_has_cap'); $addon->protect_admin_content(); wp_set_current_user(TData::id('user', 'admin')); $this->assertTrue(current_user_can('manage_options'), 'admin'); $this->assertTrue(current_user_can('edit_theme_options'), 'admin'); wp_set_current_user(TData::id('user', 'editor')); $this->assertFalse(current_user_can('manage_options'), 'editor'); $this->assertFalse(current_user_can('edit_theme_options'), 'editor'); $this->assertTrue(current_user_can('edit_pages'), 'editor'); $this->assertTrue(current_user_can('delete_pages'), 'editor'); }
/** * Checks if the user did import data from this source before. * * This information is not entirely reliable, since data could have been * deleted again after import. * * @since 1.0.0 * @return bool */ public static function did_import() { $settings = MS_Factory::load('MS_Model_Settings'); $did_import = !empty($settings->import[self::KEY]); /** * Allow users to manually declare that some M2 subscriptions were * imported from old Membership plugin. * * As a result M2 will additionally listen to the old M1 IPN URL for * PayPal payment notifications. * * @since 1.0.2.4 * @param bool $did_import */ return apply_filters('ms_did_import_m1_data', $did_import); }
public function column_membership($item) { $html = ''; $is_any = true; foreach ($item->membership_id as $id) { if (MS_Model_Membership::is_valid_membership($id)) { $is_any = false; $membership = MS_Factory::load('MS_Model_Membership', $id); $html .= sprintf('<span class="ms-bold">%s</span><br />', $membership->name); } } if ($is_any) { $html = sprintf('<span class="ms-low">%s</span>', __('Any', 'membership2')); } return $html; }
/** * Constructor. * * @since 1.0.0 * * @param array $data The data what has to be associated with this render. */ public function __construct($data = array()) { static $Simulate = null; $this->data = $data; /** * Actions to execute when constructing the parent View. * * @since 1.0.0 * @param object $this The MS_View object. */ do_action('ms_view_construct', $this); if (null === $Simulate && MS_Model_Simulate::can_simulate()) { $Simulate = MS_Factory::load('MS_Model_Simulate'); self::$is_simulating = $Simulate->is_simulating(); } }
/** * Generate/Prepare the dialog attributes. * * @since 1.0.0 */ public function prepare() { $subscription_id = $_POST['subscription_id']; $subscription = MS_Factory::load('MS_Model_Relationship', $subscription_id); $data = array('model' => $subscription); $data = apply_filters('ms_view_member_payment_data', $data); // Dialog Title $this->title = sprintf(__('Subscription Details: %1$s', MS_TEXT_DOMAIN), esc_html($subscription->get_membership()->name)); // Dialog Size $this->width = 940; $this->height = 600; // Contents $this->content = $this->get_contents($data); // Make the dialog modal $this->modal = true; }
/** * Generate/Prepare the dialog attributes. * * @since 1.0.0 */ public function prepare() { $member_id = $_POST['member_id']; $member = MS_Factory::load('MS_Model_Member', $member_id); $data = array('model' => $member); $data = apply_filters('ms_view_member_dialog_data', $data); // Dialog Title $this->title = sprintf(__('Profile: %1$s %2$s', 'membership2'), esc_html($member->first_name), esc_html($member->last_name)); // Dialog Size $this->width = 940; $this->height = 500; // Contents $this->content = $this->get_contents($data); // Make the dialog modal $this->modal = true; }
/** * Generate/Prepare the dialog attributes. * * @since 1.0.0 */ public function prepare() { $subscription_id = $_POST['subscription_id']; $subscription = MS_Factory::load('MS_Model_Relationship', $subscription_id); if (!empty($_REQUEST['statuscheck'])) { $subscription->check_membership_status(); } $data = array('model' => $subscription); $data = apply_filters('ms_view_member_subscription_data', $data); // Dialog Title $this->title = sprintf(__('Subscription Details: %1$s', 'membership2'), esc_html($subscription->get_membership()->name)); // Dialog Size $this->width = 940; $this->height = 800; // Contents $this->content = $this->get_contents($data); // Make the dialog modal $this->modal = true; }
/** * Returns tax information that must be applied to the specified amount. * * This function first checks the user-metadata for logged-in users and * takes the details that are stored in the user metadata table. * * If the user is not logged in or no metadata are found then the Taxamo API * is queried to get the default tax details for the country that * Taxamo automatically detects. * * @since 1.0.0 * @api * * @param numeric $amount The amount without taxes. * @return object { * Tax information * * string $country Tax country (2-digit code) * string $name Tax name * numeric $rate Tax rate (percent) * numeric $amount Tax amount * } */ public static function tax_info($amount = 0) { static $Info = null; if (null === $Info) { $settings = MS_Factory::load('MS_Model_Settings'); try { $profile = self::get_tax_profile(); $tax_number = null; if ($profile->use_vat_number) { $tax_number = $profile->vat_number; } $resp = self::taxamo()->calculateSimpleTax(null, $tax_number, null, $profile->tax_country->code, null, null, null, null, 100, $profile->tax_country->code, $settings->currency, null); // Prepare the result object. if (isset($resp->transaction->transaction_lines[0])) { $transaction = $resp->transaction->transaction_lines[0]; $Info = (object) array('country' => $resp->transaction->tax_country_code, 'rate' => $transaction->tax_rate, 'name' => $transaction->tax_name, 'amount' => 0); } } catch (Exception $ex) { MS_Helper_Debug::log('Taxamo error: ' . $ex->getMessage()); } } if (!is_object($Info)) { $Info = (object) array(); } if (!isset($Info->name)) { $Info->name = __('No Tax', 'membership2'); } if (!isset($Info->rate)) { $Info->rate = 0; } if (!isset($Info->amount)) { $Info->amount = 0; } if (!isset($Info->country)) { $Info->country = 'US'; } $Info->amount = $amount / 100 * $Info->rate; return $Info; }
/** * Checks if the user did import data from this source before. * * This information is not entirely reliable, since data could have been * deleted again after import. * * @since 1.0.0 * @return bool */ public static function did_import() { $settings = MS_Factory::load('MS_Model_Settings'); return !empty($settings->import[self::KEY]); }
/** * Get user's coupon application. * * @since 1.0.0 * * @param int $user_id The user id. * @param int $membership_id The membership id. * @return MS_Addon_Coupon_Model The coupon model object. */ public static function get_application($user_id, $membership_id) { $key = self::get_transient_name($user_id, $membership_id); $transient = MS_Factory::get_transient($key); $coupon = null; if (is_array($transient) && !empty($transient['id'])) { $the_id = intval($transient['id']); $coupon = MS_Factory::load('MS_Addon_Coupon_Model', $the_id); $coupon->coupon_message = $transient['message']; } else { $coupon = MS_Factory::load('MS_Addon_Coupon_Model'); } return apply_filters('ms_addon_coupon_model_get_application', $coupon, $user_id, $membership_id); }
/** * Prepare the HTML fields that can be displayed * * @since 1.0.0 * * @return array */ protected function prepare_fields($data) { // List of known Membership types; used to display the nice-name $ms_types = MS_Model_Membership::get_types(); $ms_paytypes = MS_Model_Membership::get_payment_types(); // Prepare the "Memberships" table $memberships = array(array(__('Membership name', 'membership2'), __('Membership Type', 'membership2'), __('Payment Type', 'membership2'), __('Description', 'membership2'))); foreach ($data->memberships as $item) { if (!isset($ms_types[$item->type])) { $item->type = MS_Model_Membership::TYPE_STANDARD; } switch ($item->pay_type) { case 'recurring': $payment_type = MS_Model_Membership::PAYMENT_TYPE_RECURRING; break; case 'finite': $payment_type = MS_Model_Membership::PAYMENT_TYPE_FINITE; break; case 'date': $payment_type = MS_Model_Membership::PAYMENT_TYPE_DATE_RANGE; break; default: $payment_type = MS_Model_Membership::PAYMENT_TYPE_PERMANENT; break; } $memberships[] = array($item->name, $ms_types[$item->type], $ms_paytypes[$payment_type], $item->description); } // Prepare the "Members" table $members = array(array(__('Username', 'membership2'), __('Email', 'membership2'), __('Subscriptions', 'membership2'), __('Invoices', 'membership2'))); foreach ($data->members as $item) { $inv_count = 0; if (isset($item->subscriptions) && is_array($item->subscriptions)) { foreach ($item->subscriptions as $registration) { $inv_count += count($registration->invoices); } } $members[] = array($item->username, $item->email, count($item->subscriptions), $inv_count); } $settings = array(); foreach ($data->settings as $setting => $value) { switch ($setting) { case 'addons': $model = MS_Factory::load('MS_Model_Addon'); $list = $model->get_addon_list(); $code = ''; foreach ($value as $addon => $state) { if ($state) { $code .= __('Activate: ', 'membership2'); } else { $code .= __('Dectivate: ', 'membership2'); } $code .= $list[$addon]->name . '<br/>'; } $settings[] = array(__('Add-Ons', 'membership2'), $code); break; } } if (empty($settings)) { $settings[] = array('', __('(No settings are changed)', 'membership2')); } // Prepare the return value. $fields = array(); // Export-Notes $notes = ''; if (isset($data->notes)) { if (is_scalar($data->notes)) { $notes = array($data->notes); } $in_sub = false; $notes = '<ul class="ms-import-notes">'; foreach ($data->notes as $line => $text) { $is_sub = strpos($text, '- ') === 0; if ($in_sub != $is_sub) { $in_sub = $is_sub; if ($is_sub) { $notes .= '<ul>'; } else { $notes .= '</ul>'; } } if ($in_sub) { $text = substr($text, 2); } $notes .= '<li>' . $text; } $notes .= '</ul>'; } $fields['details'] = array('type' => MS_Helper_Html::TYPE_HTML_TABLE, 'class' => 'ms-import-preview', 'value' => array(array(__('Data source', 'membership2'), $data->source . '   <small>' . sprintf(__('exported on %1$s', 'membership2'), $data->export_time) . '</small>'), array(__('Content', 'membership2'), sprintf(_n('%1$s Membership', '%1$s Memberships', count($data->memberships), 'membership2'), '<b>' . count($data->memberships) . '</b>') . ' / ' . sprintf(_n('%1$s Member', '%1$s Members', count($data->members), 'membership2'), '<b>' . count($data->members) . '</b>'))), 'field_options' => array('head_col' => true, 'head_row' => false, 'col_class' => array('preview-label', 'preview-data'))); if (!empty($notes)) { $fields['details']['value'][] = array(__('Please note', 'membership2'), $notes); } $batchsizes = array(10 => __('Small (10 items)'), 30 => __('Normal (30 items)'), 100 => __('Big (100 items)')); $fields['batchsize'] = array('id' => 'batchsize', 'type' => MS_Helper_Html::INPUT_TYPE_SELECT, 'title' => __('Batch size for import', 'membership2'), 'desc' => __('Big batches will be processed faster but may result in PHP Memory errors.', 'membership2'), 'value' => 30, 'field_options' => $batchsizes, 'class' => 'sel-batchsize'); $fields['clear_all'] = array('id' => 'clear_all', 'type' => MS_Helper_Html::INPUT_TYPE_CHECKBOX, 'title' => __('Replace current content with import data (removes existing Memberships/Members before importing data)', 'membership2'), 'class' => 'widefat'); $fields['memberships'] = array('type' => MS_Helper_Html::TYPE_HTML_TABLE, 'class' => 'ms-import-preview', 'value' => $memberships, 'field_options' => array('head_col' => false, 'head_row' => true, 'col_class' => array('preview-name', 'preview-type', 'preview-pay-type', 'preview-desc'))); $fields['members'] = array('type' => MS_Helper_Html::TYPE_HTML_TABLE, 'class' => 'ms-import-preview', 'value' => $members, 'field_options' => array('head_col' => false, 'head_row' => true, 'col_class' => array('preview-name', 'preview-email', 'preview-count', 'preview-count'))); $fields['settings'] = array('type' => MS_Helper_Html::TYPE_HTML_TABLE, 'class' => 'ms-import-preview', 'value' => $settings, 'field_options' => array('head_col' => true, 'head_row' => false)); $fields['sep'] = array('type' => MS_Helper_Html::TYPE_HTML_SEPARATOR); $fields['back'] = array('type' => MS_Helper_Html::TYPE_HTML_LINK, 'class' => 'wpmui-field-button button', 'value' => __('Cancel', 'membership2'), 'url' => $_SERVER['REQUEST_URI']); $fields['skip'] = array('type' => MS_Helper_Html::TYPE_HTML_LINK, 'class' => 'wpmui-field-button button', 'value' => __('Skip', 'membership2'), 'url' => MS_Controller_Plugin::get_admin_url(false, array('skip_import' => 1))); $fields['import'] = array('id' => 'btn-import', 'type' => MS_Helper_Html::INPUT_TYPE_BUTTON, 'value' => __('Import', 'membership2'), 'button_value' => MS_Controller_Import::AJAX_ACTION_IMPORT, 'button_type' => 'submit'); $fields['download'] = array('id' => 'btn-download', 'type' => MS_Helper_Html::INPUT_TYPE_BUTTON, 'value' => __('Download as Export File', 'membership2'), 'class' => 'button-link'); return $fields; }
/** * Save invoices using the invoices model. * * @since 1.0.0 * * @param mixed $fields Transaction fields */ private function save_invoice($fields) { $msg = MS_Helper_Billing::BILLING_MSG_NOT_UPDATED; if ($this->is_admin_user() && is_array($fields) && !empty($fields['user_id']) && !empty($fields['membership_id'])) { $member = MS_Factory::load('MS_Model_Member', $fields['user_id']); $membership_id = $fields['membership_id']; $gateway_id = 'admin'; $subscription = MS_Model_Relationship::get_subscription($member->id, $membership_id); if (empty($subscription)) { $subscription = MS_Model_Relationship::create_ms_relationship($membership_id, $member->id, $gateway_id); } else { $subscription->gateway_id = $gateway_id; $subscription->save(); } $invoice_id = intval($fields['invoice_id']); $invoice = MS_Factory::load('MS_Model_Invoice', $invoice_id); if (!$invoice->is_valid()) { $invoice = $subscription->get_current_invoice(); $msg = MS_Helper_Billing::BILLING_MSG_ADDED; } else { $msg = MS_Helper_Billing::BILLING_MSG_UPDATED; } foreach ($fields as $field => $value) { $invoice->{$field} = $value; } $invoice->save(); if (!empty($fields['execute'])) { $invoice->changed(); } } return apply_filters('ms_controller_billing_save_invoice', $msg, $fields, $this); }
/** * Add redirect settings-view callback. * * @since 1.0.0 * * @param array $callback The current function callback. * @param string $tab The current membership rule tab. * @param array $data The data shared to the view. * @return array The filtered callback. */ public function manage_render_callback($callback, $tab, $data) { if (self::ID == $tab) { $view = MS_Factory::load('MS_Addon_Redirect_View'); $callback = array($view, 'render_tab'); } return $callback; }
/** * Returns Membership object. * * @since 1.0.0 * @return MS_Model_Membership The membership object. */ public function get_membership() { $membership = MS_Factory::load('MS_Model_Membership', $this->membership_id); return apply_filters('ms_rule_get_membership', $membership); }
/** * Processes gateway IPN return. * * @since 1.0.0 */ public function handle_return() { $success = false; $ignore = false; $exit = false; $redirect = false; $notes = ''; $status = null; $notes_pay = ''; $notes_txn = ''; $external_id = null; $invoice_id = 0; $subscription_id = 0; $amount = 0; $transaction_type = ''; $payment_status = ''; $is_m1 = false; $fields_set = false; if (!empty($_POST['txn_type'])) { $transaction_type = strtolower($_POST['txn_type']); } if (!empty($_POST['payment_status'])) { $payment_status = strtolower($_POST['payment_status']); } if ($payment_status || $transaction_type) { if (!empty($_POST['invoice'])) { // 'invoice' is set in all regular M2 subscriptions. $fields_set = true; } elseif (!empty($_POST['custom'])) { // First: We cannot process this payment. $fields_set = false; // But let's check if it is an M1 payment. $infos = explode(':', $_POST['custom']); if (count($infos) > 2) { // $infos should contain [timestamp, user_id, sub_id, key] $pay_types = array('subscr_signup', 'subscr_payment'); $pay_stati = array('completed', 'processed'); if (in_array($transaction_type, $pay_types)) { $is_m1 = true; } elseif (in_array($payment_status, $pay_stati)) { $is_m1 = true; } } } } if ($fields_set) { if ($this->is_live_mode()) { $domain = 'https://www.paypal.com'; } else { $domain = 'https://www.sandbox.paypal.com'; } // Paypal post authenticity verification $ipn_data = (array) stripslashes_deep($_POST); $ipn_data['cmd'] = '_notify-validate'; $response = wp_remote_post($domain . '/cgi-bin/webscr', array('timeout' => 60, 'sslverify' => false, 'httpversion' => '1.1', 'body' => $ipn_data)); $invoice_id = intval($_POST['invoice']); $currency = $_POST['mc_currency']; $invoice = MS_Factory::load('MS_Model_Invoice', $invoice_id); if (!is_wp_error($response) && 200 == $response['response']['code'] && !empty($response['body']) && 'VERIFIED' == $response['body'] && $invoice->id == $invoice_id) { $subscription = $invoice->get_subscription(); $membership = $subscription->get_membership(); $member = $subscription->get_member(); $subscription_id = $subscription->id; // Process PayPal payment status if ($payment_status) { $amount = (double) $_POST['mc_gross']; $external_id = $_POST['txn_id']; switch ($payment_status) { // Successful payment case 'completed': case 'processed': if ($amount == $invoice->total) { $success = true; $notes .= __('Payment successful', MS_TEXT_DOMAIN); } else { $notes_pay = __('Payment amount differs from invoice total.', MS_TEXT_DOMAIN); $status = MS_Model_Invoice::STATUS_DENIED; } break; case 'reversed': $notes_pay = __('Last transaction has been reversed. Reason: Payment has been reversed (charge back).', MS_TEXT_DOMAIN); $status = MS_Model_Invoice::STATUS_DENIED; $ignore = true; break; case 'refunded': $notes_pay = __('Last transaction has been reversed. Reason: Payment has been refunded.', MS_TEXT_DOMAIN); $status = MS_Model_Invoice::STATUS_DENIED; $ignore = true; break; case 'denied': $notes_pay = __('Last transaction has been reversed. Reason: Payment Denied.', MS_TEXT_DOMAIN); $status = MS_Model_Invoice::STATUS_DENIED; $ignore = true; break; case 'pending': lib2()->array->strip_slashes($_POST, 'pending_reason'); $notes_pay = __('Last transaction is pending.', MS_TEXT_DOMAIN) . ' '; switch ($_POST['pending_reason']) { case 'address': $notes_pay .= __('Customer did not include a confirmed shipping address', MS_TEXT_DOMAIN); break; case 'authorization': $notes_pay .= __('Funds not captured yet', MS_TEXT_DOMAIN); break; case 'echeck': $notes_pay .= __('The eCheck has not cleared yet', MS_TEXT_DOMAIN); break; case 'intl': $notes_pay .= __('Payment waiting for approval by service provider', MS_TEXT_DOMAIN); break; case 'multi-currency': $notes_pay .= __('Payment waiting for service provider to handle multi-currency process', MS_TEXT_DOMAIN); break; case 'unilateral': $notes_pay .= __('Customer did not register or confirm his/her email yet', MS_TEXT_DOMAIN); break; case 'upgrade': $notes_pay .= __('Waiting for service provider to upgrade the PayPal account', MS_TEXT_DOMAIN); break; case 'verify': $notes_pay .= __('Waiting for service provider to verify his/her PayPal account', MS_TEXT_DOMAIN); break; default: $notes_pay .= __('Unknown reason', MS_TEXT_DOMAIN); break; } $status = MS_Model_Invoice::STATUS_PENDING; $ignore = true; break; default: case 'partially-refunded': case 'in-progress': $notes_pay = sprintf(__('Not handling payment_status: %s', MS_TEXT_DOMAIN), $payment_status); MS_Helper_Debug::log($notes_pay); $ignore = true; break; } } // Check for subscription details if ($transaction_type) { switch ($transaction_type) { case 'subscr_signup': case 'subscr_payment': // Payment was received $notes_txn = __('Paypal subscripton profile has been created.', MS_TEXT_DOMAIN); if (0 == $invoice->total) { $success = true; } else { $ignore = true; } break; case 'subscr_modify': // Payment profile was modified $notes_txn = __('Paypal subscription profile has been modified.', MS_TEXT_DOMAIN); $ignore = true; break; case 'recurring_payment_profile_canceled': case 'subscr_cancel': // Subscription was manually cancelled. $notes_txn = __('Paypal subscription profile has been canceled.', MS_TEXT_DOMAIN); $member->cancel_membership($membership->id); $member->save(); $ignore = true; break; case 'recurring_payment_suspended': // Recurring subscription was manually suspended. $notes_txn = __('Paypal subscription profile has been suspended.', MS_TEXT_DOMAIN); $member->cancel_membership($membership->id); $member->save(); $ignore = true; break; case 'recurring_payment_suspended_due_to_max_failed_payment': // Recurring subscription was automatically suspended. $notes_txn = __('Paypal subscription profile has failed.', MS_TEXT_DOMAIN); $member->cancel_membership($membership->id); $member->save(); $ignore = true; break; case 'new_case': // New Dispute was filed for a payment. $status = MS_Model_Invoice::STATUS_DENIED; $ignore = true; break; case 'subscr_eot': /* * Meaning: Subscription expired. * * - after a one-time payment was madeafter last * - after last transaction in a recurring subscription * - payment failed * - ... * * We do not handle this event... * * One time payment sends 3 messages: * 1. subscr_start (new subscription starts) * 2. subscr_payment (payment confirmed) * 3. subscr_eot (subscription ends) */ $notes_txn = __('No more payments will be made for this subscription.', MS_TEXT_DOMAIN); $ignore = true; break; default: // Other event that we do not have a case for... $notes_txn = sprintf(__('Not handling txn_type: %s', MS_TEXT_DOMAIN), $transaction_type); MS_Helper_Debug::log($notes_txn); $ignore = true; break; } } if (!empty($notes_pay)) { $invoice->add_notes($notes_pay); } if (!empty($notes_txn)) { $invoice->add_notes($notes_txn); } $notes .= $notes_pay . ' | ' . $notes_txn; $invoice->save(); if ($success) { $invoice->pay_it($this->id, $external_id); } elseif (!empty($status)) { $invoice->status = $status; $invoice->save(); $invoice->changed(); } do_action('ms_gateway_paypalstandard_payment_processed_' . $status, $invoice, $subscription); } else { $reason = 'Unexpected transaction response'; switch (true) { case is_wp_error($response): $reason = 'PayPal did not verify this transaction: Unknown error'; break; case 200 != $response['response']['code']: $reason = sprintf('PayPal did not verify the transaction: Code %s', $response['response']['code']); break; case empty($response['body']): $reason = 'PayPal did not verify this transaction: Empty response'; break; case 'VERIFIED' != $response['body']: $reason = sprintf('PayPal did not verify this transaction: "%s"', $response['body']); break; case $invoice->id != $invoice_id: $reason = sprintf('PayPal gave us an invalid invoice_id: "%s"', $invoice_id); break; } $notes = 'Response Error: ' . $reason; MS_Helper_Debug::log($notes); MS_Helper_Debug::log($response); MS_Helper_Debug::log($_POST); $exit = true; } } else { // Did not find expected POST variables. Possible access attempt from a non PayPal site. $u_agent = $_SERVER['HTTP_USER_AGENT']; if (false === strpos($u_agent, 'PayPal')) { // Very likely someone tried to open the URL manually. Redirect to home page $notes = 'Error: Missing POST variables. Redirect user to Home-URL.'; MS_Helper_Debug::log($notes); $redirect = home_url(); } elseif ($is_m1) { /* * The payment belongs to an imported M1 subscription and could * not be auto-matched. * Do not return an error code, but also do not modify any * invoice/subscription. */ $notes = 'M1 Payment detected. Manual matching required.'; $ignore = false; $success = false; } else { if (!$payment_status && !$transaction_type) { $notes = 'Error: payment_status and txn_type not specified. Cannot process.'; } elseif (empty($_POST['invoice']) && empty($_POST['custom'])) { $notes = 'Error: No invoice or custom data specified.'; } else { $notes = 'Error: Missing POST variables. Identification is not possible.'; } // PayPal did provide invalid details... status_header(404); MS_Helper_Debug::log($notes); } $exit = true; } if ($ignore && !$success) { $success = null; } do_action('ms_gateway_transaction_log', self::ID, 'handle', $success, $subscription_id, $invoice_id, $amount, $notes); if ($redirect) { wp_safe_redirect($redirect); exit; } if ($exit) { exit; } do_action('ms_gateway_paypalstandard_handle_return_after', $this); }
public function column_membership_id($item, $column_name) { $membership = MS_Factory::load('MS_Model_Membership', $item->membership_id); $html = $membership->name; return $html; }