PluginProbe
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments / 1.0.4
SureCart – Ecommerce Made Easy For Selling Physical Products, Digital Downloads, Subscriptions, Donations, & Payments v1.0.4
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 All 281 releases
surecart / app / src / Models / Subscription.php
Subscription.php
342 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SureCart\Models;
4
5 use SureCart\Models\Traits\HasCustomer;
6 use SureCart\Models\Traits\HasOrder;
7 use SureCart\Models\Traits\HasPrice;
8 use SureCart\Models\Traits\HasPurchase;
9
10 /**
11 * Subscription model
12 */
13 class Subscription extends Model {
14 use HasCustomer, HasOrder, HasPrice, HasPurchase;
15
16 /**
17 * Rest API endpoint
18 *
19 * @var string
20 */
21 protected $endpoint = 'subscriptions';
22
23 /**
24 * Object name
25 *
26 * @var string
27 */
28 protected $object_name = 'subscription';
29
30 /**
31 * Update the model.
32 *
33 * @param array $attributes Attributes to update.
34 * @return $this|false
35 */
36 protected function update( $attributes = [] ) {
37 // find existing subscription with purchase record.
38 $existing = ( new Subscription() )->with( [ 'purchase' ] )->find( $attributes['id'] ?? $this->attributes['id'] );
39
40 // do the update and also get the purchase record.
41 $this->with( [ 'purchase' ] );
42 $updated = parent::update( $attributes );
43 if ( is_wp_error( $updated ) ) {
44 return $updated;
45 }
46
47 // do the purchase updated event.
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 return $this;
66 }
67
68 /**
69 * Cancel a subscription
70 *
71 * @param string $id Model id.
72 * @return $this|\WP_Error
73 */
74 protected function cancel( $id = null ) {
75 if ( $id ) {
76 $this->setAttribute( 'id', $id );
77 }
78
79 if ( $this->fireModelEvent( 'canceling' ) === false ) {
80 return false;
81 }
82
83 if ( empty( $this->attributes['id'] ) ) {
84 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
85 }
86
87 $canceled = $this->with(
88 [
89 'purchase',
90 ]
91 )->makeRequest(
92 [
93 'method' => 'PATCH',
94 'query' => $this->query,
95 ],
96 $this->endpoint . '/' . $this->attributes['id'] . '/cancel/'
97 );
98
99 if ( is_wp_error( $canceled ) ) {
100 return $canceled;
101 }
102
103 $this->resetAttributes();
104
105 $this->fill( $canceled );
106
107 $this->fireModelEvent( 'canceled' );
108
109 // purchase revoked event.
110 if ( ! empty( $this->purchase->revoked ) ) {
111 do_action( 'surecart/purchase_revoked', $this->purchase );
112 }
113
114 return $this;
115 }
116
117 /**
118 * Complete a subscription
119 *
120 * @param string $id Model id.
121 * @return $this|\WP_Error
122 */
123 protected function complete( $id = null ) {
124 if ( $id ) {
125 $this->setAttribute( 'id', $id );
126 }
127
128 if ( $this->fireModelEvent( 'completeing' ) === false ) {
129 return false;
130 }
131
132 if ( empty( $this->attributes['id'] ) ) {
133 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
134 }
135
136 $completed = $this->with(
137 [
138 'purchase',
139 ]
140 )->makeRequest(
141 [
142 'method' => 'PATCH',
143 'query' => $this->query,
144 ],
145 $this->endpoint . '/' . $this->attributes['id'] . '/complete/'
146 );
147
148 if ( is_wp_error( $completed ) ) {
149 return $completed;
150 }
151
152 $this->resetAttributes();
153
154 $this->fill( $completed );
155
156 $this->fireModelEvent( 'completed' );
157
158 return $this;
159 }
160
161 /**
162 * Renew a subscription.
163 *
164 * @param string $id Model id.
165 * @return $this|\WP_Error
166 */
167 protected function renew( $id = null ) {
168 if ( $id ) {
169 $this->setAttribute( 'id', $id );
170 }
171
172 if ( $this->fireModelEvent( 'renewing' ) === false ) {
173 return false;
174 }
175
176 if ( empty( $this->attributes['id'] ) ) {
177 return new \WP_Error( 'not_saved', 'Please create the subscription.' );
178 }
179
180 $renewed = \SureCart::request(
181 $this->endpoint . '/' . $this->attributes['id'],
182 [
183 'method' => 'PATCH',
184 'query' => $this->query,
185 'body' => [
186 $this->object_name => [
187 'cancel_at_period_end' => false,
188 ],
189 ],
190 ]
191 );
192
193 if ( is_wp_error( $renewed ) ) {
194 return $renewed;
195 }
196
197 $this->resetAttributes();
198
199 $this->fill( $renewed );
200
201 $this->fireModelEvent( 'renewed' );
202
203 return $this;
204 }
205
206 /**
207 * Preview the upcoming invoice.
208 *
209 * @return $this|\WP_Error
210 */
211 protected function upcomingInvoice( $id = null ) {
212 if ( $id ) {
213 $this->setAttribute( 'id', $id );
214 }
215
216 if ( $this->fireModelEvent( 'previewingUpcomingInvoice' ) === false ) {
217 return false;
218 }
219
220 if ( empty( $this->attributes['id'] ) ) {
221 return new \WP_Error( 'not_saved', 'Please create the subscription' );
222 }
223
224 $invoice = \SureCart::request(
225 $this->endpoint . '/' . $this->attributes['id'] . '/upcoming_invoice/',
226 [
227 'method' => 'GET',
228 'query' => array_merge(
229 $this->query,
230 $this->attributes
231 ),
232 ]
233 );
234
235 if ( is_wp_error( $invoice ) ) {
236 return $invoice;
237 }
238
239 $this->resetAttributes();
240
241 $this->fill( $invoice );
242
243 $this->fireModelEvent( 'previewedUpcomingInvoice' );
244
245 return $this;
246 }
247
248 /**
249 * Is this subscription a lifetime one?
250 *
251 * @return boolean
252 */
253 protected function isLifetime() {
254 return $this->attributes['id'] && empty( $this->attributes['current_period_end_at'] );
255 }
256
257 /**
258 * Can the user upgrade this subscription?
259 *
260 * @return boolean
261 */
262 protected function canBeSwitched() {
263 return apply_filters( 'surecart/subscription/can_be_changed', $this->checkIfCanBeSwitched(), $this );
264 }
265
266 /**
267 * Can the subscription be changed?
268 *
269 * @return boolean
270 */
271 private function checkIfCanBeSwitched() {
272 // updates are not enabled for the account.
273 if ( empty( \SureCart::account()->portal_protocol->subscription_updates_enabled ) ) {
274 return false;
275 }
276 // already set to canceling.
277 if ( $this->attributes['cancel_at_period_end'] ) {
278 return false;
279 }
280 // can't update canceled, incomplete, or past due subscriptions.
281 if ( in_array( $this->attributes['status'], [ 'canceled', 'incomplete', 'past_due' ] ) ) {
282 return false;
283 }
284 // must not be lifetime.
285 if ( $this->isLifetime() ) {
286 return false;
287 }
288 return true;
289 }
290
291 /**
292 * Can we cancel the subscription?
293 *
294 * @return boolean
295 */
296 public function canBeCanceled() {
297 return apply_filters( 'surecart/subscription/can_be_canceled', $this->checkIfCanBeSwitched(), $this );
298 }
299
300 /**
301 * Can the subscription be canceled?
302 *
303 * @return boolean
304 */
305 private function checkIfCanBeCanceled() {
306 // updates are not enabled for the account.
307 if ( empty( \SureCart::account()->portal_protocol->subscription_cancellations_enabled ) ) {
308 return false;
309 }
310
311 // can't cancel canceled, incomplete, or past due subscriptions.
312 if ( in_array( $this->attributes['status'], [ 'canceled', 'incomplete', 'past_due' ] ) ) {
313 return false;
314 }
315
316 return true;
317 }
318
319 /**
320 * Can we update the quantity?
321 *
322 * @return boolean
323 */
324 protected function canUpdateQuantity() {
325 return apply_filters( 'surecart/subscription/can_update_quantity', $this->checkIfCanBeSwitched(), $this );
326 }
327
328 /**
329 * Check if we can update the quantity.
330 *
331 * @return boolean
332 */
333 private function checkIfCanUpdateQuantity() {
334 // quantity changes are not enabled for this account.
335 if ( empty( \SureCart::account()->portal_protocol->subscription_quantity_updates_enabled ) ) {
336 return false;
337 }
338 return true;
339 }
340 }
341
342