Passed
Pull Request — master (#217)
by Patrik
03:30
created

WPInv_Payment_Gateway_Cardinal_OneConnect   F

Complexity

Total Complexity 66

Size/Duplication

Total Lines 648
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 648
rs 3.072
c 0
b 0
f 0
wmc 66
lcom 1
cbo 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 233 1
A register_scripts() 0 13 1
A base64_encode_urlsafe() 0 7 1
A base64_decode_urlsafe() 0 8 1
A sign_jwt() 0 6 1
A generate_jwt() 0 8 1
A generate_cruise_jwt() 0 17 2
A parse_cruise_jwt() 0 12 3
A hidden_input() 0 3 1
A purchase_form_before_submit() 0 11 1
A pm_message() 0 20 1
A mpi_xml() 0 10 2
A parse_mpi_xml() 0 21 4
A pm_send_message() 0 20 3
A format_mpi_error() 0 13 4
A reject_with_error() 0 4 1
A order_add() 0 3 1
A order_get() 0 4 2
A status_message() 0 12 3
F process_payment() 0 139 24
A currency_numeric() 0 4 2
A currency_exponent() 0 16 4
A raw_amount() 0 6 1
A create_request_order_object() 0 32 1

How to fix   Complexity   

Complex Class

Complex classes like WPInv_Payment_Gateway_Cardinal_OneConnect 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 WPInv_Payment_Gateway_Cardinal_OneConnect, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
    exit;
5
}
6
7
class WPInv_Payment_Gateway_Cardinal_OneConnect {
8
    public function __construct() {
9
        $this->id = 'cardinalpm';
0 ignored issues
show
Bug introduced by
The property id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
10
        $this->title = 'Credit Card';
0 ignored issues
show
Bug introduced by
The property title does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
11
        $this->method_title = '3-D Secure Payment Gateway by CardinalCommerce';
0 ignored issues
show
Bug introduced by
The property method_title does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
12
13
        $this->currencies = array(
0 ignored issues
show
Bug introduced by
The property currencies does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
14
	        'ADP' => '020',
15
	        'AED' => '784',
16
	        'AFA' => '004',
17
	        'AFN' => '971',
18
	        'ALL' => '008',
19
	        'AMD' => '051',
20
	        'ANG' => '532',
21
	        'AOA' => '973',
22
	        'AON' => '024',
23
	        'ARS' => '032',
24
	        'ATS' => '040',
25
	        'AUD' => '036',
26
	        'AWG' => '533',
27
	        'AZM' => '031',
28
	        'AZN' => '944',
29
	        'BAM' => '977',
30
	        'BBD' => '052',
31
	        'BDT' => '050',
32
	        'BEF' => '056',
33
	        'BGL' => '100',
34
	        'BGN' => '975',
35
	        'BHD' => '048',
36
	        'BIF' => '108',
37
	        'BMD' => '060',
38
	        'BND' => '096',
39
	        'BOB' => '068',
40
	        'BOV' => '984',
41
	        'BRL' => '986',
42
	        'BSD' => '044',
43
	        'BTN' => '064',
44
	        'BWP' => '072',
45
	        'BYR' => '974',
46
	        'BZD' => '084',
47
	        'CAD' => '124',
48
	        'CDF' => '976',
49
	        'CHE' => '947',
50
	        'CHF' => '756',
51
	        'CHW' => '948',
52
	        'CLF' => '990',
53
	        'CLP' => '152',
54
	        'CNY' => '156',
55
	        'COP' => '170',
56
	        'COU' => '970',
57
	        'CRC' => '188',
58
	        'CSD' => '891',
59
	        'CUC' => '931',
60
	        'CUP' => '192',
61
	        'CVE' => '132',
62
	        'CYP' => '196',
63
	        'CZK' => '203',
64
	        'DEM' => '276',
65
	        'DJF' => '262',
66
	        'DKK' => '208',
67
	        'DOP' => '214',
68
	        'DZD' => '012',
69
	        'EEK' => '233',
70
	        'EGP' => '818',
71
	        'ERN' => '232',
72
	        'ESP' => '724',
73
	        'ETB' => '230',
74
	        'EUR' => '978',
75
	        'FIM' => '246',
76
	        'FJD' => '242',
77
	        'FKP' => '238',
78
	        'FRF' => '250',
79
	        'GBP' => '826',
80
	        'GEL' => '981',
81
	        'GHC' => '288',
82
	        'GHS' => '936',
83
	        'GIP' => '292',
84
	        'GMD' => '270',
85
	        'GNF' => '324',
86
	        'GTQ' => '320',
87
	        'GWP' => '624',
88
	        'GYD' => '328',
89
	        'HKD' => '344',
90
	        'HNL' => '340',
91
	        'HRK' => '191',
92
	        'HTG' => '332',
93
	        'HUF' => '348',
94
	        'IDR' => '360',
95
	        'IEP' => '372',
96
	        'ILS' => '376',
97
	        'INR' => '356',
98
	        'IQD' => '368',
99
	        'IRR' => '364',
100
	        'ISK' => '352',
101
	        'ITL' => '380',
102
	        'JMD' => '388',
103
	        'JOD' => '400',
104
	        'JPY' => '392',
105
	        'KES' => '404',
106
	        'KGS' => '417',
107
	        'KHR' => '116',
108
	        'KMF' => '174',
109
	        'KPW' => '408',
110
	        'KRW' => '410',
111
	        'KWD' => '414',
112
	        'KYD' => '136',
113
	        'KZT' => '398',
114
	        'LAK' => '418',
115
	        'LBP' => '422',
116
	        'LKR' => '144',
117
	        'LRD' => '430',
118
	        'LSL' => '426',
119
	        'LTL' => '440',
120
	        'LUF' => '442',
121
	        'LVL' => '428',
122
	        'LYD' => '434',
123
	        'MAD' => '504',
124
	        'MDL' => '498',
125
	        'MGA' => '969',
126
	        'MGF' => '450',
127
	        'MKD' => '807',
128
	        'MMK' => '104',
129
	        'MNT' => '496',
130
	        'MOP' => '446',
131
	        'MRO' => '478',
132
	        'MTL' => '470',
133
	        'MUR' => '480',
134
	        'MVR' => '462',
135
	        'MWK' => '454',
136
	        'MXN' => '484',
137
	        'MXV' => '979',
138
	        'MYR' => '458',
139
	        'MZM' => '508',
140
	        'MZN' => '943',
141
	        'NAD' => '516',
142
	        'NGN' => '566',
143
	        'NIO' => '558',
144
	        'NLG' => '528',
145
	        'NOK' => '578',
146
	        'NPR' => '524',
147
	        'NZD' => '554',
148
	        'OMR' => '512',
149
	        'PAB' => '590',
150
	        'PEN' => '604',
151
	        'PGK' => '598',
152
	        'PHP' => '608',
153
	        'PKR' => '586',
154
	        'PLN' => '985',
155
	        'PTE' => '620',
156
	        'PYG' => '600',
157
	        'QAR' => '634',
158
	        'ROL' => '642',
159
	        'RON' => '946',
160
	        'RSD' => '941',
161
	        'RUB' => '643',
162
	        'RUR' => '810',
163
	        'RWF' => '646',
164
	        'SAR' => '682',
165
	        'SBD' => '090',
166
	        'SCR' => '690',
167
	        'SDD' => '736',
168
	        'SDG' => '938',
169
	        'SEK' => '752',
170
	        'SGD' => '702',
171
	        'SHP' => '654',
172
	        'SIT' => '705',
173
	        'SKK' => '703',
174
	        'SLL' => '694',
175
	        'SOS' => '706',
176
	        'SRD' => '968',
177
	        'SRG' => '740',
178
	        'SSP' => '728',
179
	        'STD' => '678',
180
	        'SVC' => '222',
181
	        'SYP' => '760',
182
	        'SZL' => '748',
183
	        'THB' => '764',
184
	        'TJS' => '972',
185
	        'TMM' => '795',
186
	        'TMT' => '934',
187
	        'TND' => '788',
188
	        'TOP' => '776',
189
	        'TPE' => '626',
190
	        'TRL' => '792',
191
	        'TRY' => '949',
192
	        'TTD' => '780',
193
	        'TWD' => '901',
194
	        'TZS' => '834',
195
	        'UAH' => '980',
196
	        'UGX' => '800',
197
	        'USD' => '840',
198
	        'USN' => '997',
199
	        'UYI' => '940',
200
	        'UYU' => '858',
201
	        'UZS' => '860',
202
	        'VEB' => '862',
203
	        'VEF' => '937',
204
	        'VND' => '704',
205
	        'VUV' => '548',
206
	        'WST' => '882',
207
	        'XAF' => '950',
208
	        'XCD' => '951',
209
	        'XOF' => '952',
210
	        'XPF' => '953',
211
	        'XXX' => '999',
212
	        'YER' => '886',
213
	        'YUM' => '891',
214
	        'ZAR' => '710',
215
	        'ZMK' => '894',
216
	        'ZMW' => '967',
217
	        'ZWD' => '716',
218
	        'ZWL' => '932',
219
        );
220
221
        $this->instances = array(
0 ignored issues
show
Bug introduced by
The property instances does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
222
	        'STAG' => 'centineltest.cardinalcommerce.com',
223
	        'CYBERSOURCE' => 'cybersource.cardinalcommerce.com',
224
	        'FIRSTDATA' => 'production.altpayfirstdata.com',
225
	        'FIRSTDATA_TEST' => 'test.altpayfirstdata.com',
226
	        'PAYMENTECH' => 'paymentech.cardinalcommerce.com',
227
	        'PAYPAL' => 'paypal.cardinalcommerce.com',
228
	        '200' => 'centinel.cardinalcommerce.com',
229
	        '300' => 'centinel300.cardinalcommerce.com',
230
	        '400' => 'centinel400.cardinalcommerce.com',
231
	        'PROD' => 'centinel600.cardinalcommerce.com',
232
	        '800' => 'centinel800.cardinalcommerce.com',
233
	        '1000' => 'centinel1000.cardinalcommerce.com',
234
	        '1200' => 'centinel1200.cardinalcommerce.com',
235
        );
236
237
	    add_filter( 'wp_enqueue_scripts', array($this, 'register_scripts') );
238
	    add_filter( 'wpinv_purchase_form_before_submit', array($this, 'purchase_form_before_submit') );
239
240
    }
241
242
    public function register_scripts() {
243
        $songbird_domain = 'songbird.cardinalcommerce.com';
244
        /*if ($this->get_option('environment') == 'STAG') {
245
            $songbird_domain = 'songbirdstag.cardinalcommerce.com';
246
        }*/
247
        wp_register_script(
248
            'cardinalcommerce-oneconnect-songbird',
249
            "https://{$songbird_domain}/edge/v1/songbird.js");
250
        wp_register_script(
251
            'cardinalcommerce-oneconnect', WPINV_PLUGIN_URL.'assets/js/cardinalcommerce-oneconnect.js',
252
            array('jquery', 'cardinalcommerce-oneconnect-songbird'),
253
	        WPINV_VERSION, true);
254
    }
255
256
    private static function base64_encode_urlsafe($source) {
257
        $rv = base64_encode($source);
258
        $rv = str_replace('=', '', $rv);
259
        $rv = str_replace('+', '-', $rv);
260
        $rv = str_replace('/', '_', $rv);
261
        return $rv;
262
    }
263
264
    private static function base64_decode_urlsafe($source) {
265
        $s = $source;
266
        $s = str_replace('-', '+', $s);
267
        $s = str_replace('_', '/', $s);
268
        $s = str_pad($s, strlen($s) + strlen($s) % 4, '=');
269
        $rv = base64_decode($s);
270
        return $rv;
271
    }
272
273
    public function sign_jwt($header, $body) {
274
        $secret = '863ef1c5-6a63-48ee-a711-20f1babb570f';
275
        $plaintext = $header . '.' . $body;
276
        return self::base64_encode_urlsafe(hash_hmac(
277
            'sha256', $plaintext, $secret, true));
278
    }
279
280
    private function generate_jwt($data) {
281
        $header = self::base64_encode_urlsafe(json_encode(array(
282
            'alg' => 'HS256', 'typ' => 'JWT'
283
        )));
284
        $body = self::base64_encode_urlsafe(json_encode($data));
285
        $signature = $this->sign_jwt($header, $body);
286
        return $header . '.' . $body . '.' . $signature;
287
    }
288
289
    private function generate_cruise_jwt($invoice = null) {
290
        $iat = time();
291
        $data = array(
292
            'jti' => uniqid(),
293
            'iat' => $iat,
294
            'exp' => $iat + 7200,
295
            'iss' => '5d79e83d031e732958e19532',
296
            'OrgUnitId' => '5d79e83de0919f19584569b6',
297
        );
298
        if ( $invoice ) {
299
            $payload = $this->create_request_order_object($invoice);
300
            $data['Payload'] = $payload;
301
            $data['ObjectifyPayload'] = true;
302
        }
303
        $rv = $this->generate_jwt($data);
304
        return $rv;
305
    }
306
307
    public function parse_cruise_jwt($jwt) {
308
        $split = explode('.', $jwt);
309
        if (count($split) != 3) {
310
            return;
311
        }
312
        list($header, $body, $signature) = $split;
313
        if ($signature != $this->sign_jwt($header, $body)) {
314
            return;
315
        }
316
        $payload = json_decode(self::base64_decode_urlsafe($body));
317
        return $payload;
318
    }
319
320
    public function hidden_input($id, $value = '') {
321
        echo "<input type='hidden' id='{$id}' value='{$value}' />";
322
    }
323
324
    public function purchase_form_before_submit() {
325
        wp_enqueue_script('cardinalcommerce-oneconnect');
326
	    $invoice = wpinv_get_invoice_cart();
327
	    $jwt = $this->generate_cruise_jwt($invoice);
328
	    $this->hidden_input('CardinalOneConnectJWT', $jwt);
329
	    $this->hidden_input('CardinalOneConnectLoggingLevel','verbose');
330
331
        $id = 'CardinalOneConnectResult';
332
        $merchant_content = 'Consumer Messaging';
333
        echo "<input type='hidden' autocomplete='off' id='{$id}' name='$id' /><div id='merchant-content-wrapper' style='display: none'><div id='actual-merchant-content'>{$merchant_content}</div></div>";
334
    }
335
336
    public function pm_message($type, $orderid, $amount, $currency, $fields=array()) {
337
        $timestamp = time() * 1000;
338
        $plaintext = $timestamp . '9b11d472-91c9-4c5d-aadf-c32e710db171';
339
        $signature = base64_encode(hash('sha256', $plaintext, true));
340
        $msg = array(
341
            'Version' => '1.7',
342
            'TransactionType' => 'CC',
343
            'MsgType' => "cmpi_{$type}",
344
            'OrgUnit' => '5d763f6fe0919f19583ea3e7',
345
            'OrderId' => $orderid,
346
            'Amount' => $amount,
347
            'CurrencyCode' => $this->currency_numeric($currency),
348
            'Identifier' => '5d763f6f031e732958da85c9',
349
            'Algorithm' => 'SHA-256',
350
            'Timestamp' => $timestamp,
351
            'Signature' => $signature,
352
        );
353
        $msg = array_merge($msg, $fields);
354
        return $msg;
355
    }
356
357
    public function mpi_xml($msg) {
358
        $rv = '<CardinalMPI>';
359
        foreach ($msg as $k => $v) {
360
            $v = str_replace('&', '&amp;', $v);
361
            $v = str_replace('<', '&lt;', $v);
362
            $rv .= "<{$k}>{$v}</{$k}>";
363
        }
364
        $rv .= '</CardinalMPI>';
365
        return $rv;
366
    }
367
368
    public function parse_mpi_xml($xml) {
369
        if (strpos($xml, '<CardinalMPI>') === false) {
370
            return "No mpi response received from centinel";
371
        }
372
        $msg = array();
373
        $fields = array(
374
            'AuthorizationCode', 'AVSResult', 'CardCodeResult', 'ErrorDesc',
375
            'ErrorNo', 'MerchantData', 'MerchantReferenceNumber', 'OrderId',
376
            'OrderNumber', 'ProcessorOrderNumber', 'ProcessorStatusCode',
377
            'ProcessorTransactionId', 'ReasonCode', 'ReasonDesc', 'StatusCode',
378
            'TransactionId',
379
        );
380
        foreach ($fields as $key) {
381
            $value = '';
382
            if (preg_match("{<{$key}>([^<]*)</{$key}>}", $xml, $m)) {
383
                $value = $m[1];
384
            }
385
            $msg[$key] = $value;
386
        }
387
        return $msg;
388
    }
389
390
    public function pm_send_message($msg) {
391
        $env = 'STAG';
392
        //$env = $this->get_option('environment');
393
        $mpi_domain = $this->instances[$env];
394
        $maps_url = "https://{$mpi_domain}/maps/txns.asp";
395
        $xml = $this->mpi_xml($msg);
396
        $response = wp_remote_post($maps_url, array(
397
            'method' => 'POST',
398
            'timeout' => 65,
399
            'body' => array('cmpi_msg' => $xml),
400
        ));
401
        if (is_wp_error($response)) {
402
            return $response->get_error_message();
403
        }
404
        $body = wp_remote_retrieve_body($response);
405
        if (!$body) {
406
            return "No response received from centinel";
407
        }
408
        return $this->parse_mpi_xml($body);
409
    }
410
411
    public function format_mpi_error($response) {
412
        $rv = $response['ErrorDesc'];
413
        if ($response['ErrorNo']) {
414
            $rv .= " ({$response['ErrorNo']})";
415
        }
416
        if ($response['ReasonDesc']) {
417
            $rv .= " {$response['ReasonDesc']}";
418
        }
419
        if ($response['ReasonCode']) {
420
            $rv .= " ({$response['ReasonCode']})";
421
        }
422
        return $rv;
423
    }
424
425
    public function reject_with_error($message, $permanent = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $permanent is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
426
        wpinv_set_error('wpinv_error', "{$this->method_title}: {$message}");
427
	    wpinv_send_back_to_checkout( '?payment-mode=paypalpro' );
0 ignored issues
show
Documentation introduced by
'?payment-mode=paypalpro' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
428
    }
429
430
    public function order_add($invoice, $key, $value) {
431
        update_post_meta($invoice->ID, "_{$this->id}_{$key}", $value);
432
    }
433
434
    public function order_get($invoice, $key) {
435
        $meta = get_post_meta($invoice->ID, "_{$this->id}_{$key}");
436
        return isset($meta[0]) ? $meta[0] : null;
437
    }
438
439
    public function status_message($invoice, $message, $amount = null,
440
                                   $error = null) {
441
        if (!$amount) {
442
            $amount = $invoice->get_total();
443
        }
444
        $price = wpinv_price($amount, array('currency' => $invoice->get_currency()));
0 ignored issues
show
Documentation introduced by
array('currency' => $invoice->get_currency()) is of type array<string,?,{"currency":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
445
        $rv = "{$this->method_title}: {$message} for $price";
446
        if (isset($error)) {
447
            $rv .= " - {$error}";
448
        }
449
        return $rv;
450
    }
451
452
    public function process_payment( $invoice_id ) {
453
	    $invoice = wpinv_get_invoice( $invoice_id );
454
455
        $cruise_result_json = $_POST['CardinalOneConnectResult'];
456
        if ( ! $cruise_result_json ) {
457
            $jwt = $this->generate_cruise_jwt($invoice);
458
            wp_send_json(array(
459
                'messages' =>
460
                    "<script>Cardinal.OneConnect.start('{$jwt}')</script>"
461
            ));
462
            exit;
463
        }
464
465
        $cruise_result = json_decode(stripslashes($cruise_result_json));
466
        $data = $cruise_result->data;
467
        $this->order_add($invoice, "ActionCode", $data->ActionCode);
468
469
        switch ($data->ActionCode) {
470
        case 'SUCCESS':
471
        case 'NOACTION':
472
            break;
473
        case 'FAILURE':
474
            $this->reject_with_error('Payment was unsuccessful. ' .
475
                'Please try again or provide another form of payment.');
476
            break;
477
        case 'ERROR':
478
            $message = $data->ErrorDescription;
479
            if ( isset($data->ErrorNumber) ) {
480
                $message .= " ({$data->ErrorNumber})";
481
            }
482
            $this->reject_with_error($message, isset($data->PermanentFatal));
483
            break;
484
        default:
485
            $this->reject_with_error('Unknown ActionCode');
486
            break;
487
        }
488
489
        if (!isset($cruise_result->jwt)) {
490
            $this->reject_with_error('Missing jwt');
491
        }
492
493
        $jwt = $this->parse_cruise_jwt($cruise_result->jwt);
494
        if (!$jwt) {
495
            $this->reject_with_error('Failed to parse jwt');
496
        }
497
498
        $payload = $jwt->Payload;
499
        if ($payload->ActionCode != $data->ActionCode) {
500
            $this->reject_with_error('data and Payload ActionCode do not match');
501
        }
502
503
	    $invoiceid = $payload->AuthorizationProcessor->ProcessorOrderId;
504
        $cca = $payload->Payment->ExtendedData;
505
        $eci = isset($cca->ECIFlag) ? $cca->ECIFlag : '';
506
        $cavv = isset($cca->CAVV) ? $cca->CAVV : '';
507
        $xid = isset($cca->XID) ? $cca->XID : '';
508
509
        $currency = $invoice->get_currency();
510
        $amount = self::raw_amount($invoice->get_total(), $currency);
511
        $msg = $this->pm_message(
512
            'authorize', $invoiceid, $amount, $currency, array(
513
                'Eci' => $eci,
514
                'Cavv' => $cavv,
515
                'Xid' => $xid,
516
                'OrderNumber' => $invoice->get_order_number(),
0 ignored issues
show
Bug introduced by
The method get_order_number() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
517
                'EMail' => $invoice->get_billing_email(),
0 ignored issues
show
Bug introduced by
The method get_billing_email() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
518
                "BillingFirstName" => $invoice->get_billing_first_name(),
0 ignored issues
show
Bug introduced by
The method get_billing_first_name() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
519
                "BillingLastName" => $invoice->get_billing_last_name(),
0 ignored issues
show
Bug introduced by
The method get_billing_last_name() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
520
                "BillingAddress1" => $invoice->get_billing_address_1(),
0 ignored issues
show
Bug introduced by
The method get_billing_address_1() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
521
                "BillingAddress2" => $invoice->get_billing_address_2(),
0 ignored issues
show
Bug introduced by
The method get_billing_address_2() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
522
                "BillingCity" => $invoice->get_billing_city(),
0 ignored issues
show
Bug introduced by
The method get_billing_city() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
523
                "BillingState" => $invoice->get_billing_state(),
0 ignored issues
show
Bug introduced by
The method get_billing_state() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
524
                "BillingPostalCode" => $invoice->get_billing_postcode(),
0 ignored issues
show
Bug introduced by
The method get_billing_postcode() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
525
                "BillingCountryCode" => $invoice->get_billing_country(),
0 ignored issues
show
Bug introduced by
The method get_billing_country() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
526
                "BillingPhone" => $invoice->get_billing_phone(),
0 ignored issues
show
Bug introduced by
The method get_billing_phone() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
527
                "ShippingFirstName" => $invoice->get_shipping_first_name(),
0 ignored issues
show
Bug introduced by
The method get_shipping_first_name() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
528
                "ShippingLastName" => $invoice->get_shipping_last_name(),
0 ignored issues
show
Bug introduced by
The method get_shipping_last_name() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
529
                "ShippingAddress1" => $invoice->get_shipping_address_1(),
0 ignored issues
show
Bug introduced by
The method get_shipping_address_1() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
530
                "ShippingAddress2" => $invoice->get_shipping_address_2(),
0 ignored issues
show
Bug introduced by
The method get_shipping_address_2() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
531
                "ShippingCity" => $invoice->get_shipping_city(),
0 ignored issues
show
Bug introduced by
The method get_shipping_city() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
532
                "ShippingState" => $invoice->get_shipping_state(),
0 ignored issues
show
Bug introduced by
The method get_shipping_state() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
533
                "ShippingPostalCode" => $invoice->get_shipping_postcode(),
0 ignored issues
show
Bug introduced by
The method get_shipping_postcode() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
534
                "ShippingCountryCode" => $invoice->get_shipping_country(),
0 ignored issues
show
Bug introduced by
The method get_shipping_country() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
535
            )
536
        );
537
        $auth_response = $response = $this->pm_send_message($msg);
538
        if (!is_array($response)) {
539
            $this->reject_with_error($response);
540
        }
541
        $auth_status = $response['StatusCode'];
542
        if ($auth_status == 'E' && $response['ReasonCode'] == '4' &&
543
                preg_match('/^25[23] /', $response['ReasonDesc'])) {
544
            $auth_status = 'P';
545
        }
546
        $this->order_add($invoice, 'AuthorizationStatus', $auth_status);
547
        if (!in_array($auth_status, array('Y', 'P'))) {
548
            $this->reject_with_error($this->format_mpi_error($response));
549
        }
550
551
        if ($auth_status == 'Y' &&
552
                $this->get_option('paymentAuthType') == 'AUTH_CAPTURE') {
0 ignored issues
show
Bug introduced by
The method get_option() does not seem to exist on object<WPInv_Payment_Gateway_Cardinal_OneConnect>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
553
            $msg = $this->pm_message('capture', $invoiceid, $amount, $currency);
554
            $response = $this->pm_send_message($msg);
555
            $void = $this->pm_message('void', $invoiceid, $amount, $currency);
556
            if (!is_array($response)) {
557
                $this->pm_send_message($void);
558
                $this->reject_with_error($response);
559
            }
560
            if ($response['StatusCode'] != 'Y') {
561
                $this->pm_send_message($void);
562
                $this->reject_with_error($this->format_mpi_error($response));
563
            }
564
565
            $this->order_add($invoice, 'CaptureStatus', $response['StatusCode']);
566
            $invoice->add_order_note($this->status_message(
0 ignored issues
show
Bug introduced by
The method add_order_note() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
567
                $invoice, 'Payment authorized and captured'));
568
            $invoice->payment_complete($invoiceid);
0 ignored issues
show
Bug introduced by
The method payment_complete() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
569
        } else {
570
            $invoice->set_transaction_id($invoiceid);
0 ignored issues
show
Bug introduced by
The method set_transaction_id() does not exist on WPInv_Invoice. Did you maybe mean setup_transaction_id()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
571
            if ($auth_status == 'Y') {
572
                $invoice->update_status('on-hold',
0 ignored issues
show
Documentation introduced by
'on-hold' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
573
                    $this->status_message($invoice, 'Payment authorized'));
574
            } else {
575
                $invoice->update_status('on-hold',
0 ignored issues
show
Documentation introduced by
'on-hold' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
576
                    $this->status_message($invoice, 'Payment held for review. Please, login to your processor account to manage this order.'));
577
            }
578
            $invoice->reduce_order_stock();
0 ignored issues
show
Bug introduced by
The method reduce_order_stock() does not seem to exist on object<WPInv_Invoice>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
579
            WC()->cart->empty_cart();
580
        }
581
582
        foreach ($auth_response as $key => $value) {
583
            $this->order_add($invoice, $key, $value);
584
        }
585
586
        return array(
587
            'result' => 'success',
588
            'redirect' => $this->get_return_url( $invoice )
0 ignored issues
show
Bug introduced by
The method get_return_url() does not seem to exist on object<WPInv_Payment_Gateway_Cardinal_OneConnect>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
589
        );
590
    }
591
592
    public function currency_numeric($alpha) {
593
        return isset($this->currencies[$alpha]) ?
594
            $this->currencies[$alpha] : null;
595
    }
596
597
    public static function currency_exponent($alpha) {
598
        if (in_array($alpha, array(
599
            'ADP', 'BEF', 'BIF', 'BYR', 'CLP', 'DJF', 'ESP', 'GNF', 'ISK',
600
            'ITL', 'JPY', 'KMF', 'KRW', 'LUF', 'MGF', 'PTE', 'PYG', 'RWF',
601
            'TPE', 'TRL', 'UYI', 'VND', 'VUV', 'XAF', 'XOF', 'XPF',
602
        ))) {
603
            return 0;
604
        } elseif (in_array($alpha, array(
605
            'BHD', 'CSD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND',
606
        ))) {
607
            return 3;
608
        } elseif ($alpha == 'CLF') {
609
            return 4;
610
        }
611
        return 2;
612
    }
613
614
    public static function raw_amount($amount, $currency_alpha) {
615
        $float_amount = (float) $amount;
616
        $exponent = self::currency_exponent($currency_alpha);
617
        $int_amount = (int) round($float_amount * pow(10, $exponent));
618
        return (string) $int_amount;
619
    }
620
621
    public function create_request_order_object($invoice) {
622
        $currency = $invoice->get_currency();
623
    	$currency_alpha = $this->currencies[$currency];
624
        $raw_amount = self::raw_amount($invoice->get_total(), $currency_alpha);
625
626
        $request_order_object = array(
627
            "Consumer" => array(
628
                "BillingAddress" => array(
629
                    "FirstName" => $invoice->get_first_name(),
630
                    "LastName" => $invoice->get_last_name(),
631
                    "Address1" => $invoice->get_address(),
632
                    "City" => $invoice->city,
633
                    "State" => $invoice->state,
634
                    "PostalCode" => $invoice->zip,
635
                    "CountryCode" => $invoice->country,
636
                    "Phone1" => $invoice->phone,
637
                ),
638
                "Email1" => $invoice->email,
639
            ),
640
            "OrderDetails" => array(
641
                "OrderNumber" => $invoice->ID,
642
                "Amount" => $raw_amount,
643
                "CurrencyCode" => $currency_alpha,
644
                "OrderChannel" => "S",
645
            ),
646
            "Options" => array(
647
                "EnableCCA" => 'yes',
648
            ),
649
        );
650
651
        return $request_order_object;
652
    }
653
654
}
655
656
new WPInv_Payment_Gateway_Cardinal_OneConnect();