Passed
Pull Request — master (#148)
by
unknown
08:54
created

Payment::refund()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 11
c 1
b 0
f 1
nc 4
nop 2
dl 0
loc 22
rs 9.9
1
<?php
2
3
namespace Shetabit\Multipay;
4
5
use Shetabit\Multipay\Contracts\DriverInterface;
6
use Shetabit\Multipay\Contracts\ReceiptInterface;
7
use Shetabit\Multipay\Exceptions\DriverNotFoundException;
8
use Shetabit\Multipay\Exceptions\InvoiceNotFoundException;
9
use Shetabit\Multipay\Traits\HasPaymentEvents;
10
use Shetabit\Multipay\Traits\InteractsWithRedirectionForm;
11
12
class Payment
13
{
14
    use InteractsWithRedirectionForm;
15
    use HasPaymentEvents;
16
17
    /**
18
     * Payment Configuration.
19
     *
20
     * @var array
21
     */
22
    protected $config;
23
24
    /**
25
     * Payment Driver Settings.
26
     *
27
     * @var array
28
     */
29
    protected $settings;
30
31
    /**
32
     * callbackUrl
33
     *
34
     * @var string
35
     */
36
    protected $callbackUrl;
37
38
    /**
39
     * Payment Driver Name.
40
     *
41
     * @var string
42
     */
43
    protected $driver;
44
45
    /**
46
     * Payment Driver Instance.
47
     *
48
     * @var object
49
     */
50
    protected $driverInstance;
51
52
    /**
53
     * @var Invoice
54
     */
55
    protected $invoice;
56
57
    /**
58
     * PaymentManager constructor.
59
     *
60
     * @param array $config
61
     *
62
     * @throws \Exception
63
     */
64
    public function __construct(array $config = [])
65
    {
66
        $this->config = empty($config) ? $this->loadDefaultConfig() : $config;
67
        $this->invoice(new Invoice());
68
        $this->via($this->config['default']);
69
    }
70
71
    /**
72
     * Retrieve Default config's path.
73
     *
74
     * @return string
75
     */
76
    public static function getDefaultConfigPath() : string
77
    {
78
        return dirname(__DIR__).'/config/payment.php';
79
    }
80
81
    /**
82
     * Set custom configs
83
     * we can use this method when we want to use dynamic configs
84
     *
85
     * @param $key
86
     * @param $value|null
87
     *
88
     * @return $this
89
     */
90
    public function config($key, $value = null)
91
    {
92
        $configs = [];
93
94
        $key = is_array($key) ? $key : [$key => $value];
95
96
        foreach ($key as $k => $v) {
97
            $configs[$k] = $v;
98
        }
99
100
        $this->settings = array_merge($this->settings, $configs);
101
102
        return $this;
103
    }
104
105
    /**
106
     * Set callbackUrl.
107
     *
108
     * @param $url|null
109
     * @return $this
110
     */
111
    public function callbackUrl($url = null)
112
    {
113
        $this->config('callbackUrl', $url);
114
115
        return $this;
116
    }
117
118
    /**
119
     * Reset the callbackUrl to its original that exists in configs.
120
     *
121
     * @return $this
122
     */
123
    public function resetCallbackUrl()
124
    {
125
        $this->callbackUrl();
126
127
        return $this;
128
    }
129
130
    /**
131
     * Set payment amount.
132
     *
133
     * @param $amount
134
     * @return $this
135
     * @throws \Exception
136
     */
137
    public function amount($amount)
138
    {
139
        $this->invoice->amount($amount);
140
141
        return $this;
142
    }
143
144
    /**
145
     * Set a piece of data to the details.
146
     *
147
     * @param $key
148
     *
149
     * @param $value|null
150
     *
151
     * @return $this
152
     */
153
    public function detail($key, $value = null)
154
    {
155
        $this->invoice->detail($key, $value);
156
157
        return $this;
158
    }
159
160
    /**
161
     * Set transaction's id
162
     *
163
     * @param $id
164
     *
165
     * @return $this
166
     */
167
    public function transactionId($id)
168
    {
169
        $this->invoice->transactionId($id);
170
171
        return $this;
172
    }
173
174
    /**
175
     * Change the driver on the fly.
176
     *
177
     * @param $driver
178
     *
179
     * @return $this
180
     *
181
     * @throws \Exception
182
     */
183
    public function via($driver)
184
    {
185
        $this->driver = $driver;
186
        $this->validateDriver();
187
        $this->invoice->via($driver);
188
        $this->settings = $this->config['drivers'][$driver];
189
190
        return $this;
191
    }
192
193
    /**
194
     * Purchase the invoice
195
     *
196
     * @param Invoice $invoice|null
197
     * @param $finalizeCallback|null
198
     *
199
     * @return $this
200
     *
201
     * @throws \Exception
202
     */
203
    public function purchase(Invoice $invoice = null, $finalizeCallback = null)
204
    {
205
        if ($invoice) { // create new invoice
206
            $this->invoice($invoice);
207
        }
208
209
        $this->driverInstance = $this->getFreshDriverInstance();
210
211
        //purchase the invoice
212
        $transactionId = $this->driverInstance->purchase();
213
        if ($finalizeCallback) {
214
            call_user_func_array($finalizeCallback, [$this->driverInstance, $transactionId]);
215
        }
216
217
        // dispatch event
218
        $this->dispatchEvent(
219
            'purchase',
220
            $this->driverInstance,
221
            $this->driverInstance->getInvoice()
222
        );
223
224
        return $this;
225
    }
226
227
    /**
228
     * Refund the invoice
229
     *
230
     * @param Invoice $invoice|null
231
     * @param $finalizeCallback|null
232
     *
233
     * @return $this
234
     *
235
     * @throws \Exception
236
     */
237
    public function refund(Invoice $invoice = null, $finalizeCallback = null)
238
    {
239
        if ($invoice) { // create new invoice
240
            $this->invoice($invoice);
241
        }
242
243
        $this->driverInstance = $this->getFreshDriverInstance();
244
245
        //purchase the invoice
246
        $transactionId = $this->driverInstance->refund();
247
        if ($finalizeCallback) {
248
            call_user_func_array($finalizeCallback, [$this->driverInstance, $transactionId]);
249
        }
250
251
        // dispatch event
252
        $this->dispatchEvent(
253
            'refund',
254
            $this->driverInstance,
255
            $this->driverInstance->getInvoice()
256
        );
257
258
        return $this;
259
    }
260
261
    /**
262
     * Pay the purchased invoice.
263
     *
264
     * @param $initializeCallback|null
265
     *
266
     * @return mixed
267
     *
268
     * @throws \Exception
269
     */
270
    public function pay($initializeCallback = null)
271
    {
272
        $this->driverInstance = $this->getDriverInstance();
273
274
        if ($initializeCallback) {
275
            call_user_func($initializeCallback, $this->driverInstance);
276
        }
277
278
        $this->validateInvoice();
279
280
        // dispatch event
281
        $this->dispatchEvent(
282
            'pay',
283
            $this->driverInstance,
284
            $this->driverInstance->getInvoice()
285
        );
286
287
        return $this->driverInstance->pay();
288
    }
289
290
    /**
291
     * Verifies the payment
292
     *
293
     * @param $finalizeCallback|null
294
     *
295
     * @return ReceiptInterface
296
     *
297
     * @throws InvoiceNotFoundException
298
     */
299
    public function verify($finalizeCallback = null) : ReceiptInterface
300
    {
301
        $this->driverInstance = $this->getDriverInstance();
302
        $this->validateInvoice();
303
        $receipt = $this->driverInstance->verify();
304
305
        if (!empty($finalizeCallback)) {
306
            call_user_func($finalizeCallback, $receipt, $this->driverInstance);
307
        }
308
309
        // dispatch event
310
        $this->dispatchEvent(
311
            'verify',
312
            $receipt,
313
            $this->driverInstance,
314
            $this->driverInstance->getInvoice()
315
        );
316
317
        return $receipt;
318
    }
319
320
    /**
321
     * Retrieve default config.
322
     *
323
     * @return array
324
     */
325
    protected function loadDefaultConfig() : array
326
    {
327
        return require(static::getDefaultConfigPath());
328
    }
329
330
    /**
331
     * Set invoice instance.
332
     *
333
     * @param Invoice $invoice
334
     *
335
     * @return self
336
     */
337
    protected function invoice(Invoice $invoice)
338
    {
339
        $this->invoice = $invoice;
340
341
        return $this;
342
    }
343
344
    /**
345
     * Retrieve current driver instance or generate new one.
346
     *
347
     * @return mixed
348
     * @throws \Exception
349
     */
350
    protected function getDriverInstance()
351
    {
352
        if (!empty($this->driverInstance)) {
353
            return $this->driverInstance;
354
        }
355
356
        return $this->getFreshDriverInstance();
357
    }
358
359
    /**
360
     * Get new driver instance
361
     *
362
     * @return mixed
363
     * @throws \Exception
364
     */
365
    protected function getFreshDriverInstance()
366
    {
367
        $this->validateDriver();
368
        $class = $this->config['map'][$this->driver];
369
370
        if (!empty($this->callbackUrl)) { // use custom callbackUrl if exists
371
            $this->settings['callbackUrl'] = $this->callbackUrl;
372
        }
373
374
        return new $class($this->invoice, $this->settings);
375
    }
376
377
    /**
378
     * Validate Invoice.
379
     *
380
     * @throws InvoiceNotFoundException
381
     */
382
    protected function validateInvoice()
383
    {
384
        if (empty($this->invoice)) {
385
            throw new InvoiceNotFoundException('Invoice not selected or does not exist.');
386
        }
387
    }
388
389
    /**
390
     * Validate driver.
391
     *
392
     * @throws \Exception
393
     */
394
    protected function validateDriver()
395
    {
396
        if (empty($this->driver)) {
397
            throw new DriverNotFoundException('Driver not selected or default driver does not exist.');
398
        }
399
400
        if (empty($this->config['drivers'][$this->driver]) || empty($this->config['map'][$this->driver])) {
401
            throw new DriverNotFoundException('Driver not found in config file. Try updating the package.');
402
        }
403
404
        if (!class_exists($this->config['map'][$this->driver])) {
405
            throw new DriverNotFoundException('Driver source not found. Please update the package.');
406
        }
407
408
        $reflect = new \ReflectionClass($this->config['map'][$this->driver]);
409
410
        if (!$reflect->implementsInterface(DriverInterface::class)) {
411
            throw new \Exception("Driver must be an instance of Contracts\DriverInterface.");
412
        }
413
    }
414
}
415