PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 1.3.2
Subscriptions for WooCommerce with Stripe Recurring Payments v1.3.2
2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
subscription / includes / Illuminate / Helper.php

Helper.php in Subscriptions for WooCommerce with Stripe Recurring Payments 1.3.2, at includes/Illuminate/Helper.php

592 lines 18.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SpringDevs\Subscription\Illuminate;
4
5 /**
6 * Class Helper || Some Helper Methods
7 *
8 * @package SpringDevs\Subscription\Illuminate
9 */
10 class Helper {
11
12 /**
13 * Get type's singular or plural from time_per.
14 *
15 * @param int $number timing_per.
16 * @param string $typo timing_option.
17 *
18 * @return string
19 */
20 public static function get_typos( $number, $typo ) {
21 if ( 1 === (int) $number && 'days' === $typo ) {
22 return __( 'day', 'sdevs_subscrpt' );
23 } elseif ( 1 === (int) $number && 'weeks' === $typo ) {
24 return __( 'week', 'sdevs_subscrpt' );
25 } elseif ( 1 === (int) $number && 'months' === $typo ) {
26 return __( 'month', 'sdevs_subscrpt' );
27 } elseif ( 1 === (int) $number && 'years' === $typo ) {
28 return __( 'year', 'sdevs_subscrpt' );
29 } else {
30 return $typo;
31 }
32 }
33
34 /**
35 * Generate start date
36 *
37 * @param null|string $trial Trial.
38 *
39 * @return string
40 */
41 public static function start_date( $trial = null ) {
42 if ( null === $trial ) {
43 $start_date = time();
44 } else {
45 $start_date = strtotime( $trial );
46 }
47 return wp_date( get_option( 'date_format' ), $start_date );
48 }
49
50 /**
51 * Generate next date
52 *
53 * @param string $time Time.
54 * @param null|string $trial Trial.
55 *
56 * @return string
57 */
58 public static function next_date( $time, $trial = null ) {
59 if ( null === $trial ) {
60 $start_date = time();
61 } else {
62 $start_date = strtotime( $trial );
63 }
64 return wp_date( get_option( 'date_format' ), strtotime( $time, $start_date ) );
65 }
66
67 /**
68 * Check subscription exists by product ID.
69 *
70 * @param int $product_id Product ID.
71 * @param string|array $status Status.
72 *
73 * @return \WP_Post | false
74 */
75 public static function subscription_exists( int $product_id, $status ) {
76 if ( 0 === get_current_user_id() ) {
77 return false;
78 }
79
80 $args = array(
81 'post_type' => 'subscrpt_order',
82 'post_status' => $status,
83 'fields' => 'ids',
84 'meta_query' => array(
85 array(
86 'key' => '_subscrpt_product_id',
87 'value' => $product_id,
88 ),
89 ),
90 'author' => get_current_user_id(),
91 );
92
93 $posts = get_posts( $args );
94 return count( $posts ) > 0 ? $posts[0] : false;
95 }
96
97 /**
98 * Check if product trial exixts for an user.
99 *
100 * @param int $product_id Product ID.
101 *
102 * @return boolean
103 */
104 public static function check_trial( int $product_id ): bool {
105 return ! self::subscription_exists( $product_id, array( 'expired', 'pending', 'active', 'on-hold', 'pe_cancelled', 'cancelled' ) );
106 }
107
108 /**
109 * Rewew when expired.
110 *
111 * @param int $subscription_id Subscription ID.
112 */
113 public static function renew( int $subscription_id ) {
114 $trial = get_post_meta( $subscription_id, '_subscrpt_trial', true );
115 if ( null !== $trial ) {
116 update_post_meta( $subscription_id, '_subscrpt_trial', null );
117 }
118
119 do_action( 'subscrpt_when_product_expired', $subscription_id, true );
120 }
121
122 /**
123 * Get Subscriptions Histories
124 *
125 * @param int $order_id Order ID.
126 */
127 public static function get_subscriptions_from_order( $order_id ) {
128 global $wpdb;
129 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
130 $histories = $wpdb->get_results(
131 $wpdb->prepare(
132 // @phpcs:ignore
133 'SELECT * FROM %i WHERE order_id=%d',
134 array( $table_name, $order_id )
135 )
136 );
137
138 return $histories;
139 }
140
141 /**
142 * Get Subscriptions Histories
143 *
144 * @param int $order_item_id Order item ID.
145 */
146 public static function get_subscription_from_order_item_id( $order_item_id ) {
147 global $wpdb;
148 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
149 return $wpdb->get_row(
150 $wpdb->prepare(
151 // @phpcs:ignore
152 'SELECT * FROM %i WHERE order_item_id=%d',
153 array( $table_name, $order_item_id )
154 )
155 );
156 }
157
158 /**
159 * Format price with Subscription
160 *
161 * @param string $price Price.
162 * @param int $subscription_id Subscription ID.
163 * @param bool $display_trial True/False.
164 *
165 * @return string
166 */
167 public static function format_price_with_subscription( $price, $subscription_id, $display_trial = false ) {
168 $order_id = get_post_meta( $subscription_id, '_subscrpt_order_id', true );
169 $order_item_id = get_post_meta( $subscription_id, '_subscrpt_order_item_id', true );
170 $item_meta = wc_get_order_item_meta( $order_item_id, '_subscrpt_meta', true );
171
172 $order = wc_get_order( $order_id );
173 $time = '1' === $item_meta['time'] ? null : $item_meta['time'] . ' ';
174 $type = self::get_typos( $item_meta['time'], $item_meta['type'] );
175
176 $formatted_price = wc_price(
177 $price,
178 array(
179 'currency' => $order->get_currency(),
180 )
181 ) . ' / ' . $time . $type;
182
183 if ( $display_trial ) {
184 $trial = $item_meta['trial'];
185 $has_trial = isset( $item_meta['trial'] ) && strlen( $item_meta['trial'] ) > 2;
186
187 if ( $has_trial ) {
188 $trial_html = '<br/><small> + Got ' . $trial . ' free trial!</small>';
189 $formatted_price .= $trial_html;
190 }
191 }
192
193 return apply_filters( 'subscrpt_format_price_with_subscription', $formatted_price, $price, $subscription_id );
194 }
195
196 /**
197 * Format price with order item
198 *
199 * @param string $price Price.
200 * @param int $item_id Item Id.
201 * @param bool $display_trial display trial?.
202 *
203 * @return string
204 */
205 public static function format_price_with_order_item( $price, $item_id, $display_trial = false ) {
206 $order_id = wc_get_order_id_by_order_item_id( $item_id );
207 $order = wc_get_order( $order_id );
208
209 $item_meta = wc_get_order_item_meta( $item_id, '_subscrpt_meta', true );
210
211 if ( ! $item_meta || ! is_array( $item_meta ) ) {
212 return false;
213 }
214
215 $time = 1 === (int) $item_meta['time'] ? null : $item_meta['time'] . '-';
216 $type = self::get_typos( $item_meta['time'], $item_meta['type'] );
217
218 $formatted_price = wc_price(
219 $price,
220 array(
221 'currency' => $order->get_currency(),
222 )
223 ) . ' / ' . $time . $type;
224
225 if ( $display_trial ) {
226 $trial = $item_meta['trial'];
227 $has_trial = isset( $item_meta['trial'] ) && strlen( $item_meta['trial'] ) > 2;
228
229 if ( $has_trial ) {
230 $trial_html = '<br/><small> + Got ' . $trial . ' free trial!</small>';
231 $formatted_price .= $trial_html;
232 }
233 }
234
235 return apply_filters( 'subscrpt_format_price_with_subscription', $formatted_price, $price, $item_id );
236 }
237
238 /**
239 * Get total subscriptions by product ID.
240 *
241 * @param int $product_id Product ID.
242 * @param string | array $status Status.
243 *
244 * @return \WP_Post | false
245 */
246 public static function get_total_subscriptions_from_product( int $product_id, $status = array( 'active', 'pending', 'expired', 'pe_cancelled', 'cancelled' ) ) {
247 $args = array(
248 'post_type' => 'subscrpt_order',
249 'post_status' => $status,
250 'fields' => 'ids',
251 'meta_query' => array(
252 array(
253 'key' => '_subscrpt_product_id',
254 'value' => $product_id,
255 ),
256 ),
257 );
258
259 $posts = get_posts( $args );
260
261 return count( $posts );
262 }
263
264 /**
265 * Process renewal on order.
266 *
267 * @param int $subscription_id Subscription Id.
268 * @param int $order_id Order Id.
269 * @param int $order_item_id Order Item Id.
270 *
271 * @return void
272 */
273 public static function process_order_renewal( $subscription_id, $order_id, $order_item_id ) {
274 global $wpdb;
275 $history_table = $wpdb->prefix . 'subscrpt_order_relation';
276
277 $comment_id = wp_insert_comment(
278 array(
279 'comment_author' => 'Subscription for WooCommerce',
280 'comment_content' => sprintf(
281 // translators: order id.
282 __( 'The order %s has been created for the subscription', 'sdevs_subscrpt' ),
283 $order_id
284 ),
285 'comment_post_ID' => $subscription_id,
286 'comment_type' => 'order_note',
287 )
288 );
289 update_comment_meta( $comment_id, '_subscrpt_activity', __( 'Renewal Order', 'sdevs_subscrpt' ) );
290
291 $wpdb->insert(
292 $history_table,
293 array(
294 'subscription_id' => $subscription_id,
295 'order_id' => $order_id,
296 'order_item_id' => $order_item_id,
297 'type' => 'renew',
298 )
299 );
300 }
301
302 /**
303 * Process new subscription on order.
304 *
305 * @param \WC_Order_Item $order_item Order Item.
306 * @param string $post_status status.
307 * @param \WC_Product $product Product.
308 *
309 * @return int
310 */
311 public static function process_new_subscription_order( $order_item, $post_status, $product ) {
312 global $wpdb;
313 $history_table = $wpdb->prefix . 'subscrpt_order_relation';
314
315 $args = array(
316 'post_title' => 'Subscription',
317 'post_type' => 'subscrpt_order',
318 'post_status' => $post_status,
319 );
320 $subscription_id = wp_insert_post( $args );
321 wp_update_post(
322 array(
323 'ID' => $subscription_id,
324 'post_title' => "Subscription #{$subscription_id}",
325 )
326 );
327 $comment_id = wp_insert_comment(
328 array(
329 'comment_author' => 'Subscription for WooCommerce',
330 'comment_content' => sprintf(
331 // translators: Order Id.
332 __( 'Subscription successfully created. order is %s', 'sdevs_subscrpt' ),
333 $order_item->get_order_id()
334 ),
335 'comment_post_ID' => $subscription_id,
336 'comment_type' => 'order_note',
337 )
338 );
339 update_comment_meta( $comment_id, '_subscrpt_activity', __( 'New Subscription', 'sdevs_subscrpt' ) );
340
341 update_post_meta( $subscription_id, '_subscrpt_product_id', $product->get_id() );
342
343 $wpdb->insert(
344 $history_table,
345 array(
346 'subscription_id' => $subscription_id,
347 'order_id' => $order_item->get_order_id(),
348 'order_item_id' => $order_item->get_id(),
349 'type' => 'new',
350 )
351 );
352
353 return $subscription_id;
354 }
355
356 /**
357 * Get recurrings items from cart items.
358 *
359 * @param array $cart_items Cart items.
360 *
361 * @return array
362 */
363 public static function get_recurrs_for_cart( $cart_items ) {
364 $recurrs = array();
365 foreach ( $cart_items as $key => $cart_item ) {
366 $product = $cart_item['data'];
367 if ( $product->is_type( 'simple' ) && isset( $cart_item['subscription'] ) ) {
368 $cart_subscription = $cart_item['subscription'];
369 $type = $cart_subscription['type'];
370
371 $price_html = wc_price( $cart_subscription['per_cost'] * $cart_item['quantity'] ) . '/ ' . $type;
372 $recurrs[ $key ] = array(
373 'trial_status' => ! is_null( $cart_subscription['trial'] ),
374 'price_html' => $price_html,
375 'start_date' => self::start_date( $cart_subscription['trial'] ),
376 'next_date' => self::next_date( ( $cart_subscription['time'] ?? 1 ) . ' ' . $cart_subscription['type'], $cart_subscription['trial'] ),
377 'can_user_cancel' => $cart_item['data']->get_meta( '_subscrpt_user_cancel' ),
378 );
379 }
380 }
381
382 return apply_filters( 'subscrpt_cart_recurring_items', $recurrs, $cart_items );
383 }
384
385 /**
386 * Create renewal order when subscription expired. [wip]
387 *
388 * @param int $subscription_id Subscription ID.
389 * @throws \WC_Data_Exception Exception.
390 * @throws \Exception Exception.
391 */
392 public static function create_renewal_order( $subscription_id ) {
393 $order_item_id = get_post_meta( $subscription_id, '_subscrpt_order_item_id', true );
394 $order_id = wc_get_order_id_by_order_item_id( $order_item_id );
395 $old_order = self::check_order_for_renewal( $order_id );
396
397 if ( ! $old_order ) {
398 return;
399 }
400
401 $order_item = $old_order->get_item( $order_item_id );
402 $subscription_price = get_post_meta( $subscription_id, '_subscrpt_price', true );
403 $product_args = array(
404 'name' => $order_item->get_name(),
405 'subtotal' => $subscription_price,
406 'total' => $subscription_price,
407 );
408
409 // creating new order.
410 $new_order_data = self::create_new_order_for_renewal( $old_order, $order_item, $product_args );
411 if ( ! $new_order_data ) {
412 return;
413 }
414 $new_order = $new_order_data['order'];
415 $new_order_item_id = $new_order_data['order_item_id'];
416
417 self::create_renewal_history( $subscription_id, $new_order->get_id(), $new_order_item_id );
418 update_post_meta( $subscription_id, '_subscrpt_order_id', $new_order->get_id() );
419 update_post_meta( $subscription_id, '_subscrpt_order_item_id', $new_order_item_id );
420
421 self::clone_order_metadata( $new_order, $old_order );
422 self::clone_stripe_metadata_for_renewal( $subscription_id, $old_order, $new_order );
423
424 $new_order->calculate_totals();
425 $new_order->save();
426 if ( ! is_admin() && function_exists( 'wc_add_notice' ) ) {
427 $message = 'Renewal Order(#' . $new_order->get_id() . ') Created.';
428 if ( $new_order->has_status( 'pending' ) ) {
429 $message .= 'Please <a href="' . $new_order->get_checkout_payment_url() . '">Pay now</a>';
430 }
431 wc_add_notice( $message, 'success' );
432 }
433
434 do_action( 'subscrpt_after_create_renew_order', $new_order, $old_order, $subscription_id, false );
435 }
436
437 /**
438 * Clone stripe metadata from old order.
439 *
440 * @param int $subscription_id Subscription Id.
441 * @param \WC_Order $old_order Old Order Object.
442 * @param \WC_Order $new_order New Order Object.
443 *
444 * @return void
445 */
446 public static function clone_stripe_metadata_for_renewal( $subscription_id, $old_order, $new_order ) {
447 $is_auto_renew = get_post_meta( $subscription_id, '_subscrpt_auto_renew', true );
448 $stripe_enabled = ( 'stripe' === $old_order->get_payment_method() && in_array( $is_auto_renew, array( 1, '1' ), true ) && subscrpt_is_auto_renew_enabled() && '1' === get_option( 'subscrpt_stripe_auto_renew', '1' ) );
449 if ( $stripe_enabled ) {
450 $new_order->update_meta_data( '_stripe_customer_id', $old_order->get_meta( '_stripe_customer_id' ) );
451 $new_order->update_meta_data( '_stripe_source_id', $old_order->get_meta( '_stripe_source_id' ) );
452 $new_order->set_payment_method( $old_order->get_payment_method() );
453 $new_order->set_payment_method_title( $old_order->get_payment_method_title() );
454 }
455 }
456
457 /**
458 * Create history for renewal.
459 *
460 * @param int $subscription_id Subscription Id.
461 * @param int $new_order_id New Order Id.
462 * @param int $new_order_item_id New Order Item Id.
463 *
464 * @return void
465 */
466 public static function create_renewal_history( $subscription_id, $new_order_id, $new_order_item_id ) {
467 global $wpdb;
468 $history_table = $wpdb->prefix . 'subscrpt_order_relation';
469 $wpdb->insert(
470 $history_table,
471 array(
472 'subscription_id' => $subscription_id,
473 'order_id' => $new_order_id,
474 'order_item_id' => $new_order_item_id,
475 'type' => 'renew',
476 )
477 );
478
479 $comment_id = wp_insert_comment(
480 array(
481 'comment_author' => 'Subscription for WooCommerce',
482 'comment_content' => sprintf( 'Subscription Renewal order successfully created. order is %s', $new_order_id ),
483 'comment_post_ID' => $subscription_id,
484 'comment_type' => 'order_note',
485 )
486 );
487 update_comment_meta( $comment_id, '_subscrpt_activity', 'Renewal Order' );
488 }
489
490 /**
491 * Create new order for renewal.
492 *
493 * @param \WC_Order $old_order Old Order Object.
494 * @param \WC_Order_Item $order_item Old Order Item Object.
495 * @param array $product_args Product args for add product.
496 *
497 * @return array|false
498 */
499 public static function create_new_order_for_renewal( \WC_Order $old_order, \WC_Order_Item $order_item, array $product_args ) {
500 $product = $order_item->get_product();
501 $user_id = $old_order->get_user_id();
502 $new_order = wc_create_order(
503 array(
504 'customer_id' => $user_id,
505 'status' => 'pending',
506 )
507 );
508 $product_meta = apply_filters( 'subscrpt_renewal_item_meta', wc_get_order_item_meta( $order_item->get_id(), '_subscrpt_meta', true ), $product, $order_item );
509 $product_args = apply_filters( 'subscrpt_renewal_product_args', $product_args, $product, $order_item );
510 if ( ! $product_args ) {
511 return false;
512 }
513
514 $new_order_item_id = $new_order->add_product(
515 $product,
516 $order_item->get_quantity(),
517 $product_args
518 );
519 wc_update_order_item_meta(
520 $new_order_item_id,
521 '_subscrpt_meta',
522 array(
523 'time' => $product_meta['time'],
524 'type' => $product_meta['type'],
525 'trial' => null,
526 )
527 );
528
529 return array(
530 'order' => $new_order,
531 'order_item_id' => $new_order_item_id,
532 );
533 }
534
535 /**
536 * Check if old order is completed or deleted!
537 *
538 * @param mixed $old_order_id Old Order Id.
539 *
540 * @return \WC_Order|false
541 */
542 public static function check_order_for_renewal( $old_order_id ) {
543 $old_order = wc_get_order( $old_order_id );
544 if ( ! $old_order || 'completed' !== $old_order->get_status() ) {
545 if ( ! is_admin() && function_exists( 'wc_add_notice' ) ) {
546 return wc_add_notice( __( 'Subscription renewal isn\'t possible due to previous order not completed or deletion.', 'sdevs_subscrpt' ), 'error' );
547 }
548 return false;
549 }
550
551 return $old_order;
552 }
553
554 /**
555 * Save meta-data from old order
556 *
557 * @param \WC_Order $new_order new order object.
558 * @param \WC_Order $old_order old order object.
559 *
560 * @return void
561 */
562 public static function clone_order_metadata( $new_order, $old_order ) {
563 $new_order->set_customer_id( $old_order->get_customer_id() );
564 $new_order->set_currency( $old_order->get_currency() );
565
566 // 3 Add Billing Fields
567 $customer = new \WC_Customer( $old_order->get_customer_id() );
568 $new_order->set_billing_city( $customer->get_billing_city() );
569 $new_order->set_billing_state( $customer->get_billing_state() );
570 $new_order->set_billing_postcode( $customer->get_billing_postcode() );
571 $new_order->set_billing_email( $customer->get_billing_email() );
572 $new_order->set_billing_phone( $customer->get_billing_phone() );
573 $new_order->set_billing_address_1( $customer->get_billing_address_1() );
574 $new_order->set_billing_address_2( $customer->get_billing_address_2() );
575 $new_order->set_billing_country( $customer->get_billing_country() );
576 $new_order->set_billing_first_name( $customer->get_billing_first_name() );
577 $new_order->set_billing_last_name( $customer->get_billing_last_name() );
578 $new_order->set_billing_company( $customer->get_billing_company() );
579
580 // 4 Add Shipping Fields
581 $new_order->set_shipping_country( $customer->get_shipping_country() );
582 $new_order->set_shipping_first_name( $customer->get_shipping_first_name() );
583 $new_order->set_shipping_last_name( $customer->get_shipping_last_name() );
584 $new_order->set_shipping_company( $customer->get_shipping_company() );
585 $new_order->set_shipping_address_1( $customer->get_shipping_address_1() );
586 $new_order->set_shipping_address_2( $customer->get_shipping_address_2() );
587 $new_order->set_shipping_city( $customer->get_shipping_city() );
588 $new_order->set_shipping_state( $customer->get_shipping_state() );
589 $new_order->set_shipping_postcode( $customer->get_shipping_postcode() );
590 }
591 }
592