MS_Controller_Billing

Controller to manage billing and invoices.

Defined (1)

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

/app/controller/class-ms-controller-billing.php  
  1. class MS_Controller_Billing extends MS_Controller { 
  2.  
  3. /** 
  4. * Default action to open the invoice edit form. 
  5. * @since 1.0.1.0 
  6. * @var string 
  7. */ 
  8. const ACTION_EDIT = 'edit'; 
  9.  
  10. /** 
  11. * Action used to quick-pay an invoice via a link in the billings list. 
  12. * @since 1.0.1.0 
  13. * @var string 
  14. */ 
  15. const ACTION_PAY_IT = 'pay_it'; 
  16.  
  17. /** 
  18. * Ajax action used in the transaction log list. 
  19. * Sets the Manual-State flag of an transaction. 
  20. * @since 1.0.1.0 
  21. * @var string 
  22. */ 
  23. const AJAX_ACTION_TRANSACTION_UPDATE = 'transaction_update'; 
  24.  
  25. /** 
  26. * Ajax action used in the transaction log list. 
  27. * Returns a form to link a transaction with an invoice. 
  28. * @since 1.0.1.0 
  29. * @var string 
  30. */ 
  31. const AJAX_ACTION_TRANSACTION_LINK = 'transaction_link'; 
  32.  
  33. /** 
  34. * Ajax action used in the transaction log list. 
  35. * Returns a list of requested items. 
  36. * @since 1.0.1.0 
  37. * @var string 
  38. */ 
  39. const AJAX_ACTION_TRANSACTION_LINK_DATA = 'transaction_link_data'; 
  40.  
  41. /** 
  42. * Prepare the Billing manager. 
  43. * @since 1.0.0 
  44. */ 
  45. public function __construct() { 
  46. parent::__construct(); 
  47.  
  48. $this->add_ajax_action( 
  49. self::AJAX_ACTION_TRANSACTION_UPDATE,  
  50. 'ajax_change_transaction' 
  51. ); 
  52.  
  53. $this->add_ajax_action( 
  54. self::AJAX_ACTION_TRANSACTION_LINK,  
  55. 'ajax_link_transaction' 
  56. ); 
  57.  
  58. $this->add_ajax_action( 
  59. self::AJAX_ACTION_TRANSACTION_LINK_DATA,  
  60. 'ajax_link_data_transaction' 
  61. ); 
  62.  
  63. /** 
  64. * Initialize the admin-side functions. 
  65. * @since 1.0.0 
  66. */ 
  67. public function admin_init() { 
  68. $hook = MS_Controller_Plugin::admin_page_hook( 'billing' ); 
  69.  
  70. $this->run_action( 'load-' . $hook, 'admin_billing_manager' ); 
  71. $this->run_action( 'admin_print_scripts-' . $hook, 'enqueue_scripts' ); 
  72. $this->run_action( 'admin_print_styles-' . $hook, 'enqueue_styles' ); 
  73.  
  74. /** 
  75. * Show admin notices. 
  76. * @since 1.0.0 
  77. */ 
  78. public function print_admin_message() { 
  79. add_action( 'admin_notices', array( 'MS_Helper_Billing', 'print_admin_message' ) ); 
  80.  
  81. /** 
  82. * Manages billing actions. 
  83. * Verifies GET and POST requests to manage billing. 
  84. * @since 1.0.0 
  85. */ 
  86. public function admin_billing_manager() { 
  87. $this->print_admin_message(); 
  88. $msg = 0; 
  89. $redirect = false; 
  90.  
  91. if ( ! $this->is_admin_user() ) { 
  92. return; 
  93.  
  94. $fields_edit = array( 'user_id', 'membership_id' ); 
  95. $fields_pay = array( 'invoice_id' ); 
  96. $fields_bulk = array( 'action', 'action2', 'invoice_id' ); 
  97.  
  98. // Save details of a single invoice. 
  99. if ( $this->verify_nonce( self::ACTION_EDIT ) 
  100. && self::validate_required( $fields_edit ) 
  101. ) { 
  102. $msg = $this->save_invoice( $_POST ); 
  103.  
  104. $redirect = esc_url_raw( 
  105. add_query_arg( 
  106. array( 'msg' => $msg ),  
  107. remove_query_arg( array( 'invoice_id') ) 
  108. ); 
  109.  
  110. // Quick-Pay an invoice. 
  111. elseif ( $this->verify_nonce( self::ACTION_PAY_IT, 'GET' ) 
  112. && self::validate_required( $fields_pay, 'GET' ) 
  113. ) { 
  114. $msg = $this->billing_do_action( 'pay', $_GET['invoice_id'] ); 
  115. $redirect = esc_url_raw( 
  116. add_query_arg( 
  117. array( 'msg' => $msg ),  
  118. remove_query_arg( 
  119. array( 'action', '_wpnonce', 'invoice_id' ) 
  120. ); 
  121.  
  122. // Bulk edit invoices. 
  123. elseif ( $this->verify_nonce( 'bulk' ) 
  124. && self::validate_required( $fields_bulk ) 
  125. ) { 
  126. $action = $_POST['action'] != -1 ? $_POST['action'] : $_POST['action2']; 
  127. $msg = $this->billing_do_action( $action, $_POST['invoice_id'] ); 
  128. $redirect = esc_url_raw( 
  129. add_query_arg( array( 'msg' => $msg ) ) 
  130. ); 
  131.  
  132. if ( $redirect ) { 
  133. wp_safe_redirect( $redirect ); 
  134. exit; 
  135.  
  136. /** 
  137. * Sets up the 'Billing' navigation and list page. 
  138. * @since 1.0.0 
  139. */ 
  140. public function admin_page() { 
  141. $this->print_admin_message(); 
  142.  
  143. // Action view page request 
  144. $isset = array( 'action', 'invoice_id' ); 
  145. if ( self::validate_required( $isset, 'GET', false ) && 'edit' == $_GET['action'] ) { 
  146. $invoice_id = ! empty( $_GET['invoice_id'] ) ? $_GET['invoice_id'] : 0; 
  147. $data['invoice'] = MS_Factory::load( 'MS_Model_Invoice', $_GET['invoice_id'] ); 
  148. $data['action'] = $_GET['action']; 
  149. $data['memberships'] = MS_Model_Membership::get_membership_names( 
  150. array( 'include_guest' => 0 ) 
  151. ); 
  152. $view = MS_Factory::create( 'MS_View_Billing_Edit' ); 
  153. $view->data = apply_filters( 'ms_view_billing_edit_data', $data ); 
  154. $view->render(); 
  155. } else { 
  156. $view = MS_Factory::create( 'MS_View_Billing_List' ); 
  157. $view->render(); 
  158.  
  159. /** 
  160. * Ajax action handler used by the transaction logs list to change a 
  161. * transaction log entry. 
  162. * Sets the Manual-State flag of an transaction. 
  163. * @since 1.0.1.0 
  164. */ 
  165. public function ajax_change_transaction() { 
  166. $res = MS_Helper_Billing::BILLING_MSG_NOT_UPDATED; 
  167. $fields_state = array( 'id', 'state' ); 
  168. $fields_link = array( 'id', 'link' ); 
  169.  
  170. if ( $this->verify_nonce() ) { 
  171. if ( self::validate_required( $fields_state ) ) { 
  172. $id = intval( $_POST['id'] ); 
  173. $state = $_POST['state']; 
  174.  
  175. $log = MS_Factory::load( 'MS_Model_Transactionlog', $id ); 
  176.  
  177. if ( $log->manual_state( $state ) ) { 
  178. $log->save(); 
  179. $res = MS_Helper_Billing::BILLING_MSG_UPDATED; 
  180. } elseif ( self::validate_required( $fields_link ) ) { 
  181. $id = intval( $_POST['id'] ); 
  182. $link = intval( $_POST['link'] ); 
  183.  
  184. $log = MS_Factory::load( 'MS_Model_Transactionlog', $id ); 
  185.  
  186. $log->invoice_id = $link; 
  187. if ( $log->manual_state( 'ok' ) ) { 
  188. $invoice = $log->get_invoice(); 
  189. if ( $invoice ) { 
  190. $invoice->pay_it( $log->gateway_id, 'manual' ); 
  191. $log->save(); 
  192. $res = MS_Helper_Billing::BILLING_MSG_UPDATED; 
  193.  
  194. echo $res; 
  195. exit; 
  196.  
  197. /** 
  198. * Ajax action handler used by the transaction logs list to change a 
  199. * transaction log entry. 
  200. * Returns a form to link a transaction with an invoice. 
  201. * @since 1.0.1.0 
  202. */ 
  203. public function ajax_link_transaction() { 
  204. $data = array(); 
  205. $resp = ''; 
  206. $fields = array( 'id' ); 
  207.  
  208. if ( self::validate_required( $fields ) && $this->verify_nonce() ) { 
  209. $id = intval( $_POST['id'] ); 
  210.  
  211. $log = MS_Factory::load( 'MS_Model_Transactionlog', $id ); 
  212. if ( $log->member_id ) { 
  213. $data['member'] = $log->get_member(); 
  214. } else { 
  215. $data['member'] = false; 
  216. $data['log'] = $log; 
  217.  
  218. $view = MS_Factory::create( 'MS_View_Billing_Link' ); 
  219. $view->data = apply_filters( 'ms_view_billing_link_data', $data ); 
  220. $resp = $view->to_html(); 
  221.  
  222. echo $resp; 
  223. exit; 
  224.  
  225. /** 
  226. * Ajax action handler used by the transaction logs list to change a 
  227. * transaction log entry. 
  228. * Returns a list of requested items 
  229. * @since 1.0.1.0 
  230. */ 
  231. public function ajax_link_data_transaction() { 
  232. $resp = array(); 
  233. $fields = array( 'get', 'for' ); 
  234.  
  235. if ( self::validate_required( $fields ) && $this->verify_nonce() ) { 
  236. $type = $_POST['get']; 
  237. $id = intval( $_POST['for'] ); 
  238. $settings = MS_Plugin::instance()->settings; 
  239.  
  240. if ( 'subscriptions' == $type ) { 
  241. $member = MS_Factory::load( 'MS_Model_Member', $id ); 
  242.  
  243. $resp[0] = __( 'Select a subscription', 'membership2' ); 
  244. $active = array(); 
  245. $inactive = array(); 
  246. foreach ( $member->subscriptions as $subscription ) { 
  247. if ( $subscription->is_system() ) { continue; } 
  248.  
  249. $membership = $subscription->get_membership(); 
  250. if ( $membership->is_free() ) { 
  251. $price = __( 'Free', 'membership2' ); 
  252. } else { 
  253. $price = sprintf( 
  254. '%s %s',  
  255. $settings->currency,  
  256. MS_Helper_Billing::format_price( $membership->price ) 
  257. ); 
  258. $line = sprintf( 
  259. __( 'Membership: %s, Base price: %s', 'membership2' ),  
  260. $membership->name,  
  261. $price 
  262. ); 
  263. if ( $subscription->is_expired() ) { 
  264. $inactive[$subscription->id] = $line; 
  265. } else { 
  266. $active[$subscription->id] = $line; 
  267. if ( ! count( $active ) && ! count( $inactive ) ) { 
  268. $resp[0] = __( 'No subscriptions found', 'membership2' ); 
  269. } else { 
  270. if ( count( $active ) ) { 
  271. $resp[__( 'Active Subscriptions', 'membership2' )] = $active; 
  272. if ( count( $inactive ) ) { 
  273. $resp[__( 'Expired Subscriptions', 'membership2' )] = $inactive; 
  274. } elseif ( 'invoices' == $type ) { 
  275. $subscription = MS_Factory::load( 'MS_Model_Relationship', $id ); 
  276. $invoices = $subscription->get_invoices(); 
  277.  
  278. $resp[0] = __( 'Select an invoice', 'membership2' ); 
  279. $unpaid = array(); 
  280. $paid = array(); 
  281. foreach ( $invoices as $invoice ) { 
  282. $line = sprintf( 
  283. __( 'Invoice: %s from %s (%s)', 'membership2' ),  
  284. $invoice->get_invoice_number(),  
  285. $invoice->due_date,  
  286. $invoice->currency . ' ' . 
  287. MS_Helper_Billing::format_price( $invoice->total ) 
  288. ); 
  289. if ( $invoice->is_paid() ) { 
  290. $paid[$invoice->id] = $line; 
  291. } else { 
  292. $unpaid[$invoice->id] = $line; 
  293. if ( ! count( $unpaid ) && ! count( $paid ) ) { 
  294. $resp[0] = __( 'No invoices found', 'membership2' ); 
  295. } else { 
  296. if ( count( $unpaid ) ) { 
  297. $resp[__( 'Unpaid Invoices', 'membership2' )] = $unpaid; 
  298. if ( count( $paid ) ) { 
  299. $resp[__( 'Paid Invoices', 'membership2' )] = $paid; 
  300.  
  301. echo json_encode( $resp ); 
  302. exit; 
  303.  
  304. /** 
  305. * Perform actions for each invoice. 
  306. * @since 1.0.0 
  307. * @param string $action The action to perform on selected invoices. 
  308. * @param int[] $invoice_ids The list of invoices ids to process. 
  309. */ 
  310. public function billing_do_action( $action, $invoice_ids ) { 
  311. $msg = MS_Helper_Billing::BILLING_MSG_NOT_UPDATED; 
  312.  
  313. if ( ! is_array( $invoice_ids ) ) { 
  314. $invoice_ids = array( $invoice_ids ); 
  315.  
  316. foreach ( $invoice_ids as $invoice_id ) { 
  317. $invoice = MS_Factory::load( 'MS_Model_Invoice', $invoice_id ); 
  318.  
  319. switch ( $action ) { 
  320. case 'pay': 
  321. $invoice->status = MS_Model_Invoice::STATUS_PAID; 
  322. $invoice->changed(); 
  323. $msg = MS_Helper_Billing::BILLING_MSG_UPDATED; 
  324. break; 
  325.  
  326. case 'archive': 
  327. $invoice->archive(); 
  328. $msg = MS_Helper_Billing::BILLING_MSG_DELETED; 
  329. break; 
  330.  
  331. default: 
  332. do_action( 
  333. 'ms_controller_billing_do_action_' . $action,  
  334. $invoice 
  335. ); 
  336. break; 
  337.  
  338. return apply_filters( 
  339. 'ms_controller_billing_billing_do_action',  
  340. $msg,  
  341. $action,  
  342. $invoice_ids,  
  343. $this 
  344. ); 
  345.  
  346. /** 
  347. * Save invoices using the invoices model. 
  348. * @since 1.0.0 
  349. * @param mixed $fields Transaction fields 
  350. */ 
  351. private function save_invoice( $fields ) { 
  352. $msg = MS_Helper_Billing::BILLING_MSG_NOT_UPDATED; 
  353.  
  354. if ( $this->is_admin_user() 
  355. && is_array( $fields ) 
  356. && ! empty( $fields['user_id'] ) 
  357. && ! empty( $fields['membership_id'] ) 
  358. ) { 
  359. $member = MS_Factory::load( 'MS_Model_Member', $fields['user_id'] ); 
  360. $membership_id = $fields['membership_id']; 
  361. $gateway_id = 'admin'; 
  362.  
  363. $subscription = MS_Model_Relationship::get_subscription( 
  364. $member->id,  
  365. $membership_id 
  366. ); 
  367.  
  368. if ( empty( $subscription ) ) { 
  369. $subscription = MS_Model_Relationship::create_ms_relationship( 
  370. $membership_id,  
  371. $member->id,  
  372. $gateway_id 
  373. ); 
  374. } else { 
  375. $subscription->gateway_id = $gateway_id; 
  376. $subscription->save(); 
  377.  
  378. $invoice_id = intval( $fields['invoice_id'] ); 
  379. $invoice = MS_Factory::load( 'MS_Model_Invoice', $invoice_id ); 
  380. if ( ! $invoice->is_valid() ) { 
  381. $invoice = $subscription->get_current_invoice(); 
  382. $msg = MS_Helper_Billing::BILLING_MSG_ADDED; 
  383. } else { 
  384. $msg = MS_Helper_Billing::BILLING_MSG_UPDATED; 
  385.  
  386. foreach ( $fields as $field => $value ) { 
  387. $invoice->$field = $value; 
  388.  
  389. $invoice->save(); 
  390.  
  391. if ( ! empty( $fields['execute'] ) ) { 
  392. $invoice->changed(); 
  393.  
  394. return apply_filters( 
  395. 'ms_controller_billing_save_invoice',  
  396. $msg,  
  397. $fields,  
  398. $this 
  399. ); 
  400.  
  401. /** 
  402. * Load Billing specific styles. 
  403. * @since 1.0.0 
  404. */ 
  405. public function enqueue_styles() { 
  406. if ( empty( $_GET['action'] ) ) { 
  407. $action = ''; 
  408. } else { 
  409. $action = $_GET['action']; 
  410.  
  411. if ( 'edit' == $action ) { 
  412. lib3()->ui->add( 'jquery-ui' ); 
  413.  
  414. /** 
  415. * Load Billing specific scripts. 
  416. * @since 1.0.0 
  417. */ 
  418. public function enqueue_scripts() { 
  419. $data = array( 
  420. 'ms_init' => array(),  
  421. ); 
  422.  
  423. if ( isset( $_GET['action'] ) && 'edit' == $_GET['action'] ) { 
  424. wp_enqueue_script( 'jquery-ui-datepicker' ); 
  425. wp_enqueue_script( 'jquery-validate' ); 
  426.  
  427. $data['ms_init'][] = 'view_billing_edit'; 
  428. } else { 
  429. $module = ''; 
  430. if ( isset( $_GET['show'] ) ) { 
  431. $module = $_GET['show']; 
  432.  
  433. if ( 'logs' == $module || 'matching' == $module ) { 
  434. $data['ms_init'][] = 'view_billing_transactions'; 
  435. $data['lang'] = array( 
  436. 'link_title' => __( 'Link Transaction', 'membership2' ),  
  437. ); 
  438.  
  439. lib3()->ui->data( 'ms_data', $data ); 
  440. wp_enqueue_script( 'ms-admin' ); 
  441.