Completed
Push — master ( 39b49d...880b28 )
by Nicolaas
06:42 queued 03:15
created

OrderConfirmationPage::canCreate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
eloc 2
nc 2
nop 1
1
<?php
2
3
/**
4
 * @description:
5
 * The Order Confirmation page shows order history.
6
 * It also serves as the end point for the current order...
7
 * once submitted, the Order Confirmation page shows the
8
 * finalised detail of the order.
9
 *
10
 *
11
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
12
 * @package: ecommerce
13
 * @sub-package: Pages
14
 * @inspiration: Silverstripe Ltd, Jeremy
15
 **/
16
class OrderConfirmationPage extends CartPage
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /**
19
     * Standard SS variable.
20
     *
21
     * @var string
22
     */
23
    private static $icon = 'ecommerce/images/icons/OrderConfirmationPage';
0 ignored issues
show
Unused Code introduced by
The property $icon is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
24
25
    /**
26
     * Standard SS variable.
27
     *
28
     * @var array
29
     */
30
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
31
        'StartNewOrderLinkLabel' => 'Varchar(100)',
32
        'CopyOrderLinkLabel' => 'Varchar(100)',
33
        'OrderCancelledHeader' => 'Varchar(255)',
34
        'PaymentSuccessfulHeader' => 'Varchar(255)',
35
        'PaymentNotSuccessfulHeader' => 'Varchar(255)',
36
        'PaymentPendingHeader' => 'Varchar(255)',
37
        'OrderCancelledMessage' => 'HTMLText',
38
        'PaymentSuccessfulMessage' => 'HTMLText',
39
        'PaymentNotSuccessfulMessage' => 'HTMLText',
40
        'PaymentPendingMessage' => 'HTMLText',
41
        'EnableGoogleAnalytics' => 'Boolean',
42
    );
43
44
    /**
45
     * Standard SS variable.
46
     *
47
     * @var array
48
     */
49
    private static $defaults = array(
0 ignored issues
show
Unused Code introduced by
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
50
        'ShowInMenus' => false,
51
        'ShowInSearch' => false,
52
        'StartNewOrderLinkLabel' => 'start new order',
53
        'CopyOrderLinkLabel' => 'copy order items into a new order',
54
        'OrderCancelledHeader' => 'Order has been cancelled',
55
        'PaymentSuccessfulHeader' => 'Payment Successful',
56
        'PaymentNotSuccessfulHeader' => 'Payment not Completed',
57
        'PaymentPendingHeader' => 'Payment Pending',
58
        'OrderCancelledMessage' => '<p>This order is no longer valid.</p>',
59
        'PaymentSuccessfulMessage' => '<p>Your order will be processed.</p>',
60
        'PaymentNotSuccessfulMessage' => '<p>Your order will not be processed until your payment has been completed.</p>',
61
        'PaymentPendingMessage' => '<p>Please complete your payment before the order can be processed.</p>',
62
    );
63
64
    private static $casting = array(
0 ignored issues
show
Unused Code introduced by
The property $casting is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
65
        "PaymentMessage" => "HTMLText"
66
    );
67
68
    /**
69
     * standard SS variable.
70
     *
71
     * @Var String
72
     */
73
    private static $singular_name = 'Order Confirmation Page';
0 ignored issues
show
Unused Code introduced by
The property $singular_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
74
    public function i18n_singular_name()
75
    {
76
        return _t('OrderConfirmationpage.SINGULARNAME', 'Order Confirmation Page');
77
    }
78
79
    /**
80
     * standard SS variable.
81
     *
82
     * @Var String
83
     */
84
    private static $plural_name = 'Order Confirmation Pages';
0 ignored issues
show
Unused Code introduced by
The property $plural_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
85
    public function i18n_plural_name()
86
    {
87
        return _t('OrderConfirmationpage.PLURALNAME', 'Order Confirmation Pages');
88
    }
89
90
    /**
91
     * Standard SS variable.
92
     *
93
     * @var string
94
     */
95
    private static $description = 'A page where the customer can view her or his submitted order. Every e-commerce site needs an Order Confirmation Page.';
0 ignored issues
show
Unused Code introduced by
The property $description is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
96
97
    /**
98
     * Standard SS function, we only allow for one OrderConfirmation Page to exist
99
     * but we do allow for extensions to exist at the same time.
100
     *
101
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
102
     *
103
     * @return bool
104
     */
105
    public function canCreate($member = null)
106
    {
107
        return OrderConfirmationPage::get()->filter(array('ClassName' => 'OrderConfirmationPage'))->Count() ? false : $this->canEdit($member);
108
    }
109
110
    /**
111
     * Shop Admins can edit.
112
     *
113
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
114
     *
115
     * @return bool
116
     */
117
    public function canEdit($member = null)
118
    {
119
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
120
            return true;
121
        }
122
123
        return parent::canEdit($member);
124
    }
125
126
    /**
127
     * Standard SS method.
128
     *
129
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
130
     *
131
     * @return bool
132
     */
133
    public function canDelete($member = null)
134
    {
135
        return false;
136
    }
137
138
    /**
139
     * Standard SS method.
140
     *
141
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
142
     *
143
     * @return bool
144
     */
145
    public function canPublish($member = null)
146
    {
147
        return $this->canEdit($member);
148
    }
149
150
    public function customFieldLabels()
151
    {
152
        $newLabels = array(
153
            'StartNewOrderLinkLabel' => _t('OrderConfirmationPage.STARTNEWORDERLINKLABEL', 'Label for starting new order - e.g. click here to start new order.'),
154
            'CopyOrderLinkLabel' => _t('OrderConfirmationPage.COPYORDERLINKLABEL', 'Label for copying order items into a new one  - e.g. click here start a new order with the current order items.'),
155
            'OrderCancelledHeader' => _t('OrderConfirmationPage.ORDERCANCELLEDHEADER', 'Header showing when order has been cancelled.'),
156
            'PaymentSuccessfulHeader' => _t('OrderConfirmationPage.PAYMENTSUCCESSFULHEADER', 'Header showing when order has been paid in full.'),
157
            'PaymentNotSuccessfulHeader' => _t('OrderConfirmationPage.PAYMENTNOTSUCCESSFULHEADER', 'Header showing when the order has not been paid in full.'),
158
            'PaymentPendingHeader' => _t('OrderConfirmationPage.PAYMENTPENDINGHEADER', 'Header showing when the order has not been paid in full - but the payment is pending.'),
159
            'OrderCancelledMessage' => _t('OrderConfirmationPage.ORDERCANCELLEDMESSAGE', 'Message showing when order has been paid cancelled.'),
160
            'PaymentSuccessfulMessage' => _t('OrderConfirmationPage.PAYMENTSUCCESSFULMESSAGE', 'Message showing when order has been paid in full.'),
161
            'PaymentNotSuccessfulMessage' => _t('OrderConfirmationPage.PAYMENTNOTSUCCESSFULMESSAGE', 'Message showing when the order has not been paid in full.'),
162
            'PaymentPendingMessage' => _t('OrderConfirmationPage.PAYMENTPENDINGMESSAGE', 'Message showing when the order has not been paid in full - but the payment is pending.'),
163
            'EnableGoogleAnalytics' => _t('OrderConfirmationPage.ENABLEGOOGLEANALYTICS', 'Enable E-commerce Google Analytics.  Make sure it is turned on in your Google Analytics account.'),
164
        );
165
166
        return $newLabels;
167
    }
168
169
    /**
170
     * standard SS method for decorators.
171
     *
172
     * @param bool - $includerelations: array of fields to start with
173
     *
174
     * @return array
175
     */
176
    public function fieldLabels($includerelations = true)
177
    {
178
        $defaultLabels = parent::fieldLabels();
179
        $newLabels = $this->customFieldLabels();
180
        $labels = array_merge($defaultLabels, $newLabels);
181
        $extendedArray = $this->extend('updateFieldLabels', $labels);
182
        if ($extendedArray !== null && is_array($extendedArray) && count($extendedArray)) {
183
            foreach ($extendedArray as $extendedResult) {
184
                $labels = array_merge($labels, $extendedResult);
185
            }
186
        }
187
188
        return $labels;
189
    }
190
191
    /**
192
     *@return FieldList
193
     **/
194
    public function getCMSFields()
195
    {
196
        $fields = parent::getCMSFields();
197
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'ProceedToCheckoutLabel');
198
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'ContinueShoppingLabel');
199
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'ContinuePageID');
200
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'SaveOrderLinkLabel');
201
        $fields->removeFieldFromTab('Root.Messages.Messages.Errors', 'NoItemsInOrderMessage');
202
        $fieldLabels = $this->fieldLabels();
203
        $fields->addFieldToTab('Root.Messages.Messages.Actions', new TextField('StartNewOrderLinkLabel', $fieldLabels['StartNewOrderLinkLabel']));
204
        $fields->addFieldToTab('Root.Messages.Messages.Actions', new TextField('CopyOrderLinkLabel', $fieldLabels['CopyOrderLinkLabel']));
205
        $fields->addFieldsToTab('Root.Messages.Messages.Payment', array(
206
            HeaderField::create('Successful'),
207
            TextField::create('PaymentSuccessfulHeader', $fieldLabels['PaymentSuccessfulHeader']),
208
            HTMLEditorField::create('PaymentSuccessfulMessage', $fieldLabels['PaymentSuccessfulMessage'])->setRows(3),
209
            HeaderField::create('Unsuccessful'),
210
            TextField::create('PaymentNotSuccessfulHeader', $fieldLabels['PaymentNotSuccessfulHeader']),
211
            HTMLEditorField::create('PaymentNotSuccessfulMessage', $fieldLabels['PaymentNotSuccessfulMessage'])->setRows(3),
212
            HeaderField::create('Pending'),
213
            TextField::create('PaymentPendingHeader', $fieldLabels['PaymentPendingHeader']),
214
            HTMLEditorField::create('PaymentPendingMessage', $fieldLabels['PaymentPendingMessage'])->setRows(3),
215
            HeaderField::create('Cancelled'),
216
            TextField::create('OrderCancelledHeader', $fieldLabels['OrderCancelledHeader']),
217
            HTMLEditorField::create('OrderCancelledMessage', $fieldLabels['OrderCancelledMessage'])->setRows(3),
218
        ));
219
        $fields->addFieldToTab('Root.Analytics', new CheckboxField('EnableGoogleAnalytics', $fieldLabels['EnableGoogleAnalytics']));
220
221
        return $fields;
222
    }
223
224
    /**
225
     * Returns the link or the Link to the OrderConfirmationPage page on this site.
226
     * @param string $action [optional]
0 ignored issues
show
Documentation introduced by
Should the type for parameter $action not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
227
     * @return string (URLSegment)
228
     */
229
    public static function find_link($action = null)
230
    {
231
        if ($page = OrderConfirmationPage::get()->filter(array('ClassName' => 'OrderConfirmationPage'))->First()) {
232
            return $page->Link($action);
233
        } elseif ($page = OrderConfirmationPage::get()->First()) {
234
            return $page->Link($action);
235
        }
236
237
        return CartPage::find_link();
238
    }
239
240
    /**
241
     * Return a link to view the order on this page.
242
     *
243
     * @param int|string $orderID ID of the order
244
     *
245
     * @return string (URLSegment)
246
     */
247
    public static function get_order_link($orderID)
248
    {
249
        return OrderConfirmationPage::find_link().'showorder/'.$orderID.'/';
250
    }
251
252
    /**
253
     * Return a link to view the order on this page.
254
     *
255
     * @param int|string $orderID                ID of the order
256
     * @param string     $type                   - the type of email you want to send.
0 ignored issues
show
Bug introduced by
There is no parameter named $type. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
257
     * @param bool       $actuallySendEmail      - do we actually send the email
258
     * @param int        $alternativeOrderStepID - OrderStep to use
259
     *
260
     * @return string (URLSegment)
261
     */
262
    public static function get_email_link($orderID, $emailClassName = 'Order_StatusEmail', $actuallySendEmail = false, $alternativeOrderStepID = 0)
263
    {
264
        $link = OrderConfirmationPage::find_link().'sendemail/'.$orderID.'/'.$emailClassName;
265
        $getParams = array();
266
        if ($actuallySendEmail) {
267
            $getParams['send'] = 1;
268
        }
269
        if ($alternativeOrderStepID) {
270
            $getParams['use'] = $alternativeOrderStepID;
271
        }
272
        $query = parse_url($url, PHP_URL_QUERY);
0 ignored issues
show
Bug introduced by
The variable $url does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
273
        $getParams = http_build_query($getParams);
274
        if ($query) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $query of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
275
            $link .= '&'.$getParams;
276
        } else {
277
            $link .= '?'.$getParams;
278
        }
279
        return $link;
280
    }
281
282
    /**
283
     * Return a link to view the order on this page.
284
     *
285
     * @param int|string $orderID ID of the order
286
     *
287
     * @return string (URLSegment)
288
     */
289
    public function getOrderLink($orderID)
290
    {
291
        return OrderConfirmationPage::get_order_link($orderID);
292
    }
293
294
    /**
295
     * returns the Checkout_StepDescription assocatiated with the final step: the order confirmation.
296
     *
297
     * @param bool $isCurrentStep
298
     *
299
     * @return Checkout_StepDescription
0 ignored issues
show
Documentation introduced by
Should the return type not be CheckoutPage_StepDescription?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
300
     */
301
    public function CurrentCheckoutStep($isCurrentStep = false)
302
    {
303
        $do = new CheckoutPage_StepDescription();
304
        $do->Link = $this->Link;
0 ignored issues
show
Documentation introduced by
The property Link does not exist on object<CheckoutPage_StepDescription>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
305
        $do->Heading = $this->MenuTitle;
0 ignored issues
show
Documentation introduced by
The property Heading does not exist on object<CheckoutPage_StepDescription>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
306
        $do->Code = $this->URLSegment;
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<CheckoutPage_StepDescription>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
307
        $do->LinkingMode = 'notCompleted';
0 ignored issues
show
Documentation introduced by
The property LinkingMode does not exist on object<CheckoutPage_StepDescription>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
308
        if ($isCurrentStep) {
309
            $do->LinkingMode .= ' current';
0 ignored issues
show
Documentation introduced by
The property LinkingMode does not exist on object<CheckoutPage_StepDescription>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
310
        }
311
        $do->Completed = 0;
0 ignored issues
show
Documentation introduced by
The property Completed does not exist on object<CheckoutPage_StepDescription>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
312
        $do->ID = 99;
313
314
        return $do;
315
    }
316
317
    /**
318
     * standard SS method for use in templates
319
     * we are overriding the code from the Cart Page here.
320
     *
321
     * @return string
322
     */
323
    public function LinkingMode()
324
    {
325
        return parent::LinkingMode();
326
    }
327
328
    /**
329
     * standard SS method for use in templates
330
     * we are overriding the code from the Cart Page here.
331
     *
332
     * @return string
333
     */
334
    public function LinkOrSection()
335
    {
336
        return parent::LinkOrSection();
337
    }
338
339
    /**
340
     * standard SS method for use in templates
341
     * we are overriding the code from the Cart Page here.
342
     *
343
     * @return string
344
     */
345
    public function LinkOrCurrent()
346
    {
347
        return parent::LinkOrCurrent();
348
    }
349
350
    public function requireDefaultRecords()
351
    {
352
        parent::requireDefaultRecords();
353
        $checkoutPage = CheckoutPage::get()->first();
354
        if ($checkoutPage) {
355
            $orderConfirmationPage = OrderConfirmationPage::get()->first();
356
            if (!$orderConfirmationPage) {
357
                $orderConfirmationPage = OrderConfirmationPage::create();
358
                $orderConfirmationPage->Title = 'Order Confirmation';
359
                $orderConfirmationPage->MenuTitle = 'Order Confirmation';
360
                $orderConfirmationPage->URLSegment = 'order-confirmation';
361
                $orderConfirmationPage->writeToStage('Stage');
362
                $orderConfirmationPage->publish('Stage', 'Live');
363
            }
364
        }
365
    }
366
}
367
368
class OrderConfirmationPage_Controller extends CartPage_Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
369
{
370
    /**
371
     * @static array
372
     * standard SS variable
373
     * it is important that we list all the options here
374
     */
375
    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...
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
376
        'saveorder',
377
        'sendreceipt',
378
        'CreateAccountForm',
379
        'retrieveorder',
380
        'loadorder',
381
        'startneworder',
382
        'showorder',
383
        'copyorder',
384
        'sendemail',
385
        'CancelForm',
386
        'PaymentForm',
387
    );
388
389
    /**
390
     * standard controller function.
391
     **/
392
    public function init()
393
    {
394
        //we retrieve the order in the parent page
395
        //the parent page also takes care of the security
396
        if ($sessionOrderID = Session::get('CheckoutPageCurrentOrderID')) {
397
            $this->currentOrder = Order::get()->byID($sessionOrderID);
398
            if ($this->currentOrder) {
399
                $this->overrideCanView = true;
400
                //more than an hour has passed...
401
                if (strtotime($this->currentOrder->LastEdited) < (strtotime('Now') - 60 * 60)) {
402
                    Session::clear('CheckoutPageCurrentOrderID');
403
                    Session::clear('CheckoutPageCurrentOrderID');
404
                    Session::set('CheckoutPageCurrentOrderID', 0);
405
                    Session::save();
406
                    $this->overrideCanView = false;
407
                    $this->currentOrder = null;
408
                }
409
            }
410
        }
411
        parent::init();
412
        Requirements::themedCSS('Order', 'ecommerce');
413
        Requirements::themedCSS('Order_Print', 'ecommerce', 'print');
414
        Requirements::themedCSS('CheckoutPage', 'ecommerce');
415
        Requirements::javascript('ecommerce/javascript/EcomPayment.js');
416
        Requirements::javascript('ecommerce/javascript/EcomPrintAndMail.js');
417
        $this->includeGoogleAnalyticsCode();
418
    }
419
420
    /**
421
     * This method exists just so that template
422
     * sets CurrentOrder variable.
423
     *
424
     * @param HTTPRequest
425
     *
426
     * @return array
427
     **/
428
    public function showorder(SS_HTTPRequest $request)
0 ignored issues
show
Coding Style introduced by
showorder uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
429
    {
430
        isset($project) ? $themeBaseFolder = $project : $themeBaseFolder = 'mysite';
0 ignored issues
show
Bug introduced by
The variable $project seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
431
        if (isset($_REQUEST['print'])) {
432
            Requirements::clear();
433
            Requirements::themedCSS('typography', $themeBaseFolder); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
434
            Requirements::themedCSS('OrderReport', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
435
            Requirements::themedCSS('Order_Invoice', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
436
            Requirements::themedCSS('Order_Invoice_Print_Only', 'ecommerce', 'print'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
437
            Config::nest();
438
            Config::inst()->update('SSViewer', 'theme_enabled', true);
439
            $html = $this->renderWith('Invoice');
440
            Config::unnest();
441
442
            return $html;
443
        } elseif (isset($_REQUEST['packingslip'])) {
444
            Requirements::clear();
445
            Requirements::themedCSS('typography', $themeBaseFolder); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
446
            Requirements::themedCSS('OrderReport', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
447
            Requirements::themedCSS('Order_PackingSlip', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
448
            Config::nest();
449
            Config::inst()->update('SSViewer', 'theme_enabled', true);
450
            $html = $this->renderWith('PackingSlip');
451
            Config::unnest();
452
453
            return $html;
454
        }
455
456
        return array();
457
    }
458
459
    /**
460
     * This is an additional way to look at an order.
461
     * The order is already retrieved from the init function.
462
     *
463
     * @return array
464
     **/
465
    public function retrieveorder(SS_HTTPRequest $request)
466
    {
467
        return array();
468
    }
469
470
    /**
471
     * copies either the current order into the shopping cart.
472
     *
473
     * TO DO: untested
474
     * TO DO: what to do with old order
475
     *
476
     * @param SS_HTTPRequest
477
     *
478
     * @return array
479
     */
480
    public function copyorder(SS_HTTPRequest $request)
481
    {
482
        self::set_message(_t('CartPage.ORDERLOADED', 'Order has been loaded.'));
483
        ShoppingCart::singleton()->copyOrder($this->currentOrder->ID);
484
485
        return $this->redirect(CheckoutPage::find_link());
486
    }
487
488
    /**
489
     * @param HTTPRequest
490
     *
491
     * @return array - just so the template is still displayed
492
     **/
493
    public function sendreceipt(SS_HTTPRequest $request)
494
    {
495
        if ($o = $this->currentOrder) {
496
            if ($m = $o->Member()) {
497
                if ($m->Email) {
498
                    $subject = _t('Account.COPYONLY', '--- COPY ONLY ---');
499
                    $message = _t('Account.COPYONLY', '--- COPY ONLY ---');
500
                    $o->sendReceipt($subject, $message, true);
501
                    $this->message = _t('OrderConfirmationPage.RECEIPTSENT', 'An order receipt has been sent to: ').$m->Email.'.';
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
502
                } else {
503
                    $this->message = _t('OrderConfirmationPage.RECEIPTNOTSENTNOTSENDING', 'Email could NOT be sent.');
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
504
                }
505
            } else {
506
                $this->message = _t('OrderConfirmationPage.RECEIPTNOTSENTNOEMAIL', 'No email could be found for sending this receipt.');
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
507
            }
508
        } else {
509
            $this->message = _t('OrderConfirmationPage.RECEIPTNOTSENTNOORDER', 'Order could not be found.');
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
510
        }
511
        $baseFolder = Director::baseFolder();
512
        if (!class_exists('\Pelago\Emogrifier')) {
513
            require_once Director::baseFolder().'/ecommerce/thirdparty/Emogrifier.php';
514
        }
515
        Requirements::clear();
516
        isset($project) ? $themeBaseFolder = $project : $themeBaseFolder = 'mysite';
0 ignored issues
show
Bug introduced by
The variable $project seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
517
        Requirements::themedCSS('typography', $themeBaseFolder); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
518
        Requirements::themedCSS('OrderReport', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
519
        Requirements::themedCSS('Order_Invoice', 'ecommerce', 'print'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
520
        Config::nest();
521
        Config::inst()->update('SSViewer', 'theme_enabled', true);
522
        $html = $this->renderWith('Order_ReceiptEmail');
523
        Config::unnest();
524
        // if it's an html email, filter it through emogrifier
525
        $cssFileLocation = $baseFolder.'/'.EcommerceConfig::get('Order_Email', 'css_file_location');
526
        $html .= "\r\n\r\n<!-- CSS can be found here: $cssFileLocation -->";
527
        $cssFileHandler = fopen($cssFileLocation, 'r');
528
        $css = fread($cssFileHandler,  filesize($cssFileLocation));
529
        fclose($cssFileHandler);
530
        $emog = new \Pelago\Emogrifier($html, $css);
531
        $html = $emog->emogrify();
532
533
        return $html;
534
    }
535
536
    /**
537
     * Returns a dataobject set of the checkout steps if
538
     * the OrderConfirmationPage is shown as part of the checkout process
539
     * We repeat these here so that you can show the user that (s)he has reached the last step.
540
     *
541
     * @param int $number - if set, it returns that one step.
542
     */
543
    public function CheckoutSteps($number = 0)
544
    {
545
        $where = '';
546
        if ($number) {
547
            $where = "\"CheckoutPage_StepDescription\".\"ID\" = $number";
548
        }
549
        if (EcommerceConfig::get('OrderConfirmationPage_Controller', 'include_as_checkout_step')) {
550
            if ($this->currentOrder->IsInSession()) {
551
                $dos = CheckoutPage_StepDescription::get()->where($where)->sort('ID', 'ASC');
552
                if ($number) {
553
                    if ($dos && $dos->count()) {
554
                        return $dos->First();
555
                    }
556
                }
557
                $arrayList = new ArrayList(array());
558
                foreach ($dos as $do) {
559
                    $do->LinkingMode = 'link completed';
560
                    $do->Completed = 1;
561
                    $do->Link = '';
562
                    $arrayList->push($do);
563
                }
564
                $do = $this->CurrentCheckoutStep(true);
565
                if ($do) {
566
                    $arrayList->push($do);
567
                }
568
569
                return $arrayList;
570
            }
571
        }
572
    }
573
574
    /**
575
     * returns the percentage of checkout steps done (0 - 100).
576
     *
577
     * @return int
578
     */
579
    public function PercentageDone()
580
    {
581
        return 100;
582
    }
583
584
    /**
585
     * @return string
586
     */
587
    public function PaymentHeader()
588
    {
589
        if ($order = $this->Order()) {
0 ignored issues
show
Unused Code introduced by
$order is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
590
            if ($this->OrderIsCancelled()) {
591
                return $this->OrderCancelledHeader;
592
            } elseif ($this->PaymentIsPending()) {
593
                return $this->PaymentPendingHeader;
594
            } elseif ($this->IsPaid()) {
595
                return $this->PaymentSuccessfulHeader;
596
            } else {
597
                return $this->PaymentNotSuccessfulHeader;
598
            }
599
        }
600
    }
601
602
    /**
603
     * @return string | null
604
     */
605
    public function PaymentMessage()
606
    {
607
        if ($order = $this->Order()) {
0 ignored issues
show
Unused Code introduced by
$order is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
608
            if ($this->OrderIsCancelled()) {
609
                return $this->OrderCancelledMessage;
610
            } elseif ($this->PaymentIsPending()) {
611
                return $this->PaymentPendingMessage;
612
            } elseif ($this->IsPaid()) {
613
                return $this->PaymentSuccessfulMessage;
614
            } else {
615
                return $this->PaymentNotSuccessfulMessage;
616
            }
617
        }
618
    }
619
620
    /**
621
     * @return string | null
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
622
     */
623
    public function PaymentMessageType()
624
    {
625
        if ($order = $this->Order()) {
0 ignored issues
show
Unused Code introduced by
$order is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
626
            if ($this->OrderIsCancelled()) {
627
                return "bad";
628
            } elseif ($this->PaymentIsPending()) {
629
                return "warning";
630
            } elseif ($this->IsPaid()) {
631
                return "good";
632
            } else {
633
                return "bad";
634
            }
635
        }
636
    }
637
638
    /**
639
     * @return bool
640
     */
641
    public function OrderIsCancelled()
642
    {
643
        if ($order = $this->Order()) {
644
            return $order->getIsCancelled();
645
        }
646
    }
647
648
    /**
649
     * Is the Order paid?
650
     * This can be useful for choosing what header to show.
651
     *
652
     * @return bool
653
     */
654
    public function IsPaid()
655
    {
656
        if ($order = $this->Order()) {
657
            return $order->IsPaid();
658
        }
659
    }
660
661
    /**
662
     * Are there any order Payments Pending
663
     * This can be useful for choosing what header to show.
664
     *
665
     * @return bool
666
     */
667
    public function PaymentIsPending()
668
    {
669
        if ($order = $this->Order()) {
670
            return $order->PaymentIsPending();
671
        }
672
    }
673
674
    /**
675
     * Returns the form to cancel the current order,
676
     * checking to see if they can cancel their order
677
     * first of all.
678
     *
679
     * @return OrderForm_Cancel
0 ignored issues
show
Documentation introduced by
Should the return type not be OrderConfirmationPage_Controller|array|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
680
     */
681
    public function CancelForm()
682
    {
683
        if ($this->Order()) {
684
            if ($this->currentOrder->canCancel()) {
685
                return OrderForm_Cancel::create($this, 'CancelForm', $this->currentOrder);
686
            }
687
        }
688
        //once cancelled, you will be redirected to main page - hence we need this...
689
        if ($this->orderID) {
690
            return array();
691
        }
692
    }
693
694
    /**
695
     * show the payment form.
696
     *
697
     * @return Form (OrderForm_Payment) or Null
0 ignored issues
show
Documentation introduced by
Should the return type not be OrderConfirmationPage_Controller|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
698
     **/
699
    public function PaymentForm()
700
    {
701
        if ($this->currentOrder) {
702
            if ($this->currentOrder->canPay()) {
703
                Requirements::javascript('ecommerce/javascript/EcomPayment.js');
704
705
                return OrderForm_Payment::create($this, 'PaymentForm', $this->currentOrder);
706
            }
707
        }
708
709
        return array();
710
    }
711
712
    /**
713
     * Can this page only show Submitted Orders (e.g. OrderConfirmationPage) ?
714
     *
715
     * @return bool
716
     */
717
    protected function onlyShowSubmittedOrders()
718
    {
719
        return true;
720
    }
721
722
    /**
723
     * Can this page only show Unsubmitted Orders (e.g. CartPage) ?
724
     *
725
     * @return bool
726
     */
727
    protected function onlyShowUnsubmittedOrders()
728
    {
729
        return false;
730
    }
731
732
    /**
733
     * sends an order email, which can be specified in the URL
734
     * and displays a sample email
735
     * typically this link is opened in a new window.
736
     *
737
     * @param SS_HTTPRequest $request
738
     *
739
     * @return HTML
740
     **/
741
    public function sendemail(SS_HTTPRequest $request)
742
    {
743
        if ($this->currentOrder) {
744
            $emailClassName = 'Order_ReceiptEmail';
745
            if (class_exists($request->param('OtherID'))) {
746
                if (is_a(singleton($request->param('OtherID')), Object::getCustomClass('Order_Email'))) {
747
                    $emailClassName = $request->param('OtherID');
748
                }
749
            }
750
            if ($statusID = intval($request->getVar('use'))) {
751
                $subject = _t('Account.TEST_ONLY', '--- TEST ONLY ---');
752
                $step = OrderStep::get()->byID($statusID);
753
                if ($step) {
754
                    $emailClassName = $step->getEmailClassName();
755
                }
756
                if ($request->getVar('send')) {
757
                    $email = filter_var($request->getVar('send'), FILTER_SANITIZE_EMAIL);
758
                    if(! $email) {
759
                        $email = true;
760
                    }
761
                    $this->currentOrder->sendEmail(
762
                        $subject,
763
                        $message,
0 ignored issues
show
Bug introduced by
The variable $message seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
764
                        $resend = true,
765
                        $adminOnlyOrToEmail = $email,
766
                        $emailClassName
767
                    );
768
                }
769
            }
770
            if ($request->getVar('send')) {
771
                if ($email = $this->currentOrder->getOrderEmail()) {
772
                    $subject = _t('Account.COPYONLY', '--- COPY ONLY ---');
773
                    $message = _t('Account.COPYONLY', '--- COPY ONLY ---');
774
                    if (
775
                        $this->currentOrder->sendEmail(
776
                            $subject,
777
                            $message,
778
                            $resend = true,
779
                            $adminOnlyOrToEmail = false,
780
                            $emailClassName
781
                        )
782
                    ) {
783
                        $this->message = _t('OrderConfirmationPage.RECEIPTSENT', 'An email has been sent to: ').$email.'.';
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
784
                    } else {
785
                        $this->message = _t('OrderConfirmationPage.RECEIPT_NOT_SENT', 'Email sent unsuccesfully to: ').$email.'. EMAIL NOT SENT.';
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
786
                    }
787
                } else {
788
                    $this->message = _t('OrderConfirmationPage.RECEIPTNOTSENTNOEMAIL', 'No customer details found.  EMAIL NOT SENT.');
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
789
                }
790
            }
791
            //display same data...
792
            Requirements::clear();
793
794
            return $this->currentOrder->renderOrderInEmailFormat($this->message, $emailClassName);
0 ignored issues
show
Bug introduced by
The property message cannot be accessed from this context as it is declared private in class CartPage_Controller.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
795
        } else {
796
            return _t('OrderConfirmationPage.RECEIPTNOTSENTNOORDER', 'Order could not be found.');
797
        }
798
    }
799
800
    protected function includeGoogleAnalyticsCode()
801
    {
802
        if ($this->EnableGoogleAnalytics && $this->currentOrder && Director::isLive()) {
803
            $currencyUsedObject = $this->currentOrder->CurrencyUsed();
804
            if ($currencyUsedObject) {
805
                $currencyUsedString = $currencyUsedObject->Code;
806
            }
807
            if (empty($currencyUsedString)) {
808
                $currencyUsedString = EcommerceCurrency::default_currency_code();
809
            }
810
            $js = '
811
            jQuery(document).ready(
812
                function(){
813
                    _gaq(\'require\', \'ecommerce\');
814
                    _gaq(
815
                        \'ecommerce:addTransaction\',
816
                        {
817
                            \'id\': \''.$this->currentOrder->ID.'\',
818
                            \'revenue\': \''.$this->currentOrder->getSubTotal().'\',
819
                            \'currency\': \''.$currencyUsedString.'\'
820
                        }
821
                    );
822
                    _gaq(\'ecommerce:send\');
823
                }
824
            );
825
';
826
            Requirements::customScript($js, 'GoogleAnalyticsEcommerce');
827
        }
828
    }
829
}
830