PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
charitable / includes / square / gateway / class-charitable-square-subscription-plan.php

class-charitable-square-subscription-plan.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at includes/square/gateway/class-charitable-square-subscription-plan.php

455 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Model for creating and retrieving the plans related to a particular campaign.
4 *
5 * @package Charitable Square
6 * @author Studio 164a
7 * @copyright Copyright (c) 2022, Studio 164a
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.0.0
10 */
11
12 // namespace Charitable\Pro\Square\Gateway;
13
14 // use Charitable\Pro\Square\Domain\PackageLoader;
15
16 // Exit if accessed directly.
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21
22 if ( ! class_exists( 'Charitable_Square_Subscription_Plan' ) ) :
23
24 /**
25 * SubscriptionPlan
26 *
27 * @since 1.0.0
28 */
29 class Charitable_Square_Subscription_Plan {
30
31 /**
32 * Campaign ID.
33 *
34 * @since 1.0.0
35 *
36 * @var int
37 */
38 private $campaign_id;
39
40 /**
41 * Options.
42 *
43 * @since 1.0.0
44 *
45 * @var array|null
46 */
47 private $options;
48
49 /**
50 * Mode.
51 *
52 * @since 1.0.0
53 *
54 * @var string
55 */
56 private $mode;
57
58 /**
59 * The campaign's stored plans.
60 *
61 * @since 1.0.0
62 *
63 * @var array
64 */
65 private $plans;
66
67 /**
68 * Internal arguments used for defining a particular plan.
69 *
70 * @since 1.0.0
71 *
72 * @var array
73 */
74 private $args;
75
76 /**
77 * Plan args.
78 *
79 * @since 1.0.0
80 *
81 * @var array
82 */
83 private $plan_args;
84
85 /**
86 * Plan key.
87 *
88 * @since 1.0.0
89 *
90 * @var string
91 */
92 private $plan_key;
93
94 /**
95 * Create class object.
96 *
97 * @since 1.0.0
98 *
99 * @param int $campaign_id The campaign id.
100 * @param array $args Mixed set of args.
101 * @param array|null $options Additional options to pass to Square in API request.
102 */
103 public function __construct( $campaign_id, $args, $options = null ) {
104 $this->campaign_id = $campaign_id;
105 $this->mode = charitable_get_option( 'test_mode' ) ? 'test' : 'live';
106 $this->args = $args;
107 $this->options = $options;
108 }
109
110 /**
111 * Return a class property if set.
112 *
113 * @since 1.0.0
114 *
115 * @param string $prop The class property to return.
116 * @return mixed Returns null if the class property is not set.
117 */
118 public function __get( $prop ) {
119 return isset( $this->$prop ) ? $this->$prop : null;
120 }
121
122 /**
123 * Get the API object.
124 *
125 * @since 1.0.0
126 *
127 * @return \Charitable\Pro\Square\Gateway\Api
128 */
129 public function api() {
130 $api = new Charitable_Square_API();
131 return $api;
132 // return PackageLoader::container()->get( 'api' );
133 }
134
135 /**
136 * Return the plans for the campaign.
137 *
138 * @since 1.0.0
139 *
140 * @return array
141 */
142 public function get_plans() {
143
144 if ( isset( $this->plans ) ) {
145 return $this->plans;
146 }
147
148 $all_plans = get_post_meta( $this->campaign_id, 'square_donation_plans', true );
149
150 if ( ! is_array( $all_plans ) || ! array_key_exists( $this->mode, $all_plans ) ) {
151 $this->plans = array();
152 return $this->plans;
153 }
154
155 $this->plans = $all_plans[ $this->mode ];
156
157 return $this->plans;
158 }
159
160 /**
161 * Return the plan args.
162 * charitable_recurring_get_plan_args comes from Charitable's recurring addon.
163 *
164 * @since 1.0.0
165 *
166 * @return array
167 */
168 public function get_plan_args() {
169 if ( array_key_exists( 'recurring', $this->args ) ) {
170 $this->plan_args = charitable_recurring_get_plan_args(
171 array(
172 'period' => $this->args['recurring']->get_donation_period(),
173 'amount' => charitable_sanitize_amount( (string) $this->args['recurring']->get_recurring_donation_amount( false ) ),
174 'interval' => $this->args['recurring']->get_donation_interval(),
175 )
176 );
177 } else {
178 $this->plan_args = charitable_recurring_get_plan_args( $this->args );
179 }
180
181 return $this->plan_args;
182 }
183
184 /**
185 * Return the key for a plan.
186 *
187 * @since 1.0.0
188 *
189 * @return string
190 */
191 public function get_plan_key() {
192 if ( ! isset( $this->plan_key ) ) {
193 $this->plan_key = charitable_recurring_get_plan_key( $this->get_plan_args() );
194 }
195
196 return $this->plan_key;
197 }
198
199 /**
200 * Return the plan id, or false if none exists.
201 *
202 * @since 1.0.0
203 *
204 * @param boolean $check_api Whether to check the API for the plan.
205 * @return string|false Plan ID if set. False otherwise.
206 */
207 public function get_plan( $check_api = false ) {
208 $plan_key = $this->get_plan_key();
209 $plans = $this->get_plans();
210
211 if ( ! array_key_exists( $plan_key, $plans ) ) {
212 return false;
213 }
214
215 if ( ! $check_api ) {
216 return $plans[ $plan_key ];
217 }
218
219 return $this->plan_exists( $plans[ $plan_key ] );
220 }
221
222 /**
223 * Checks whether a plan still exists in Square.
224 *
225 * @since 1.0.0
226 *
227 * @param string $plan_id The plan ID.
228 * @return string|false The plan ID if it still exists. False otherwise.
229 */
230 public function plan_exists( $plan_id ) {
231 $plan = $this->api()->get( 'catalog/object/' . $plan_id );
232 if ( ! $plan ) {
233 return false;
234 }
235 return $plan_id;
236 }
237
238 /**
239 * Create a plan.
240 *
241 * @since 1.8.7
242 *
243 * @return string The Plan ID.
244 */
245 public function create_plan() {
246 $currency_helper = charitable_get_currency_helper();
247 $currency = charitable_get_currency();
248 $zero_decimal_currency = $currency_helper->is_zero_decimal_currency( $currency );
249 $plan_args = $this->get_plan_args();
250 $period = $this->get_plan_period( $plan_args );
251 $amount = $this->sanitize_plan_amount( $plan_args['amount'], $currency, $zero_decimal_currency );
252 $amount_description = strval( $zero_decimal_currency ? $amount : $amount / 100 );
253 $plan_name = sprintf(
254 /* translators: %1$s: campaign title; %2$s: amount; %3$s: currency; %4$s: period */
255 _x( '%1$s - %2$s %3$s every %4$s', 'campaign title — amount every period', 'charitable' ),
256 str_replace( '&ndash;', '-', get_post( $this->campaign_id )->post_title ),
257 charitable_sanitize_amount( $amount_description ),
258 $currency,
259 charitable_recurring_get_donation_periods_i18n( 1, $plan_args['period'] )
260 );
261 $variation_name = 'Standard Variation';
262
263 $phases = array(
264 'cadence' => $period,
265 'pricing' => array(
266 'type' => 'STATIC',
267 'price' => array(
268 'amount' => $amount,
269 'currency' => $currency,
270 ),
271 ),
272 );
273
274 $subscription_plan_variations = array(
275 'id' => '#variation_1',
276 'type' => 'SUBSCRIPTION_PLAN_VARIATION',
277 'subscription_plan_variation_data' => array(
278 'name' => $variation_name,
279 'phases' => array(
280 $phases
281 ),
282 ),
283 );
284
285 $args = array(
286 'idempotency_key' => uniqid(),
287 'object' => array(
288 'id' => '#subscription',
289 'type' => 'SUBSCRIPTION_PLAN',
290 'subscription_plan_data' => array(
291 'name' => $plan_name,
292 'phases' => array(
293 $phases
294 ),
295 'subscription_plan_variations' => array(
296 $subscription_plan_variations
297 ),
298 ),
299 ),
300 );
301
302 $new_plan = $this->api()->post( 'catalog/object/', $args );
303
304 if ( false === $new_plan ) {
305 $response = $this->api()->get_last_response();
306
307 $response_body = wp_remote_retrieve_body( $response );
308
309 $decoded_response = json_decode( $response_body );
310 if ( json_last_error() !== JSON_ERROR_NONE ) {
311 charitable_get_notices()->add_error( __( 'Invalid response from Square API', 'charitable' ) );
312 return false;
313 }
314
315 if ( isset( $decoded_response->errors ) ) {
316 $this->handle_errors( $decoded_response->errors );
317 } else {
318 charitable_get_notices()->add_error( __( 'Unknown error occurred while creating subscription plan', 'charitable' ) );
319 }
320 return false;
321 }
322
323 $plan_id = $new_plan->catalog_object->id;
324
325 $plan_variation_id = $new_plan->catalog_object->subscription_plan_data->subscription_plan_variations[0]->id;
326
327 $this->save_plan( $plan_id );
328
329 return $plan_id;
330 }
331
332 public function create_plan_variation_id( $plan_id, $plan ) {
333
334 $catalog_object = $this->api()->get( 'catalog/object/' . $plan_id );
335
336 $plan_variation_id = $catalog_object->object->subscription_plan_data->subscription_plan_variations[0]->id;
337
338 return $plan_variation_id;
339 }
340
341 /**
342 * Save plan to campaign meta.
343 *
344 * @since 1.0.0
345 *
346 * @param string $plan_id Save a new plan ID.
347 * @return mixed
348 */
349 public function save_plan( $plan_id ) {
350
351 $mode_plans = $this->get_plans();
352 $mode_plans[ $this->get_plan_key() ] = $plan_id;
353
354 $all_plans = get_post_meta( $this->campaign_id, 'square_donation_plans', true );
355
356 if ( ! is_array( $all_plans ) ) {
357 $all_plans = array();
358 }
359
360 $all_plans[ $this->mode ] = $mode_plans;
361
362 return update_post_meta( $this->campaign_id, 'square_donation_plans', $all_plans );
363 }
364
365 /**
366 * Return the Square period given a set of plan args.
367 *
368 * @since 1.0.0
369 *
370 * @param array $args The plan args.
371 * @return string
372 */
373 public function get_plan_period( $args ) {
374 switch ( $args['period'] ) {
375 case 'day':
376 $period = 'DAILY';
377 break;
378 case 'week':
379 $period = 'WEEKLY';
380 break;
381 case 'month':
382 $period = 'MONTHLY';
383 break;
384 case 'quarter':
385 $period = 'QUARTERLY';
386 break;
387 case 'semiannual':
388 $period = 'EVERY_SIX_MONTHS';
389 break;
390 case 'year':
391 $period = 'ANNUAL';
392 break;
393 }
394
395 return $period;
396 }
397
398 /**
399 * Sanitize the plan amount.
400 *
401 * @since 1.0.0
402 *
403 * @param string $amount The plan amount.
404 * @param string $currency The site currency.
405 * @param boolean $zero_decimal_currency Whether the site is using a zero decimal currency.
406 * @return string
407 */
408 public function sanitize_plan_amount( $amount, $currency, $zero_decimal_currency ) {
409 /* Unless it's a zero decimal currency, multiply the currency x 100 to get the amount in cents. */
410 if ( $zero_decimal_currency ) {
411 $amount = $amount * 1;
412 } else {
413 $amount = $amount * 100;
414 }
415
416 return absint( round( $amount ) );
417 }
418
419 /**
420 * Handle some common errors with nicer messages
421 *
422 * @since 1.0.0
423 *
424 * @param array $errors The errors returned by Square
425 * @return void
426 */
427 private function handle_errors( $errors ) {
428 if ( 0 === count( $errors ) ) {
429 charitable_get_notices()->add_error( __( 'An unexpected error occurred trying to process your payment', 'charitable' ) );
430 return;
431 }
432
433 // Only worry about the first error.
434 $error = $errors[0];
435
436 // For authentication errors, keep the message generic.
437 if ( 'AUTHENTICATION_ERROR' === $error->category ) {
438 charitable_get_notices()->add_error( __( 'Unable to connect to Square. If you are an administrator, please check your Square Gateway settings.', 'charitable' ) );
439 return;
440 }
441
442 // Just output the error code provided by Square.
443 charitable_get_notices()->add_error(
444 sprintf(
445 /* translators: %s: error message from Square */
446 __( 'Payment request failed with error: %s.', 'charitable' ),
447 $error->code
448 )
449 );
450 return;
451 }
452 }
453
454 endif;
455