Completed
Push — master ( d0a149...d07a9e )
by Arthur
03:35
created

PaymentRepository::recordSubscriptionPayment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php namespace BB\Repo;
2
3
use BB\Entities\Payment;
4
use BB\Events\MemberBalanceChanged;
5
use BB\Exceptions\NotImplementedException;
6
use BB\Exceptions\PaymentException;
7
use Carbon\Carbon;
8
9
class PaymentRepository extends DBRepository
10
{
11
12
    /**
13
     * @var Payment
14
     */
15
    protected $model;
16
17
    public static $SUBSCRIPTION = 'subscription';
18
    public static $INDUCTION = 'induction';
19
20
    private $reason = null;
21
    private $source = null;
22
23
    /**
24
     * @param Payment $model
25
     */
26
    public function __construct(Payment $model)
27
    {
28
        $this->model = $model;
29
        $this->perPage = 10;
30
    }
31
32
33
    public function getPaginated(array $params)
34
    {
35
        $model = $this->model;
36
37 View Code Duplication
        if ($this->hasDateFilter()) {
38
            $model = $model->where('created_at', '>=', $this->startDate)->where('created_at', '<=', $this->endDate);
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
39
        }
40
41
        if ($this->hasMemberFilter()) {
42
            $model = $model->where('user_id', $this->memberId);
43
        }
44
45
        if ($this->hasReasonFilter()) {
46
            $model = $model->where('reason', $this->reason);
47
        }
48
49
        if ($this->hasSourceFilter()) {
50
            $model = $model->where('source', $this->source);
51
        }
52
53 View Code Duplication
        if ($this->isSortable($params)) {
54
            return $model->orderBy($params['sortBy'], $params['direction'])->paginate($this->perPage);
55
        }
56
        return $model->paginate($this->perPage);
57
    }
58
59
60
    public function getTotalAmount()
61
    {
62
        $model = $this->model;
63
64 View Code Duplication
        if ($this->hasDateFilter()) {
65
            $model = $model->where('created_at', '>=', $this->startDate)->where('created_at', '<=', $this->endDate);
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
66
        }
67
68
        if ($this->hasMemberFilter()) {
69
            $model = $model->where('user_id', $this->memberId);
70
        }
71
72
        if ($this->hasReasonFilter()) {
73
            $model = $model->where('reason', $this->reason);
74
        }
75
76
        if ($this->hasSourceFilter()) {
77
            $model = $model->where('source', $this->source);
78
        }
79
80
        return $model->get()->sum('amount');
81
    }
82
83
84
    /**
85
     * Record a payment against a user record
86
     *
87
     * @param string   $reason What was the reason. subscription, induction, etc...
88
     * @param int      $userId The users ID
89
     * @param string   $source gocardless, paypal
90
     * @param string   $sourceId A reference for the source
91
     * @param double   $amount Amount received before a fee in pounds
92
     * @param string   $status paid, pending, cancelled, refunded
93
     * @param double   $fee The fee charged by the payment provider
94
     * @param string   $ref
95
     * @param Carbon $paidDate
96
     * @return int The ID of the payment record
97
     */
98
    public function recordPayment($reason, $userId, $source, $sourceId, $amount, $status = 'paid', $fee = 0.0, $ref = '', Carbon $paidDate = null)
99
    {
100
        if ($paidDate == null) {
101
            $paidDate = new Carbon();
102
        }
103
        //If we have an existing similer record dont create another, except for when there is no source id
104
        $existingRecord = $this->model->where('source', $source)->where('source_id', $sourceId)->where('user_id', $userId)->first();
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
105
        if ( ! $existingRecord || empty($sourceId)) {
106
            $record                   = new $this->model;
107
            $record->user_id          = $userId;
108
            $record->reason           = $reason;
109
            $record->source           = $source;
110
            $record->source_id        = $sourceId;
111
            $record->amount           = $amount;
112
            $record->amount_minus_fee = ($amount - $fee);
113
            $record->fee              = $fee;
114
            $record->status           = $status;
115
            $record->reference        = $ref;
116
            if ($status == 'paid') {
117
                $record->paid_at = $paidDate;
118
            }
119
            $record->save();
120
        } else {
121
            $record = $existingRecord;
122
        }
123
124
        //Emit an event so that things like the balance updater can run
125
        \Event::fire('payment.create', array($userId, $reason, $ref, $record->id, $status));
126
127
        return $record->id;
128
    }
129
130
    /**
131
     * Record a subscription payment
132
     *
133
     * @param int    $userId The users ID
134
     * @param string $source gocardless, paypal
135
     * @param string $sourceId A reference for the source
136
     * @param double $amount Amount received before a fee in pounds
137
     * @param string $status paid, pending, cancelled, refunded
138
     * @param double $fee The fee charged by the payment provider
139
     * @param string|null   $ref
140
     * @param Carbon $paidDate
141
     * @return int  The ID of the payment record
142
     */
143
    public function recordSubscriptionPayment($userId, $source, $sourceId, $amount, $status = 'paid', $fee = 0.0, $ref = '', Carbon $paidDate = null)
144
    {
145
        return $this->recordPayment('subscription', $userId, $source, $sourceId, $amount, $status, $fee, $ref, $paidDate);
146
    }
147
148
    /**
149
     * An existing payment has been set to paid
150
     *
151
     * @param $paymentId
152
     * @param Carbon $paidDate
153
     */
154
    public function markPaymentPaid($paymentId, $paidDate)
155
    {
156
        $payment = $this->getById($paymentId);
157
        $payment->status = 'paid';
158
        $payment->paid_at = $paidDate;
159
        $payment->save();
160
161
        \Event::fire('payment.paid', array($payment->user_id, $paymentId, $payment->reason, $payment->reference, $paidDate));
162
    }
163
164
    /**
165
     * An existing payment has been set to pending/submitted
166
     *
167
     * @param $paymentId
168
     */
169
    public function markPaymentPending($paymentId)
170
    {
171
        $payment = $this->getById($paymentId);
172
        $payment->status = 'pending';
173
        $payment->save();
174
    }
175
176
    /**
177
     * Record a payment failure or cancellation
178
     *
179
     * @param int    $paymentId
180
     * @param string $status
181
     */
182
    public function recordPaymentFailure($paymentId, $status = 'failed')
183
    {
184
        $this->update($paymentId, ['status' => $status]);
185
186
        $payment = $this->getById($paymentId);
187
188
        \Event::fire('payment.cancelled', array($paymentId, $payment->user_id, $payment->reason, $payment->reference, $status));
189
    }
190
191
    /**
192
     * Assign an unassigned payment to a user
193
     *
194
     * @param int $paymentId
195
     * @param int $userId
196
     *
197
     * @throws PaymentException
198
     */
199
    public function assignPaymentToUser($paymentId, $userId)
200
    {
201
        $payment = $this->getById($paymentId);
202
203
        if (!empty($payment->user_id)) {
204
            throw new PaymentException('Payment already assigned to user');
205
        }
206
207
        $this->update($paymentId, ['user_id' => $userId]);
208
    }
209
210
    /**
211
     * Take a payment that has been used for something and reassign it to the balance
212
     * @param $paymentId
213
     *
214
     * @throws NotImplementedException
215
     */
216
    public function refundPaymentToBalance($paymentId)
217
    {
218
        $payment = $this->getById($paymentId);
219
220 View Code Duplication
        if ($payment->reason === 'donation') {
221
            $this->update($paymentId, ['reason' => 'balance']);
222
            event(new MemberBalanceChanged($payment->user_id));
223
            return;
224
        }
225
226 View Code Duplication
        if ($payment->reason === 'induction') {
227
            //This method must only be used if the induction record has been cancelled first
228
            // otherwise an orphned record will be left behind
229
            $this->update($paymentId, ['reason' => 'balance']);
230
            event(new MemberBalanceChanged($payment->user_id));
231
            return;
232
        }
233
234
        throw new NotImplementedException('This hasn\'t been built yet');
235
    }
236
237
238
    /**
239
     * Fetch the users latest payment of a particular type
240
     * @param integer $userId
241
     * @param string  $reason
242
     * @return mixed
243
     */
244 View Code Duplication
    public function latestUserPayment($userId, $reason = 'subscription')
245
    {
246
        return $this->model->where('user_id', $userId)
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
247
            ->whereRaw('reason = ? and (status = ? or status = ? or status = ?)', [$reason, 'paid', 'pending', 'withdrawn'])
248
            ->orderBy('created_at', 'desc')
249
            ->first();
250
    }
251
252
253
    /**
254
     * Get all user payments of a specific reason
255
     * @param $userId
256
     * @param string $reason
257
     * @return mixed
258
     */
259 View Code Duplication
    public function getUserPaymentsByReason($userId, $reason)
260
    {
261
        return $this->model->where('user_id', $userId)
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
262
            ->whereRaw('reason = ? and (status = ? or status = ? or status = ?)', [$reason, 'paid', 'pending', 'withdrawn'])
263
            ->orderBy('created_at', 'desc')
264
            ->get();
265
    }
266
267
268
    /**
269
     * @param string $source
270
     */
271 View Code Duplication
    public function getUserPaymentsBySource($userId, $source)
272
    {
273
        return $this->model->where('user_id', $userId)
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
274
            ->whereRaw('source = ? and (status = ? or status = ? or status = ?)', [$source, 'paid', 'pending', 'withdrawn'])
275
            ->orderBy('created_at', 'desc')
276
            ->get();
277
    }
278
279
    /**
280
     * Get all payments with a specific reference
281
     * @param string $reference
282
     * @return \Illuminate\Database\Eloquent\Collection
283
     */
284
    public function getPaymentsByReference($reference)
285
    {
286
        return $this->model->where('reference', $reference)->get();
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
287
    }
288
289
    /**
290
     * @param string $referencePrefix
291
     * @return \Illuminate\Database\Eloquent\Collection
292
     */
293
    public function getEquipmentFeePayments($referencePrefix)
294
    {
295
        return $this->model->where('reason', 'equipment-fee')->get()->filter(function($payment) use($referencePrefix) {
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
296
            return strpos($payment->reference, ':' . $referencePrefix) !== false;
297
        });
298
    }
299
300
301
    /**
302
     * Return a paginated list of balance affecting payment for a user
303
     * @param $userId
304
     * @return \Illuminate\Database\Eloquent\Collection
305
     */
306 View Code Duplication
    public function getBalancePaymentsPaginated($userId)
307
    {
308
        return $this->model->where('user_id', $userId)
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
309
            ->whereRaw('(source = ? or reason = ?) and (status = ? or status = ? or status = ?)', ['balance', 'balance', 'paid', 'pending', 'withdrawn'])
310
            ->orderBy('created_at', 'desc')
311
            ->simplePaginate($this->perPage);
312
    }
313
314
315
    /**
316
     * Return a collection of payments specifically for storage boxes
317
     * @param integer $userId
318
     * @return mixed
319
     */
320 View Code Duplication
    public function getStorageBoxPayments($userId)
321
    {
322
        return $this->model->where('user_id', $userId)
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
323
            ->whereRaw('reason = ? and (status = ? or status = ? or status = ?)', ['storage-box', 'paid', 'pending', 'withdrawn'])
324
            ->orderBy('created_at', 'desc')
325
            ->get();
326
    }
327
328
    public function dateFilter($startDate, $endDate)
329
    {
330
        $this->startDate = $startDate;
331
        $this->endDate = $endDate;
332
    }
333
334
    private function hasDateFilter()
335
    {
336
        return ($this->startDate && $this->endDate);
337
    }
338
339
    /**
340
     * Delete a record
341
     * @param $recordId
342
     * @return bool|null
343
     * @throws \Exception
344
     */
345
    public function delete($recordId)
346
    {
347
        $payment = $this->getById($recordId);
348
349
        $state = $payment->delete();
350
351
        //Fire an event, allows the balance to get updated
352
        \Event::fire('payment.delete', array($payment->user_id, $payment->source, $payment->reason, $payment->id));
353
354
        return $state;
355
    }
356
357
    public function canDelete($recordId)
358
    {
359
        throw new NotImplementedException();
360
    }
361
362
    /**
363
     * Used for the getPaginated and getTotalAmount method
364
     * @param $reasonFilter
365
     */
366
    public function reasonFilter($reasonFilter)
367
    {
368
        $this->reason = $reasonFilter;
369
    }
370
371
    private function hasReasonFilter()
372
    {
373
        return ! is_null($this->reason);
374
    }
375
376
    /**
377
     * Used for the getPaginated and getTotalAmount method
378
     * @param string $sourceFilter
379
     */
380
    public function sourceFilter($sourceFilter)
381
    {
382
        $this->source = $sourceFilter;
383
    }
384
385
386
    private function hasSourceFilter()
387
    {
388
        return ! is_null($this->source);
389
    }
390
391
    /**
392
     * Used for the getPaginated and getTotalAmount method
393
     */
394
    public function resetFilters()
395
    {
396
        $this->source = null;
397
        $this->reason = null;
398
        $this->memberId = null;
399
        $this->startDate = null;
400
        $this->endDate = null;
401
    }
402
403
    /**
404
     * Fetch a payment record using the id provided by the payment provider
405
     *
406
     * @param $sourceId
407
     * @return Payment
408
     */
409
    public function getPaymentBySourceId($sourceId)
410
    {
411
        return $this->model->where('source_id', $sourceId)->first();
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<BB\Entities\Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
412
    }
413
414
    /**
415
     * Record a balance payment transfer between two users
416
     * 
417
     * @param integer $sourceUserId
418
     * @param integer $targetUserId
419
     * @param double $amount
420
     */
421
    public function recordBalanceTransfer($sourceUserId, $targetUserId, $amount)
422
    {
423
        $paymentId = $this->recordPayment('transfer', $sourceUserId, 'balance', '', $amount, 'paid', 0, $targetUserId);
424
        $this->recordPayment('balance', $targetUserId, 'transfer', $paymentId, $amount, 'paid', 0, $sourceUserId);
425
426
        //Both of these events aren't needed adn the balance payment fires its own
427
        // but for the sake of neatness they are here
428
        event(new MemberBalanceChanged($sourceUserId));
429
        event(new MemberBalanceChanged($targetUserId));
430
    }
431
} 
432