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

  1. <?php 
  2. /** 
  3. * List of transaction protocol entries. 
  4. * 
  5. * @since 1.0.0 
  6. */ 
  7. class MS_Helper_ListTable_TransactionLog extends MS_Helper_ListTable { 
  8.  
  9. /** 
  10. * This ID is used as class-name for the list output and also in various 
  11. * filter names in MS_Helper_ListTable. 
  12. * 
  13. * @var string 
  14. */ 
  15. protected $id = 'transactionlog'; 
  16.  
  17. /** 
  18. * Constructor, defines general list table attributes. 
  19. * 
  20. * @since 1.0.0 
  21. */ 
  22. public function __construct() { 
  23. // 'singular' just added for fun... 
  24. // 'plural' is used as class name for the list. 
  25. parent::__construct( 
  26. array( 
  27. 'singular' => 'transaction',  
  28. 'plural' => 'transactions',  
  29. ); 
  30.  
  31. /** 
  32. * Defines the columns of the list table 
  33. * 
  34. * @since 1.0.0 
  35. * @return array 
  36. */ 
  37. public function get_columns() { 
  38. $currency = MS_Plugin::instance()->settings->currency; 
  39.  
  40. $columns = apply_filters( 
  41. 'ms_helper_listtable_transactionlog_columns',  
  42. array( 
  43. 'id' => __( 'ID', 'membership2' ),  
  44. 'date' => __( 'Time', 'membership2' ),  
  45. 'status' => '',  
  46. 'method' => '',  
  47. 'gateway' => __( 'Gateway', 'membership2' ),  
  48. 'amount' => __( 'Amount', 'membership2' ),  
  49. 'invoice' => __( 'Invoice', 'membership2' ),  
  50. 'note' => __( 'Details', 'membership2' ),  
  51. ); 
  52.  
  53. $columns = apply_filters( 
  54. 'ms_helper_listtable_transactionlog_get_columns',  
  55. $columns,  
  56. $currency 
  57. ); 
  58.  
  59. return $columns; 
  60.  
  61. /** 
  62. * Defines, which columns should be output as hidden columns. 
  63. * 
  64. * @since 1.0.0 
  65. * @return array 
  66. */ 
  67. public function get_hidden_columns() { 
  68. return apply_filters( 
  69. 'ms_helper_listtable_transactionlog_hidden_columns',  
  70. array() 
  71. ); 
  72.  
  73. /** 
  74. * Defines, which columns can be sorted. 
  75. * 
  76. * @since 1.0.0 
  77. * @return array 
  78. */ 
  79. public function get_sortable_columns() { 
  80. return apply_filters( 
  81. 'ms_helper_listtable_transactionlog_sortable_columns',  
  82. array() 
  83. ); 
  84.  
  85. /** 
  86. * Defines available bulk actions. 
  87. * 
  88. * @since 1.0.0 
  89. * @return array 
  90. */ 
  91. public function get_bulk_actions() { 
  92. return apply_filters( 
  93. 'ms_helper_listtable_transactionlog_bulk_actions',  
  94. array() 
  95. ); 
  96.  
  97. /** 
  98. * Loads the items that are displayed on the current list page. 
  99. * 
  100. * @since 1.0.0 
  101. */ 
  102. public function prepare_items() { 
  103. $this->_column_headers = array( 
  104. $this->get_columns(),  
  105. $this->get_hidden_columns(),  
  106. $this->get_sortable_columns(),  
  107. ); 
  108.  
  109. $per_page = $this->get_items_per_page( 
  110. 'transactionlog_per_page',  
  111. 50 
  112. ); 
  113.  
  114. $current_page = $this->get_pagenum(); 
  115.  
  116. $args = array( 
  117. 'posts_per_page' => $per_page,  
  118. 'offset' => ( $current_page - 1 ) * $per_page,  
  119. 'meta_query' => array(),  
  120. ); 
  121.  
  122. if ( ! empty( $_GET['state'] ) ) { 
  123. $args['state'] = $_GET['state']; 
  124.  
  125. if ( ! empty( $_GET['id'] ) ) { 
  126. $args['post__in'] = explode( ', ', $_GET['id'] ); 
  127.  
  128. if ( ! empty( $_GET['invoice'] ) ) { 
  129. $args['meta_query']['invoice_id'] = array( 
  130. 'key' => 'invoice_id',  
  131. 'value' => explode( ', ', $_GET['invoice'] ),  
  132. 'compare' => 'IN',  
  133. ); 
  134.  
  135. if ( ! empty( $_GET['gateway_id'] ) ) { 
  136. $args['meta_query']['gateway_id'] = array( 
  137. 'key' => 'gateway_id',  
  138. 'value' => $_GET['gateway_id'],  
  139. ); 
  140.  
  141. $total_items = MS_Model_Transactionlog::get_item_count( $args ); 
  142.  
  143. $this->items = apply_filters( 
  144. 'ms_helper_listtable_transactionlog_items',  
  145. MS_Model_Transactionlog::get_items( $args ) 
  146. ); 
  147.  
  148. $this->set_pagination_args( 
  149. array( 
  150. 'total_items' => $total_items,  
  151. 'per_page' => $per_page,  
  152. ); 
  153.  
  154. /** 
  155. * Displays a custom search box for this list. 
  156. * 
  157. * @since 1.0.0 
  158. */ 
  159. public function search_box( $text = null, $input_id = 'search' ) { 
  160. // Do not display anything. 
  161. // Transaction logs cannot be searched currently 
  162.  
  163. /** 
  164. * Defines predefines filters for this list table. 
  165. * 
  166. * @since 1.0.0 
  167. * @return array 
  168. */ 
  169. public function get_views() { 
  170. $views = array(); 
  171. $base_url = remove_query_arg( array( 'state', 'id', 'invoice' ) ); 
  172.  
  173. $views['all'] = array( 
  174. 'label' => __( 'All', 'membership2' ),  
  175. 'url' => $base_url,  
  176. 'count' => MS_Model_Transactionlog::get_item_count(),  
  177. ); 
  178.  
  179. $views['ok'] = array( 
  180. 'label' => __( 'Successful', 'membership2' ),  
  181. 'url' => add_query_arg( 'state', 'ok', $base_url ),  
  182. 'count' => MS_Model_Transactionlog::get_item_count( 
  183. array( 'state' => 'ok' ) 
  184. ),  
  185. ); 
  186.  
  187. $views['err'] = array( 
  188. 'label' => __( 'Failed', 'membership2' ),  
  189. 'url' => add_query_arg( 'state', 'err', $base_url ),  
  190. 'count' => MS_Model_Transactionlog::get_item_count( 
  191. array( 'state' => 'err' ) 
  192. ),  
  193. ); 
  194.  
  195. $views['ignore'] = array( 
  196. 'label' => __( 'Ignored', 'membership2' ),  
  197. 'url' => add_query_arg( 'state', 'ignore', $base_url ),  
  198. 'count' => MS_Model_Transactionlog::get_item_count( 
  199. array( 'state' => 'ignore' ) 
  200. ),  
  201. ); 
  202.  
  203. return apply_filters( 
  204. 'ms_helper_listtable_transactionlog_views',  
  205. $views 
  206. ); 
  207.  
  208. /** 
  209. * Returns the row-class to be used for the specified table item. 
  210. * 
  211. * @param object $item The current item. 
  212. * @return string Class to be added to the table row. 
  213. */ 
  214. protected function single_row_class( $item ) { 
  215. $class = 'log-' . $item->state; 
  216.  
  217. if ( $item->is_manual ) { 
  218. $class .= ' is-manual'; 
  219.  
  220. return $class; 
  221.  
  222. /** 
  223. * Output column content 
  224. * 
  225. * @since 1.0.0 
  226. * @param object $item The item that is displayed. 
  227. * @return string The HTML code to output. 
  228. */ 
  229. public function column_id( $item, $column_name ) { 
  230. $html = $item->id; 
  231. return $html; 
  232.  
  233. /** 
  234. * Output column content 
  235. * 
  236. * @since 1.0.0 
  237. * @param object $item The item that is displayed. 
  238. * @return string The HTML code to output. 
  239. */ 
  240. public function column_date( $item, $column_name ) { 
  241. $html = MS_Helper_Period::format_date( $item->date, 'Y-m-d H:i' ); 
  242.  
  243. return $html; 
  244.  
  245. /** 
  246. * Output column content 
  247. * 
  248. * @since 1.0.0 
  249. * @param object $item The item that is displayed. 
  250. * @return string The HTML code to output. 
  251. */ 
  252. public function column_status( $item, $column_name ) { 
  253. $html = '<span class="log-status"><i class="wpmui-fa log-status-icon"></i></span>'; 
  254.  
  255. return $html; 
  256.  
  257. /** 
  258. * Output column content 
  259. * 
  260. * @since 1.0.0 
  261. * @param object $item The item that is displayed. 
  262. * @return string The HTML code to output. 
  263. */ 
  264. public function column_method( $item, $column_name ) { 
  265. $html = '<span class="log-method" data-info="%2$s"><i class="wpmui-fa wpmui-%1$s"></i></span>'; 
  266. $icon = ''; 
  267. $info = __( 'Unknown method', 'membership2' ); 
  268.  
  269. switch ( $item->method ) { 
  270. case 'handle': 
  271. $icon = 'fa-cloud-download'; 
  272. $info = __( 'Gateway called the IPN URL', 'membership2' ); 
  273. break; 
  274.  
  275. case 'request': 
  276. $icon = 'fa-refresh'; 
  277. $info = __( 'Plugin requested a recuring payment', 'membership2' ); 
  278. break; 
  279.  
  280. case 'process': 
  281. $icon = 'fa-shopping-cart'; 
  282. $info = __( 'User entered payment details', 'membership2' ); 
  283. break; 
  284.  
  285. $html = sprintf( $html, $icon, $info ); 
  286.  
  287. return $html; 
  288.  
  289. /** 
  290. * Output column content 
  291. * 
  292. * @since 1.0.0 
  293. * @param object $item The item that is displayed. 
  294. * @return string The HTML code to output. 
  295. */ 
  296. public function column_gateway( $item, $column_name ) { 
  297. $html = MS_Model_Gateway::get_name( $item->gateway_id, true ); 
  298. return $html; 
  299.  
  300. /** 
  301. * Output column content 
  302. * 
  303. * @since 1.0.0 
  304. * @param object $item The item that is displayed. 
  305. * @return string The HTML code to output. 
  306. */ 
  307. public function column_amount( $item, $column_name ) { 
  308. $html = MS_Helper_Billing::format_price( $item->amount ); 
  309.  
  310. return $html; 
  311.  
  312. /** 
  313. * Output column content 
  314. * 
  315. * @since 1.0.0 
  316. * @param object $item The item that is displayed. 
  317. * @return string The HTML code to output. 
  318. */ 
  319. public function column_invoice( $item, $column_name ) { 
  320. if ( $item->invoice_id ) { 
  321. $invoice_url = MS_Controller_Plugin::get_admin_url( 
  322. 'billing',  
  323. array( 'action' => 'edit', 'invoice_id' => $item->invoice_id ) 
  324. ); 
  325.  
  326. $html = sprintf( 
  327. '<a href="%1$s">%2$s</a>',  
  328. $invoice_url,  
  329. $item->invoice_id 
  330. ); 
  331. } else { 
  332. $html = '-'; 
  333.  
  334. return $html; 
  335.  
  336. /** 
  337. * Output column content 
  338. * 
  339. * @since 1.0.0 
  340. * @param object $item The item that is displayed. 
  341. * @return string The HTML code to output. 
  342. */ 
  343. public function column_note( $item, $column_name ) { 
  344. $extra_infos = ''; 
  345. $row_actions = ''; 
  346. $nonce_action = ''; 
  347. $detail_lines = array(); 
  348. $actions = array(); 
  349. $ind = 0; 
  350.  
  351. // 1. Prepare the "Additional Details" popup. 
  352. $detail_lines = self::get_details( $item ); 
  353.  
  354. if ( count( $detail_lines ) ) { 
  355. $icon_class = ''; 
  356. $post_data = $item->post; 
  357. if ( ! $post_data ) { 
  358. $icon_class = 'no-post'; 
  359.  
  360. $extra_infos = sprintf( 
  361. '<div class="more-details %3$s">%2$s<div class="post-data"><div class="inner">%1$s</div></div></div>',  
  362. implode( '<br>', $detail_lines ),  
  363. '<i class="wpmui-fa wpmui-fa-info-circle"></i>',  
  364. $icon_class 
  365. ); 
  366.  
  367. // 2. Prepare the row actions. 
  368. if ( 'err' == $item->state ) { 
  369. $actions = array( 
  370. 'action-link' => __( 'Link', 'membership2' ),  
  371. 'action-ignore' => __( 'Ignore', 'membership2' ),  
  372. ); 
  373.  
  374. // We can only re-process the transaction if we have POST data. 
  375. $postdata = $item->post; 
  376. if ( is_array( $postdata ) && ! empty( $postdata ) ) { 
  377. $actions['action-retry'] = __( 'Retry', 'membership2' ); 
  378. } elseif ( 'ignore' == $item->state && $item->is_manual ) { 
  379. $actions = array( 
  380. 'action-clear' => __( 'Reset', 'membership2' ),  
  381. ); 
  382. $nonce_action = MS_Controller_Billing::AJAX_ACTION_TRANSACTION_LINK; 
  383.  
  384. if ( count( $actions ) ) { 
  385. $nonces = array(); 
  386. $nonces[] = wp_nonce_field( 
  387. MS_Controller_Billing::AJAX_ACTION_TRANSACTION_UPDATE,  
  388. 'nonce_update',  
  389. false,  
  390. false 
  391. ); 
  392. $nonces[] = wp_nonce_field( 
  393. MS_Controller_Billing::AJAX_ACTION_TRANSACTION_LINK,  
  394. 'nonce_link',  
  395. false,  
  396. false 
  397. ); 
  398. $nonces[] = wp_nonce_field( 
  399. MS_Controller_Import::AJAX_ACTION_RETRY,  
  400. 'nonce_retry',  
  401. false,  
  402. false 
  403. ); 
  404. $action_tags = array(); 
  405. foreach ( $actions as $class => $label ) { 
  406. $action_tags[] = sprintf( 
  407. '<a href="#" class="%s">%s</a>',  
  408. $class,  
  409. $label 
  410. ); 
  411.  
  412. $row_actions = sprintf( 
  413. '<div class="actions %1$s-actions">%2$s %3$s</div>',  
  414. $item->state,  
  415. implode( '', $nonces ),  
  416. implode( ' | ', $action_tags ) 
  417. ); 
  418.  
  419. // 3. Combine the prepared parts. 
  420. $html = sprintf( 
  421. '<div class="detail-block">%s <span class="txt">%s</span> %s</div>',  
  422. $extra_infos,  
  423. $item->description,  
  424. $row_actions 
  425. ); 
  426.  
  427. return $html; 
  428.  
  429. /** 
  430. * Returns an array with additional details about the transaction. 
  431. * 
  432. * This function is used in the note-column and is shared in the objects for 
  433. * TransactionLog and TransactionMatching. 
  434. * 
  435. * @since 1.0.1.2 
  436. * @param MS_Model_Transaction $item Transaction object. 
  437. * @return array The transaction details. 
  438. */ 
  439. static public function get_details( $item ) { 
  440. $detail_lines = array(); 
  441.  
  442. if ( $item->is_manual ) { 
  443. $detail_lines[] = __( 'Transaction state manually changed', 'membership2' ); 
  444. $detail_lines[] = sprintf( 
  445. __( 'Modified on: %s', 'membership2' ),  
  446. $item->manual_date 
  447. ); 
  448. $detail_lines[] = sprintf( 
  449. __( 'Modified by: %s', 'membership2' ),  
  450. $item->get_manual_user()->display_name 
  451. ); 
  452.  
  453. $postdata = $item->post; 
  454. $group = array(); 
  455. if ( ! empty( $postdata ) && is_array( $postdata ) ) { 
  456. $id_fields = array(); 
  457. switch ( $item->gateway_id ) { 
  458. case MS_Gateway_Paypalstandard::ID: 
  459. if ( isset( $postdata['invoice'] ) ) { 
  460. $id_fields[] = 'invoice'; 
  461. } elseif ( isset( $postdata['custom'] ) ) { 
  462. $id_fields[] = 'custom'; 
  463. $detail_lines[] = __( 'Imported subscription from old Membership plugin.', 'membership2' ); 
  464. } elseif ( isset( $postdata['btn_id'] ) ) { 
  465. $id_fields[] = 'btn_id'; 
  466. $id_fields[] = 'payer_email'; 
  467. $detail_lines[] = __( 'Payment via a PayPal Payment button.', 'membership2' ); 
  468. } elseif ( isset( $postdata['txn_type'] ) ) { 
  469. // Highlight invalid transactions. 
  470. if ( 'send_money' == $postdata['txn_type'] ) { 
  471. $id_fields[] = 'txn_type'; 
  472. $detail_lines[] = __( 'Someone sent you money inside PayPal or PayPal re-sent a previous payment.<br>Plugin did not attempt to match payment to a subscription.', 'membership2' ); 
  473. break; 
  474.  
  475. if ( count( $detail_lines ) ) { 
  476. $detail_lines[] = '<hr />'; 
  477. ksort( $postdata ); 
  478. $ind = 0; 
  479. foreach ( $postdata as $key => $value ) { 
  480. if ( strpos( $key, ':' ) > 0 ) { 
  481. $parts = explode( ':', $key ); 
  482. if ( ! isset( $groups[ $parts[0] ] ) ) { 
  483. $groups[ $parts[0] ] = array(); 
  484. $groups[ $parts[0] ][ $parts[1] ] = $value; 
  485. continue; 
  486.  
  487. if ( 0 === $ind ) { 
  488. $detail_lines[] = __( 'POST data:', 'membership2' ); 
  489.  
  490. $ind += 1; 
  491.  
  492. $line_class = ''; 
  493. if ( in_array( $key, $id_fields ) ) { 
  494. $line_class = 'is-id'; 
  495.  
  496. $detail_lines[] = sprintf( 
  497. '<span class="line %s"><small class="line-num">%s</small> <span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  498. $line_class,  
  499. $ind,  
  500. $key,  
  501. htmlspecialchars( $value ) 
  502. ); 
  503.  
  504. foreach ( $groups as $group => $values ) { 
  505. $ind = 0; 
  506. foreach ( $values as $key => $value ) { 
  507. if ( 0 === $ind ) { 
  508. $detail_lines[] = '<hr />'; 
  509. $detail_lines[] = $group . ':'; 
  510.  
  511. $ind += 1; 
  512.  
  513. $detail_lines[] = sprintf( 
  514. '<span class="line"><small class="line-num">%s</small> <span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  515. $ind,  
  516. $key,  
  517. htmlspecialchars( $value ) 
  518. ); 
  519.  
  520. $headers = $item->headers; 
  521. $cookies = false; 
  522. if ( ! empty( $headers ) && is_array( $headers ) ) { 
  523. if ( count( $detail_lines ) ) { 
  524. $detail_lines[] = '<hr />'; 
  525. ksort( $headers ); 
  526. $ind = 0; 
  527. $detail_lines[] = __( 'HTTP Headers:', 'membership2' ); 
  528. foreach ( $headers as $key => $value ) { 
  529. if ( 'Cookie' == $key ) { 
  530. $cookies = explode( ';', $value ); 
  531. continue; 
  532. $ind += 1; 
  533.  
  534. $detail_lines[] = sprintf( 
  535. '<span class="line"><small class="line-num">%s</small> <span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  536. $ind,  
  537. $key,  
  538. htmlspecialchars( $value ) 
  539. ); 
  540.  
  541. if ( ! empty( $cookies ) && is_array( $cookies ) ) { 
  542. if ( count( $detail_lines ) ) { 
  543. $detail_lines[] = '<hr />'; 
  544. ksort( $cookies ); 
  545. $ind = 0; 
  546. $detail_lines[] = __( 'Cookies:', 'membership2' ); 
  547. foreach ( $cookies as $key => $value ) { 
  548. $ind += 1; 
  549. $parts = explode( '=', $value ); 
  550. if ( count( $parts ) < 2 ) { continue; } 
  551.  
  552. $detail_lines[] = sprintf( 
  553. '<span class="line"><small class="line-num">%s</small> <span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  554. $ind,  
  555. array_shift( $parts ),  
  556. htmlspecialchars( implode( '=', $parts ) ) 
  557. ); 
  558.  
  559. if ( count( $detail_lines ) ) { 
  560. $detail_lines[] = '<hr />'; 
  561.  
  562. $detail_lines[] = __( 'Logged in user:', 'membership2' ); 
  563. $user_id = $item->user_id; 
  564. if ( $user_id ) { 
  565. $user = get_user_by( 'id', $user_id ); 
  566. $detail_lines[] = sprintf( 
  567. '<span class="line"><small class="line-num">%s</small><span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  568. 1,  
  569. __( 'User ID', 'membership2' ),  
  570. $user_id 
  571. ); 
  572. $detail_lines[] = sprintf( 
  573. '<span class="line"><small class="line-num">%s</small><span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  574. 2,  
  575. __( 'Username', 'membership2' ),  
  576. $user->user_login 
  577. ); 
  578. $detail_lines[] = sprintf( 
  579. '<span class="line"><small class="line-num">%s</small><span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  580. 3,  
  581. __( 'Email', 'membership2' ),  
  582. $user->user_email 
  583. ); 
  584. } else { 
  585. $detail_lines[] = sprintf( 
  586. '<span class="line"><small class="line-num">%s</small><span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  587. 1,  
  588. __( 'Guest', 'membership2' ),  
  589. __( 'Could not determine a logged in user', 'membership2' ) 
  590. ); 
  591.  
  592. $req_url = $item->url; 
  593. if ( ! empty( $req_url ) ) { 
  594. if ( count( $detail_lines ) ) { 
  595. $detail_lines[] = '<hr />'; 
  596. $detail_lines[] = sprintf( 
  597. '<span class="line"><span class="line-key">%s</span> <span class="line-val">%s</span></span>',  
  598. __( 'Request URL', 'membership2' ),  
  599. $req_url 
  600. ); 
  601.  
  602. return $detail_lines; 
  603.  
.