Completed
Pull Request — 2.0 (#511)
by Roman
49:11 queued 46:11
created

OrderActionsForm   B

Complexity

Total Complexity 31

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 80.15%

Importance

Changes 8
Bugs 2 Features 2
Metric Value
wmc 31
c 8
b 2
f 2
lcom 1
cbo 17
dl 0
loc 214
ccs 109
cts 136
cp 0.8015
rs 7.7

4 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 75 10
C dopayment() 0 31 8
B docancel() 0 23 6
C getCCFields() 0 40 7
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
28
    protected      $order;
29
30 3
    public function __construct($controller, $name, Order $order)
31
    {
32 3
        $this->order = $order;
33 3
        $fields = FieldList::create(
34 3
            HiddenField::create('OrderID', '', $order->ID)
35 3
        );
36 3
        $actions = FieldList::create();
37
        //payment
38 3
        if (self::config()->allow_paying && $order->canPay()) {
39 3
            $gateways = GatewayInfo::getSupportedGateways();
40
            //remove manual gateways
41 3
            foreach ($gateways as $gateway => $gatewayname) {
42 3
                if (GatewayInfo::isManual($gateway)) {
43 3
                    unset($gateways[$gateway]);
44 3
                }
45 3
            }
46 3
            if (!empty($gateways)) {
47 3
                $fields->push(
48 3
                    HeaderField::create(
49 3
                        "MakePaymentHeader",
50 3
                        _t("OrderActionsForm.MakePayment", "Make Payment")
51 3
                    )
52 3
                );
53 3
                $outstandingfield = Currency::create();
54 3
                $outstandingfield->setValue($order->TotalOutstanding(true));
55 3
                $fields->push(
56 3
                    LiteralField::create(
57 3
                        "Outstanding",
58 3
                        _t(
59 3
                            'Order.OutstandingWithAmount',
60 3
                            'Outstanding: {Amount}',
61 3
                            '',
62 3
                            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 3
                        )
64 3
                    )
65 3
                );
66 3
                $fields->push(
67 3
                    OptionsetField::create(
68 3
                        'PaymentMethod',
69 3
                        _t("OrderActionsForm.PaymentMethod", "Payment Method"),
70 3
                        $gateways,
71 3
                        key($gateways)
72 3
                    )
73 3
                );
74
75 3
                if ($ccFields = $this->getCCFields($gateways)) {
76 2
                    if ($this->config()->include_jquery) {
77 2
                       Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.min.js');
78 2
                    }
79 2
                    Requirements::javascript(SHOP_DIR . '/javascript/OrderActionsForm.js');
80 2
                    $fields->push($ccFields);
81 2
                }
82
83 3
                $actions->push(
84 3
                    FormAction::create(
85 3
                        'dopayment',
86 3
                        _t('OrderActionsForm.PayOrder', 'Pay outstanding balance')
87 3
                    )
88 3
                );
89 3
            }
90 3
        }
91
        //cancelling
92 3
        if (self::config()->allow_cancelling && $order->canCancel()) {
93 3
            $actions->push(
94 3
                FormAction::create(
95 3
                    'docancel',
96 3
                    _t('OrderActionsForm.CancelOrder', 'Cancel this order')
97 3
                )
98 3
            );
99 3
        }
100 3
        parent::__construct($controller, $name, $fields, $actions, OrderActionsForm_Validator::create(array(
101
            'PaymentMethod'
102 3
        )));
103 3
        $this->extend("updateForm", $order);
104 3
    }
105
106
    /**
107
     * Make payment for a place order, where payment had previously failed.
108
     *
109
     * @param array $data
110
     * @param Form  $form
111
     *
112
     * @return boolean
113
     */
114 2
    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
    {
116 2
        if (self::config()->allow_paying
117 2
            && $this->order
118 2
            && $this->order->canPay()
119 2
        ) {
120
            // Save payment data from form and process payment
121 2
            $data = $form->getData();
122 2
            $gateway = (!empty($data['PaymentMethod'])) ? $data['PaymentMethod'] : null;
123
124 2
            if (!GatewayInfo::isManual($gateway)) {
125
                /** @var OrderProcessor $processor */
126 2
                $processor = OrderProcessor::create($this->order);
127 2
                $response = $processor->makePayment($gateway, $data, $processor->getReturnUrl());
128 2
                if($response && !$response->isError()){
129 2
                    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
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
    /**
181
     * Get credit card fields for the given gateways
182
     * @param array $gateways
183
     * @return CompositeField|null
184
     */
185 3
    protected function getCCFields(array $gateways)
186
    {
187 3
        $onsiteGateways = array();
188 3
        $allRequired = array();
189 3
        foreach ($gateways as $gateway => $title) {
190 3
            if (!GatewayInfo::isOffsite($gateway)) {
191 2
                $required = GatewayInfo::requiredFields($gateway);
192 2
                $onsiteGateways[$gateway] = $required;
193 2
                $allRequired += $required;
194 2
            }
195 3
        }
196
197 3
        $allRequired = array_unique($allRequired);
198
199 3
        if (empty($onsiteGateways)) {
200 1
            return null;
201
        }
202
203 2
        $factory = new GatewayFieldsFactory(null, array('Card'));
204 2
        $ccFields = $factory->getCardFields();
205
206
        // Remove all the credit card fields that aren't required by any gateway
207 2
        foreach ($ccFields->dataFields() as $name => $field) {
208 2
            if ($name && !in_array($name, $allRequired)) {
209 2
                $ccFields->removeByName($name, true);
210 2
            }
211 2
        }
212
213 2
        $lookupField = LiteralField::create(
214 2
            '_CCLookupField',
215 2
            sprintf(
216 2
                '<span class="gateway-lookup" data-gateways=\'%s\'></span>',
217 2
                json_encode($onsiteGateways, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP)
218 2
            )
219 2
        );
220
221 2
        $ccFields->push($lookupField);
222
223 2
        return CompositeField::create($ccFields)->setTag('fieldset')->addExtraClass('credit-card');
224
    }
225
}
226
227
class OrderActionsForm_Validator extends RequiredFields
228
{
229 3
    public function php($data)
230
    {
231
        // Check if we should do a payment
232 3
        if (Form::current_action() == 'dopayment' && !empty($data['PaymentMethod'])) {
233 3
            $gateway = $data['PaymentMethod'];
234
            // If the gateway isn't manual and not offsite, Check for credit-card fields!
235 3
            if (!GatewayInfo::isManual($gateway) && !GatewayInfo::isOffsite($gateway)) {
236
                // Merge the required fields and the Credit-Card fields that are required for the gateway
237 2
                $this->required = array_merge($this->required, array_intersect(
238
                    array(
239 2
                        'type',
240 2
                        'name',
241 2
                        'number',
242 2
                        'startMonth',
243 2
                        'startYear',
244 2
                        'expiryMonth',
245 2
                        'expiryYear',
246 2
                        'cvv',
247
                        'issueNumber'
248 2
                    ),
249 2
                    GatewayInfo::requiredFields($gateway)
250 2
                ));
251 2
            }
252 3
        }
253
254 3
        return parent::php($data);
255
    }
256
}
257