Passed
Push — v2.0 ( d79b43...27e8f8 )
by Raza
09:44 queued 14s
created

Helpers::addDailyPlan()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 12
rs 10
cc 3
nc 3
nop 3
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 array
48
     */
49
    protected $taxes;
50
51
    /**
52
     * Setup a subscription.
53
     *
54
     * @param string $customer_name
55
     * @param string $customer_email
56
     * @param string $start_date
57
     *
58
     * @throws Throwable
59
     *
60
     * @return array|\Psr\Http\Message\StreamInterface|string
61
     */
62
    public function setupSubscription(string $customer_name, string $customer_email, string $start_date = '')
63
    {
64
        $start_date = !empty($start_date) ? Carbon::parse($start_date)->toIso8601String() : Carbon::now()->toIso8601String();
65
66
        $body = [
67
            'plan_id'    => $this->billing_plan['id'],
68
            'start_time' => $start_date,
69
            'quantity'   => 1,
70
            'subscriber' => [
71
                'name'          => [
72
                    'given_name' => $customer_name,
73
                ],
74
                'email_address' => $customer_email,
75
            ],
76
        ];
77
78
        if ($this->has_setup_fee) {
79
            $body['plan'] = [
80
                'payment_preferences' => $this->payment_preferences,
81
            ];
82
        }
83
84
        if (isset($this->shipping_address)) {
85
            $body['subscriber']['shipping_address'] = $this->shipping_address;
86
        }
87
88
        if (isset($this->experience_context)) {
89
            $body['application_context'] = $this->experience_context;
90
        }
91
92
        if (isset($this->taxes)) {
93
            $body['taxes'] = $this->taxes;
94
        }
95
96
        $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

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

271
                'currency_code' => $this->/** @scrutinizer ignore-call */ getCurrency(),
Loading history...
272
            ],
273
        ];
274
275
        if (empty($this->trial_pricing)) {
276
            $plan_sequence = 1;
277
        } else {
278
            $plan_sequence = 2;
279
        }
280
281
        return [
282
            'frequency' => [
283
                'interval_unit'  => $interval_unit,
284
                'interval_count' => $interval_count,
285
            ],
286
            'tenure_type'    => ($trial === true) ? 'TRIAL' : 'REGULAR',
287
            'sequence'       => ($trial === true) ? 1 : $plan_sequence,
288
            'total_cycles'   => ($trial === true) ? 1 : 0,
289
            'pricing_scheme' => $pricing_scheme,
290
        ];
291
    }
292
293
    /**
294
     * Create a product for a subscription's billing plan.
295
     *
296
     * @param string $name
297
     * @param string $description
298
     * @param string $type
299
     * @param string $category
300
     *
301
     * @throws Throwable
302
     *
303
     * @return \Srmklive\PayPal\Services\PayPal
304
     */
305
    public function addProduct(string $name, string $description, string $type, string $category): \Srmklive\PayPal\Services\PayPal
306
    {
307
        if (isset($this->product)) {
308
            return $this;
309
        }
310
311
        $this->setRequestHeader('PayPal-Request-Id', Str::random());
0 ignored issues
show
Bug introduced by
It seems like setRequestHeader() 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

311
        $this->/** @scrutinizer ignore-call */ 
312
               setRequestHeader('PayPal-Request-Id', Str::random());
Loading history...
312
313
        $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

313
        /** @scrutinizer ignore-call */ 
314
        $this->product = $this->createProduct([
Loading history...
314
            'name'          => $name,
315
            'description'   => $description,
316
            'type'          => $type,
317
            'category'      => $category,
318
        ]);
319
320
        return $this;
321
    }
322
323
    /**
324
     * Add subscription's billing plan's product by ID.
325
     *
326
     * @param string $product_id
327
     *
328
     * @return \Srmklive\PayPal\Services\PayPal
329
     */
330
    public function addProductById(string $product_id): \Srmklive\PayPal\Services\PayPal
331
    {
332
        $this->product = [
333
            'id' => $product_id,
334
        ];
335
336
        return $this;
337
    }
338
339
    /**
340
     * Add subscription's billing plan by ID.
341
     *
342
     * @param string $plan_id
343
     *
344
     * @return \Srmklive\PayPal\Services\PayPal
345
     */
346
    public function addBillingPlanById(string $plan_id): \Srmklive\PayPal\Services\PayPal
347
    {
348
        $this->billing_plan = [
349
            'id' => $plan_id,
350
        ];
351
352
        return $this;
353
    }
354
355
    /**
356
     * Create a product for a subscription's billing plan.
357
     *
358
     * @param string $name
359
     * @param string $description
360
     * @param array  $billing_cycles
361
     *
362
     * @throws Throwable
363
     *
364
     * @return void
365
     */
366
    protected function addBillingPlan(string $name, string $description, array $billing_cycles)
367
    {
368
        $this->setRequestHeader('PayPal-Request-Id', Str::random());
369
370
        $plan_params = [
371
            'product_id'          => $this->product['id'],
372
            'name'                => $name,
373
            'description'         => $description,
374
            'status'              => 'ACTIVE',
375
            'billing_cycles'      => $billing_cycles,
376
            'payment_preferences' => [
377
                'auto_bill_outstanding'     => true,
378
                'setup_fee_failure_action'  => 'CONTINUE',
379
                'payment_failure_threshold' => $this->payment_failure_threshold,
380
            ],
381
        ];
382
383
        $this->billing_plan = $this->createPlan($plan_params);
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

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