MS_Model_Invoice

Invoice model.

Defined (1)

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

/app/model/class-ms-model-invoice.php  
  1. class MS_Model_Invoice extends MS_Model_CustomPostType { 
  2.  
  3. /** 
  4. * Model custom post type. 
  5. * Both static and class property are used to handle php 5.2 limitations. 
  6. * @since 1.0.0 
  7. * @var string 
  8. */ 
  9. protected static $POST_TYPE = 'ms_invoice'; 
  10.  
  11. /** 
  12. * Invoice status constants. 
  13. * @since 1.0.0 
  14. * @see $status property. 
  15. * @var string 
  16. */ 
  17. // Invoice was created but user did not yet confirm that he wants to sign up/pay. 
  18. const STATUS_NEW = 'new'; 
  19.  
  20. // Invoice was created but user did not make any attempt to pay. 
  21. const STATUS_BILLED = 'billed'; 
  22.  
  23. // User confirmed payment and it was successful. 
  24. const STATUS_PAID = 'paid'; 
  25.  
  26. // User confirmed payment but gateway returned a "pending" notification. 
  27. const STATUS_PENDING = 'pending'; 
  28.  
  29. // User confirmed payment but gateway returned some error (dispute, wrong amount, etc). 
  30. const STATUS_DENIED = 'denied'; 
  31.  
  32. // Archived invoices are hidden from invoice lists, i.e. "deleted" 
  33. const STATUS_ARCHIVED = 'archived'; 
  34.  
  35. /** 
  36. * External transaction ID. 
  37. * Used to link 3rd party transaction ID to $this->id 
  38. * @since 1.0.0 
  39. * @var string 
  40. */ 
  41. protected $external_id = ''; 
  42.  
  43. /** 
  44. * Gateway ID. 
  45. * Gateway used to pay this invoice. 
  46. * @since 1.0.0 
  47. * @var string 
  48. */ 
  49. protected $gateway_id = ''; 
  50.  
  51. /** 
  52. * Membership ID. 
  53. * Invoice for membership. 
  54. * @since 1.0.0 
  55. * @var int 
  56. */ 
  57. protected $membership_id = 0; 
  58.  
  59. /** 
  60. * User ID. 
  61. * Invoice for this user/member. 
  62. * @since 1.0.0 
  63. * @var int 
  64. */ 
  65. protected $user_id = 0; 
  66.  
  67. /** 
  68. * Log the users IP address once he visits the checkout page. 
  69. * This way we can also see if the user visited the checkout page to pay the 
  70. * invoice. 
  71. * @since 1.0.2.0 
  72. * @var string 
  73. */ 
  74. protected $checkout_ip = ''; 
  75.  
  76. /** 
  77. * Log the timestamp when the user visits the checkout page. 
  78. * @since 1.0.2.0 
  79. * @var string 
  80. */ 
  81. protected $checkout_date = ''; 
  82.  
  83. /** 
  84. * Membership Relationship ID. 
  85. * @since 1.0.0 
  86. * @var int 
  87. */ 
  88. protected $ms_relationship_id = 0; 
  89.  
  90. /** 
  91. * Coupon ID. 
  92. * Used coupon ID. 
  93. * @since 1.0.0 
  94. * @var int 
  95. */ 
  96. protected $coupon_id = 0; 
  97.  
  98. /** 
  99. * Currency of this invoice. 
  100. * @since 1.0.0 
  101. * @var string 
  102. */ 
  103. protected $currency = ''; 
  104.  
  105. /** 
  106. * Amount value not including discounts. 
  107. * @since 1.0.0 
  108. * @var float 
  109. */ 
  110. protected $amount = 0; 
  111.  
  112. /** 
  113. * Discount value. 
  114. * @since 1.0.0 
  115. * @var float 
  116. */ 
  117. protected $discount = 0; 
  118.  
  119. /** 
  120. * Pro rate value. 
  121. * @since 1.0.0 
  122. * @var float 
  123. */ 
  124. protected $pro_rate = 0; 
  125.  
  126. /** 
  127. * READ-ONLY. Invoice amount including all discounts but no taxes. 
  128. * To modify this value change any of these properties: 
  129. * amount, discount, pro_rate 
  130. * @since 1.0.0 
  131. * @var float 
  132. */ 
  133. protected $subtotal = 0; 
  134.  
  135. /** 
  136. * READ-ONLY. Total value (= subtotal + taxes). 
  137. * To modify this value change any of these properties: 
  138. * amount, discount, pro_rate, tax_rate 
  139. * @since 1.0.0 
  140. * @var float 
  141. */ 
  142. protected $total = 0; 
  143.  
  144. /** 
  145. * Inovoice status. 
  146. * @since 1.0.0 
  147. * @var string 
  148. */ 
  149. protected $status = ''; 
  150.  
  151. /** 
  152. * Invoice for trial period. 
  153. * @since 1.0.0 
  154. * @var boolean 
  155. */ 
  156. protected $uses_trial = false; 
  157.  
  158. /** 
  159. * The trial period price. 
  160. * @since 1.0.0 
  161. * @var numeric 
  162. */ 
  163. protected $trial_price = 0; 
  164.  
  165. /** 
  166. * This is the last day of the trial period. The next day is paid. 
  167. * @since 1.0.0 
  168. * @var date 
  169. */ 
  170. protected $trial_ends = ''; 
  171.  
  172. /** 
  173. * Invoice date. 
  174. * This is the date when the INVOICE WAS CREATED. It may be differe than the 
  175. * due date if the subscription uses a trial period. 
  176. * @since 1.0.0 
  177. * @var string 
  178. */ 
  179. protected $invoice_date = ''; 
  180.  
  181. /** 
  182. * Defines date WHEN PAYMENT IS DUE. 
  183. * When invoice uses_trial is true then this is the first day that is paid. 
  184. * @since 1.0.0 
  185. * @var string 
  186. */ 
  187. protected $due_date = ''; 
  188.  
  189. /** 
  190. * Date when the invoice was MARKED AS PAID. 
  191. * Note that free invoices do not have a pay-date! The pay-date is only set 
  192. * when something was actually paid ;) 
  193. * @since 1.0.2.0 
  194. * @var string 
  195. */ 
  196. protected $pay_date = ''; 
  197.  
  198. /** 
  199. * Invoice notes. 
  200. * When adding notes we are assigning an array, so it only makes sense to set  
  201. * this by default as an array 
  202. * @since 1.0.0 
  203. * @var array 
  204. */ 
  205. protected $notes = array(); 
  206.  
  207. /** 
  208. * Invoice number. 
  209. * @since 1.0.0 
  210. * @var int 
  211. */ 
  212. protected $invoice_number = 0; 
  213.  
  214. /** 
  215. * Tax rate value. 
  216. * @since 1.0.0 
  217. * @var float 
  218. */ 
  219. protected $tax_rate = 0; 
  220.  
  221. /** 
  222. * Tax name. 
  223. * @since 1.0.0 
  224. * @var string 
  225. */ 
  226. protected $tax_name = ''; 
  227.  
  228. /** 
  229. * Short, compact version of the payment description 
  230. * @since 1.0.0 
  231. * @var string 
  232. */ 
  233. protected $short_description = ''; 
  234.  
  235. /** 
  236. * Where the data came from. Can only be changed by data import tool 
  237. * @since 1.0.0 
  238. * @var string 
  239. */ 
  240. protected $source = ''; 
  241.  
  242. /** 
  243. * Timestamp of price calculation. 
  244. * This information is used when price-options of the memberhsip is changed. 
  245. * @since 1.0.0 
  246. * @var int 
  247. */ 
  248. protected $price_date = 0; 
  249.  
  250. // 
  251. // 
  252. // 
  253. // -------------------------------------------------------------- COLLECTION 
  254.  
  255. /** 
  256. * Returns the post-type of the current object. 
  257. * @since 1.0.0 
  258. * @return string The post-type name. 
  259. */ 
  260. public static function get_post_type() { 
  261. return parent::_post_type( self::$POST_TYPE ); 
  262.  
  263. /** 
  264. * Get custom register post type args for this model. 
  265. * @since 1.0.0 
  266. */ 
  267. public static function get_register_post_type_args() { 
  268. $args = array( 
  269. 'label' => __( 'Membership2 Invoices', 'membership2' ),  
  270. 'description' => __( 'Member Invoices', 'membership2' ),  
  271. 'public' => true,  
  272. 'show_ui' => false,  
  273. 'show_in_menu' => false,  
  274. 'has_archive' => false,  
  275. 'publicly_queryable' => true,  
  276. 'supports' => false,  
  277. 'hierarchical' => false,  
  278. 'exclude_from_search' => true 
  279. ); 
  280.  
  281. return apply_filters( 
  282. 'ms_customposttype_register_args',  
  283. $args,  
  284. self::get_post_type() 
  285. ); 
  286.  
  287. /** 
  288. * Get invoice status types. 
  289. * @since 1.0.0 
  290. * @param bool $extended Optional. If true, additional details will be 
  291. * returned, not only the status name. 
  292. * @return array A list of status IDs with status name/description. 
  293. */ 
  294. public static function get_status_types( $extended = false ) { 
  295. if ( $extended ) { 
  296. $result = array( 
  297. self::STATUS_NEW => __( 'Draft - Invoice is prepared but user cannot see it yet', 'membership2' ),  
  298. self::STATUS_BILLED => __( 'Billed - User can see the invoice and needs to pay', 'membership2' ),  
  299. self::STATUS_PENDING => __( 'Pending - Waiting for confirmation from payment gateway', 'membership2' ),  
  300. self::STATUS_PAID => __( 'Paid - Payment arrived on our account!', 'membership2' ),  
  301. self::STATUS_DENIED => __( 'Denied - Payment was denied', 'membership2' ),  
  302. ); 
  303. } else { 
  304. $result = array( 
  305. self::STATUS_NEW => __( 'Draft', 'membership2' ),  
  306. self::STATUS_BILLED => __( 'Billed', 'membership2' ),  
  307. self::STATUS_PENDING => __( 'Pending', 'membership2' ),  
  308. self::STATUS_PAID => __( 'Paid', 'membership2' ),  
  309. self::STATUS_DENIED => __( 'Denied', 'membership2' ),  
  310. ); 
  311.  
  312. return apply_filters( 
  313. 'ms_model_invoice_get_status_types',  
  314. $result,  
  315. $extended 
  316. ); 
  317.  
  318. /** 
  319. * Returns the default query-arg array 
  320. * @since 1.0.0 
  321. * @return array 
  322. */ 
  323. public static function get_query_args() { 
  324. $args = array(); 
  325.  
  326. if ( ! empty( $_REQUEST['orderby'] ) && ! empty( $_REQUEST['order'] ) ) { 
  327. $args['orderby'] = $_REQUEST['orderby']; 
  328. $args['order'] = $_REQUEST['order']; 
  329. } else { 
  330. $args['orderby'] = 'ID'; 
  331. $args['order'] = 'DESC'; 
  332.  
  333. // Prepare order by statement. 
  334. $orderby = $args['orderby']; 
  335. if ( ! empty( $orderby ) 
  336. && ! in_array( $orderby, array( 'ID', 'author' ) ) 
  337. && property_exists( 'MS_Model_Invoice', $orderby ) 
  338. ) { 
  339. $args['meta_key'] = $orderby; 
  340. if ( in_array( $orderby, array( 'amount', 'total' ) ) ) { 
  341. $args['orderby'] = 'meta_value_num'; 
  342. } else { 
  343. $args['orderby'] = 'meta_value'; 
  344.  
  345. // Search string. 
  346. if ( ! empty( $_REQUEST['s'] ) ) { 
  347. $user_args = array( 
  348. 'search' => '*' . $_REQUEST['s'] . '*',  
  349. ); 
  350. $user_list = new WP_User_Query( $user_args ); 
  351. $user_ids = array(); 
  352. foreach ( $user_list->results as $user ) { 
  353. $user_ids[] = $user->ID; 
  354. $args['author__in'] = $user_ids; 
  355.  
  356. $args['meta_query'] = array(); 
  357.  
  358. // Gateway filter. 
  359. if ( ! empty( $_REQUEST['gateway_id'] ) ) { 
  360. $args['meta_query']['gateway_id'] = array( 
  361. 'key' => 'gateway_id',  
  362. 'value' => $_REQUEST['gateway_id'],  
  363. ); 
  364.  
  365. // Payment status filter. 
  366. if ( ! empty( $_REQUEST['status'] ) ) { 
  367. if ( 'default' === $_REQUEST['status'] ) { 
  368. $args['meta_query']['status'] = array( 
  369. 'key' => 'status',  
  370. 'value' => array( 
  371. self::STATUS_BILLED,  
  372. self::STATUS_PENDING,  
  373. self::STATUS_PAID,  
  374. self::STATUS_DENIED,  
  375. ),  
  376. 'compare' => 'IN',  
  377. ); 
  378. } elseif ( 'open' === $_REQUEST['status'] ) { 
  379. $args['meta_query']['status'] = array( 
  380. 'key' => 'status',  
  381. 'value' => array( 
  382. self::STATUS_BILLED,  
  383. self::STATUS_PENDING,  
  384. ),  
  385. 'compare' => 'IN',  
  386. ); 
  387. } else { 
  388. $args['meta_query']['status'] = array( 
  389. 'key' => 'status',  
  390. 'value' => $_REQUEST['status'],  
  391. ); 
  392.  
  393. return $args; 
  394.  
  395. /** 
  396. * Get the number of invoices. 
  397. * @since 1.0.0 
  398. * @param array $args The query post args 
  399. * @see http://codex.wordpress.org/Class_Reference/WP_Query 
  400. * @return int 
  401. */ 
  402. public static function get_invoice_count( $args = null ) { 
  403. $defaults = array( 
  404. 'post_type' => self::get_post_type(),  
  405. 'post_status' => 'any',  
  406. ); 
  407. $args = apply_filters( 
  408. 'ms_model_invoice_get_invoice_count_args',  
  409. wp_parse_args( $args, $defaults ) 
  410. ); 
  411.  
  412. MS_Factory::select_blog(); 
  413. $query = new WP_Query( $args ); 
  414. MS_Factory::revert_blog(); 
  415.  
  416. return apply_filters( 
  417. 'ms_model_invoice_get_invoice_count',  
  418. $query->found_posts,  
  419. $args 
  420. ); 
  421.  
  422. /** 
  423. * Count the number of unpaid invoices. Unpaid is any invoice with status 
  424. * BILLED or PENDING. 
  425. * @since 1.0.0 
  426. * @param array $args The query post args 
  427. * @see http://codex.wordpress.org/Class_Reference/WP_Query 
  428. * @param bool $for_badge if true then return value is a string 
  429. * @return int|string 
  430. */ 
  431. public static function get_unpaid_invoice_count( $args = null, $for_badge = false ) { 
  432. $defaults = self::get_query_args(); 
  433.  
  434. $args = apply_filters( 
  435. 'ms_model_invoice_get_unpaid_invoice_count_args',  
  436. wp_parse_args( $args, $defaults ) 
  437. ); 
  438.  
  439. $args['meta_query']['status']['value'] = array( 
  440. self::STATUS_BILLED,  
  441. self::STATUS_PENDING,  
  442. ); 
  443. $args['meta_query']['status']['compare'] = 'IN'; 
  444.  
  445. $bill_count = self::get_invoice_count( $args ); 
  446.  
  447. $res = $bill_count; 
  448. if ( $for_badge ) { 
  449. if ( $bill_count > 99 ) { 
  450. $res = '99+'; 
  451. } elseif ( ! $bill_count ) { 
  452. $res = ''; 
  453.  
  454. return apply_filters( 
  455. 'ms_model_invoice_get_unpaid_invoice_count',  
  456. $res,  
  457. $bill_count,  
  458. $args,  
  459. $for_badge 
  460. ); 
  461.  
  462. /** 
  463. * Get invoices. 
  464. * @since 1.0.0 
  465. * @param mixed $args The arguments to select data. 
  466. * @return array $invoices 
  467. */ 
  468. public static function get_invoices( $args = null ) { 
  469. $defaults = array( 
  470. 'post_type' => self::get_post_type(),  
  471. 'posts_per_page' => 10,  
  472. 'post_status' => 'any',  
  473. 'fields' => 'ids',  
  474. 'order' => 'DESC',  
  475. 'orderby' => 'ID',  
  476. ); 
  477. $args = apply_filters( 
  478. 'ms_model_invoice_get_invoices_args',  
  479. wp_parse_args( $args, $defaults ) 
  480. ); 
  481.  
  482. MS_Factory::select_blog(); 
  483. $query = new WP_Query( $args ); 
  484. $items = $query->posts; 
  485. $invoices = array(); 
  486. MS_Factory::revert_blog(); 
  487.  
  488. foreach ( $items as $item ) { 
  489. $invoices[] = MS_Factory::load( 'MS_Model_Invoice', $item ); 
  490.  
  491. return apply_filters( 
  492. 'ms_model_invoice_get_invoices',  
  493. $invoices,  
  494. $args 
  495. ); 
  496.  
  497. /** 
  498. * Returns all invoices of the specified user that are "public" for the 
  499. * user. This means that some internal invoices will not be displayed: 
  500. * - Invoices with 0.00 total amount are not displayed 
  501. * - Invoices with status New are not displayed 
  502. * @since 1.0.0 
  503. * @param int $user_id 
  504. * @param int $limit 
  505. * @return array List of MS_Model_Invoice objects. 
  506. */ 
  507. public static function get_public_invoices( $user_id, $limit = -1 ) { 
  508. $list = self::get_invoices( 
  509. array( 
  510. 'author' => $user_id,  
  511. 'posts_per_page' => $limit,  
  512. 'meta_query' => array( 
  513. 'relation' => 'AND',  
  514. // Do not display invoices for free memberships. 
  515. array( 
  516. 'key' => 'amount',  
  517. 'value' => '0',  
  518. 'compare' => '!=',  
  519. ),  
  520. // Do not display and Invoice with status "New". 
  521. array( 
  522. 'key' => 'status',  
  523. 'value' => MS_Model_Invoice::STATUS_NEW,  
  524. 'compare' => '!=',  
  525. ),  
  526. ); 
  527.  
  528. return $list; 
  529.  
  530. /** 
  531. * Get specific invoice. 
  532. * Get invoice of a user and membership. 
  533. * @since 1.0.0 
  534. * @param int $subscription_id The membership relationship id. 
  535. * @param int $invoice_number Optional. The invoice number. Get the current number if null. 
  536. * @param string $status Optional. The invoice status. 
  537. * @return MS_Model_Invoice The found invoice or null if not found. 
  538. */ 
  539. public static function get_invoice( $subscription_id, $invoice_number = null, $status = null ) { 
  540. $args = array( 
  541. 'post_type' => self::get_post_type(),  
  542. 'post_status' => 'any',  
  543. 'fields' => 'ids',  
  544. 'order' => 'DESC',  
  545. ); 
  546.  
  547. $args['meta_query']['ms_relationship_id'] = array( 
  548. 'key' => 'ms_relationship_id',  
  549. 'value' => $subscription_id,  
  550. ); 
  551. if ( ! empty( $status ) ) { 
  552. $args['meta_query']['status'] = array( 
  553. 'key' => 'status',  
  554. 'value' => $status,  
  555. ); 
  556. if ( ! empty( $invoice_number ) ) { 
  557. $args['meta_query']['invoice_number'] = array( 
  558. 'key' => 'invoice_number',  
  559. 'value' => $invoice_number,  
  560. ); 
  561.  
  562. MS_Factory::select_blog(); 
  563. $args = apply_filters( 'ms_model_invoice_get_invoice_args', $args ); 
  564. $query = new WP_Query( $args ); 
  565. $item = $query->posts; 
  566. MS_Factory::revert_blog(); 
  567.  
  568. $invoice = null; 
  569. if ( ! empty( $item[0] ) ) { 
  570. $invoice = MS_Factory::load( 'MS_Model_Invoice', $item[0] ); 
  571.  
  572. return apply_filters( 
  573. 'ms_model_invoice_get_invoice',  
  574. $invoice,  
  575. $subscription_id,  
  576. $invoice_number,  
  577. $status 
  578. ); 
  579.  
  580. /** 
  581. * Get current member membership invoice. 
  582. * The current invoice is the not paid one. Every time a invoice is paid,  
  583. * the current invoice number is incremented. 
  584. * @since 1.0.0 
  585. * @param MS_Model_Relationship $subscription The membership relationship. 
  586. * @param bool $create_missing Optional. True to overwrite existing 
  587. * invoice or false to create a new one if doesn't exist. 
  588. * @return MS_Model_Invoice 
  589. */ 
  590. public static function get_current_invoice( $subscription, $create_missing = true ) { 
  591. $invoice = self::get_invoice( 
  592. $subscription->id,  
  593. $subscription->current_invoice_number 
  594. ); 
  595.  
  596. if ( ! $invoice && $create_missing ) { 
  597. // Create a new invoice. 
  598. $invoice = self::create_invoice( 
  599. $subscription,  
  600. $subscription->current_invoice_number 
  601. ); 
  602.  
  603. return apply_filters( 
  604. 'ms_model_invoice_get_current_invoice',  
  605. $invoice,  
  606. $subscription,  
  607. $create_missing 
  608. ); 
  609.  
  610. /** 
  611. * Get next invoice for the membership. 
  612. * @since 1.0.0 
  613. * @param MS_Model_Relationship $subscription The membership relationship. 
  614. * @param bool $create_missing Optional. True to overwrite existing 
  615. * invoice or false to create a new one if doesn't exist. 
  616. * @return MS_Model_Invoice 
  617. */ 
  618. public static function get_next_invoice( $subscription, $create_missing = true ) { 
  619. $invoice = self::get_invoice( 
  620. $subscription->id,  
  621. $subscription->current_invoice_number + 1 
  622. ); 
  623.  
  624. if ( ! $invoice && $create_missing ) { 
  625. // Create a new invoice. 
  626. $invoice = self::create_invoice( 
  627. $subscription,  
  628. $subscription->current_invoice_number + 1 
  629. ); 
  630.  
  631. /** 
  632. * Since only the *first* invoice can have discount/pro-rating we 
  633. * manually set those values to 0. 
  634. */ 
  635. $invoice->discount = 0; 
  636. $invoice->pro_rate = 0; 
  637. $invoice->notes = array(); 
  638.  
  639. return apply_filters( 
  640. 'ms_model_invoice_get_next_invoice',  
  641. $invoice,  
  642. $subscription,  
  643. $create_missing 
  644. ); 
  645.  
  646. /** 
  647. * Get previous invoice for the membership. 
  648. * @since 1.0.0 
  649. * @param MS_Model_Relationship $subscription The membership relationship. 
  650. * @param string $status The invoice status to find. Optional 
  651. * @return MS_Model_Invoice 
  652. */ 
  653. public static function get_previous_invoice( $subscription, $status = null ) { 
  654. $invoice = self::get_invoice( 
  655. $subscription->id,  
  656. $subscription->current_invoice_number - 1,  
  657. $status 
  658. ); 
  659.  
  660. return apply_filters( 
  661. 'ms_model_invoice_get_previous_invoice',  
  662. $invoice,  
  663. $subscription,  
  664. $status 
  665. ); 
  666.  
  667. /** 
  668. * Create invoice. 
  669. * Create a new invoice using the membership information. 
  670. * @since 1.0.0 
  671. * @param MS_Model_Relationship $subscription The membership to create invoice for. 
  672. * @param int $invoice_number Optional. The invoice number. 
  673. * @return object $invoice 
  674. */ 
  675. public static function create_invoice( $subscription, $invoice_number = false ) { 
  676. $membership = $subscription->get_membership(); 
  677.  
  678. if ( ! MS_Model_Membership::is_valid_membership( $membership->id ) ) { 
  679. throw new Exception( 'Invalid Membership.' ); 
  680.  
  681. $invoice = null; 
  682. $member = MS_Factory::load( 'MS_Model_Member', $subscription->user_id ); 
  683.  
  684. if( isset( $_SESSION['m2_status_check'] ) && $_SESSION['m2_status_check'] == 'inv' ) { 
  685. $invoice_status = self::STATUS_BILLED; 
  686. }else{ 
  687. $invoice_status = self::STATUS_NEW; 
  688. unset( $_SESSION['m2_status_check'] ); 
  689.  
  690. $notes = array(); 
  691.  
  692. if ( empty( $invoice_number ) ) { 
  693. $invoice_number = $subscription->current_invoice_number; 
  694.  
  695. $invoice = self::get_invoice( $subscription->id, $invoice_number ); 
  696.  
  697. // No existing invoice, create a new one. 
  698. if ( ! $invoice || ! $invoice->id ) { 
  699. $invoice = MS_Factory::create( 'MS_Model_Invoice' ); 
  700. $invoice = apply_filters( 'ms_model_invoice', $invoice ); 
  701.  
  702. // Update invoice info. 
  703. $invoice->ms_relationship_id = $subscription->id; 
  704. $invoice->gateway_id = $subscription->gateway_id; 
  705. $invoice->status = $invoice_status; 
  706. $invoice->invoice_date = MS_Helper_Period::current_date(); 
  707. $invoice->membership_id = $membership->id; 
  708. $invoice->currency = MS_Plugin::instance()->settings->currency; 
  709. $invoice->user_id = $member->id; 
  710. $invoice->name = apply_filters( 
  711. 'ms_model_invoice_name',  
  712. sprintf( 
  713. __( 'Invoice for %s - %s', 'membership2' ),  
  714. $membership->name,  
  715. $member->username 
  716. ); 
  717. $invoice->invoice_number = $invoice_number; 
  718. $invoice->discount = 0; 
  719. $invoice->notes = $notes; 
  720. $invoice->amount = $membership->price; // Without taxes! 
  721.  
  722. // Check for trial period in the first period. 
  723. if ( $subscription->is_trial_eligible() 
  724. && $invoice_number === $subscription->current_invoice_number 
  725. ) { 
  726. $invoice->trial_price = $membership->trial_price; // Without taxes! 
  727. $invoice->uses_trial = true; 
  728. $invoice->trial_ends = $subscription->trial_expire_date; 
  729.  
  730. $invoice->set_due_date(); 
  731.  
  732. $invoice = apply_filters( 
  733. 'ms_model_invoice_create_before_save',  
  734. $invoice,  
  735. $subscription 
  736. ); 
  737.  
  738. $invoice->save(); 
  739.  
  740. // Refresh the tax-rate and payment description. 
  741. $invoice->total_amount_changed(); 
  742.  
  743. $invoice->save(); 
  744.  
  745. //If gateway is admin then set the invoice as paid. 
  746. if ( 'admin' == $invoice->gateway_id) { 
  747. $invoice->pay_it( $invoice->gateway_id ); 
  748.  
  749. return apply_filters( 
  750. 'ms_model_relationship_create_invoice',  
  751. $invoice,  
  752. $subscription,  
  753. $invoice_number 
  754. ); 
  755.  
  756.  
  757. // 
  758. // 
  759. // 
  760. // ------------------------------------------------------------- SINGLE ITEM 
  761.  
  762.  
  763. /** 
  764. * Save model. 
  765. * @since 1.0.0 
  766. */ 
  767. public function save() { 
  768. // Validate the pay_date attribute of the invoice. 
  769. $this->validate_pay_date(); 
  770.  
  771. parent::save(); 
  772. parent::store_singleton(); 
  773.  
  774. /** 
  775. * Move an invoice to tha archive - i.e. hide it from the user. 
  776. * @since 1.0.2.0 
  777. */ 
  778. public function archive() { 
  779. if ( $this->id ) { 
  780. $this->add_notes( '----------' ); 
  781. $this->add_notes( 
  782. sprintf( 
  783. __( 'Archived on: %s', 'membership2' ),  
  784. MS_Helper_Period::current_date() 
  785. ); 
  786. $this->add_notes( 
  787. sprintf( 
  788. __( 'Former status: %s', 'membership2' ),  
  789. $this->status 
  790. ); 
  791.  
  792. $this->status = self::STATUS_ARCHIVED; 
  793. $this->save(); 
  794.  
  795. /** 
  796. * Registers the payment and marks the invoice as paid. 
  797. * This should be the only place that sets an invoice status to PAID. 
  798. * @since 1.0.0 
  799. * @param string $gateway_id The payment gateway. 
  800. * @param string $external_id Payment-ID provided by the gateway 
  801. */ 
  802. public function pay_it( $gateway_id = null, $external_id = null ) { 
  803. if ( $gateway_id ) { 
  804. $this->gateway_id = $gateway_id; 
  805. if ( $external_id ) { 
  806. $this->external_id = $external_id; 
  807. $is_paid = false; 
  808.  
  809. $subscription = $this->get_subscription(); 
  810.  
  811. // Save details on the payment. 
  812. if ( 0 == $this->total || MS_Gateway_Free::ID == $gateway_id ) { 
  813. $is_paid = $subscription->add_payment( 
  814. 0,  
  815. MS_Gateway_Free::ID,  
  816. 'free' 
  817. ); 
  818. } else { 
  819. $is_paid = $subscription->add_payment( 
  820. $this->total,  
  821. $gateway_id,  
  822. $external_id 
  823. ); 
  824.  
  825. if ( $is_paid ) { 
  826. $this->status = self::STATUS_PAID; 
  827. $this->pay_date = MS_Helper_Period::current_date(); 
  828. } else { 
  829. $this->status = self::STATUS_BILLED; 
  830.  
  831. // Manual gateway works differently. This conditon avoids infinite loop. 
  832. if ( MS_Gateway_Manual::ID != $gateway_id ) { 
  833. /** 
  834. * Process the payment and update the subscription. 
  835. * This function will call the config_period() function to calculate 
  836. * the new expire date of the subscription. 
  837. * All changes above are also saved at the end of changed() 
  838. */ 
  839. $this->changed(); 
  840.  
  841. /** 
  842. * Notify Add-ons that an invoice was paid. 
  843. * @since 1.0.0 
  844. */ 
  845. do_action( 'ms_invoice_paid', $this, $subscription ); 
  846.  
  847. /** 
  848. * Returns true if the invoice was paid. 
  849. * @since 1.0.0 
  850. * @return bool Payment status. 
  851. */ 
  852. public function is_paid() { 
  853. return $this->status == self::STATUS_PAID; 
  854.  
  855. /** 
  856. * Makes sure that the pay_date attribtue has a valid value. 
  857. * @since 1.0.2.0 
  858. */ 
  859. protected function validate_pay_date() { 
  860. if ( $this->is_paid() && $this->amount ) { 
  861. if ( ! $this->pay_date ) { 
  862. $subscription = $this->get_subscription(); 
  863. $payments = $subscription->get_payments(); 
  864. $last_payment = end( $payments ); 
  865. $this->pay_date = $last_payment['date']; 
  866. if ( ! $this->pay_date ) { 
  867. $this->pay_date = $this->due_date; 
  868. } elseif ( $this->pay_date ) { 
  869. $this->pay_date = ''; 
  870.  
  871. /** 
  872. * Update the subscription details after the invoice has changed. 
  873. * Process transaction status change related to this membership relationship. 
  874. * Change status accordinly to transaction status. 
  875. * @since 1.0.0 
  876. * @param MS_Model_Invoice $invoice The invoice to process. 
  877. * @return MS_Model_Invoice The processed invoice. 
  878. */ 
  879. public function changed() { 
  880. do_action( 
  881. 'ms_model_invoice_changed_before',  
  882. $this 
  883. ); 
  884.  
  885. if ( ! $this->ms_relationship_id ) { 
  886. MS_Helper_Debug::log( 'Cannot process transaction: No relationship defined (inv #' . $this->id .')' ); 
  887. } else { 
  888. $subscription = $this->get_subscription(); 
  889. $member = MS_Factory::load( 'MS_Model_Member', $this->user_id ); 
  890. $membership = $subscription->get_membership(); 
  891.  
  892. switch ( $this->status ) { 
  893. case self::STATUS_NEW: 
  894. case self::STATUS_BILLED: 
  895. break; 
  896.  
  897. case self::STATUS_PAID: 
  898. if ( $this->total > 0 ) { 
  899. MS_Model_Event::save_event( 
  900. MS_Model_Event::TYPE_PAID,  
  901. $subscription 
  902. ); 
  903.  
  904. do_action( 
  905. 'ms_model_invoice_changed-paid',  
  906. $this,  
  907. $member 
  908. ); 
  909.  
  910. // Check for moving memberships 
  911. if ( $subscription->move_from_id ) { 
  912. $ids = explode( ', ', $subscription->move_from_id ); 
  913. foreach ( $ids as $id ) { 
  914. $move_from = MS_Model_Relationship::get_subscription( 
  915. $subscription->user_id,  
  916. $id 
  917. ); 
  918.  
  919. if ( $move_from->is_valid() ) { 
  920. /** 
  921. * @since 1.0.1.2 The old subscription will be 
  922. * deactivated instantly, and not cancelled. 
  923. * When the subscription is cancelled the user 
  924. * still has full access to the membership 
  925. * contents. When it is deactivated he cannot 
  926. * access protected content anymore (instantly). 
  927. */ 
  928. $move_from->deactivate_membership(); 
  929.  
  930. $subscription->cancelled_memberships = $subscription->move_from_id; 
  931. $subscription->move_from_id = ''; 
  932.  
  933. /** 
  934. * Memberships with those payment types can have multiple 
  935. * invoices for a single subscription. 
  936. */ 
  937. $multi_invoice = array( 
  938. MS_Model_Membership::PAYMENT_TYPE_RECURRING,  
  939. MS_Model_Membership::PAYMENT_TYPE_FINITE,  
  940. ); 
  941.  
  942. if ( in_array( $membership->payment_type, $multi_invoice ) ) { 
  943. // Update the current_invoice_number counter. 
  944. $subscription->current_invoice_number = max( 
  945. $subscription->current_invoice_number,  
  946. $this->invoice_number + 1 
  947. ); 
  948.  
  949. if ( MS_Gateway_Manual::ID == $this->gateway_id ) { 
  950. $this->pay_it( $this->gateway_id ); 
  951. break; 
  952.  
  953. case self::STATUS_DENIED: 
  954. MS_Model_Event::save_event( MS_Model_Event::TYPE_PAYMENT_DENIED, $subscription ); 
  955. break; 
  956.  
  957. case self::STATUS_PENDING: 
  958. MS_Model_Event::save_event( MS_Model_Event::TYPE_PAYMENT_PENDING, $subscription ); 
  959. break; 
  960.  
  961. default: 
  962. do_action( 'ms_model_invoice_changed-unknown', $this ); 
  963. break; 
  964.  
  965. $member->save(); 
  966. $this->save(); 
  967.  
  968. $subscription->set_gateway( $this->gateway_id ); 
  969. $subscription->save(); 
  970. return apply_filters( 
  971. 'ms_model_invoice_changed',  
  972. $this,  
  973. $this 
  974. ); 
  975.  
  976. /** 
  977. * Add invoice notes. 
  978. * @since 1.0.0 
  979. * @param string $notes 
  980. */ 
  981. public function add_notes( $notes ) { 
  982. if ( is_string( $this->notes ) ) { 
  983. $this->notes = empty($this->notes) ? array() : (array)$this->notes; 
  984. $this->notes[] = apply_filters( 
  985. 'ms_model_invoice_add_notes',  
  986. $notes,  
  987. $this 
  988. ); 
  989.  
  990. /** 
  991. * Get notes array as string. 
  992. * @since 1.0.0 
  993. * @return string The notes as text description. 
  994. */ 
  995. public function get_notes_desc() { 
  996. $desc = $this->notes; 
  997. if ( is_array( $desc ) ) { 
  998. $desc = implode( "\n", $desc ); 
  999.  
  1000. return apply_filters( 
  1001. 'ms_model_invoice_get_notes_desc',  
  1002. $desc,  
  1003. $this 
  1004. ); 
  1005.  
  1006. /** 
  1007. * Returns a translated version of the invoice status 
  1008. * @since 1.0.0 
  1009. * @return string 
  1010. */ 
  1011. public function status_text() { 
  1012. static $Status = null; 
  1013.  
  1014. if ( null === $Status ) { 
  1015. $Status = self::get_status_types(); 
  1016.  
  1017. $result = $this->status; 
  1018.  
  1019. if ( isset( $Status[$this->status] ) ) { 
  1020. $result = $Status[$this->status]; 
  1021.  
  1022. return apply_filters( 
  1023. 'ms_invoice_status_text',  
  1024. $result,  
  1025. $this->status 
  1026. ); 
  1027.  
  1028. /** 
  1029. * Updates various fields that display/depend on the invoice total amount. 
  1030. * @since 1.0.0 
  1031. */ 
  1032. public function total_amount_changed() { 
  1033. $subscription = $this->get_subscription(); 
  1034.  
  1035. // Allow add-ons or other plugins to set the tax infos for this invoice. 
  1036. $this->tax_rate = apply_filters( 
  1037. 'ms_invoice_tax_rate',  
  1038. 0,  
  1039. $this 
  1040. ); 
  1041. $this->tax_name = apply_filters( 
  1042. 'ms_invoice_tax_name',  
  1043. '',  
  1044. $this 
  1045. ); 
  1046.  
  1047. // Update the invoice descriptions that are displayed to the user. 
  1048. $this->description = apply_filters( 
  1049. 'ms_model_invoice_description',  
  1050. $subscription->get_payment_description( $this ) 
  1051. ); 
  1052. $this->short_description = apply_filters( 
  1053. 'ms_model_invoice_short_description',  
  1054. $subscription->get_payment_description( $this, true ) 
  1055. ); 
  1056.  
  1057. /** 
  1058. * Sets the invoice amount to the price defined by the membership settings. 
  1059. * Provides the filter `ms_model_invoice_price_timeout` which can be used to 
  1060. * define the price-timeout value. The price will not be updated before the 
  1061. * timeout is reached. 
  1062. * Only unpaid invoices are updated! 
  1063. * @since 1.0.0 
  1064. */ 
  1065. private function refresh_amount() { 
  1066. // Never change the amount of paid invoices. 
  1067. if ( $this->is_paid() ) { return; } 
  1068.  
  1069. /** 
  1070. * Define a timeout for the price in unpaid invoices. 
  1071. * The price will not change before the timeout expires, after this 
  1072. * it is updated again based on the current membership settings. 
  1073. * @var int 
  1074. */ 
  1075. $timeout = apply_filters( 
  1076. 'ms_model_invoice_price_timeout',  
  1077. 604800, // 604800 = 7 days 
  1078. $this 
  1079. ); 
  1080.  
  1081. $expire_timestamp = absint( $this->price_date ) + absint( $timeout ); 
  1082.  
  1083. // Do not change price before timeout is reached. 
  1084. if ( $expire_timestamp > time() ) { return; } 
  1085.  
  1086. // Store the current timestamp, so we don't refresh the price until 
  1087. // the timeout expires again. 
  1088. $this->price_date = time(); 
  1089. $membership = $this->get_membership(); 
  1090.  
  1091. // The invoice always has the real membership price as amount, never 
  1092. // the trial amount. 
  1093. $this->amount = $membership->price; // Without taxes! 
  1094.  
  1095. // Re-Calculate the subscription dates 
  1096. $this->set_due_date(); 
  1097.  
  1098. /** 
  1099. * Refreshes the due-date of the invoice. 
  1100. * @since 1.0.0 
  1101. */ 
  1102. public function set_due_date() { 
  1103. // Never change due-date of paid invoices. 
  1104. if ( $this->is_paid() ) { return; } 
  1105.  
  1106. $subscription = $this->get_subscription(); 
  1107.  
  1108. $due_date = false; 
  1109.  
  1110. // Handle special cases in due date calculation. 
  1111. switch ( $subscription->status ) { 
  1112. case MS_Model_Relationship::STATUS_TRIAL: 
  1113. $due_date = $subscription->trial_expire_date; 
  1114. break; 
  1115.  
  1116. case MS_Model_Relationship::STATUS_ACTIVE: 
  1117. case MS_Model_Relationship::STATUS_CANCELED: 
  1118. $due_date = $subscription->expire_date; 
  1119. break; 
  1120.  
  1121. // Default due date is today. 
  1122. if ( empty( $due_date ) ) { 
  1123. if ( $subscription->is_trial_eligible() ) { 
  1124. /** 
  1125. * This invoice includes a trial period. 
  1126. * Payment is due on last day of trial 
  1127. */ 
  1128. $due_date = $subscription->trial_expire_date; 
  1129. } else { 
  1130. // No trial period is used for this invoice. Due now. 
  1131. $due_date = MS_Helper_Period::current_date(); 
  1132.  
  1133. // Update the trial expiration date. 
  1134. $this->trial_ends = $subscription->trial_expire_date; 
  1135.  
  1136. $this->due_date = $due_date; 
  1137.  
  1138. /** 
  1139. * Get invoice net amount: Amount excluding taxes. 
  1140. * Discounting coupon and pro-rating. 
  1141. * Add taxes. 
  1142. * @since 1.0.0 
  1143. */ 
  1144. private function get_net_amount() { 
  1145. if ( ! $this->is_paid() ) { 
  1146. $this->refresh_amount(); 
  1147.  
  1148. $net_amount = $this->amount; // Net amount 
  1149. $net_amount -= $this->discount; // Remove discount 
  1150. $net_amount -= $this->pro_rate; // Remove Pro-Rate 
  1151.  
  1152. if ( $net_amount < 0 ) { 
  1153. $net_amount = 0; 
  1154.  
  1155. // Set precission to 2 decimal points. 
  1156. $net_amount = round( $net_amount, 2 ); 
  1157.  
  1158. return apply_filters( 
  1159. 'ms_model_invoice_get_net_amount',  
  1160. $net_amount,  
  1161. $this 
  1162. ); 
  1163.  
  1164. /** 
  1165. * Returns the tax-value in currency (opposed to the percentage value) 
  1166. * @since 1.0.0 
  1167. * @return float Total tax amount 
  1168. */ 
  1169. private function get_tax() { 
  1170. $tax_rate = $this->tax_rate; 
  1171.  
  1172. if ( ! is_numeric( $tax_rate ) ) { 
  1173. $tax_rate = 0; 
  1174.  
  1175. $value = $this->get_net_amount() * ( $tax_rate / 100 ); 
  1176. if ( $value < 0 ) { 
  1177. $value = 0; 
  1178.  
  1179. return $value; 
  1180.  
  1181. /** 
  1182. * Returns the tax-value in currency for the trial membership (opposed to 
  1183. * the percentage value) 
  1184. * @since 1.0.0 
  1185. * @return float Total tax amount (trial membership) 
  1186. */ 
  1187. private function get_trial_tax() { 
  1188. $tax_rate = $this->tax_rate; 
  1189.  
  1190. if ( ! is_numeric( $tax_rate ) ) { 
  1191. $tax_rate = 0; 
  1192.  
  1193. $value = floatval( $this->trial_price ) * ( $tax_rate / 100 ); 
  1194. if ( $value < 0 ) { 
  1195. $value = 0; 
  1196.  
  1197. return $value; 
  1198.  
  1199. /** 
  1200. * Get invoice total. 
  1201. * Discounting coupon and pro-rating. 
  1202. * Add taxes. 
  1203. * @since 1.0.0 
  1204. */ 
  1205. private function get_total() { 
  1206. $total = $this->get_net_amount(); // Net amount 
  1207. $total += $this->get_tax(); // Tax-Rate was defined in `create_invoice()` 
  1208.  
  1209. if ( $total < 0 ) { 
  1210. $total = 0; 
  1211.  
  1212. // Set precission to 2 decimal points. 
  1213. $total = round( $total, 2 ); 
  1214.  
  1215. $this->total = apply_filters( 
  1216. 'ms_model_invoice_get_total',  
  1217. $total,  
  1218. $this 
  1219. ); 
  1220.  
  1221. return $this->total; 
  1222.  
  1223. /** 
  1224. * Get invoice trial price. 
  1225. * @since 1.0.0 
  1226. */ 
  1227. private function get_trial_price() { 
  1228. $membership = $this->get_membership(); 
  1229. $trial_price = $membership->trial_price; // Net amount 
  1230. $trial_price += $this->get_trial_tax(); // Tax-Rate was defined in `create_invoice()` 
  1231.  
  1232. if ( $trial_price < 0 ) { 
  1233. $trial_price = 0; 
  1234.  
  1235. // Set precission to 2 decimal points. 
  1236. $trial_price = round( $trial_price, 2 ); 
  1237.  
  1238. $this->trial_price = apply_filters( 
  1239. 'ms_model_invoice_get_trial_price',  
  1240. $trial_price,  
  1241. $this 
  1242. ); 
  1243.  
  1244. return $this->trial_price; 
  1245.  
  1246. /** 
  1247. * Returns the public invoice number for this invoice. 
  1248. * The public invoice number is the official identifier that is displayed 
  1249. * to the end user that refers to an invoice 
  1250. * @since 1.0.0 
  1251. * @return string The public invoice number. 
  1252. */ 
  1253. public function get_invoice_number() { 
  1254. $identifier = '#' . $this->id . '-' . $this->invoice_number; 
  1255.  
  1256. return apply_filters( 
  1257. 'ms_model_invoice_the_number',  
  1258. $identifier,  
  1259. $this 
  1260. ); 
  1261.  
  1262. /** 
  1263. * Returns the membership model that is linked to this invoice. 
  1264. * @since 1.0.0 
  1265. * @return MS_Model_Membership 
  1266. */ 
  1267. public function get_membership() { 
  1268. return MS_Factory::load( 'MS_Model_Membership', $this->membership_id ); 
  1269.  
  1270. /** 
  1271. * Returns the membership model that is linked to this invoice. 
  1272. * @since 1.0.0 
  1273. * @return MS_Model_Membership 
  1274. */ 
  1275. public function get_member() { 
  1276. return MS_Factory::load( 'MS_Model_Member', $this->user_id ); 
  1277.  
  1278. /** 
  1279. * Returns the subscription model that is linked to this invoice. 
  1280. * @since 1.0.0 
  1281. * @return MS_Model_Relationship 
  1282. */ 
  1283. public function get_subscription() { 
  1284. return MS_Factory::load( 'MS_Model_Relationship', $this->ms_relationship_id ); 
  1285.  
  1286. /** 
  1287. * Returns property associated with the render. 
  1288. * @since 1.0.0 
  1289. * @internal 
  1290. * @param string $property The name of a property. 
  1291. * @return mixed Returns mixed value of a property or NULL if a property doesn't exist. 
  1292. */ 
  1293. public function __get( $property ) { 
  1294. $value = null; 
  1295.  
  1296. switch ( $property ) { 
  1297. case 'total': 
  1298. $value = $this->get_total(); 
  1299. break; 
  1300.  
  1301. case 'trial_price': 
  1302. $value = $this->get_trial_price(); 
  1303. break; 
  1304.  
  1305. case 'invoice': 
  1306. $value = $this->id; 
  1307. break; 
  1308.  
  1309. case 'short_description': 
  1310. if ( empty( $this->short_description ) ) { 
  1311. $value = $this->description; 
  1312. } else { 
  1313. $value = $this->short_description; 
  1314. break; 
  1315.  
  1316. case 'invoice_date': 
  1317. $value = $this->invoice_date; 
  1318.  
  1319. if ( empty( $value ) ) { 
  1320. $value = get_the_date( 'Y-m-d', $this->id ); 
  1321. break; 
  1322.  
  1323. case 'pay_date': 
  1324. $this->validate_pay_date(); 
  1325. $value = $this->pay_date; 
  1326. break; 
  1327.  
  1328. case 'tax': 
  1329. $value = $this->get_tax(); 
  1330. break; 
  1331.  
  1332. case 'trial_tax': 
  1333. $value = $this->get_trial_tax(); 
  1334. break; 
  1335.  
  1336. case 'subtotal': 
  1337. $value = $this->get_net_amount(); 
  1338. break; 
  1339.  
  1340. default: 
  1341. if ( property_exists( $this, $property ) ) { 
  1342. $value = $this->$property; 
  1343. break; 
  1344.  
  1345. return apply_filters( 
  1346. 'ms_model_invoice__get',  
  1347. $value,  
  1348. $property,  
  1349. $this 
  1350. ); 
  1351.  
  1352. /** 
  1353. * Set specific property. 
  1354. * @since 1.0.0 
  1355. * @internal 
  1356. * @param string $property The name of a property to associate. 
  1357. * @param mixed $value The value of a property. 
  1358. */ 
  1359. public function __set( $property, $value ) { 
  1360. switch ( $property ) { 
  1361. case 'name': 
  1362. case 'currency': 
  1363. $this->$property = sanitize_text_field( $value ); 
  1364. break; 
  1365.  
  1366. case 'notes': 
  1367. if ( is_array( $value ) ) { 
  1368. $this->notes = array_map( 'sanitize_text_field', $value ); 
  1369. } else { 
  1370. $this->notes = array( sanitize_text_field( $value ) ); 
  1371. break; 
  1372.  
  1373. case 'status': 
  1374. if ( array_key_exists( $value, self::get_status_types() ) ) { 
  1375. $this->$property = $value; 
  1376. break; 
  1377.  
  1378. case 'due_date': 
  1379. $this->$property = $this->validate_date( $value ); 
  1380. break; 
  1381.  
  1382. case 'amount': 
  1383. case 'discount': 
  1384. case 'pro_rate': 
  1385. case 'trial_price': 
  1386. $this->$property = floatval( $value ); 
  1387. $this->total_amount_changed(); 
  1388. $this->get_total(); 
  1389. $this->get_trial_price(); 
  1390. break; 
  1391.  
  1392. default: 
  1393. if ( property_exists( $this, $property ) ) { 
  1394. $this->$property = $value; 
  1395. break; 
  1396.  
  1397. do_action( 
  1398. 'ms_model_invoice__set_after',  
  1399. $property,  
  1400. $value,  
  1401. $this 
  1402. ); 
  1403.  
  1404. /** 
  1405. * Check if property isset. 
  1406. * @since 1.0.0 
  1407. * @internal 
  1408. * @param string $property The name of a property. 
  1409. * @return mixed Returns true/false. 
  1410. */ 
  1411. public function __isset( $property ) { 
  1412. return isset($this->$property); 
  1413. }