PluginProbe ʕ •ᴥ•ʔ
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 1.5.0
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v1.5.0
4.7.2 4.7.1 4.7.0 4.6.6 4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 4.5.1 4.5.0 4.4.2 4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.3 4.2.2 4.2.1 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.11.1 1.11.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 2.0.0 2.0.1 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.10.0 2.10.1 2.11.0 2.11.1 2.11.2 2.11.3 2.11.4 2.12.0 2.13.0 2.14.0 2.14.1 2.15.0 2.15.1 2.16.0 2.16.1 2.16.2 2.16.3 2.17.0 2.17.1 2.17.2 2.18.0 2.19.0 2.19.2 2.19.3 2.19.4 2.2.0 2.2.1 2.20.0 2.20.1 2.20.2 2.20.3 2.20.4 2.20.5 2.20.6 2.21.0 2.22.0 2.22.1 2.23.0 2.24.0 2.25.0 2.25.1 2.25.2 2.26.0 2.27.0 2.27.1 2.28.0 2.29.0 2.29.1 2.29.2 2.29.3 2.29.4 2.3.0 2.3.1 2.30.0 2.31.0 2.31.1 2.31.2 2.31.3 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.40.0 2.40.1 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.9.0 3.0.0 3.0.0-RC1 3.0.0-RC2 3.0.0-beta1 3.0.0-beta2 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.10.0 3.10.1 3.11.0 3.12.0 3.13.0 3.13.1 3.13.2 3.13.3 3.13.4 3.14.0 3.15.0 3.15.1 3.15.2 3.15.3 3.15.4 3.15.5 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.16.6 3.16.7 3.16.8 3.17.0 3.17.1 3.17.2 3.17.3 3.17.4 3.17.5 3.17.6 3.18.0 3.19.0 3.19.1 3.19.2 3.2.0 3.2.1 3.2.2 3.20.0 3.20.1 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 4.0.0 4.0.1 4.0.2 4.0.3 trunk 4.1.0 0.2.19.1 4.1.1 1.0.0 4.2.0 1.0.1 1.0.2
surecart / app / src / Models / Subscription.php
surecart / app / src / Models Last commit date
Traits 3 years ago AbandonedCheckout.php 3 years ago AbandonedCheckoutProtocol.php 3 years ago Account.php 3 years ago AccountPortalSession.php 4 years ago Activation.php 4 years ago ApiToken.php 4 years ago BalanceTransaction.php 4 years ago Brand.php 4 years ago Bump.php 3 years ago CancellationAct.php 3 years ago CancellationReason.php 3 years ago Charge.php 4 years ago Checkout.php 3 years ago Collection.php 4 years ago Component.php 4 years ago Coupon.php 4 years ago Customer.php 4 years ago CustomerLink.php 4 years ago CustomerNotificationProtocol.php 4 years ago DatabaseModel.php 4 years ago Download.php 4 years ago Event.php 4 years ago Form.php 4 years ago Integration.php 4 years ago Invoice.php 4 years ago License.php 4 years ago LineItem.php 4 years ago ManualPaymentMethod.php 3 years ago Media.php 4 years ago Model.php 3 years ago ModelInterface.php 4 years ago Order.php 4 years ago OrderProtocol.php 4 years ago PaymentIntent.php 4 years ago PaymentMethod.php 4 years ago Period.php 3 years ago PortalProtocol.php 4 years ago PortalSession.php 4 years ago Price.php 4 years ago Processor.php 3 years ago Product.php 4 years ago ProductGroup.php 4 years ago Promotion.php 4 years ago Purchase.php 4 years ago Refund.php 4 years ago Statistic.php 4 years ago Subscription.php 3 years ago SubscriptionProtocol.php 4 years ago TaxProtocol.php 4 years ago TaxRegistration.php 4 years ago TaxZone.php 4 years ago Upload.php 4 years ago User.php 3 years ago VerificationCode.php 3 years ago Webhook.php 4 years ago
Subscription.php
425 lines
1 <?php
2
3 namespace SureCart\Models;
4
5 use SureCart\Models\Traits\HasCustomer;
6 use SureCart\Models\Traits\HasPrice;
7 use SureCart\Models\Traits\HasPurchase;
8
9 /**
10 * Subscription model
11 */
12 class Subscription extends Model {
13 use HasCustomer, HasPrice, HasPurchase;
14
15 /**
16 * Rest API endpoint
17 *
18 * @var string
19 */
20 protected $endpoint = 'subscriptions';
21
22 /**
23 * Object name
24 *
25 * @var string
26 */
27 protected $object_name = 'subscription';
28
29 /**
30 * Update the model.
31 *
32 * @param array $attributes Attributes to update.
33 * @return $this|false
34 */
35 protected function update( $attributes = [] ) {
36 // find existing subscription with purchase record.
37 $existing = ( new Subscription() )->with( [ 'purchase' ] )->find( $attributes['id'] ?? $this->attributes['id'] );
38
39 // do the update and also get the purchase record.
40 $this->with( [ 'purchase' ] );
41 $updated = parent::update( $attributes );
42 if ( is_wp_error( $updated ) ) {
43 return $updated;
44 }
45
46 // do the purchase updated event.
47 if ( ! empty( $updated->purchase ) ) {
48 do_action(
49 'surecart/purchase_updated',
50 $updated->purchase,
51 [
52 'data' => [
53 'object' => $updated->purchase->toArray(),
54 'previous_attributes' => array_filter(
55 [
56 // conditionally have the previous product and quantity as the previous attributes.
57 'product' => $updated->purchase->product_id !== $existing->purchase->product_id ? ( $existing->purchase->product_id ?? null ) : null,
58 'quantity' => $updated->purchase->quantity !== $existing->purchase->quantity ? ( $existing->purchase->quantity ?? 1 ) : null,
59 ]
60 ),
61 ],
62 ]
63 );
64 }
65
66 return $this;
67 }
68
69 /**
70 * Cancel a subscription
71 *
72 * @param string $id Model id.
73 * @return $this|\WP_Error
74 */
75 protected function cancel( $id = null ) {
76 if ( $id ) {
77 $this->setAttribute( 'id', $id );
78 }
79
80 if ( $this->fireModelEvent( 'canceling' ) === false ) {
81 return false;
82 }
83
84 if ( empty( $this->attributes['id'] ) ) {
85 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
86 }
87
88 $canceled = $this->with(
89 [
90 'purchase',
91 ]
92 )->makeRequest(
93 [
94 'method' => 'PATCH',
95 'query' => $this->query,
96 ],
97 $this->endpoint . '/' . $this->attributes['id'] . '/cancel/'
98 );
99
100 if ( is_wp_error( $canceled ) ) {
101 return $canceled;
102 }
103
104 $this->resetAttributes();
105
106 $this->fill( $canceled );
107
108 $this->fireModelEvent( 'canceled' );
109
110 // purchase revoked event.
111 if ( ! empty( $this->purchase->revoked ) ) {
112 do_action( 'surecart/purchase_revoked', $this->purchase );
113 }
114
115 return $this;
116 }
117
118 /**
119 * Complete a subscription
120 *
121 * @param string $id Model id.
122 * @return $this|\WP_Error
123 */
124 protected function complete( $id = null ) {
125 if ( $id ) {
126 $this->setAttribute( 'id', $id );
127 }
128
129 if ( $this->fireModelEvent( 'completeing' ) === false ) {
130 return false;
131 }
132
133 if ( empty( $this->attributes['id'] ) ) {
134 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
135 }
136
137 $completed = $this->with(
138 [
139 'purchase',
140 ]
141 )->makeRequest(
142 [
143 'method' => 'PATCH',
144 'query' => $this->query,
145 ],
146 $this->endpoint . '/' . $this->attributes['id'] . '/complete/'
147 );
148
149 if ( is_wp_error( $completed ) ) {
150 return $completed;
151 }
152
153 $this->resetAttributes();
154
155 $this->fill( $completed );
156
157 $this->fireModelEvent( 'completed' );
158
159 return $this;
160 }
161
162 /**
163 * Restore a subscription
164 *
165 * @param string $id Model id.
166 * @return $this|\WP_Error
167 */
168 protected function restore( $id = null ) {
169 if ( $id ) {
170 $this->setAttribute( 'id', $id );
171 }
172
173 if ( $this->fireModelEvent( 'restoring' ) === false ) {
174 return false;
175 }
176
177 if ( empty( $this->attributes['id'] ) ) {
178 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
179 }
180
181 $restored = \SureCart::request(
182 $this->endpoint . '/' . $this->attributes['id'] . '/restore/',
183 [
184 'method' => 'PATCH',
185 'query' => $this->query,
186 ]
187 );
188
189 if ( is_wp_error( $restored ) ) {
190 return $restored;
191 }
192
193 $this->resetAttributes();
194
195 $this->fill( $restored );
196
197 $this->fireModelEvent( 'restored' );
198
199 return $this;
200 }
201
202 /**
203 * Renew a subscription.
204 *
205 * @param string $id Model id.
206 * @return $this|\WP_Error
207 */
208 protected function renew( $id = null ) {
209 if ( $id ) {
210 $this->setAttribute( 'id', $id );
211 }
212
213 if ( $this->fireModelEvent( 'renewing' ) === false ) {
214 return false;
215 }
216
217 if ( empty( $this->attributes['id'] ) ) {
218 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
219 }
220
221 $renewed = \SureCart::request(
222 $this->endpoint . '/' . $this->attributes['id'],
223 [
224 'method' => 'PATCH',
225 'query' => $this->query,
226 'body' => [
227 $this->object_name => [
228 'cancel_at_period_end' => false,
229 ],
230 ],
231 ]
232 );
233
234 if ( is_wp_error( $renewed ) ) {
235 return $renewed;
236 }
237
238 $this->resetAttributes();
239
240 $this->fill( $renewed );
241
242 $this->fireModelEvent( 'renewed' );
243
244 return $this;
245 }
246
247 /**
248 * Preserve a subscription.
249 *
250 * @param string $id Model id.
251 * @return $this|\WP_Error
252 */
253 protected function preserve( $id = null ) {
254 if ( $id ) {
255 $this->setAttribute( 'id', $id );
256 }
257
258 if ( $this->fireModelEvent( 'preserving' ) === false ) {
259 return false;
260 }
261
262 if ( empty( $this->attributes['id'] ) ) {
263 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
264 }
265
266 $preserved = $this->makeRequest(
267 [
268 'method' => 'PATCH',
269 'query' => $this->query,
270 ],
271 $this->endpoint . '/' . $this->attributes['id'] . '/preserve/'
272 );
273
274 if ( is_wp_error( $preserved ) ) {
275 return $preserved;
276 }
277
278 $this->resetAttributes();
279
280 $this->fill( $preserved );
281
282 $this->fireModelEvent( 'preserved' );
283
284 return $this;
285 }
286
287 /**
288 * Preview the upcoming invoice.
289 *
290 * @param string $args Arguments
291 * @return $this|\WP_Error
292 */
293 protected function upcomingPeriod( $args = [] ) {
294 if ( ! empty( $args['id'] ) ) {
295 $this->setAttribute( 'id', $args['id'] );
296 unset( $args['id'] );
297 }
298
299 if ( $this->fireModelEvent( 'previewingUpcomingPeriod' ) === false ) {
300 return false;
301 }
302
303 if ( empty( $this->attributes['id'] ) ) {
304 return new \WP_Error( 'not_saved', 'Please create the subscription' );
305 }
306
307 $upcoming_period = $this->makeRequest(
308 [
309 'method' => 'PATCH',
310 'query' => $this->query,
311 'body' => [
312 $this->object_name => $args,
313 ],
314 ],
315 $this->endpoint . '/' . $this->attributes['id'] . '/upcoming_period/'
316 );
317
318 if ( is_wp_error( $upcoming_period ) ) {
319 return $upcoming_period;
320 }
321
322 $this->resetAttributes();
323
324 $this->fill( $upcoming_period );
325
326 $this->fireModelEvent( 'previewedUpcomingPeriod' );
327
328 return $this;
329 }
330
331 /**
332 * Is this subscription a lifetime one?
333 *
334 * @return boolean
335 */
336 protected function isLifetime() {
337 return $this->attributes['id'] && empty( $this->attributes['current_period_end_at'] );
338 }
339
340 /**
341 * Can the user upgrade this subscription?
342 *
343 * @return boolean
344 */
345 protected function canBeSwitched() {
346 return apply_filters( 'surecart/subscription/can_be_changed', $this->checkIfCanBeSwitched(), $this );
347 }
348
349 /**
350 * Can the subscription be changed?
351 *
352 * @return boolean
353 */
354 private function checkIfCanBeSwitched() {
355 // updates are not enabled for the account.
356 if ( empty( \SureCart::account()->portal_protocol->subscription_updates_enabled ) ) {
357 return false;
358 }
359 // already set to canceling.
360 if ( $this->attributes['cancel_at_period_end'] ) {
361 return false;
362 }
363 // can't update canceled, incomplete, or past due subscriptions.
364 if ( in_array( $this->attributes['status'], [ 'canceled', 'incomplete', 'past_due' ] ) ) {
365 return false;
366 }
367 // must not be lifetime.
368 if ( $this->isLifetime() ) {
369 return false;
370 }
371 return true;
372 }
373
374 /**
375 * Can we cancel the subscription?
376 *
377 * @return boolean
378 */
379 public function canBeCanceled() {
380 return apply_filters( 'surecart/subscription/can_be_canceled', $this->checkIfCanBeSwitched(), $this );
381 }
382
383 /**
384 * Can the subscription be canceled?
385 *
386 * @return boolean
387 */
388 private function checkIfCanBeCanceled() {
389 // updates are not enabled for the account.
390 if ( empty( \SureCart::account()->portal_protocol->subscription_cancellations_enabled ) ) {
391 return false;
392 }
393
394 // can't cancel canceled, incomplete, or past due subscriptions.
395 if ( in_array( $this->attributes['status'], [ 'canceled', 'incomplete', 'past_due' ] ) ) {
396 return false;
397 }
398
399 return true;
400 }
401
402 /**
403 * Can we update the quantity?
404 *
405 * @return boolean
406 */
407 protected function canUpdateQuantity() {
408 return apply_filters( 'surecart/subscription/can_update_quantity', $this->checkIfCanBeSwitched(), $this );
409 }
410
411 /**
412 * Check if we can update the quantity.
413 *
414 * @return boolean
415 */
416 private function checkIfCanUpdateQuantity() {
417 // quantity changes are not enabled for this account.
418 if ( empty( \SureCart::account()->portal_protocol->subscription_quantity_updates_enabled ) ) {
419 return false;
420 }
421 return true;
422 }
423 }
424
425