Completed
Pull Request — 2.0 (#511)
by Roman
47:21 queued 17:21
created

OrderActionsForm::getCCFields()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 41
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 41
ccs 0
cts 0
cp 0
rs 6.7272
cc 7
eloc 24
nc 12
nop 1
crap 56
1
<?php
2
3
use SilverStripe\Omnipay\GatewayInfo;
4
use SilverStripe\Omnipay\GatewayFieldsFactory;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, GatewayFieldsFactory.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
6
/**
7
 * Perform actions on placed orders
8
 *
9
 * @package    shop
10
 * @subpackage forms
11
 */
12
class OrderActionsForm extends Form
13
{
14
    private static $allowed_actions    = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
15
        'docancel',
16
        'dopayment',
17
        'httpsubmission',
18
    );
19
20
    private static $email_notification = false;
21
22
    private static $allow_paying       = true;
23
24
    private static $allow_cancelling   = true;
25
26
    private static $include_jquery = true;
27 1
28
    protected      $order;
29 1
30 1
    public function __construct($controller, $name, Order $order)
31 1
    {
32 1
        $this->order = $order;
33 1
        $fields = FieldList::create(
34
            HiddenField::create('OrderID', '', $order->ID)
35 1
        );
36 1
        $actions = FieldList::create();
37
        //payment
38 1
        if (self::config()->allow_paying && $order->canPay()) {
39 1
            $gateways = GatewayInfo::getSupportedGateways();
40 1
            //remove manual gateways
41 1
            foreach ($gateways as $gateway => $gatewayname) {
42 1
                if (GatewayInfo::isManual($gateway)) {
43 1
                    unset($gateways[$gateway]);
44 1
                }
45 1
            }
46 1
            if (!empty($gateways)) {
47 1
                $fields->push(
48 1
                    HeaderField::create(
49 1
                        "MakePaymentHeader",
50 1
                        _t("OrderActionsForm.MakePayment", "Make Payment")
51 1
                    )
52 1
                );
53 1
                $outstandingfield = Currency::create();
54 1
                $outstandingfield->setValue($order->TotalOutstanding(true));
55 1
                $fields->push(
56 1
                    LiteralField::create(
57 1
                        "Outstanding",
58 1
                        _t(
59 1
                            'Order.OutstandingWithAmount',
60 1
                            'Outstanding: {Amount}',
61 1
                            '',
62 1
                            array('Amount' => $outstandingfield->Nice())
0 ignored issues
show
Documentation introduced by
array('Amount' => $outstandingfield->Nice()) is of type array<string,?,{"Amount":"?"}>, 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...
63 1
                        )
64 1
                    )
65 1
                );
66 1
                $fields->push(
67 1
                    OptionsetField::create(
68 1
                        'PaymentMethod',
69 1
                        _t("OrderActionsForm.PaymentMethod", "Payment Method"),
70 1
                        $gateways,
71
                        key($gateways)
72 1
                    )
73 1
                );
74 1
75 1
                if ($ccFields = $this->getCCFields($gateways)) {
76 1
                    if ($this->config()->include_jquery) {
77 1
                       Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.min.js');
78 1
                    }
79 1
                    Requirements::javascript(SHOP_DIR . '/javascript/OrderActionsForm.js');
80
                    $fields->push($ccFields);
81 1
                }
82 1
83 1
                $actions->push(
84 1
                    FormAction::create(
85 1
                        'dopayment',
86 1
                        _t('OrderActionsForm.PayOrder', 'Pay outstanding balance')
87 1
                    )
88 1
                );
89 1
            }
90 1
        }
91 1
        //cancelling
92
        if (self::config()->allow_cancelling && $order->canCancel()) {
93
            $actions->push(
94
                FormAction::create(
95
                    'docancel',
96
                    _t('OrderActionsForm.CancelOrder', 'Cancel this order')
97
                )
98
            );
99
        }
100
        parent::__construct($controller, $name, $fields, $actions, OrderActionsForm_Validator::create(array(
101 1
            'PaymentMethod'
102
        )));
103 1
        $this->extend("updateForm", $order);
104 1
    }
105 1
106 1
    /**
107
     * Make payment for a place order, where payment had previously failed.
108 1
     *
109 1
     * @param array $data
110
     * @param Form  $form
111 1
     *
112
     * @return boolean
113 1
     */
114 1
    public function dopayment($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $data 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...
115 1
    {
116
        if (self::config()->allow_paying
117
            && $this->order
118 1
            && $this->order->canPay()
119
        ) {
120 1
            // Save payment data from form and process payment
121
            $data = $form->getData();
122
            $gateway = (!empty($data['PaymentMethod'])) ? $data['PaymentMethod'] : null;
123
124 1
            if (!GatewayInfo::isManual($gateway)) {
125
                /** @var OrderProcessor $processor */
126
                $processor = OrderProcessor::create($this->order);
127
                $response = $processor->makePayment($gateway, $data, $processor->getReturnUrl());
128
                if($response && !$response->isError()){
129
                    return $response->redirectOrRespond();
0 ignored issues
show
Bug Compatibility introduced by
The expression $response->redirectOrRespond(); of type SS_HTTPResponse|null adds the type SS_HTTPResponse to the return on line 129 which is incompatible with the return type documented by OrderActionsForm::dopayment of type boolean.
Loading history...
130
                } else {
131
                    $form->sessionMessage($processor->getError(), 'bad');
132
                }
133
            } else {
134
                $form->sessionMessage(_t('OrderActionsForm.ManualNotAllowed', "Manual payment not allowed"), 'bad');
135
            }
136
137
            return $this->controller->redirectBack();
138
        }
139
        $form->sessionMessage(
140
            _t('OrderForm.CouldNotProcessPayment', 'Payment could not be processed.'),
141
            'bad'
142
        );
143
        $this->controller->redirectBack();
144
    }
145
146
    /**
147
     * Form action handler for CancelOrderForm.
148
     *
149
     * Take the order that this was to be change on,
150
     * and set the status that was requested from
151
     * the form request data.
152
     *
153
     * @param array $data The form request data submitted
154
     * @param Form  $form The {@link Form} this was submitted on
155
     */
156
    public function docancel($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $data 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...
Unused Code introduced by
The parameter $form 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...
157
    {
158
        if (self::config()->allow_cancelling
159
            && $this->order->canCancel()
160
        ) {
161
            $this->order->Status = 'MemberCancelled';
162
            $this->order->write();
163
164
            if (self::config()->email_notification) {
165
                OrderEmailNotifier::create($this->order)->sendCancelNotification();
166
            }
167 1
168
            $this->controller->sessionMessage(
169
                _t("OrderForm.OrderCancelled", "Order sucessfully cancelled"),
170
                'warning'
171
            );
172
            if (Member::currentUser() && $link = $this->order->Link()) {
173
                $this->controller->redirect($link);
174
            } else {
175
                $this->controller->redirectBack();
176
            }
177
        }
178
    }
179
180 1
    /**
181
     * Get credit card fields for the given gateways
182
     * @param array $gateways
183
     * @return CompositeField|null
184
     */
185
    protected function getCCFields(array $gateways)
186
    {
187
        $onsiteGateways = array();
188
        $allRequired = array();
189
        foreach ($gateways as $gateway => $title) {
190
            if (!GatewayInfo::isOffsite($gateway)) {
191
                $required = GatewayInfo::requiredFields($gateway);
192
                $onsiteGateways[$gateway] = $required;
193
                $allRequired += $required;
194
            }
195
        }
196
197
        $allRequired = array_unique($allRequired);
198
199
        if (empty($onsiteGateways)) {
200
            return null;
201
        }
202
203
        $factory = new GatewayFieldsFactory(null, array('Card'));
204
        $ccFields = $factory->getCardFields();
205
206
        // Remove all the credit card fields that aren't required by any gateway
207
        foreach ($ccFields as $name => $field) {
208
            $name = $field->getName();
209
            if ($name && !in_array($field->getName(), $allRequired)) {
210
                $ccFields->removeByName($field->getName(), true);
211
            }
212
        }
213
214
        $lookupField = LiteralField::create(
215
            '_CCLookupField',
216
            sprintf(
217
                '<span class="gateway-lookup" data-gateways=\'%s\'></span>',
218
                json_encode($onsiteGateways, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP)
219
            )
220
        );
221
222
        $ccFields->push($lookupField);
223
224
        return CompositeField::create($ccFields)->setTag('fieldset')->addExtraClass('credit-card');
225
    }
226
}
227
228
class OrderActionsForm_Validator extends RequiredFields
229
{
230
    public function php($data)
231
    {
232
        // Check if we should do a payment
233
        if (Form::current_action() == 'dopayment' && !empty($data['PaymentMethod'])) {
234
            $gateway = $data['PaymentMethod'];
235
            // If the gateway isn't manual and not offsite, Check for credit-card fields!
236
            if (!GatewayInfo::isManual($gateway) && !GatewayInfo::isOffsite($gateway)) {
237
                // Merge the required fields and the Credit-Card fields that are required for the gateway
238
                $this->required = array_merge($this->required, array_intersect(
239
                    array(
240
                        'type',
241
                        'name',
242
                        'number',
243
                        'startMonth',
244
                        'startYear',
245
                        'expiryMonth',
246
                        'expiryYear',
247
                        'cvv',
248
                        'issueNumber'
249
                    ),
250
                    GatewayInfo::requiredFields($gateway)
251
                ));
252
            }
253
        }
254
255
        return parent::php($data);
256
    }
257
}
258