MS_Model_Import

Base class for all import handlers.

Defined (1)

The class is defined in the following location(s).

/app/model/class-ms-model-import.php  
  1. class MS_Model_Import extends MS_Model { 
  2.  
  3. /** 
  4. * The sanitized import source object. The value of this property is set by 
  5. * the prepare() function. 
  6. * This is used to render the Import-Preview view. 
  7. * @since 1.0.0 
  8. * @var array 
  9. */ 
  10. public $source = array(); 
  11.  
  12. /** 
  13. * Holds a list of all errors that happen during import. 
  14. * @since 1.0.0 
  15. * @var array 
  16. */ 
  17. protected $errors = array(); 
  18.  
  19. /** 
  20. * The data source name. 
  21. * @since 1.0.0 
  22. * @var string 
  23. */ 
  24. public $source_key = ''; 
  25.  
  26. /** 
  27. * This function parses the Import source (e.g. an file-upload or settings 
  28. * of another plugin) and returns true in case the source data is valid. 
  29. * When returning true then the $source property of the model is set to 
  30. * the sanitized import source data. 
  31. * Logic has to be implemented by child classes. 
  32. * @since 1.0.0 
  33. * @return bool 
  34. */ 
  35. public function prepare() { 
  36. throw new Exception( 'Method to be implemented in child class' ); 
  37.  
  38. /** 
  39. * Returns true if the specific import-source is present and can be used 
  40. * for import. 
  41. * Must be implemented by the child classes. 
  42. * @since 1.0.0 
  43. * @return bool 
  44. */ 
  45. static public function present() { 
  46. return false; 
  47.  
  48. /** 
  49. * Checks if the provided data is a recognized import object. 
  50. * If not an import object then FALSE will be returned, otherwise the 
  51. * object itself. 
  52. * @since 1.0.0 
  53. * @param object $data Import object to test. 
  54. * @return object|false 
  55. */ 
  56. protected function validate_object( $data ) { 
  57. $data = apply_filters( 'ms_import_validate_object_before', $data ); 
  58.  
  59. if ( empty( $data ) 
  60. || ! is_object( $data ) 
  61. || ! isset( $data->source_key ) 
  62. || ! isset( $data->source ) 
  63. || ! isset( $data->plugin_version ) 
  64. || ! isset( $data->export_time ) 
  65. || ! isset( $data->notes ) 
  66. || ! isset( $data->memberships ) 
  67. || ! isset( $data->members ) 
  68. || ! isset( $data->settings ) 
  69. ) { 
  70. return false; 
  71. } else { 
  72. return apply_filters( 'ms_import_validate_object', $data ); 
  73.  
  74. /** 
  75. * The first action of the import process. This should prepare the site for 
  76. * a new import. 
  77. * @since 1.0.0 
  78. * @param bool $clear If true then existing memberships will be deleted. 
  79. */ 
  80. public function start( $clear ) { 
  81. $this->clear_import_obj_cache(); 
  82.  
  83. if ( $clear ) { 
  84. $this->clear_memberships(); 
  85.  
  86. // Remember this import. 
  87. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  88. $settings->import[ $this->source_key ] = date( 'Y-m-d H:i' ); 
  89. $settings->save(); 
  90.  
  91. /** 
  92. * The last action of the import process, responsible to clean up temp data. 
  93. * @since 1.0.0 
  94. */ 
  95. public function done() { 
  96. $this->clear_import_obj_cache(); 
  97.  
  98. /** 
  99. * Returns the import cache object. 
  100. * @since 1.0.0 
  101. * @param string $req_type The object type name that is requested. 
  102. * @return array The full import object cache. 
  103. */ 
  104. private function get_import_obj_cache( $req_type ) { 
  105. $cache = get_option( 'MS_Import_Obj_Cache', false ); 
  106. $cache = lib3()->array->get( $cache ); 
  107. if ( ! isset( $cache[$req_type] ) ) { $cache[$req_type] = array(); } 
  108.  
  109. return $cache; 
  110.  
  111. /** 
  112. * Stores the import cache object. 
  113. * @since 1.0.0 
  114. * @param array The full import object cache. 
  115. */ 
  116. private function set_import_obj_cache( $cache ) { 
  117. update_option( 'MS_Import_Obj_Cache', $cache ); 
  118.  
  119. /** 
  120. * Deletes the temporary import cache object. 
  121. * @since 1.0.0 
  122. */ 
  123. private function clear_import_obj_cache() { 
  124. delete_option( 'MS_Import_Obj_Cache' ); 
  125.  
  126. /** 
  127. * Stores data about an imported object. 
  128. * This is a temporary map of all objects created during import and 
  129. * associates the real object ID with an import ID to recognize them again. 
  130. * @since 1.0.0 
  131. * @param string $type Object type ('membership', ...) 
  132. * @param string $import_id Import-ID 
  133. * @param any $obj The imported object 
  134. */ 
  135. protected function store_import_obj( $type, $import_id, $obj ) { 
  136. $cache = $this->get_import_obj_cache( $type ); 
  137.  
  138. /** 
  139. * We store class-name and obj-ID in the array. 
  140. * The object ID will be different from the import_id! 
  141. */ 
  142. $cache[$type][$import_id] = array( 
  143. 'class' => get_class( $obj ),  
  144. 'id' => $obj->id,  
  145. ); 
  146.  
  147. $this->set_import_obj_cache( $cache ); 
  148.  
  149. /** 
  150. * Returns an object previously defined by store_import_obj(). 
  151. * This is a temporary map of all objects created during import and 
  152. * associates the real object ID with an import ID to recognize them again. 
  153. * @since 1.0.0 
  154. * @param string $type Object type ('membership', ...) 
  155. * @param string $import_id Import-ID 
  156. * @return MS_Model The requested object 
  157. */ 
  158. protected function get_import_obj( $type, $import_id ) { 
  159. $cache = $this->get_import_obj_cache( $type ); 
  160.  
  161. $obj = null; 
  162. if ( isset( $cache[$type][$import_id] ) ) { 
  163. $info = $cache[$type][$import_id]; 
  164. $obj = MS_Factory::load( $info['class'], $info['id'] ); 
  165. return $obj; 
  166.  
  167. /** 
  168. * Removes all subscriptions and memberships from the current site. 
  169. * This is done before the import if the "Replace existing data" flag is set. 
  170. * @since 1.0.0 
  171. */ 
  172. protected function clear_memberships() { 
  173. // Delete all Relationships. 
  174. $subscriptions = MS_Model_Relationship::get_subscriptions( 
  175. array( 'status' => 'all' ) 
  176. ); 
  177. foreach ( $subscriptions as $subscription ) { 
  178. $subscription->delete(); 
  179.  
  180. // Delete all Memberships. 
  181. $memberships = MS_Model_Membership::get_memberships(); 
  182. foreach ( $memberships as $membership ) { 
  183. if ( $membership->is_base() ) { continue; } 
  184. $membership->delete( true ); 
  185.  
  186. /** 
  187. * Import specific data: A single membership 
  188. * @since 1.0.0 
  189. * @param object $obj The import object 
  190. */ 
  191. public function import_membership( $obj ) { 
  192. $membership = MS_Factory::create( 'MS_Model_Membership' ); 
  193. $this->populate_membership( $membership, $obj ); 
  194. $membership->save(); 
  195.  
  196. $this->store_import_obj( 'membership', $obj->id, $membership ); 
  197.  
  198. /** 
  199. * Makes sure the specified period-type is a recognized value. 
  200. * @since 1.0.0 
  201. * @param string $period_type An unvalidated period string 
  202. * @return string A valid period-type string 
  203. */ 
  204. protected function valid_period( $period_type ) { 
  205. $res = 'days'; 
  206.  
  207. if ( strlen( $period_type ) > 0 ) { 
  208. switch ( $period_type[0] ) { 
  209. case 'd': $res = 'days'; break; 
  210. case 'w': $res = 'weeks'; break; 
  211. case 'm': $res = 'months'; break; 
  212. case 'y': $res = 'years'; break; 
  213.  
  214. return $res; 
  215.  
  216. /** 
  217. * Helper function used by import_membership 
  218. * This is a separate function because it is used to populate normal 
  219. * memberships and also child memberships 
  220. * @since 1.0.0 
  221. */ 
  222. protected function populate_membership( &$membership, $obj ) { 
  223. $membership->name = $obj->name; 
  224. $membership->description = $obj->description; 
  225. $membership->active = (bool) $obj->active; 
  226. $membership->private = (bool) $obj->private; 
  227. $membership->is_free = (bool) $obj->free; 
  228. $membership->is_setup_complete = true; 
  229.  
  230. if ( isset( $obj->period_type ) ) { 
  231. $obj->period_type = $this->valid_period( $obj->period_type ); 
  232. if ( isset( $obj->trial_period_type ) ) { 
  233. $obj->trial_period_type = $this->valid_period( $obj->trial_period_type ); 
  234.  
  235. if ( empty( $obj->pay_type ) ) { 
  236. $obj->pay_type = 'permanent'; 
  237.  
  238. $membership->period = array(); 
  239. $membership->pay_cycle_period = array(); 
  240.  
  241. switch ( $obj->pay_type ) { 
  242. case 'finite': 
  243. $membership->payment_type = MS_Model_Membership::PAYMENT_TYPE_FINITE; 
  244. if ( isset( $obj->period_unit ) ) { 
  245. $membership->period_unit = $obj->period_unit; 
  246. if ( isset( $obj->period_type ) ) { 
  247. $membership->period_type = $obj->period_type; 
  248. break; 
  249.  
  250. case 'recurring': 
  251. $membership->payment_type = MS_Model_Membership::PAYMENT_TYPE_RECURRING; 
  252. if ( isset( $obj->period_unit ) ) { 
  253. $membership->pay_cycle_period_unit = $obj->period_unit; 
  254. if ( isset( $obj->period_type ) ) { 
  255. $membership->pay_cycle_period_type = $obj->period_type; 
  256. if ( isset( $obj->period_repetitions ) ) { 
  257. $membership->pay_cycle_repetitions = $obj->period_repetitions; 
  258. break; 
  259.  
  260. case 'date': 
  261. $membership->payment_type = MS_Model_Membership::PAYMENT_TYPE_DATE_RANGE; 
  262. if ( isset( $obj->period_start ) ) { 
  263. $membership->period_date_start = $obj->period_start; 
  264. if ( isset( $obj->period_end ) ) { 
  265. $membership->period_date_end = $obj->period_end; 
  266. break; 
  267.  
  268. default: 
  269. $membership->payment_type = MS_Model_Membership::PAYMENT_TYPE_PERMANENT; 
  270. break; 
  271.  
  272. if ( ! $membership->is_free ) { 
  273. if ( isset( $obj->price ) ) { 
  274. $membership->price = $obj->price; 
  275.  
  276. if ( isset( $obj->trial ) ) { 
  277. $membership->trial_period_enabled = (bool) $obj->trial; 
  278.  
  279. if ( $membership->trial_period_enabled ) { 
  280. $membership->trial_period = array(); 
  281. if ( isset( $obj->trial_price ) ) { 
  282. $membership->trial_price = $obj->trial_price; 
  283. if ( isset( $obj->trial_period_unit ) ) { 
  284. $membership->trial_period['period_unit'] = $obj->trial_period_unit; 
  285. if ( isset( $obj->trial_period_type ) ) { 
  286. $membership->trial_period['period_type'] = $obj->trial_period_type; 
  287.  
  288. // Remember where this membership comes from. 
  289. $membership->source = $this->source_key; 
  290. $membership->source_id = $obj->id; 
  291.  
  292. // We set this last because it might change some other values as well... 
  293. $membership->type = $obj->type; 
  294.  
  295. /** 
  296. * Import specific data: A single member 
  297. * @since 1.0.0 
  298. * @param object $obj The import object 
  299. */ 
  300. public function import_member( $obj ) { 
  301. $wpuser = get_user_by( 'email', $obj->email ); 
  302. lib3()->array->equip( $obj, 'username', 'email', 'payment', 'subscriptions' ); 
  303.  
  304. if ( $wpuser ) { 
  305. $member = MS_Factory::load( 'MS_Model_Member', $wpuser->ID ); 
  306. } else { 
  307. $wpuser = wp_create_user( $obj->username, '', $obj->email ); 
  308. if ( is_numeric( $wpuser ) ) { 
  309. $member = MS_Factory::load( 'MS_Model_Member', $wpuser ); 
  310. } else { 
  311. $this->errors[] = sprintf( 
  312. __( 'Could not import Member <strong>%1$s</strong> (%2$s)', 'membership2' ),  
  313. esc_attr( $obj->username ),  
  314. esc_attr( $obj->email ) 
  315. ); 
  316.  
  317. // We could not find/create the user, so don't import this item. 
  318. return; 
  319.  
  320. // Import the member details. 
  321. $member->is_member = true; 
  322.  
  323. $pay = $obj->payment; 
  324. if ( is_array( $pay ) ) { $pay = (object) $pay; } 
  325. elseif ( ! is_object( $pay ) ) { $pay = (object) array(); } 
  326.  
  327. lib3()->array->equip( 
  328. $pay,  
  329. 'stripe_card_exp',  
  330. 'stripe_card_num',  
  331. 'stripe_customer',  
  332. 'authorize_card_exp',  
  333. 'authorize_card_num',  
  334. 'authorize_cim_profile',  
  335. 'authorize_cim_payment_profile' 
  336. ); 
  337.  
  338. // Stripe. 
  339. $gw_stripe = MS_Gateway_Stripe::ID; 
  340. $member->set_gateway_profile( $gw_stripe, 'card_exp', $pay->stripe_card_exp ); 
  341. $member->set_gateway_profile( $gw_stripe, 'card_num', $pay->stripe_card_num ); 
  342. $member->set_gateway_profile( $gw_stripe, 'customer_id', $pay->stripe_customer ); 
  343.  
  344. // Authorize. 
  345. $gw_auth = MS_Gateway_Authorize::ID; 
  346. $member->set_gateway_profile( $gw_auth, 'card_exp', $pay->authorize_card_exp ); 
  347. $member->set_gateway_profile( $gw_auth, 'card_num', $pay->authorize_card_num ); 
  348. $member->set_gateway_profile( $gw_auth, 'cim_profile_id', $pay->authorize_cim_profile ); 
  349. $member->set_gateway_profile( $gw_auth, 'cim_payment_profile_id', $pay->authorize_cim_payment_profile ); 
  350.  
  351. $member->save(); 
  352.  
  353. // Import all memberships of the member 
  354. foreach ( $obj->subscriptions as $subscription ) { 
  355. $subscription = (object) $subscription; 
  356. $this->import_subscription( $member, $subscription ); 
  357.  
  358. /** 
  359. * Import specific data: A single subscription (= relationship) 
  360. * @since 1.0.0 
  361. * @param object $obj The import object 
  362. */ 
  363. protected function import_subscription( $member, $obj ) { 
  364. $membership = $this->get_import_obj( 'membership', $obj->membership ); 
  365.  
  366. if ( empty( $membership ) ) { 
  367. $this->errors[] = sprintf( 
  368. __( 'Could not import a Membership for User <strong>%1$s</strong> (%2$s)', 'membership2' ),  
  369. esc_attr( $obj->username ),  
  370. esc_attr( $obj->email ) 
  371. ); 
  372. return; 
  373.  
  374. if ( $membership->is_base() ) { 
  375. $this->errors[] = sprintf( 
  376. __( 'Did not import the base membership %2$s for <strong>%1$s</strong>', 'membership2' ),  
  377. esc_attr( $obj->username ),  
  378. esc_attr( $membership->name ) 
  379. ); 
  380. return; 
  381.  
  382. $subscription = $member->add_membership( $membership->id ); 
  383. $subscription->status = $obj->status; 
  384. $subscription->gateway_id = $obj->gateway; 
  385. $subscription->start_date = $obj->start; 
  386. $subscription->expire_date = $obj->end; 
  387.  
  388. if ( isset( $obj->trial_finished ) ) { 
  389. $subscription->trial_period_completed = $obj->trial_finished; 
  390. if ( isset( $obj->trial_end ) ) { 
  391. $subscription->trial_expire_date = $obj->trial_end; 
  392.  
  393. // Remember where this subscription comes from. 
  394. $subscription->source = $this->source_key; 
  395. $membership->source_id = $obj->id; 
  396. $subscription->save(); 
  397.  
  398. $is_paid = false; 
  399.  
  400. // Import invoices for this subscription 
  401. if ( ! empty( $obj->invoices ) && is_array( $obj->invoices ) ) { 
  402. foreach ( $obj->invoices as $invoice ) { 
  403. $invoice = (object) $invoice; 
  404. $this->import_invoice( $subscription, $invoice ); 
  405. $is_paid = true; 
  406.  
  407. // Add a payment for active subscriptions. 
  408. if ( ! $is_paid && MS_Model_Relationship::STATUS_ACTIVE == $subscription->status ) { 
  409. $subscription->add_payment( 
  410. $membership->price,  
  411. 'admin',  
  412. 'imported' 
  413. ); 
  414.  
  415. /** 
  416. * Import specific data: A single invoice 
  417. * @since 1.0.0 
  418. * @param object $obj The import object 
  419. */ 
  420. protected function import_invoice( $subscription, $obj ) { 
  421. $ms_invoice = MS_Model_Invoice::create_invoice( $subscription ); 
  422. $ms_invoice->invoice_number = $obj->invoice_number; 
  423. $ms_invoice->external_id = $obj->external_id; 
  424. $ms_invoice->gateway_id = $obj->gateway; 
  425. $ms_invoice->status = $obj->status; 
  426. $ms_invoice->coupon_id = $obj->coupon; 
  427. $ms_invoice->currency = $obj->currency; 
  428. $ms_invoice->amount = $obj->amount; 
  429. $ms_invoice->discount = $obj->discount; 
  430. $ms_invoice->pro_rate = $obj->discount2; 
  431. $ms_invoice->total = $obj->total; 
  432. $ms_invoice->trial_period = $obj->for_trial; 
  433. $ms_invoice->due_date = $obj->due; 
  434. $ms_invoice->notes = $obj->notes; 
  435.  
  436. // Remember where this invoice comes from. 
  437. $ms_invoice->source = $this->source_key; 
  438. $ms_invoice->save(); 
  439.  
  440. $subscription->add_payment( 
  441. $ms_invoice->amount,  
  442. $ms_invoice->gateway_id,  
  443. 'imported-' . $ms_invoice->id 
  444. ); 
  445.  
  446. /** 
  447. * Import specific data: A single setting 
  448. * @since 1.0.0 
  449. * @param object $obj The import object 
  450. */ 
  451. public function import_setting( $setting, $value ) { 
  452. switch ( $setting ) { 
  453. // Import Add-On states. 
  454. case 'addons': 
  455. $model = MS_Factory::load( 'MS_Model_Addon' ); 
  456. foreach ( $value as $addon => $state ) { 
  457. if ( $state ) { 
  458. $model->enable( $addon ); 
  459. } else { 
  460. $model->disable( $addon ); 
  461. break; 
  462.  
  463. /** 
  464. * ------------------------------------------------------------------------- 
  465. * ACCESS IMPORTED DATA 
  466. */ 
  467.  
  468. /** 
  469. * Checks if the specified source/ID need matching. 
  470. * If the source or source_id is empty then the return value TRUE means that 
  471. * there is *any* transaction that needs matching. 
  472. * See MS_Helper_Listtable_TransactionMatching for a list of sources. 
  473. * @since 1.0.1.2 
  474. * @param int $source_id The M1 sub_id. 
  475. * @param string $source The import source. 
  476. * @return bool True if the transaction details need matching. 
  477. */ 
  478. static public function can_match( $source_id = null, $source = null ) { 
  479. $res = false; 
  480. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  481.  
  482. if ( empty( $source_id ) || empty( $source ) ) { 
  483. $src = $settings->get_custom_setting( 'import_match' ); 
  484. $src = lib3()->array->get( $src ); 
  485.  
  486. foreach ( $src as $lst ) { 
  487. if ( is_array( $lst ) ) { 
  488. if ( count( $lst ) ) { 
  489. $res = true; 
  490. break; 
  491. } else { 
  492. $lst = $settings->get_custom_setting( 'import_match', $source ); 
  493.  
  494. if ( ! is_array( $lst ) ) { 
  495. $lst = array(); 
  496.  
  497. $res = in_array( $source_id, $lst ); 
  498.  
  499. return $res; 
  500.  
  501. /** 
  502. * Remembers that the source_id needs to be matched with a membership_id to 
  503. * complete the connected transaction. 
  504. * See MS_Helper_Listtable_TransactionMatching for a list of sources. 
  505. * @since 1.0.1.2 
  506. * @param int $source_id The M1 sub_id. 
  507. * @param string $source The import source. 
  508. */ 
  509. static public function need_matching( $source_id, $source ) { 
  510. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  511.  
  512. $lst = $settings->get_custom_setting( 'import_match', $source ); 
  513.  
  514. if ( ! is_array( $lst ) ) { 
  515. $lst = array(); 
  516.  
  517. if ( ! in_array( $source_id, $lst ) ) { 
  518. $lst[] = $source_id; 
  519.  
  520. $settings->set_custom_setting( 'import_match', $source, $lst ); 
  521. $settings->save(); 
  522.  
  523. /** 
  524. * Remove the source_id from the missing-matching-list again. 
  525. * See MS_Helper_Listtable_TransactionMatching for a list of sources. 
  526. * @since 1.0.1.2 
  527. * @param int $source_id The M1 sub_id. 
  528. * @param string $source The import source. 
  529. */ 
  530. static public function dont_need_matching( $source_id, $source ) { 
  531. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  532.  
  533. $lst = $settings->get_custom_setting( 'import_match', $source ); 
  534.  
  535. if ( ! is_array( $lst ) ) { 
  536. $lst = array(); 
  537.  
  538. foreach ( $lst as $key => $id ) { 
  539. if ( $id == $source_id ) { 
  540. unset( $lst[$key] ); 
  541.  
  542. $settings->set_custom_setting( 'import_match', $source, $lst ); 
  543. $settings->save(); 
  544.  
  545. /** 
  546. * Save a permanent matching between the specified membership and the 
  547. * transaction source. 
  548. * See MS_Helper_Listtable_TransactionMatching for a list of sources. 
  549. * @since 1.0.1.2 
  550. * @param int $membership_id The M2 membership_id. 
  551. * @param string $source_id The matching-ID to identify transactions. 
  552. * @param string $source The matching-key to identify transactions. 
  553. * @return bool True if the matching was saved. 
  554. */ 
  555. static public function match_with_source( $membership_id, $source_id, $source ) { 
  556. $membership = MS_Factory::load( 'MS_Model_Membership', $membership_id ); 
  557.  
  558. if ( ! $membership || ! $membership->is_valid() ) { 
  559. return false; 
  560.  
  561. // First make sure that no other membership is matched to the source. 
  562. $memberships = MS_Model_Membership::get_memberships(); 
  563.  
  564. foreach ( $memberships as $item ) { 
  565. if ( 'm1' == $source ) { 
  566. if ( $item->source_id == $source_id ) { 
  567. $item->source_id = ''; 
  568. $item->save(); 
  569. } else { 
  570. $data = $item->get_custom_data( 'matching' ); 
  571. $changed = false; 
  572.  
  573. if ( ! is_array( $data ) ) { continue; } 
  574. if ( empty( $data[$source] ) ) { continue; } 
  575. if ( ! is_array( $data[$source] ) ) { continue; } 
  576.  
  577. foreach ( $data[$source] as $key => $id ) { 
  578. if ( $id == $source_id ) { 
  579. unset( $data[$source][$key] ); 
  580. $changed = true; 
  581. if ( $changed ) { 
  582. $item->set_custom_data( 'matching', $data ); 
  583. $item->save(); 
  584.  
  585. // Then add the matching to the specified membership. 
  586. if ( 'm1' == $source ) { 
  587. if ( $membership->source_id ) { 
  588. // This membership is already matched with an M1 sub_id. 
  589. return false; 
  590.  
  591. $membership->source = 'membership'; 
  592. $membership->source_id = $source_id; 
  593. } else { 
  594. $data = lib3()->array->get( 
  595. $membership->get_custom_data( 'matching' ) 
  596. ); 
  597.  
  598. if ( empty( $data[$source] ) || ! array( $data[$source] ) ) { 
  599. $data[$source] = array(); 
  600.  
  601. $data[$source][] = $source_id; 
  602. $membership->set_custom_data( 'matching', $data ); 
  603. $membership->save(); 
  604.  
  605. self::dont_need_matching( $source_id, $source ); 
  606.  
  607. return true; 
  608.  
  609. /** 
  610. * Tries to process a single transaction again. 
  611. * This function is only useful when the transaction matching was added 
  612. * before callig it again. 
  613. * @since 1.0.1.2 
  614. * @param int $transaction_id The ID of the transaction log item. 
  615. * @return bool True means that the transaction was processed. 
  616. */ 
  617. static public function retry_to_process( $transaction_id ) { 
  618. $res = false; 
  619. $log = MS_Factory::load( 'MS_Model_Transactionlog', $transaction_id ); 
  620.  
  621. if ( empty( $log ) || $log->id != $transaction_id ) { 
  622. // Could not find the requested transaction log item. 
  623. return $res; 
  624.  
  625. if ( 'err' != $log->state ) { 
  626. // The transaction was already processed (automatically or manual). 
  627. return $res; 
  628.  
  629. $post_data = $log->post; 
  630. if ( empty( $post_data ) || ! is_array( $post_data ) ) { 
  631. // We do not have POST data available for the transaction. 
  632. // Re-Processing is not possible. 
  633. return $res; 
  634.  
  635. $orig_post = $_POST; 
  636. $orig_req = $_REQUEST; 
  637.  
  638. // Set up the PHP environment to process the transaction again. 
  639. $gateway = MS_Model_Gateway::factory( $log->gateway_id ); 
  640. $_POST = $post_data; 
  641. $_REQUEST = $post_data; 
  642.  
  643. $invoice = false; 
  644. switch ( $log->method ) { 
  645. case 'request': 
  646. // Intentionally not implemented: 
  647. // Request payment needs a subscription to work. 
  648. break; 
  649.  
  650. case 'process': 
  651. // Intentionally not implemented: 
  652. // Request payment needs a subscription to work. 
  653. break; 
  654.  
  655. case 'handle': 
  656. $log = $gateway->handle_return( $log ); 
  657. break; 
  658.  
  659. if ( 'ok' == $log->state ) { 
  660. $res = true; 
  661.  
  662. $_POST = $orig_post; 
  663. $_REQUEST = $orig_req; 
  664.  
  665. return $res; 
  666.  
  667. /** 
  668. * Find a M2 membership by the M1 sub_id. 
  669. * @since 1.0.1.2 
  670. * @param int $source_id The M1 sub_id. 
  671. * @return MS_Model_Membership|null The M2 membership. 
  672. */ 
  673. static public function membership_by_source_id( $source_id ) { 
  674. $res = null; 
  675. $args = array( 'include_guest' => 0 ); 
  676. $memberships = MS_Model_Membership::get_memberships( $args ); 
  677.  
  678. if ( ! is_numeric( $source_id ) || $source_id < 1 ) { 
  679. return $res; 
  680. $source_id = intval( $source_id ); 
  681.  
  682. foreach ( $memberships as $membership ) { 
  683. if ( $membership->source_id == $source_id ) { 
  684. $res = $membership; 
  685. break; 
  686.  
  687. return $res; 
  688.  
  689. /** 
  690. * Find a M2 membership by a custom matching ID. 
  691. * The matching key and matching ID are stored in the memberships custom 
  692. * data array. 
  693. * See MS_Helper_Listtable_TransactionMatching for a list of matching_keys. 
  694. * @since 1.0.1.2 
  695. * @param int $matching_key The matching key. 
  696. * @param int $matching_id The matching ID. 
  697. * @return MS_Model_Membership|null The M2 membership. 
  698. */ 
  699. static public function membership_by_matching( $matching_key, $matching_id ) { 
  700. $res = null; 
  701. $args = array( 'include_guest' => 0 ); 
  702. $memberships = MS_Model_Membership::get_memberships( $args ); 
  703.  
  704. foreach ( $memberships as $membership ) { 
  705. $data = $membership->get_custom_data( 'matching' ); 
  706. if ( empty( $data ) || ! is_array( $data ) ) { continue; } 
  707. if ( ! isset( $data[$matching_key] ) ) { continue; } 
  708. $ids = lib3()->array->get( $data[$matching_key] ); 
  709.  
  710. foreach ( $ids as $id ) { 
  711. if ( $matching_id == $id ) { 
  712. $res = $membership; 
  713. break 2; 
  714.  
  715. return $res; 
  716.  
  717. /** 
  718. * Tries to find a subscription based on the user-ID and M1 sub_id 
  719. * About matching types: 
  720. * 'source' .. Default, which will check the memberships 'source_id' 
  721. * attribute to find the matching membership. 
  722. * Other values are looked up in the memberships custom data array. 
  723. * See MS_Helper_Listtable_TransactionMatching for a list of sources. 
  724. * @since 1.0.1.2 
  725. * @param int $user_id The user-ID. 
  726. * @param string|int $matching_id The matching-ID (M1 sub_id, a btn_id, etc). 
  727. * @param string $type The matching type to apply. Default is 'source'. 
  728. * @param string $gateway The payment gateway. 
  729. * @return MS_Model_Relationship|null The subscription object. 
  730. */ 
  731. static public function find_subscription( $user_id, $matching_id, $type = 'source', $gateway = 'admin' ) { 
  732. $res = null; 
  733.  
  734. if ( ! is_numeric( $user_id ) ) { 
  735. // Seems like we got invalid values... 
  736. return $res; 
  737.  
  738. $user_id = intval( $user_id ); 
  739. $matching_id = trim( $matching_id ); 
  740.  
  741. if ( $user_id < 1 || empty( $matching_id ) ) { 
  742. // Seems like user or sub_id are empty or invalid. 
  743. return $res; 
  744.  
  745. $member = MS_Factory::load( 'MS_Model_Member', $user_id ); 
  746. if ( $user_id != $member->id ) { 
  747. // The user_id is invalid. 
  748. return $res; 
  749.  
  750. if ( 'source' == $type ) { 
  751. $membership = self::membership_by_source_id( $matching_id ); 
  752. } else { 
  753. $membership = self::membership_by_matching( $type, $matching_id ); 
  754.  
  755. if ( ! $membership || ! $membership->is_valid() ) { 
  756. // The sub_id is invalid. 
  757. return $res; 
  758.  
  759. // Finally we have a member and a membership. Fetch the subscription! 
  760. $res = $member->get_subscription( $membership->id ); 
  761. if ( ! $res ) { 
  762. $res = $member->add_membership( $membership->id, $gateway ); 
  763.  
  764. return $res;