Passed
Push — v3.0 ( dc36dd...eccb01 )
by Raza
02:06
created

Helpers::addBillingPlan()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 18
rs 9.8666
1
<?php
2
3
namespace Srmklive\PayPal\Traits\PayPalAPI\Subscriptions;
4
5
use Carbon\Carbon;
6
use Illuminate\Support\Str;
7
use Throwable;
8
9
trait Helpers
10
{
11
    /**
12
     * @var array
13
     */
14
    protected $trial_pricing = [];
15
16
    /**
17
     * @var int
18
     */
19
    protected $payment_failure_threshold = 3;
20
21
    /**
22
     * @var array
23
     */
24
    protected $product;
25
26
    /**
27
     * @var array
28
     */
29
    protected $billing_plan;
30
31
    /**
32
     * @var array
33
     */
34
    protected $shipping_address;
35
36
    /**
37
     * @var array
38
     */
39
    protected $payment_preferences;
40
41
    /**
42
     * @var bool
43
     */
44
    protected $has_setup_fee = false;
45
46
    /**
47
     * @var string
48
     */
49
    protected $return_url;
50
51
    /**
52
     * @var string
53
     */
54
    protected $cancel_url;
55
56
    /**
57
     * Setup a subscription.
58
     *
59
     * @param string $customer_name
60
     * @param string $customer_email
61
     * @param string $start_date
62
     *
63
     * @throws Throwable
64
     *
65
     * @return array|\Psr\Http\Message\StreamInterface|string
66
     */
67
    public function setupSubscription(string $customer_name, string $customer_email, string $start_date = '')
68
    {
69
        $start_date = isset($start_date) ? Carbon::parse($start_date)->toIso8601String() : Carbon::now()->toIso8601String();
70
71
        $body = [
72
            'plan_id'    => $this->billing_plan['id'],
73
            'start_time' => $start_date,
74
            'quantity'   => 1,
75
            'subscriber' => [
76
                'name'          => [
77
                    'given_name' => $customer_name,
78
                ],
79
                'email_address' => $customer_email,
80
            ],
81
        ];
82
83
        if ($this->has_setup_fee) {
84
            $body['plan'] = [
85
                'payment_preferences' => $this->payment_preferences,
86
            ];
87
        }
88
89
        if(isset($this->shipping_address)) {
90
            $body['subscriber']['shipping_address'] = $this->shipping_address;
91
        }        
92
        
93
        if ($this->return_url && $this->cancel_url) {
94
            $body['application_context'] = [
95
                'return_url' => $this->return_url,
96
                'cancel_url' => $this->cancel_url,
97
            ];
98
        }
99
100
        $subscription = $this->createSubscription($body);
0 ignored issues
show
Bug introduced by
It seems like createSubscription() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

100
        /** @scrutinizer ignore-call */ 
101
        $subscription = $this->createSubscription($body);
Loading history...
101
102
        unset($this->product);
103
        unset($this->billing_plan);
104
        unset($this->trial_pricing);
105
        unset($this->return_url);
106
        unset($this->cancel_url);
107
108
        return $subscription;
109
    }
110
111
    /**
112
     * Add a subscription trial pricing tier.
113
     *
114
     * @param string    $interval_type
115
     * @param int       $interval_count
116
     * @param float|int $price
117
     *
118
     * @return \Srmklive\PayPal\Services\PayPal
119
     */
120
    public function addPlanTrialPricing(string $interval_type, int $interval_count, float $price = 0): \Srmklive\PayPal\Services\PayPal
121
    {
122
        $this->trial_pricing = $this->addPlanBillingCycle($interval_type, $interval_count, $price, true);
123
124
        return $this;
125
    }
126
127
    /**
128
     * Create a recurring daily billing plan.
129
     *
130
     * @param string    $name
131
     * @param string    $description
132
     * @param float|int $price
133
     *
134
     * @throws Throwable
135
     *
136
     * @return \Srmklive\PayPal\Services\PayPal
137
     */
138
    public function addDailyPlan(string $name, string $description, float $price): \Srmklive\PayPal\Services\PayPal
139
    {
140
        if (isset($this->billing_plan)) {
141
            return $this;
142
        }
143
144
        $plan_pricing = $this->addPlanBillingCycle('DAY', 1, $price);
145
        $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray();
146
147
        $this->addBillingPlan($name, $description, $billing_cycles);
148
149
        return $this;
150
    }
151
152
    /**
153
     * Create a recurring weekly billing plan.
154
     *
155
     * @param string    $name
156
     * @param string    $description
157
     * @param float|int $price
158
     *
159
     * @throws Throwable
160
     *
161
     * @return \Srmklive\PayPal\Services\PayPal
162
     */
163
    public function addWeeklyPlan(string $name, string $description, float $price): \Srmklive\PayPal\Services\PayPal
164
    {
165
        if (isset($this->billing_plan)) {
166
            return $this;
167
        }
168
169
        $plan_pricing = $this->addPlanBillingCycle('WEEK', 1, $price);
170
        $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray();
171
172
        $this->addBillingPlan($name, $description, $billing_cycles);
173
174
        return $this;
175
    }
176
177
    /**
178
     * Create a recurring monthly billing plan.
179
     *
180
     * @param string    $name
181
     * @param string    $description
182
     * @param float|int $price
183
     *
184
     * @throws Throwable
185
     *
186
     * @return \Srmklive\PayPal\Services\PayPal
187
     */
188
    public function addMonthlyPlan(string $name, string $description, float $price): \Srmklive\PayPal\Services\PayPal
189
    {
190
        if (isset($this->billing_plan)) {
191
            return $this;
192
        }
193
194
        $plan_pricing = $this->addPlanBillingCycle('MONTH', 1, $price);
195
        $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray();
196
197
        $this->addBillingPlan($name, $description, $billing_cycles);
198
199
        return $this;
200
    }
201
202
    /**
203
     * Create a recurring annual billing plan.
204
     *
205
     * @param string    $name
206
     * @param string    $description
207
     * @param float|int $price
208
     *
209
     * @throws Throwable
210
     *
211
     * @return \Srmklive\PayPal\Services\PayPal
212
     */
213
    public function addAnnualPlan(string $name, string $description, float $price): \Srmklive\PayPal\Services\PayPal
214
    {
215
        if (isset($this->billing_plan)) {
216
            return $this;
217
        }
218
219
        $plan_pricing = $this->addPlanBillingCycle('YEAR', 1, $price);
220
        $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray();
221
222
        $this->addBillingPlan($name, $description, $billing_cycles);
223
224
        return $this;
225
    }
226
227
    /**
228
     * Create a recurring billing plan with custom intervals.
229
     *
230
     * @param string    $name
231
     * @param string    $description
232
     * @param float|int $price
233
     * @param string    $interval_unit
234
     * @param int       $interval_count
235
     *
236
     * @throws Throwable
237
     *
238
     * @return \Srmklive\PayPal\Services\PayPal
239
     */
240
    public function addCustomPlan(string $name, string $description, float $price, string $interval_unit, int $interval_count): \Srmklive\PayPal\Services\PayPal
241
    {
242
        $billing_intervals = ['DAY', 'WEEK', 'MONTH', 'YEAR'];
243
244
        if (isset($this->billing_plan)) {
245
            return $this;
246
        }
247
248
        if (!in_array($interval_unit, $billing_intervals)) {
249
            throw new \RuntimeException('Billing intervals should either be '.implode(', ', $billing_intervals));
250
        }
251
252
        $plan_pricing = $this->addPlanBillingCycle($interval_unit, $interval_count, $price);
253
        $billing_cycles = empty($this->trial_pricing) ? [$plan_pricing] : collect([$this->trial_pricing, $plan_pricing])->filter()->toArray();
254
255
        $this->addBillingPlan($name, $description, $billing_cycles);
256
257
        return $this;
258
    }
259
260
    /**
261
     * Add Plan's Billing cycle.
262
     *
263
     * @param string $interval_unit
264
     * @param int    $interval_count
265
     * @param float  $price
266
     * @param bool   $trial
267
     *
268
     * @return array
269
     */
270
    protected function addPlanBillingCycle(string $interval_unit, int $interval_count, float $price, bool $trial = false): array
271
    {
272
        $pricing_scheme = [
273
            'fixed_price' => [
274
                'value'         => $price,
275
                'currency_code' => $this->getCurrency(),
0 ignored issues
show
Bug introduced by
It seems like getCurrency() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

275
                'currency_code' => $this->/** @scrutinizer ignore-call */ getCurrency(),
Loading history...
276
            ],
277
        ];
278
279
        if (empty($this->trial_pricing)) {
280
            $plan_sequence = 1;
281
        } else {
282
            $plan_sequence = 2;
283
        }
284
285
        return [
286
            'frequency' => [
287
                'interval_unit'  => $interval_unit,
288
                'interval_count' => $interval_count,
289
            ],
290
            'tenure_type'    => ($trial === true) ? 'TRIAL' : 'REGULAR',
291
            'sequence'       => ($trial === true) ? 1 : $plan_sequence,
292
            'total_cycles'   => ($trial === true) ? 1 : 0,
293
            'pricing_scheme' => $pricing_scheme,
294
        ];
295
    }
296
297
    /**
298
     * Create a product for a subscription's billing plan.
299
     *
300
     * @param string $name
301
     * @param string $description
302
     * @param string $type
303
     * @param string $category
304
     *
305
     * @throws Throwable
306
     *
307
     * @return \Srmklive\PayPal\Services\PayPal
308
     */
309
    public function addProduct(string $name, string $description, string $type, string $category): \Srmklive\PayPal\Services\PayPal
310
    {
311
        if (isset($this->product)) {
312
            return $this;
313
        }
314
315
        $request_id = Str::random();
316
317
        $this->product = $this->createProduct([
0 ignored issues
show
Bug introduced by
It seems like createProduct() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

317
        /** @scrutinizer ignore-call */ 
318
        $this->product = $this->createProduct([
Loading history...
318
            'name'          => $name,
319
            'description'   => $description,
320
            'type'          => $type,
321
            'category'      => $category,
322
        ], $request_id);
323
324
        return $this;
325
    }
326
327
    /**
328
     * Add subscription's billing plan's product by ID.
329
     *
330
     * @param string $product_id
331
     *
332
     * @return \Srmklive\PayPal\Services\PayPal
333
     */
334
    public function addProductById(string $product_id): \Srmklive\PayPal\Services\PayPal
335
    {
336
        $this->product = [
337
            'id' => $product_id,
338
        ];
339
340
        return $this;
341
    }
342
343
    /**
344
     * Add subscription's billing plan by ID.
345
     *
346
     * @param string $plan_id
347
     *
348
     * @return \Srmklive\PayPal\Services\PayPal
349
     */
350
    public function addBillingPlanById(string $plan_id): \Srmklive\PayPal\Services\PayPal
351
    {
352
        $this->billing_plan = [
353
            'id' => $plan_id,
354
        ];
355
356
        return $this;
357
    }
358
359
    /**
360
     * Create a product for a subscription's billing plan.
361
     *
362
     * @param string $name
363
     * @param string $description
364
     * @param array  $billing_cycles
365
     *
366
     * @throws Throwable
367
     *
368
     * @return void
369
     */
370
    protected function addBillingPlan(string $name, string $description, array $billing_cycles): void
371
    {
372
        $request_id = Str::random();
373
374
        $plan_params = [
375
            'product_id'          => $this->product['id'],
376
            'name'                => $name,
377
            'description'         => $description,
378
            'status'              => 'ACTIVE',
379
            'billing_cycles'      => $billing_cycles,
380
            'payment_preferences' => [
381
                'auto_bill_outstanding'     => true,
382
                'setup_fee_failure_action'  => 'CONTINUE',
383
                'payment_failure_threshold' => $this->payment_failure_threshold,
384
            ],
385
        ];
386
387
        $this->billing_plan = $this->createPlan($plan_params, $request_id);
0 ignored issues
show
Bug introduced by
It seems like createPlan() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

387
        /** @scrutinizer ignore-call */ 
388
        $this->billing_plan = $this->createPlan($plan_params, $request_id);
Loading history...
388
    }
389
390
    /**
391
     * Set return & cancel urls.
392
     *
393
     * @param string $return_url
394
     * @param string $cancel_url
395
     *
396
     * @return \Srmklive\PayPal\Services\PayPal
397
     */
398
    public function setReturnAndCancelUrl(string $return_url, string $cancel_url): \Srmklive\PayPal\Services\PayPal
399
    {
400
        $this->return_url = $return_url;
401
        $this->cancel_url = $cancel_url;
402
403
        return $this;
404
    }
405
406
    /**
407
     * Set custom failure threshold when adding a subscription.
408
     *
409
     * @param int $threshold
410
     *
411
     * @return \Srmklive\PayPal\Services\PayPal
412
     */
413
    public function addPaymentFailureThreshold(int $threshold): \Srmklive\PayPal\Services\PayPal
414
    {
415
        $this->payment_failure_threshold = $threshold;
416
417
        return $this;
418
    }
419
420
    /**
421
     * Add setup fee when adding a subscription.
422
     *
423
     * @param float $price
424
     *
425
     * @return \Srmklive\PayPal\Services\PayPal
426
     */
427
    public function addSetupFee(float $price): \Srmklive\PayPal\Services\PayPal
428
    {
429
        $this->has_setup_fee = true;
430
        $this->payment_preferences = [
431
            'auto_bill_outstanding'     => true,
432
            'setup_fee'                 => [
433
                'value'         => $price,
434
                'currency_code' => $this->getCurrency(),
435
            ],
436
            'setup_fee_failure_action'  => 'CONTINUE',
437
            'payment_failure_threshold' => $this->payment_failure_threshold,
438
        ];
439
440
        return $this;
441
    }
442
443
    /**
444
     * Add shipping address.
445
     *
446
     * @param string $full_name
447
     * @param string $address_line_1
448
     * @param string $address_line_2
449
     * @param string $admin_area_2
450
     * @param string $admin_area_1
451
     * @param string $postal_code
452
     * @param string $country_code
453
     *
454
     * @return \Srmklive\PayPal\Services\PayPal
455
     */
456
    public function addShippingAddress(string $full_name, string $address_line_1, string $address_line_2, string $admin_area_2, string $admin_area_1, string $postal_code, string $country_code): \Srmklive\PayPal\Services\PayPal
457
    {
458
        $this->shipping_address = [
459
            "name" => [
460
                "full_name" => $full_name,
461
            ],
462
            "address" =>  [
463
                "address_line_1"  => $address_line_1,
464
                "address_line_2"  => $address_line_2,
465
                "admin_area_2"    => $admin_area_2,
466
                "admin_area_1"    => $admin_area_1,
467
                "postal_code"     => $postal_code,
468
                "country_code"    => $country_code,
469
            ],
470
        ];
471
472
        return $this;
473
    }
474
}
475