PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 1.9.5
Subscriptions for WooCommerce with Stripe Recurring Payments v1.9.5
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 / Order.php

Order.php in Subscriptions for WooCommerce with Stripe Recurring Payments 1.9.5, at includes/Illuminate/Order.php

464 lines 15.3 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 Order
7 *
8 * @package SpringDevs\Subscription\Illuminate
9 */
10 class Order {
11
12 /**
13 * Initialize the class.
14 */
15 public function __construct() {
16 add_action( 'woocommerce_admin_order_item_headers', array( $this, 'register_custom_column' ) );
17 add_action( 'woocommerce_admin_order_item_values', array( $this, 'add_column_value' ), 10, 2 );
18 add_action( 'woocommerce_before_order_itemmeta', array( $this, 'add_order_item_data' ), 10, 3 );
19 add_action( 'woocommerce_order_status_changed', array( $this, 'order_status_changed' ) );
20 add_action( 'woocommerce_before_delete_order', array( $this, 'delete_the_subscription' ) );
21 add_action( 'subscrpt_subscription_activated', array( $this, 'generate_dates_for_subscription' ) );
22
23 add_action( 'subscrpt_queue_trial_order_autocomplete', array( $this, 'auto_complete_subscription_trial_order' ) );
24 }
25
26 /**
27 * Generate start, next and trial dates.
28 *
29 * @param int $subscription_id Subscription Id.
30 *
31 * @return void
32 */
33 public function generate_dates_for_subscription( $subscription_id ) {
34 $order_item_id = get_post_meta( $subscription_id, '_subscrpt_order_item_id', true );
35 $subscription_history = Helper::get_subscription_from_order_item_id( $order_item_id );
36
37 $order_item_meta = wc_get_order_item_meta( $order_item_id, '_subscrpt_meta' );
38 $type = Helper::get_typos( 1, $order_item_meta['type'] );
39 $trial = get_post_meta( $subscription_id, '_subscrpt_trial', true );
40 $recurr_timing = ( $order_item_meta['time'] ?? 1 ) . ' ' . $type;
41
42 if ( 'new' === $subscription_history->type ) {
43 $start_date = time();
44 $next_date = sdevs_wp_strtotime( $recurr_timing, $start_date );
45
46 if ( $trial && ! empty( $trial ) ) {
47 $trial_started = get_post_meta( $subscription_id, '_subscrpt_trial_started', true );
48 $trial_ended = get_post_meta( $subscription_id, '_subscrpt_trial_ended', true );
49
50 if ( empty( $trial_started ) && empty( $trial_ended ) ) {
51 $start_date = sdevs_wp_strtotime( $trial );
52 $next_date = $start_date;
53
54 update_post_meta( $subscription_id, '_subscrpt_trial_started', time() );
55 update_post_meta( $subscription_id, '_subscrpt_trial_ended', $start_date );
56 update_post_meta( $subscription_id, '_subscrpt_trial_mode', 'on' );
57 }
58
59 if ( ! empty( $trial_ended ) ) {
60 $start_date = $trial_ended;
61 $next_date = $start_date;
62 }
63 }
64
65 update_post_meta( $subscription_id, '_subscrpt_start_date', $start_date );
66
67 } elseif ( 'renew' === $subscription_history->type ) {
68 if ( $trial ) {
69 delete_post_meta( $subscription_id, '_subscrpt_trial' );
70 delete_post_meta( $subscription_id, '_subscrpt_trial_mode' );
71 delete_post_meta( $subscription_id, '_subscrpt_trial_started' );
72 delete_post_meta( $subscription_id, '_subscrpt_trial_ended' );
73 }
74
75 $next_date = sdevs_wp_strtotime( $recurr_timing, time() );
76
77 } elseif ( 'early-renew' === $subscription_history->type ) {
78 if ( $trial ) {
79 delete_post_meta( $subscription_id, '_subscrpt_trial' );
80 delete_post_meta( $subscription_id, '_subscrpt_trial_mode' );
81 delete_post_meta( $subscription_id, '_subscrpt_trial_started' );
82 delete_post_meta( $subscription_id, '_subscrpt_trial_ended' );
83 }
84
85 $next_date = sdevs_wp_strtotime( $recurr_timing, time() );
86 }
87
88 // Allow filtering of next due date logic
89 $next_date = apply_filters( 'subscrpt_split_payment_next_due_date', $next_date, $subscription_id, $recurr_timing, $subscription_history->type );
90
91 update_post_meta( $subscription_id, '_subscrpt_next_date', $next_date );
92 }
93
94 /**
95 * Add custom column on order item.
96 *
97 * @return void
98 */
99 public function register_custom_column() {
100 ?>
101 <th class="item_recurring sortable" data-sort="float"><?php esc_html_e( 'Recurring', 'subscription' ); ?></th>
102 <?php
103 }
104
105 /**
106 * Display data for custom column.
107 *
108 * @param \WC_Product $product Product Object.
109 * @param \WC_Order_Item $item Order Item.
110 *
111 * @return void
112 */
113 public function add_column_value( $product, $item ) {
114 if ( ! method_exists( $item, 'get_id' ) || ! method_exists( $item, 'get_subtotal' ) ) {
115 return;
116 }
117
118 $subtotal = '-';
119 $item_id = $item->get_id();
120 $subscription_id = Helper::get_subscription_from_order_item_id( $item->get_id() );
121
122 if ( ! $subscription_id ) {
123 echo "<td class='item_recurring' width='15%'>-</td>";
124 return;
125 }
126 $subscription_id = $subscription_id->subscription_id;
127
128 $price = get_post_meta( $subscription_id, '_subscrpt_price', true );
129 $subtotal = Helper::format_price_with_order_item( $price, $item_id );
130 ?>
131 <td class="item_recurring" width="15%">
132 <div class="view">
133 <?php echo wp_kses_post( $subtotal ); ?>
134 </div>
135 </td>
136 <?php
137 }
138
139 public function add_order_item_data( $item_id, $item, $product ) {
140 if ( ! $product ) {
141 return;
142 }
143
144 $item_meta = wc_get_order_item_meta( $item_id, '_subscrpt_meta', true );
145
146 if ( ! $item_meta || ! is_array( $item_meta ) ) {
147 return false;
148 }
149
150 $trial = $item_meta['trial'];
151 $has_trial = isset( $item_meta['trial'] ) && strlen( $item_meta['trial'] ) > 2;
152
153 if ( $has_trial ) {
154 echo '<br/><small> + Got ' . esc_html( $trial ) . ' free trial!</small>';
155 }
156 }
157
158 /**
159 * Take some actions based on order status changed.
160 *
161 * @param int $order_id Order Id.
162 */
163 public function order_status_changed( $order_id ) {
164 $order = wc_get_order( $order_id );
165 $post_status = 'active';
166
167 switch ( $order->get_status() ) {
168 case 'on-hold':
169 case 'pending':
170 $post_status = 'pending';
171 break;
172
173 case 'refunded':
174 case 'failed':
175 case 'cancelled':
176 $post_status = 'cancelled';
177 break;
178
179 default:
180 $post_status = 'active';
181 break;
182 }
183 $post_status = apply_filters( 'subscript_order_status_to_post_status', $post_status, $order );
184
185 global $wpdb;
186 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
187 // @phpcs:ignore
188 $histories = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE order_id=%d', array( $table_name, $order_id ) ) );
189
190 foreach ( $histories as $history ) {
191 if ( 'new' === $history->type || 'renew' === $history->type ) {
192 $subscription_id = $history->subscription_id;
193 wp_update_post(
194 array(
195 'ID' => $subscription_id,
196 'post_status' => $post_status,
197 )
198 );
199
200 // If possible change order status to completed if it has a trial subscription.
201 $this->maybe_trigger_auto_complete_trial_order( $order_id, $subscription_id );
202
203 // Increment renewal count for completed renewal orders (wps-pro)
204 if ( 'renew' === $history->type && 'active' === $post_status && function_exists( 'subscrpt_pro_activated' ) && subscrpt_pro_activated() ) {
205 if ( class_exists( '\\SpringDevs\\SubscriptionPro\\Illuminate\\LimitChecker' ) ) {
206 \SpringDevs\SubscriptionPro\Illuminate\LimitChecker::increment_renewal_count( $history->subscription_id );
207 }
208 }
209
210 // Add enhanced split payment activity logging
211 $this->add_split_payment_activity_note( $history->subscription_id, $history->type, $post_status, $order );
212
213 Action::write_comment( $post_status, $history->subscription_id );
214 } else {
215 do_action( 'subscrpt_order_status_changed', $order, $history );
216 }
217 }
218 }
219
220 /**
221 * Delete the subscription.
222 *
223 * @param int $order_id Order ID.
224 *
225 * @return void
226 */
227 public function delete_the_subscription( $order_id ) {
228 global $wpdb;
229 $table_name = $wpdb->prefix . 'subscrpt_order_relation';
230
231 $histories = Helper::get_subscriptions_from_order( $order_id );
232 foreach ( (array) $histories as $history ) {
233 $subscription_order_id = get_post_meta( $history->subscription_id, '_subscrpt_order_id', true );
234 if ( (int) $subscription_order_id === $order_id ) {
235 wp_delete_post( $history->subscription_id, true );
236 }
237 }
238
239 // phpcs:ignore
240 $wpdb->delete( $table_name, array( 'order_id' => $order_id ), array( '%d' ) );
241 }
242
243 /**
244 * Add enhanced split payment activity note with payment progress and access information.
245 *
246 * @param int $subscription_id Subscription ID.
247 * @param string $history_type History type (new, renew, etc.).
248 * @param string $post_status Post status.
249 * @param \WC_Order $order WooCommerce order object.
250 */
251 private function add_split_payment_activity_note( $subscription_id, $history_type, $post_status, $order ) {
252 // Only add enhanced notes for active subscriptions
253 if ( 'active' !== $post_status ) {
254 return;
255 }
256
257 // Check if this is a split payment subscription
258 if ( ! function_exists( 'subscrpt_get_payment_type' ) ) {
259 return;
260 }
261
262 $payment_type = subscrpt_get_payment_type( $subscription_id );
263 if ( 'split_payment' !== $payment_type ) {
264 return;
265 }
266
267 // Get payment progress information
268 $max_payments = function_exists( 'subscrpt_get_max_payments' ) ? subscrpt_get_max_payments( $subscription_id ) : 0;
269 $payments_made = function_exists( 'subscrpt_count_payments_made' ) ? subscrpt_count_payments_made( $subscription_id ) : 0;
270 $remaining_payments = function_exists( 'subscrpt_get_remaining_payments' ) ? subscrpt_get_remaining_payments( $subscription_id ) : 0;
271
272 // Determine payment number for this order
273 $payment_number = $payments_made;
274 $order_total = $order->get_total();
275 $order_currency = $order->get_currency();
276
277 // Create enhanced activity note
278 $comment_content = '';
279 $activity_type = '';
280
281 if ( 'new' === $history_type ) {
282 $comment_content = sprintf(
283 /* translators: %1$d: payment number, %2$d: total payments, %3$s: amount, %4$s: currency */
284 __( 'Split payment %1$d of %2$d received (%3$s %4$s). Initial access granted.', 'subscription' ),
285 $payment_number,
286 $max_payments,
287 $order_total,
288 $order_currency
289 );
290 $activity_type = __( 'Split Payment - Initial', 'subscription' );
291 } elseif ( 'renew' === $history_type ) {
292 $comment_content = sprintf(
293 /* translators: %1$d: payment number, %2$d: total payments, %3$s: amount, %4$s: currency, %5$d: remaining */
294 __( 'Split payment %1$d of %2$d received (%3$s %4$s). %5$d payments remaining.', 'subscription' ),
295 $payment_number,
296 $max_payments,
297 $order_total,
298 $order_currency,
299 $remaining_payments
300 );
301 $activity_type = __( 'Split Payment - Installment', 'subscription' );
302 }
303
304 // Add the enhanced activity note
305 if ( $comment_content ) {
306 $comment_id = wp_insert_comment(
307 array(
308 'comment_author' => 'Subscription for WooCommerce',
309 'comment_content' => $comment_content,
310 'comment_post_ID' => $subscription_id,
311 'comment_type' => 'order_note',
312 )
313 );
314 update_comment_meta( $comment_id, '_subscrpt_activity', $activity_type );
315 update_comment_meta( $comment_id, '_subscrpt_activity_type', 'split_payment' );
316
317 // Add order note with split payment context
318 $order_note = sprintf(
319 /* translators: %1$d: payment number, %2$d: total payments, %3$d: subscription id */
320 __( 'Split payment %1$d of %2$d received for subscription #%3$d', 'subscription' ),
321 $payment_number,
322 $max_payments,
323 $subscription_id
324 );
325 $order->add_order_note( $order_note );
326 }
327
328 // Add payment milestone notes for significant progress
329 $this->add_payment_milestone_notes( $subscription_id, $payments_made, $max_payments );
330 }
331
332 /**
333 * Add payment milestone notes for significant progress (25%, 50%, 75%, 100%).
334 *
335 * @param int $subscription_id Subscription ID.
336 * @param int $payments_made Number of payments made.
337 * @param int $max_payments Maximum number of payments.
338 */
339 private function add_payment_milestone_notes( $subscription_id, $payments_made, $max_payments ) {
340 if ( ! $max_payments || $max_payments <= 0 ) {
341 return;
342 }
343
344 $percentage = round( ( $payments_made / $max_payments ) * 100 );
345 $milestone_key = '_subscrpt_milestone_' . $percentage . '_logged';
346
347 // Check if this milestone has already been logged
348 if ( get_post_meta( $subscription_id, $milestone_key, true ) ) {
349 return;
350 }
351
352 $milestone_note = '';
353 $activity_type = '';
354
355 switch ( $percentage ) {
356 case 25:
357 $milestone_note = sprintf(
358 /* translators: %1$d: payments made, %2$d: total payments */
359 __( 'Payment milestone reached: %1$d of %2$d payments completed (25%%).', 'subscription' ),
360 $payments_made,
361 $max_payments
362 );
363 $activity_type = __( 'Payment Milestone - 25%', 'subscription' );
364 break;
365
366 case 50:
367 $milestone_note = sprintf(
368 /* translators: %1$d: payments made, %2$d: total payments */
369 __( 'Payment milestone reached: %1$d of %2$d payments completed (50%%). Halfway there!', 'subscription' ),
370 $payments_made,
371 $max_payments
372 );
373 $activity_type = __( 'Payment Milestone - 50%', 'subscription' );
374 break;
375
376 case 75:
377 $milestone_note = sprintf(
378 /* translators: %1$d: payments made, %2$d: total payments */
379 __( 'Payment milestone reached: %1$d of %2$d payments completed (75%%). Almost complete!', 'subscription' ),
380 $payments_made,
381 $max_payments
382 );
383 $activity_type = __( 'Payment Milestone - 75%', 'subscription' );
384 break;
385
386 case 100:
387 $milestone_note = sprintf(
388 /* translators: %1$d: payments made, %2$d: total payments */
389 __( 'Payment milestone reached: %1$d of %2$d payments completed (100%%). Split payment plan complete!', 'subscription' ),
390 $payments_made,
391 $max_payments
392 );
393 $activity_type = __( 'Payment Milestone - 100%', 'subscription' );
394 break;
395 }
396
397 // Add milestone note if applicable
398 if ( $milestone_note ) {
399 $comment_id = wp_insert_comment(
400 array(
401 'comment_author' => 'Subscription for WooCommerce',
402 'comment_content' => $milestone_note,
403 'comment_post_ID' => $subscription_id,
404 'comment_type' => 'order_note',
405 )
406 );
407 update_comment_meta( $comment_id, '_subscrpt_activity', $activity_type );
408 update_comment_meta( $comment_id, '_subscrpt_activity_type', 'split_payment' );
409
410 // Mark milestone as logged
411 update_post_meta( $subscription_id, $milestone_key, current_time( 'timestamp' ) );
412 }
413 }
414
415 /**
416 * Maybe complete the order if it has a trial subscription and is still in processing status.
417 *
418 * @param int $order_id Order ID.
419 * @param int $subscription_id Subscription ID.
420 */
421 public function maybe_trigger_auto_complete_trial_order( $order_id, $subscription_id ) {
422 $order = wc_get_order( $order_id );
423 $order_items = $order->get_items();
424
425 // Only attempt to complete if order is still in processing status.
426 if ( 'processing' !== $order->get_status() ) {
427 return;
428 }
429
430 $is_subs_trial_order = false;
431 foreach ( $order_items as $order_item ) {
432 $subscrpt_meta = $order_item->get_meta( '_subscrpt_meta', true );
433
434 if ( ! empty( $subscrpt_meta ) && isset( $subscrpt_meta['trial'] ) ) {
435 $is_subs_trial_order = true;
436 }
437 }
438
439 if ( $is_subs_trial_order ) {
440 as_enqueue_async_action( 'subscrpt_queue_trial_order_autocomplete', [ 'order_id' => $order_id ] );
441
442 $log_message = "Queued auto complete task for free trial order [ID: {$order_id}]";
443 subscrpt_write_log( $log_message );
444 subscrpt_write_debug_log( $log_message );
445 }
446 }
447
448 /**
449 * Autocomplete subscription trial order.
450 *
451 * @param int $order_id Order ID.
452 */
453 public function auto_complete_subscription_trial_order( $order_id ) {
454 $order = wc_get_order( $order_id );
455 if ( ! $order ) {
456 return;
457 }
458
459 sleep( 3 ); // Adding a small delay to ensure order status is updated before we check it.
460
461 $order->update_status( 'completed', __( 'Subscription order with trial.', 'subscription' ) );
462 }
463 }
464