/app/helper/listtable/class-ms-helper-listtable-transactionmatching.php

  1. <?php 
  2. /** 
  3. * List unmatched M1 sub_ids and external payment options with membership_ids. 
  4. * 
  5. * Currently supported Sources: 
  6. * m1 .. M1 subscription 
  7. * pay_btn .. PayPal Payment Button 
  8. * 
  9. * Currently supported matching_keys 
  10. * pay_btn .. PayPal Payment Button 
  11. * 
  12. * The M1 matching_key is saved in the memberships source_id and is referenced 
  13. * in MS_Model_Import::find_subscription() as 'source' - and not as 'm1'! 
  14. * 
  15. * @since 1.0.1.2 
  16. */ 
  17. class MS_Helper_ListTable_TransactionMatching extends MS_Helper_ListTable { 
  18.  
  19. /** 
  20. * This ID is used as class-name for the list output and also in various 
  21. * filter names in MS_Helper_ListTable. 
  22. * 
  23. * @var string 
  24. */ 
  25. protected $id = 'transaction_matching'; 
  26.  
  27. /** 
  28. * Currently selected matching source; 
  29. * 
  30. * Supported types are 
  31. * m1 .. Imported from M1 
  32. * pay_btn .. Custom PayPal Payment Button 
  33. * 
  34. * @var string 
  35. */ 
  36. protected $source = false; 
  37.  
  38. /** 
  39. * Currently selected source_id that should be matched. 
  40. * 
  41. * @var mixed 
  42. */ 
  43. protected $source_id = false; 
  44.  
  45. /** 
  46. * Constructor, defines general list table attributes. 
  47. * 
  48. * @since 1.0.1.2 
  49. */ 
  50. public function __construct() { 
  51. // 'singular' just added for fun... 
  52. // 'plural' is used as class name for the list. 
  53. parent::__construct( 
  54. array( 
  55. 'singular' => 'transaction_match',  
  56. 'plural' => 'transaction_matches',  
  57. ); 
  58.  
  59. /** 
  60. * Defines the columns of the list table 
  61. * 
  62. * @since 1.0.1.2 
  63. * @return array 
  64. */ 
  65. public function get_columns() { 
  66. $currency = MS_Plugin::instance()->settings->currency; 
  67.  
  68. $columns = apply_filters( 
  69. 'ms_helper_listtable_transactionmatching_columns',  
  70. array( 
  71. 'id' => __( 'ID', 'membership2' ),  
  72. 'date' => __( 'Time', 'membership2' ),  
  73. 'status' => '',  
  74. 'method' => '',  
  75. 'gateway' => __( 'Gateway', 'membership2' ),  
  76. 'amount' => __( 'Amount', 'membership2' ),  
  77. 'invoice' => __( 'Invoice', 'membership2' ),  
  78. 'note' => __( 'Details', 'membership2' ),  
  79. ); 
  80.  
  81. $columns = apply_filters( 
  82. 'ms_helper_listtable_transactionmatching_get_columns',  
  83. $columns,  
  84. $currency 
  85. ); 
  86.  
  87. return $columns; 
  88.  
  89. /** 
  90. * Defines, which columns should be output as hidden columns. 
  91. * 
  92. * @since 1.0.1.2 
  93. * @return array 
  94. */ 
  95. public function get_hidden_columns() { 
  96. return apply_filters( 
  97. 'ms_helper_listtable_transactionmatching_hidden_columns',  
  98. array() 
  99. ); 
  100.  
  101. /** 
  102. * Defines, which columns can be sorted. 
  103. * 
  104. * @since 1.0.1.2 
  105. * @return array 
  106. */ 
  107. public function get_sortable_columns() { 
  108. return apply_filters( 
  109. 'ms_helper_listtable_transactionmatching_sortable_columns',  
  110. array() 
  111. ); 
  112.  
  113. /** 
  114. * Defines available bulk actions. 
  115. * 
  116. * @since 1.0.1.2 
  117. * @return array 
  118. */ 
  119. public function get_bulk_actions() { 
  120. return apply_filters( 
  121. 'ms_helper_listtable_transactionmatching_bulk_actions',  
  122. array() 
  123. ); 
  124.  
  125. /** 
  126. * Loads the items that are displayed on the current list page. 
  127. * 
  128. * @since 1.0.1.2 
  129. */ 
  130. public function prepare_items() { 
  131. $this->_column_headers = array( 
  132. $this->get_columns(),  
  133. $this->get_hidden_columns(),  
  134. $this->get_sortable_columns(),  
  135. ); 
  136.  
  137. $current_page = $this->get_pagenum(); 
  138.  
  139. $args = array( 
  140. 'posts_per_page' => -1,  
  141. 'offset' => 0,  
  142. ); 
  143.  
  144. if ( ! empty( $_GET['source'] ) && ! empty( $_GET['source_id'] ) ) { 
  145. $this->source = $_GET['source']; 
  146. $this->source_id = $_GET['source_id']; 
  147.  
  148. $args['state'] = 'err'; 
  149. $args['source'] = array( $this->source_id, $this->source ); 
  150.  
  151. $total_items = MS_Model_Transactionlog::get_item_count( $args ); 
  152.  
  153. $this->items = apply_filters( 
  154. 'ms_helper_listtable_transactionmatching_items',  
  155. MS_Model_Transactionlog::get_items( $args ) 
  156. ); 
  157.  
  158. $this->set_pagination_args( 
  159. array( 
  160. 'total_items' => $total_items,  
  161. 'per_page' => $per_page,  
  162. ); 
  163.  
  164. /** 
  165. * Displays a custom search box for this list. 
  166. * 
  167. * @since 1.0.1.2 
  168. */ 
  169. public function search_box( $text = null, $input_id = 'search' ) { 
  170. // Do not display anything. 
  171. // Transaction logs cannot be searched currently 
  172.  
  173. /** 
  174. * Return true if the current list is a view except "all" 
  175. * 
  176. * In this list the function always returns true to force the filters to 
  177. * be displayed. 
  178. * 
  179. * @since 1.0.0 
  180. * @return bool 
  181. */ 
  182. public function is_view() { 
  183. return true; 
  184.  
  185. /** 
  186. * Returns a human readable description of the import source. 
  187. * 
  188. * @since 1.0.0 
  189. * @param string $source The import source. 
  190. * @param mixed $source_id The original ID. 
  191. * @return string The label. 
  192. */ 
  193. protected function get_source_label( $source, $source_id ) { 
  194. $label = __( 'Unknown ID: %s', 'membership2' ); 
  195.  
  196. switch ( $source ) { 
  197. case 'pay_btn': 
  198. $label = __( 'PayPal Payment Button #%s', 'membership2' ); 
  199. break; 
  200.  
  201. case 'm1': 
  202. default: 
  203. $label = __( 'M1 Subscription Level #%s', 'membership2' ); 
  204. break; 
  205.  
  206. $label = sprintf( $label, $source_id ); 
  207.  
  208. return $label; 
  209.  
  210. /** 
  211. * Defines predefines filters for this list table. 
  212. * 
  213. * Filters display the unmatched source_id values. 
  214. * 
  215. * @since 1.0.1.2 
  216. * @return array 
  217. */ 
  218. public function get_views() { 
  219. $views = array(); 
  220.  
  221. if ( MS_Model_Import::can_match() ) { 
  222. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  223. $lst = $settings->get_custom_setting( 'import_match' ); 
  224. if ( ! is_array( $lst ) ) { 
  225. $lst = array(); 
  226.  
  227. $views['label'] = array( 
  228. 'label' => __( 'Undefined transactions:', 'membership2' ),  
  229. ); 
  230.  
  231. foreach ( $lst as $source => $ids ) { 
  232. foreach ( $ids as $source_id ) { 
  233. $key = $source . '_' . $source_id; 
  234. $label = $this->get_source_label( $source, $source_id ); 
  235.  
  236. $views[$key] = array( 
  237. 'label' => $label,  
  238. 'url' => add_query_arg( 
  239. array( 'source' => $source, 'source_id' => $source_id ) 
  240. ),  
  241. ); 
  242.  
  243. return apply_filters( 
  244. 'ms_helper_listtable_transactionmatching_views',  
  245. $views 
  246. ); 
  247.  
  248. /** 
  249. * Display custom text after the view-links are rendered. 
  250. * 
  251. * @since 1.0.1.2 
  252. */ 
  253. public function views() { 
  254. parent::views(); 
  255.  
  256. if ( ! $this->source || ! $this->source_id ) { 
  257. if ( ! MS_Model_Import::can_match() ) { 
  258. $url = MS_Controller_Plugin::get_admin_url( 
  259. 'billing',  
  260. array( 'show' => 'logs' ) 
  261. ); 
  262.  
  263. echo '<p>'; 
  264. _e( 'No suitable transaction found.', 'membership2' ); 
  265. echo '</p><p>'; 
  266. printf( 
  267. '<strong>%s</strong><br />',  
  268. __( 'Nothing to do right now:', 'membership2' ) 
  269. ); 
  270. _e( 'Transactions that can be automatically matched will appear here when they are processed by a payment gateway.<br>So simply check again later after new payments were made.', 'membership2' ); 
  271. echo '</p><p>'; 
  272. printf( 
  273. __( 'If you are impatient then "Retry" some error-state transactions in the %sTransaction Logs%s section and then see if they appear on this page.', 'membership2' ),  
  274. '<a href="' . $url . '">',  
  275. '</a>' 
  276. ); 
  277. echo '</p>'; 
  278.  
  279. // Don't display anything if no matching source was selected. 
  280. return; 
  281.  
  282. if ( ! MS_Model_Import::can_match( $this->source_id, $this->source ) ) { 
  283. // For this transaction details is no matching possible right now. 
  284. return; 
  285.  
  286. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  287. $label = $this->get_source_label( $this->source, $this->source_id ); 
  288. $memberships = MS_Model_Membership::get_memberships(); 
  289.  
  290. $options = array( '0' => '-----' ); 
  291. foreach ( $memberships as $item ) { 
  292. if ( $item->is_system() ) { continue; } 
  293. if ( 'm1' == $this->source ) { 
  294. // Only one membership can be matched with a M1 sub_id. 
  295. if ( $item->source_id ) { continue; } 
  296.  
  297. if ( $item->is_free() ) { 
  298. $options[$item->id] = sprintf( 
  299. '%s • %s',  
  300. $item->name,  
  301. __( 'Free', 'membership2' ) 
  302. ); 
  303. } else { 
  304. $options[$item->id] = sprintf( 
  305. '%s • %s • %s',  
  306. $item->name,  
  307. $settings->currency . ' ' . MS_Helper_Billing::format_price( $item->price ),  
  308. $item->get_payment_type_desc() 
  309. ); 
  310.  
  311. asort( $options ); 
  312.  
  313. $field_memberships = array( 
  314. 'id' => 'match_with',  
  315. 'type' => MS_Helper_Html::INPUT_TYPE_SELECT,  
  316. 'before' => sprintf( 
  317. __( '2. Link %s with', 'membership2' ),  
  318. '<b>' . $label . '</b>' 
  319. ),  
  320. 'field_options' => $options,  
  321. ); 
  322. $field_action = array( 
  323. 'id' => 'action',  
  324. 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN,  
  325. 'value' => MS_Controller_Import::AJAX_ACTION_MATCH,  
  326. ); 
  327. $field_source = array( 
  328. 'id' => 'source',  
  329. 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN,  
  330. 'value' => $this->source,  
  331. ); 
  332. $field_source_id = array( 
  333. 'id' => 'source_id',  
  334. 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN,  
  335. 'value' => $this->source_id,  
  336. ); 
  337. $field_save = array( 
  338. 'class' => 'action-match',  
  339. 'type' => MS_Helper_Html::INPUT_TYPE_SUBMIT,  
  340. 'value' => __( 'Save', 'membership2' ),  
  341. ); 
  342. $field_retry_action = array( 
  343. 'class' => 'retry_action',  
  344. 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN,  
  345. 'value' => MS_Controller_Import::AJAX_ACTION_RETRY,  
  346. ); 
  347. $field_retry_nonce = array( 
  348. 'class' => 'retry_nonce',  
  349. 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN,  
  350. 'value' => wp_create_nonce( MS_Controller_Import::AJAX_ACTION_RETRY ),  
  351. ); 
  352.  
  353. ?> 
  354. <div class="cf"></div> 
  355. <form class="transaction-matching"> 
  356. <?php 
  357. wp_nonce_field( MS_Controller_Import::AJAX_ACTION_MATCH ); 
  358. MS_Helper_Html::html_element( $field_retry_action ); 
  359. MS_Helper_Html::html_element( $field_retry_nonce ); 
  360. MS_Helper_Html::html_element( $field_action ); 
  361. MS_Helper_Html::html_element( $field_source ); 
  362. MS_Helper_Html::html_element( $field_source_id ); 
  363. ?> 
  364. <div class="content"> 
  365. <p><?php 
  366. printf( 
  367. __( '1. Below is a list of past "%s" transactions. Examine these transactions to find out which Membership they refer to.', 'membership2' ),  
  368. '<b>' . $label . '</b>' 
  369. ); 
  370. ?></p> 
  371. <hr /> 
  372. <p><?php 
  373. MS_Helper_Html::html_element( $field_memberships ); 
  374. ?></p> 
  375. <div style="margin-left:14px"> 
  376. <?php 
  377. _e( 'Notes:', 'membership2' ); 
  378. ?> 
  379. <br /> 
  380. <?php 
  381. _e( 'This choice is saved so new transactions are processed automatically from now on.', 'membership2' ); 
  382. ?> 
  383. <br /> 
  384. <?php 
  385. _e( 'Upon saving all transactions below will be processed, this might take a while.', 'membership2' ); 
  386. ?> 
  387. </div> 
  388. </div> 
  389. <div class="buttons"> 
  390. <?php MS_Helper_Html::html_element( $field_save ); ?> 
  391. </div> 
  392. </form> 
  393. <?php 
  394.  
  395. /** 
  396. * Custom display function to hide item table for invalid filter options. 
  397. * 
  398. * @since 1.0.1.2 
  399. */ 
  400. public function display() { 
  401. if ( MS_Model_Import::can_match( $this->source_id, $this->source ) ) { 
  402. parent::display(); 
  403.  
  404. /** 
  405. * Returns the row-class to be used for the specified table item. 
  406. * 
  407. * @param object $item The current item. 
  408. * @return string Class to be added to the table row. 
  409. */ 
  410. protected function single_row_class( $item ) { 
  411. $class = 'log-' . $item->state; 
  412.  
  413. if ( $item->is_manual ) { 
  414. $class .= ' is-manual'; 
  415.  
  416. return $class; 
  417.  
  418. /** 
  419. * Output column content 
  420. * 
  421. * @since 1.0.1.2 
  422. * @param object $item The item that is displayed. 
  423. * @return string The HTML code to output. 
  424. */ 
  425. public function column_id( $item, $column_name ) { 
  426. $html = $item->id; 
  427. return $html; 
  428.  
  429. /** 
  430. * Output column content 
  431. * 
  432. * @since 1.0.1.2 
  433. * @param object $item The item that is displayed. 
  434. * @return string The HTML code to output. 
  435. */ 
  436. public function column_date( $item, $column_name ) { 
  437. $html = MS_Helper_Period::format_date( $item->date, 'Y-m-d H:i' ); 
  438.  
  439. return $html; 
  440.  
  441. /** 
  442. * Output column content 
  443. * 
  444. * @since 1.0.1.2 
  445. * @param object $item The item that is displayed. 
  446. * @return string The HTML code to output. 
  447. */ 
  448. public function column_status( $item, $column_name ) { 
  449. $html = '<span class="log-status"><i class="wpmui-fa log-status-icon"></i></span>'; 
  450.  
  451. return $html; 
  452.  
  453. /** 
  454. * Output column content 
  455. * 
  456. * @since 1.0.1.2 
  457. * @param object $item The item that is displayed. 
  458. * @return string The HTML code to output. 
  459. */ 
  460. public function column_method( $item, $column_name ) { 
  461. $html = '<span class="log-method" data-info="%2$s"><i class="wpmui-fa wpmui-%1$s"></i></span>'; 
  462. $icon = ''; 
  463. $info = __( 'Unknown method', 'membership2' ); 
  464.  
  465. switch ( $item->method ) { 
  466. case 'handle': 
  467. $icon = 'fa-cloud-download'; 
  468. $info = __( 'Gateway called the IPN URL', 'membership2' ); 
  469. break; 
  470.  
  471. case 'request': 
  472. $icon = 'fa-refresh'; 
  473. $info = __( 'Plugin requested a recuring payment', 'membership2' ); 
  474. break; 
  475.  
  476. case 'process': 
  477. $icon = 'fa-shopping-cart'; 
  478. $info = __( 'User entered payment details', 'membership2' ); 
  479. break; 
  480.  
  481. $html = sprintf( $html, $icon, $info ); 
  482.  
  483. return $html; 
  484.  
  485. /** 
  486. * Output column content 
  487. * 
  488. * @since 1.0.1.2 
  489. * @param object $item The item that is displayed. 
  490. * @return string The HTML code to output. 
  491. */ 
  492. public function column_gateway( $item, $column_name ) { 
  493. $html = MS_Model_Gateway::get_name( $item->gateway_id, true ); 
  494. return $html; 
  495.  
  496. /** 
  497. * Output column content 
  498. * 
  499. * @since 1.0.1.2 
  500. * @param object $item The item that is displayed. 
  501. * @return string The HTML code to output. 
  502. */ 
  503. public function column_amount( $item, $column_name ) { 
  504. $html = MS_Helper_Billing::format_price( $item->amount ); 
  505.  
  506. return $html; 
  507.  
  508. /** 
  509. * Output column content 
  510. * 
  511. * @since 1.0.1.2 
  512. * @param object $item The item that is displayed. 
  513. * @return string The HTML code to output. 
  514. */ 
  515. public function column_invoice( $item, $column_name ) { 
  516. if ( $item->invoice_id ) { 
  517. $invoice_url = MS_Controller_Plugin::get_admin_url( 
  518. 'billing',  
  519. array( 'action' => 'edit', 'invoice_id' => $item->invoice_id ) 
  520. ); 
  521.  
  522. $html = sprintf( 
  523. '<a href="%1$s">%2$s</a>',  
  524. $invoice_url,  
  525. $item->invoice_id 
  526. ); 
  527. } else { 
  528. $html = '-'; 
  529.  
  530. return $html; 
  531.  
  532. /** 
  533. * Output column content 
  534. * 
  535. * @since 1.0.1.2 
  536. * @param object $item The item that is displayed. 
  537. * @return string The HTML code to output. 
  538. */ 
  539. public function column_note( $item, $column_name ) { 
  540. $extra_infos = ''; 
  541. $detail_lines = array(); 
  542.  
  543. // 1. Prepare the "Additional Details" popup. 
  544. $detail_lines = MS_Helper_ListTable_TransactionLog::get_details( $item ); 
  545.  
  546. if ( count( $detail_lines ) ) { 
  547. $icon_class = ''; 
  548. $post_data = $item->post; 
  549. if ( ! $post_data ) { 
  550. $icon_class = 'no-post'; 
  551.  
  552. $extra_infos = sprintf( 
  553. '<div class="more-details %3$s">%2$s<div class="post-data"><div class="inner">%1$s</div></div></div>',  
  554. implode( '<br>', $detail_lines ),  
  555. '<i class="wpmui-fa wpmui-fa-info-circle"></i>',  
  556. $icon_class 
  557. ); 
  558.  
  559. // 2. Combine the prepared parts. 
  560. $html = sprintf( 
  561. '<div class="detail-block">%s <span class="txt">%s</span></div>',  
  562. $extra_infos,  
  563. $item->description 
  564. ); 
  565.  
  566. return $html; 
  567.  
.