Completed
Push — 23 ( 09d773...16ee8e )
by Harald
11s
created

Transaction   F

Complexity

Total Complexity 56

Size/Duplication

Total Lines 396
Duplicated Lines 6.31 %

Coupling/Cohesion

Components 5
Dependencies 28

Importance

Changes 0
Metric Value
dl 25
loc 396
rs 1.3043
c 0
b 0
f 0
wmc 56
lcom 5
cbo 28

27 Methods

Rating   Name   Duplication   Size   Complexity  
F _initialize() 10 166 27
A __toString() 15 15 2
A isEqual() 0 4 1
A vaultCreditCard() 0 10 2
A vaultCustomer() 0 10 2
A isDisbursed() 0 3 1
A factory() 0 6 1
A cloneTransaction() 0 4 1
A createFromTransparentRedirect() 0 4 1
A createTransactionUrl() 0 4 1
A credit() 0 4 1
A creditNoValidate() 0 4 1
A find() 0 4 1
A sale() 0 4 1
A saleNoValidate() 0 4 1
A search() 0 4 1
A fetch() 0 4 1
A void() 0 4 1
A voidNoValidate() 0 4 1
A submitForSettlement() 0 4 1
A submitForSettlementNoValidate() 0 4 1
A updateDetails() 0 4 1
A submitForPartialSettlement() 0 4 1
A holdInEscrow() 0 4 1
A releaseFromEscrow() 0 4 1
A cancelRelease() 0 4 1
A refund() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Transaction often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Transaction, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Braintree;
3
4
/**
5
 * Braintree Transaction processor
6
 * Creates and manages transactions
7
 *
8
 * At minimum, an amount, credit card number, and
9
 * credit card expiration date are required.
10
 *
11
 * <b>Minimalistic example:</b>
12
 * <code>
13
 * Transaction::saleNoValidate(array(
14
 *   'amount' => '100.00',
15
 *   'creditCard' => array(
16
 *       'number' => '5105105105105100',
17
 *       'expirationDate' => '05/12',
18
 *       ),
19
 *   ));
20
 * </code>
21
 *
22
 * <b>Full example:</b>
23
 * <code>
24
 * Transaction::saleNoValidate(array(
25
 *    'amount'      => '100.00',
26
 *    'orderId'    => '123',
27
 *    'channel'    => 'MyShoppingCardProvider',
28
 *    'creditCard' => array(
29
 *         // if token is omitted, the gateway will generate a token
30
 *         'token' => 'credit_card_123',
31
 *         'number' => '5105105105105100',
32
 *         'expirationDate' => '05/2011',
33
 *         'cvv' => '123',
34
 *    ),
35
 *    'customer' => array(
36
 *     // if id is omitted, the gateway will generate an id
37
 *     'id'    => 'customer_123',
38
 *     'firstName' => 'Dan',
39
 *     'lastName' => 'Smith',
40
 *     'company' => 'Braintree',
41
 *     'email' => '[email protected]',
42
 *     'phone' => '419-555-1234',
43
 *     'fax' => '419-555-1235',
44
 *     'website' => 'http://braintreepayments.com'
45
 *    ),
46
 *    'billing'    => array(
47
 *      'firstName' => 'Carl',
48
 *      'lastName'  => 'Jones',
49
 *      'company'    => 'Braintree',
50
 *      'streetAddress' => '123 E Main St',
51
 *      'extendedAddress' => 'Suite 403',
52
 *      'locality' => 'Chicago',
53
 *      'region' => 'IL',
54
 *      'postalCode' => '60622',
55
 *      'countryName' => 'United States of America'
56
 *    ),
57
 *    'shipping' => array(
58
 *      'firstName'    => 'Andrew',
59
 *      'lastName'    => 'Mason',
60
 *      'company'    => 'Braintree',
61
 *      'streetAddress'    => '456 W Main St',
62
 *      'extendedAddress'    => 'Apt 2F',
63
 *      'locality'    => 'Bartlett',
64
 *      'region'    => 'IL',
65
 *      'postalCode'    => '60103',
66
 *      'countryName'    => 'United States of America'
67
 *    ),
68
 *    'customFields'    => array(
69
 *      'birthdate'    => '11/13/1954'
70
 *    )
71
 *  )
72
 * </code>
73
 *
74
 * <b>== Storing in the Vault ==</b>
75
 *
76
 * The customer and credit card information used for
77
 * a transaction can be stored in the vault by setting
78
 * <i>transaction[options][storeInVault]</i> to true.
79
 * <code>
80
 *   $transaction = Transaction::saleNoValidate(array(
81
 *     'customer' => array(
82
 *       'firstName'    => 'Adam',
83
 *       'lastName'    => 'Williams'
84
 *     ),
85
 *     'creditCard'    => array(
86
 *       'number'    => '5105105105105100',
87
 *       'expirationDate'    => '05/2012'
88
 *     ),
89
 *     'options'    => array(
90
 *       'storeInVault'    => true
91
 *     )
92
 *   ));
93
 *
94
 *  echo $transaction->customerDetails->id
95
 *  // '865534'
96
 *  echo $transaction->creditCardDetails->token
97
 *  // '6b6m'
98
 * </code>
99
 *
100
 * To also store the billing address in the vault, pass the
101
 * <b>addBillingAddressToPaymentMethod</b> option.
102
 * <code>
103
 *   Transaction.saleNoValidate(array(
104
 *    ...
105
 *     'options' => array(
106
 *       'storeInVault' => true
107
 *       'addBillingAddressToPaymentMethod' => true
108
 *     )
109
 *   ));
110
 * </code>
111
 *
112
 * <b>== Submitting for Settlement==</b>
113
 *
114
 * This can only be done when the transction's
115
 * status is <b>authorized</b>. If <b>amount</b> is not specified,
116
 * the full authorized amount will be settled. If you would like to settle
117
 * less than the full authorized amount, pass the desired amount.
118
 * You cannot settle more than the authorized amount.
119
 *
120
 * A transaction can be submitted for settlement when created by setting
121
 * $transaction[options][submitForSettlement] to true.
122
 *
123
 * <code>
124
 *   $transaction = Transaction::saleNoValidate(array(
125
 *     'amount'    => '100.00',
126
 *     'creditCard'    => array(
127
 *       'number'    => '5105105105105100',
128
 *       'expirationDate'    => '05/2012'
129
 *     ),
130
 *     'options'    => array(
131
 *       'submitForSettlement'    => true
132
 *     )
133
 *   ));
134
 * </code>
135
 *
136
 * <b>== More information ==</b>
137
 *
138
 * For more detailed information on Transactions, see {@link http://www.braintreepayments.com/gateway/transaction-api http://www.braintreepaymentsolutions.com/gateway/transaction-api}
139
 *
140
 * @package    Braintree
141
 * @category   Resources
142
 * @copyright  2015 Braintree, a division of PayPal, Inc.
143
 *
144
 *
145
 * @property-read string $avsErrorResponseCode
146
 * @property-read string $avsPostalCodeResponseCode
147
 * @property-read string $avsStreetAddressResponseCode
148
 * @property-read string $cvvResponseCode
149
 * @property-read string $id transaction id
150
 * @property-read string $amount transaction amount
151
 * @property-read Braintree\Transaction\AddressDetails $billingDetails transaction billing address
152
 * @property-read string $createdAt transaction created timestamp
153
 * @property-read Braintree\ApplePayCardDetails $applePayCardDetails transaction Apple Pay card info
154
 * @property-read Braintree\AndroidPayCardDetails $androidPayCardDetails transaction Android Pay card info
155
 * @property-read Braintree\AmexExpressCheckoutCardDetails $amexExpressCheckoutCardDetails transaction Amex Express Checkout card info
156
 * @property-read Braintree\CreditCardDetails $creditCardDetails transaction credit card info
157
 * @property-read Braintree\CoinbaseDetails $coinbaseDetails transaction Coinbase account info
158
 * @property-read Braintree\PayPalDetails $paypalDetails transaction paypal account info
159
 * @property-read Braintree\Transaction\CustomerDetails $customerDetails transaction customer info
160
 * @property-read Braintree\VenmoAccount $venmoAccountDetails transaction Venmo Account info
161
 * @property-read array  $customFields custom fields passed with the request
162
 * @property-read string $processorResponseCode gateway response code
163
 * @property-read string $additionalProcessorResponse raw response from processor
164
 * @property-read Braintree\Transaction\AddressDetails $shippingDetails transaction shipping address
165
 * @property-read string $status transaction status
166
 * @property-read array  $statusHistory array of StatusDetails objects
167
 * @property-read string $type transaction type
168
 * @property-read string $updatedAt transaction updated timestamp
169
 * @property-read Braintree\Disbursement $disbursementDetails populated when transaction is disbursed
170
 * @property-read Braintree\Dispute $disputes populated when transaction is disputed
171
 *
172
 */
173
174
class Transaction extends Base
175
{
176
    // Transaction Status
177
    const AUTHORIZATION_EXPIRED    = 'authorization_expired';
178
    const AUTHORIZING              = 'authorizing';
179
    const AUTHORIZED               = 'authorized';
180
    const GATEWAY_REJECTED         = 'gateway_rejected';
181
    const FAILED                   = 'failed';
182
    const PROCESSOR_DECLINED       = 'processor_declined';
183
    const SETTLED                  = 'settled';
184
    const SETTLING                 = 'settling';
185
    const SUBMITTED_FOR_SETTLEMENT = 'submitted_for_settlement';
186
    const VOIDED                   = 'voided';
187
    const UNRECOGNIZED             = 'unrecognized';
188
    const SETTLEMENT_DECLINED      = 'settlement_declined';
189
    const SETTLEMENT_PENDING       = 'settlement_pending';
190
    const SETTLEMENT_CONFIRMED     = 'settlement_confirmed';
191
192
    // Transaction Escrow Status
193
    const ESCROW_HOLD_PENDING    = 'hold_pending';
194
    const ESCROW_HELD            = 'held';
195
    const ESCROW_RELEASE_PENDING = 'release_pending';
196
    const ESCROW_RELEASED        = 'released';
197
    const ESCROW_REFUNDED        = 'refunded';
198
199
    // Transaction Types
200
    const SALE   = 'sale';
201
    const CREDIT = 'credit';
202
203
    // Transaction Created Using
204
    const FULL_INFORMATION = 'full_information';
205
    const TOKEN            = 'token';
206
207
    // Transaction Sources
208
    const API           = 'api';
209
    const CONTROL_PANEL = 'control_panel';
210
    const RECURRING     = 'recurring';
211
212
    // Gateway Rejection Reason
213
    const AVS            = 'avs';
214
    const AVS_AND_CVV    = 'avs_and_cvv';
215
    const CVV            = 'cvv';
216
    const DUPLICATE      = 'duplicate';
217
    const FRAUD          = 'fraud';
218
    const THREE_D_SECURE = 'three_d_secure';
219
    const APPLICATION_INCOMPLETE = 'application_incomplete';
220
221
    // Industry Types
222
    const LODGING_INDUSTRY           = 'lodging';
223
    const TRAVEL_AND_CRUISE_INDUSTRY = 'travel_cruise';
224
225
    /**
226
     * sets instance properties from an array of values
227
     *
228
     * @ignore
229
     * @access protected
230
     * @param array $transactionAttribs array of transaction data
231
     * @return void
232
     */
233
    protected function _initialize($transactionAttribs)
234
    {
235
        $this->_attributes = $transactionAttribs;
236
237
        if (isset($transactionAttribs['applePay'])) {
238
            $this->_set('applePayCardDetails',
239
                new Transaction\ApplePayCardDetails(
240
                    $transactionAttribs['applePay']
241
                )
242
            );
243
        }
244
245
        if (isset($transactionAttribs['androidPayCard'])) {
246
            $this->_set('androidPayCardDetails',
247
                new Transaction\AndroidPayCardDetails(
248
                    $transactionAttribs['androidPayCard']
249
                )
250
            );
251
        }
252
253
        if (isset($transactionAttribs['amexExpressCheckoutCard'])) {
254
            $this->_set('amexExpressCheckoutCardDetails',
255
                new Transaction\AmexExpressCheckoutCardDetails(
256
                    $transactionAttribs['amexExpressCheckoutCard']
257
                )
258
            );
259
        }
260
261
        if (isset($transactionAttribs['venmoAccount'])) {
262
            $this->_set('venmoAccountDetails',
263
                new Transaction\VenmoAccountDetails(
264
                    $transactionAttribs['venmoAccount']
265
                )
266
            );
267
        }
268
269
        if (isset($transactionAttribs['creditCard'])) {
270
            $this->_set('creditCardDetails',
271
                new Transaction\CreditCardDetails(
272
                    $transactionAttribs['creditCard']
273
                )
274
            );
275
        }
276
277
        if (isset($transactionAttribs['coinbaseAccount'])) {
278
            $this->_set('coinbaseDetails',
279
                new Transaction\CoinbaseDetails(
280
                    $transactionAttribs['coinbaseAccount']
281
                )
282
            );
283
        }
284
285
        if (isset($transactionAttribs['europeBankAccount'])) {
286
            $this->_set('europeBankAccount',
287
                new Transaction\EuropeBankAccountDetails(
288
                    $transactionAttribs['europeBankAccount']
289
                )
290
            );
291
        }
292
293
        if (isset($transactionAttribs['usBankAccount'])) {
294
            $this->_set('usBankAccount',
295
                new Transaction\UsBankAccountDetails(
296
                    $transactionAttribs['usBankAccount']
297
                )
298
            );
299
        }
300
301
        if (isset($transactionAttribs['paypal'])) {
302
            $this->_set('paypalDetails',
303
                new Transaction\PayPalDetails(
304
                    $transactionAttribs['paypal']
305
                )
306
            );
307
        }
308
309
        if (isset($transactionAttribs['customer'])) {
310
            $this->_set('customerDetails',
311
                new Transaction\CustomerDetails(
312
                    $transactionAttribs['customer']
313
                )
314
            );
315
        }
316
317
        if (isset($transactionAttribs['billing'])) {
318
            $this->_set('billingDetails',
319
                new Transaction\AddressDetails(
320
                    $transactionAttribs['billing']
321
                )
322
            );
323
        }
324
325
        if (isset($transactionAttribs['shipping'])) {
326
            $this->_set('shippingDetails',
327
                new Transaction\AddressDetails(
328
                    $transactionAttribs['shipping']
329
                )
330
            );
331
        }
332
333
        if (isset($transactionAttribs['subscription'])) {
334
            $this->_set('subscriptionDetails',
335
                new Transaction\SubscriptionDetails(
336
                    $transactionAttribs['subscription']
337
                )
338
            );
339
        }
340
341
        if (isset($transactionAttribs['descriptor'])) {
342
            $this->_set('descriptor',
343
                new Descriptor(
344
                    $transactionAttribs['descriptor']
345
                )
346
            );
347
        }
348
349
        if (isset($transactionAttribs['disbursementDetails'])) {
350
            $this->_set('disbursementDetails',
351
                new DisbursementDetails($transactionAttribs['disbursementDetails'])
352
            );
353
        }
354
355
        $disputes = [];
356
        if (isset($transactionAttribs['disputes'])) {
357
            foreach ($transactionAttribs['disputes'] AS $dispute) {
358
                $disputes[] = Dispute::factory($dispute);
359
            }
360
        }
361
362
        $this->_set('disputes', $disputes);
363
364
        $statusHistory = [];
365
        if (isset($transactionAttribs['statusHistory'])) {
366
            foreach ($transactionAttribs['statusHistory'] AS $history) {
367
                $statusHistory[] = new Transaction\StatusDetails($history);
368
            }
369
        }
370
371
        $this->_set('statusHistory', $statusHistory);
372
373
        $addOnArray = [];
374 View Code Duplication
        if (isset($transactionAttribs['addOns'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
375
            foreach ($transactionAttribs['addOns'] AS $addOn) {
376
                $addOnArray[] = AddOn::factory($addOn);
377
            }
378
        }
379
        $this->_set('addOns', $addOnArray);
380
381
        $discountArray = [];
382 View Code Duplication
        if (isset($transactionAttribs['discounts'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
383
            foreach ($transactionAttribs['discounts'] AS $discount) {
384
                $discountArray[] = Discount::factory($discount);
385
            }
386
        }
387
        $this->_set('discounts', $discountArray);
388
389
        if(isset($transactionAttribs['riskData'])) {
390
            $this->_set('riskData', RiskData::factory($transactionAttribs['riskData']));
391
        }
392
        if(isset($transactionAttribs['threeDSecureInfo'])) {
393
            $this->_set('threeDSecureInfo', ThreeDSecureInfo::factory($transactionAttribs['threeDSecureInfo']));
394
        }
395
        if(isset($transactionAttribs['facilitatorDetails'])) {
396
            $this->_set('facilitatorDetails', FacilitatorDetails::factory($transactionAttribs['facilitatorDetails']));
397
        }
398
    }
399
400
    /**
401
     * returns a string representation of the transaction
402
     * @return string
403
     */
404 View Code Duplication
    public function  __toString()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
405
    {
406
        // array of attributes to print
407
        $display = [
408
            'id', 'type', 'amount', 'status',
409
            'createdAt', 'creditCardDetails', 'customerDetails'
410
            ];
411
412
        $displayAttributes = [];
413
        foreach ($display AS $attrib) {
414
            $displayAttributes[$attrib] = $this->$attrib;
415
        }
416
        return __CLASS__ . '[' .
417
                Util::attributesToString($displayAttributes) .']';
418
    }
419
420
    public function isEqual($otherTx)
421
    {
422
        return $this->id === $otherTx->id;
423
    }
424
425
    public function vaultCreditCard()
426
    {
427
        $token = $this->creditCardDetails->token;
428
        if (empty($token)) {
429
            return null;
430
        }
431
        else {
432
            return CreditCard::find($token);
433
        }
434
    }
435
436
    /** @return void|Braintree\Customer */
437
    public function vaultCustomer()
438
    {
439
        $customerId = $this->customerDetails->id;
440
        if (empty($customerId)) {
441
            return null;
442
        }
443
        else {
444
            return Customer::find($customerId);
445
        }
446
    }
447
448
    /** @return bool */
449
    public function isDisbursed() {
450
        return $this->disbursementDetails->isValid();
451
    }
452
453
    /**
454
     *  factory method: returns an instance of Transaction
455
     *  to the requesting method, with populated properties
456
     *
457
     * @ignore
458
     * @return Transaction
459
     */
460
    public static function factory($attributes)
461
    {
462
        $instance = new self();
463
        $instance->_initialize($attributes);
464
        return $instance;
465
    }
466
467
468
    // static methods redirecting to gateway
469
470
    public static function cloneTransaction($transactionId, $attribs)
471
    {
472
        return Configuration::gateway()->transaction()->cloneTransaction($transactionId, $attribs);
473
    }
474
475
    public static function createFromTransparentRedirect($queryString)
476
    {
477
        return Configuration::gateway()->transaction()->createFromTransparentRedirect($queryString);
0 ignored issues
show
Deprecated Code introduced by
The method Braintree\TransactionGat...omTransparentRedirect() has been deprecated with message: since version 2.3.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
478
    }
479
480
    public static function createTransactionUrl()
481
    {
482
        return Configuration::gateway()->transaction()->createTransactionUrl();
0 ignored issues
show
Deprecated Code introduced by
The method Braintree\TransactionGat...:createTransactionUrl() has been deprecated with message: since version 2.3.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
483
    }
484
485
    public static function credit($attribs)
486
    {
487
        return Configuration::gateway()->transaction()->credit($attribs);
488
    }
489
490
    public static function creditNoValidate($attribs)
491
    {
492
        return Configuration::gateway()->transaction()->creditNoValidate($attribs);
493
    }
494
495
    public static function find($id)
496
    {
497
        return Configuration::gateway()->transaction()->find($id);
498
    }
499
500
    public static function sale($attribs)
501
    {
502
        return Configuration::gateway()->transaction()->sale($attribs);
503
    }
504
505
    public static function saleNoValidate($attribs)
506
    {
507
        return Configuration::gateway()->transaction()->saleNoValidate($attribs);
508
    }
509
510
    public static function search($query)
511
    {
512
        return Configuration::gateway()->transaction()->search($query);
513
    }
514
515
    public static function fetch($query, $ids)
516
    {
517
        return Configuration::gateway()->transaction()->fetch($query, $ids);
518
    }
519
520
    public static function void($transactionId)
521
    {
522
        return Configuration::gateway()->transaction()->void($transactionId);
523
    }
524
525
    public static function voidNoValidate($transactionId)
526
    {
527
        return Configuration::gateway()->transaction()->voidNoValidate($transactionId);
528
    }
529
530
    public static function submitForSettlement($transactionId, $amount = null, $attribs = [])
531
    {
532
        return Configuration::gateway()->transaction()->submitForSettlement($transactionId, $amount, $attribs);
533
    }
534
535
    public static function submitForSettlementNoValidate($transactionId, $amount = null, $attribs = [])
536
    {
537
        return Configuration::gateway()->transaction()->submitForSettlementNoValidate($transactionId, $amount, $attribs);
538
    }
539
540
    public static function updateDetails($transactionId, $attribs = [])
541
    {
542
        return Configuration::gateway()->transaction()->updateDetails($transactionId, $attribs);
543
    }
544
545
    public static function submitForPartialSettlement($transactionId, $amount, $attribs = [])
546
    {
547
        return Configuration::gateway()->transaction()->submitForPartialSettlement($transactionId, $amount, $attribs);
548
    }
549
550
    public static function holdInEscrow($transactionId)
551
    {
552
        return Configuration::gateway()->transaction()->holdInEscrow($transactionId);
553
    }
554
555
    public static function releaseFromEscrow($transactionId)
556
    {
557
        return Configuration::gateway()->transaction()->releaseFromEscrow($transactionId);
558
    }
559
560
    public static function cancelRelease($transactionId)
561
    {
562
        return Configuration::gateway()->transaction()->cancelRelease($transactionId);
563
    }
564
565
    public static function refund($transactionId, $amount = null)
566
    {
567
        return Configuration::gateway()->transaction()->refund($transactionId, $amount);
568
    }
569
}
570
class_alias('Braintree\Transaction', 'Braintree_Transaction');
571