Completed
Push — master ( 92d109...8f13c5 )
by
unknown
03:44
created

OrderConfirmationPage_Controller::FeedbackForm()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 3
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
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
        'IsFeedbackEnabled' => 'Boolean',
43
        'FeedbackFormLinkText' => 'Varchar(255)',
44
        'FeedbackHeader' => 'Varchar(255)',
45
        'FeedbackValuesFieldLabel' => 'Varchar(255)',
46
        'FeedbackValuesOptions' => 'Varchar(255)',
47
        'FeedbackNotesFieldLabel' => 'Varchar(255)',
48
        'FeedbackFormSubmitLabel' => 'Varchar(255)',
49
        'FeedbackFormThankYou' => 'Varchar(255)'
50
    );
51
52
    /**
53
     * Standard SS variable.
54
     *
55
     * @var array
56
     */
57
    private static $defaults = 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 $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...
58
        'ShowInMenus' => false,
59
        'ShowInSearch' => false,
60
        'StartNewOrderLinkLabel' => 'start new order',
61
        'CopyOrderLinkLabel' => 'copy order items into a new order',
62
        'OrderCancelledHeader' => 'Order has been cancelled',
63
        'PaymentSuccessfulHeader' => 'Payment Successful',
64
        'PaymentNotSuccessfulHeader' => 'Payment not Completed',
65
        'PaymentPendingHeader' => 'Payment Pending',
66
        'OrderCancelledMessage' => '<p>This order is no longer valid.</p>',
67
        'PaymentSuccessfulMessage' => '<p>Your order will be processed.</p>',
68
        'PaymentNotSuccessfulMessage' => '<p>Your order will not be processed until your payment has been completed.</p>',
69
        'PaymentPendingMessage' => '<p>Please complete your payment before the order can be processed.</p>',
70
        'FeedbackFormLinkText' => 'Do have any feedback about the order process? Let us know ... ',
71
        'FeedbackHeader' => 'Feedback',
72
        'FeedbackValuesFieldLabel' => 'How likely are you to recommend us to your friends?',
73
        'FeedbackValuesOptions' => 'Not At All, Not Likely, Not Sure, Likely, Very Likely',
74
        'FeedbackNotesFieldLabel' => 'What can we do to improve the ordering experience?',
75
        'FeedbackFormSubmitLabel' => 'Submit Your Feedback',
76
        'FeedbackFormThankYou' => 'Thank you for taking the time to submit your feedback, we appreciate it!'
77
    );
78
79
    private static $casting = 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 $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...
80
        "PaymentMessage" => "HTMLText"
81
    );
82
83
    /**
84
     * standard SS variable.
85
     *
86
     * @Var String
87
     */
88
    private static $singular_name = 'Order Confirmation Page';
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 $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...
89
    public function i18n_singular_name()
90
    {
91
        return _t('OrderConfirmationpage.SINGULARNAME', 'Order Confirmation Page');
92
    }
93
94
    /**
95
     * standard SS variable.
96
     *
97
     * @Var String
98
     */
99
    private static $plural_name = 'Order Confirmation Pages';
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 $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...
100
    public function i18n_plural_name()
101
    {
102
        return _t('OrderConfirmationpage.PLURALNAME', 'Order Confirmation Pages');
103
    }
104
105
    /**
106
     * Standard SS variable.
107
     *
108
     * @var string
109
     */
110
    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
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 $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...
111
112
    /**
113
     * Standard SS function, we only allow for one OrderConfirmation Page to exist
114
     * but we do allow for extensions to exist at the same time.
115
     *
116
     * @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...
117
     *
118
     * @return bool
119
     */
120
    public function canCreate($member = null)
121
    {
122
        return OrderConfirmationPage::get()->filter(array('ClassName' => 'OrderConfirmationPage'))->Count() ? false : $this->canEdit($member);
123
    }
124
125
    /**
126
     * Shop Admins can edit.
127
     *
128
     * @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...
129
     *
130
     * @return bool
131
     */
132
    public function canEdit($member = null)
133
    {
134
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
135
            return true;
136
        }
137
138
        return parent::canEdit($member);
139
    }
140
141
    /**
142
     * Standard SS method.
143
     *
144
     * @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...
145
     *
146
     * @return bool
147
     */
148
    public function canDelete($member = null)
149
    {
150
        return false;
151
    }
152
153
    /**
154
     * Standard SS method.
155
     *
156
     * @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...
157
     *
158
     * @return bool
159
     */
160
    public function canPublish($member = null)
161
    {
162
        return $this->canEdit($member);
163
    }
164
165
    public function customFieldLabels()
166
    {
167
        $newLabels = array(
168
            'StartNewOrderLinkLabel' => _t('OrderConfirmationPage.STARTNEWORDERLINKLABEL', 'Label for starting new order - e.g. click here to start new order.'),
169
            '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.'),
170
            'OrderCancelledHeader' => _t('OrderConfirmationPage.ORDERCANCELLEDHEADER', 'Header showing when order has been cancelled.'),
171
            'PaymentSuccessfulHeader' => _t('OrderConfirmationPage.PAYMENTSUCCESSFULHEADER', 'Header showing when order has been paid in full.'),
172
            'PaymentNotSuccessfulHeader' => _t('OrderConfirmationPage.PAYMENTNOTSUCCESSFULHEADER', 'Header showing when the order has not been paid in full.'),
173
            'PaymentPendingHeader' => _t('OrderConfirmationPage.PAYMENTPENDINGHEADER', 'Header showing when the order has not been paid in full - but the payment is pending.'),
174
            'OrderCancelledMessage' => _t('OrderConfirmationPage.ORDERCANCELLEDMESSAGE', 'Message showing when order has been paid cancelled.'),
175
            'PaymentSuccessfulMessage' => _t('OrderConfirmationPage.PAYMENTSUCCESSFULMESSAGE', 'Message showing when order has been paid in full.'),
176
            'PaymentNotSuccessfulMessage' => _t('OrderConfirmationPage.PAYMENTNOTSUCCESSFULMESSAGE', 'Message showing when the order has not been paid in full.'),
177
            'PaymentPendingMessage' => _t('OrderConfirmationPage.PAYMENTPENDINGMESSAGE', 'Message showing when the order has not been paid in full - but the payment is pending.'),
178
            'EnableGoogleAnalytics' => _t('OrderConfirmationPage.ENABLEGOOGLEANALYTICS', 'Enable E-commerce Google Analytics.  Make sure it is turned on in your Google Analytics account.'),
179
            'IsFeedbackEnabled' => _t('OrderConfirmationPage.ISFEEDBACKENABLED', 'Enable Feedback Form'),
180
            'FeedbackFormLinkText' => _t('OrderConfirmationPage.FEEDBACKFORMLINKTEXT', 'Email Link Text'),
181
            'FeedbackHeader' => _t('OrderConfirmationPage.FEEDBACKHEADER', 'Feedback Form Header'),
182
            'FeedbackValuesFieldLabel' => _t('OrderConfirmationPage.FEEDBACKVALUESFIELDLABEL', 'Feedback Form Options Label'),
183
            'FeedbackValuesOptions' => _t('OrderConfirmationPage.FEEDBACKVALUESOPTIONS', 'Feedback Form Options'),
184
            'FeedbackNotesFieldLabel' => _t('OrderConfirmationPage.FEEDBACKVALUESFIELDLABEL', 'Feedback Form Notes Label'),
185
            'FeedbackFormSubmitLabel' => _t('OrderConfirmationPage.FEEDBACKFORMSUBMITLABEL', 'Feedback Form Submit Button Text'),
186
            'FeedbackFormThankYou' => _t('OrderConfirmationPage.FEEDBACKFORMTHANKYOU', 'Feedback Form Thank you Message')
187
        );
188
189
        return $newLabels;
190
    }
191
192
    /**
193
     * standard SS method for decorators.
194
     *
195
     * @param bool - $includerelations: array of fields to start with
196
     *
197
     * @return array
198
     */
199
    public function fieldLabels($includerelations = true)
200
    {
201
        $defaultLabels = parent::fieldLabels();
202
        $newLabels = $this->customFieldLabels();
203
        $labels = array_merge($defaultLabels, $newLabels);
204
        $extendedArray = $this->extend('updateFieldLabels', $labels);
205
        if ($extendedArray !== null && is_array($extendedArray) && count($extendedArray)) {
206
            foreach ($extendedArray as $extendedResult) {
207
                $labels = array_merge($labels, $extendedResult);
208
            }
209
        }
210
211
        return $labels;
212
    }
213
214
    /**
215
     *@return FieldList
216
     **/
217
    public function getCMSFields()
218
    {
219
        $fields = parent::getCMSFields();
220
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'ProceedToCheckoutLabel');
221
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'ContinueShoppingLabel');
222
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'ContinuePageID');
223
        $fields->removeFieldFromTab('Root.Messages.Messages.Actions', 'SaveOrderLinkLabel');
224
        $fields->removeFieldFromTab('Root.Messages.Messages.Errors', 'NoItemsInOrderMessage');
225
        $fieldLabels = $this->fieldLabels();
226
        $fields->addFieldToTab('Root.Messages.Messages.Actions', new TextField('StartNewOrderLinkLabel', $fieldLabels['StartNewOrderLinkLabel']));
227
        $fields->addFieldToTab('Root.Messages.Messages.Actions', new TextField('CopyOrderLinkLabel', $fieldLabels['CopyOrderLinkLabel']));
228
        $fields->addFieldsToTab('Root.Messages.Messages.Payment', array(
229
            HeaderField::create('Successful'),
230
            TextField::create('PaymentSuccessfulHeader', $fieldLabels['PaymentSuccessfulHeader']),
231
            HTMLEditorField::create('PaymentSuccessfulMessage', $fieldLabels['PaymentSuccessfulMessage'])->setRows(3),
232
            HeaderField::create('Unsuccessful'),
233
            TextField::create('PaymentNotSuccessfulHeader', $fieldLabels['PaymentNotSuccessfulHeader']),
234
            HTMLEditorField::create('PaymentNotSuccessfulMessage', $fieldLabels['PaymentNotSuccessfulMessage'])->setRows(3),
235
            HeaderField::create('Pending'),
236
            TextField::create('PaymentPendingHeader', $fieldLabels['PaymentPendingHeader']),
237
            HTMLEditorField::create('PaymentPendingMessage', $fieldLabels['PaymentPendingMessage'])->setRows(3),
238
            HeaderField::create('Cancelled'),
239
            TextField::create('OrderCancelledHeader', $fieldLabels['OrderCancelledHeader']),
240
            HTMLEditorField::create('OrderCancelledMessage', $fieldLabels['OrderCancelledMessage'])->setRows(3),
241
        ));
242
        $fields->addFieldToTab('Root.Analytics', new CheckboxField('EnableGoogleAnalytics', $fieldLabels['EnableGoogleAnalytics']));
243
        $fields->addFieldsToTab(
244
            'Root.FeedbackForm',
245
            array(
246
                CheckboxField::create('IsFeedbackEnabled', $fieldLabels['IsFeedbackEnabled'])
247
                    ->setDescription('Enabling this option will display a feedback form on the order confirmation page and include links to the form in all order emails'),
248
                TextField::create('FeedbackHeader', $fieldLabels['FeedbackHeader'])
249
                    ->setRightTitle('Heading text shown above the form on the order confirmation page'),
250
                TextField::create('FeedbackValuesFieldLabel', $fieldLabels['FeedbackValuesFieldLabel'])
251
                    ->setRightTitle('Text for feedback options field label'),
252
                TextField::create('FeedbackValuesOptions', $fieldLabels['FeedbackValuesOptions'])
253
                    ->setRightTitle('Comma separated list of feedback rating options (eg Good, Neutral, Bad)'),
254
                TextField::create('FeedbackNotesFieldLabel', $fieldLabels['FeedbackNotesFieldLabel'])
255
                    ->setRightTitle('Text for feedback notes field label'),
256
                TextField::create('FeedbackFormSubmitLabel', $fieldLabels['FeedbackFormSubmitLabel'])
257
                    ->setRightTitle('Text shown on the feedback form submit button'),
258
                TextField::create('FeedbackFormThankYou', $fieldLabels['FeedbackFormThankYou'])
259
                    ->setRightTitle('Thank you message displayed to user after submitting the feedback form'),
260
                TextField::create('FeedbackFormLinkText', $fieldLabels['FeedbackFormLinkText'])
261
                    ->setRightTitle('This is the text shown for the <strong>request feedback link</strong> included in order emails')
262
            )
263
        );
264
        return $fields;
265
    }
266
267
    /**
268
     * Returns the link or the Link to the OrderConfirmationPage page on this site.
269
     * @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...
270
     * @return string (URLSegment)
271
     */
272
    public static function find_link($action = null)
273
    {
274
        if ($page = OrderConfirmationPage::get()->filter(array('ClassName' => 'OrderConfirmationPage'))->First()) {
275
            return $page->Link($action);
276
        } elseif ($page = OrderConfirmationPage::get()->First()) {
277
            return $page->Link($action);
278
        }
279
280
        return CartPage::find_link();
281
    }
282
283
    /**
284
     * Return a link to view the order on this page.
285
     *
286
     * @param int|string $orderID ID of the order
287
     *
288
     * @return string (URLSegment)
289
     */
290
    public static function get_order_link($orderID)
291
    {
292
        return OrderConfirmationPage::find_link().'showorder/'.$orderID.'/';
293
    }
294
295
    /**
296
     * Return a link to view the order on this page.
297
     *
298
     * @param int|string $orderID                ID of the order
299
     * @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...
300
     * @param bool       $actuallySendEmail      - do we actually send the email
301
     * @param int        $alternativeOrderStepID - OrderStep to use
302
     *
303
     * @return string (URLSegment)
304
     */
305
    public static function get_email_link($orderID, $emailClassName = 'Order_StatusEmail', $actuallySendEmail = false, $alternativeOrderStepID = 0)
306
    {
307
        $link = OrderConfirmationPage::find_link().'sendemail/'.$orderID.'/'.$emailClassName;
308
        $getParams = array();
309
        if ($actuallySendEmail) {
310
            $getParams['send'] = 1;
311
        }
312
        if ($alternativeOrderStepID) {
313
            $getParams['test'] = $alternativeOrderStepID;
314
        }
315
        $getParams = http_build_query($getParams);
316
        $link .= '?'.$getParams;
317
318
        return $link;
319
    }
320
321
    /**
322
     * Return a link to view the order on this page.
323
     *
324
     * @param int|string $orderID ID of the order
325
     *
326
     * @return string (URLSegment)
327
     */
328
    public function getOrderLink($orderID)
329
    {
330
        return OrderConfirmationPage::get_order_link($orderID);
331
    }
332
333
    /**
334
     * returns the Checkout_StepDescription assocatiated with the final step: the order confirmation.
335
     *
336
     * @param bool $isCurrentStep
337
     *
338
     * @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...
339
     */
340
    public function CurrentCheckoutStep($isCurrentStep = false)
341
    {
342
        $do = new CheckoutPage_StepDescription();
343
        $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...
344
        $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...
345
        $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...
346
        $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...
347
        if ($isCurrentStep) {
348
            $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...
349
        }
350
        $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...
351
        $do->ID = 99;
352
353
        return $do;
354
    }
355
356
    /**
357
     * standard SS method for use in templates
358
     * we are overriding the code from the Cart Page here.
359
     *
360
     * @return string
361
     */
362
    public function LinkingMode()
363
    {
364
        return parent::LinkingMode();
365
    }
366
367
    /**
368
     * standard SS method for use in templates
369
     * we are overriding the code from the Cart Page here.
370
     *
371
     * @return string
372
     */
373
    public function LinkOrSection()
374
    {
375
        return parent::LinkOrSection();
376
    }
377
378
    /**
379
     * standard SS method for use in templates
380
     * we are overriding the code from the Cart Page here.
381
     *
382
     * @return string
383
     */
384
    public function LinkOrCurrent()
385
    {
386
        return parent::LinkOrCurrent();
387
    }
388
389
    public function requireDefaultRecords()
390
    {
391
        parent::requireDefaultRecords();
392
        $checkoutPage = CheckoutPage::get()->first();
393
        if ($checkoutPage) {
394
            $orderConfirmationPage = OrderConfirmationPage::get()->first();
395
            if (!$orderConfirmationPage) {
396
                $orderConfirmationPage = OrderConfirmationPage::create();
397
                $orderConfirmationPage->Title = 'Order Confirmation';
398
                $orderConfirmationPage->MenuTitle = 'Order Confirmation';
399
                $orderConfirmationPage->URLSegment = 'order-confirmation';
400
                $orderConfirmationPage->writeToStage('Stage');
401
                $orderConfirmationPage->publish('Stage', 'Live');
402
            }
403
        }
404
    }
405
}
406
407
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...
408
{
409
    /**
410
     * @static array
411
     * standard SS variable
412
     * it is important that we list all the options here
413
     */
414
    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...
415
        'saveorder',
416
        'CreateAccountForm',
417
        'retrieveorder',
418
        'loadorder',
419
        'startneworder',
420
        'showorder',
421
        'copyorder',
422
        'sendemail',
423
        'CancelForm',
424
        'FeedbackForm',
425
        'PaymentForm',
426
    );
427
428
    /**
429
     * standard controller function.
430
     **/
431
    public function init()
432
    {
433
        //we retrieve the order in the parent page
434
        //the parent page also takes care of the security
435
        if ($sessionOrderID = Session::get('CheckoutPageCurrentOrderID')) {
436
            $this->currentOrder = Order::get()->byID($sessionOrderID);
437
            if ($this->currentOrder) {
438
                $this->overrideCanView = true;
439
                //more than an hour has passed...
440
                if (strtotime($this->currentOrder->LastEdited) < (strtotime('Now') - 60 * 60)) {
441
                    Session::clear('CheckoutPageCurrentOrderID');
442
                    Session::clear('CheckoutPageCurrentOrderID');
443
                    Session::set('CheckoutPageCurrentOrderID', 0);
444
                    Session::save();
445
                    $this->overrideCanView = false;
446
                    $this->currentOrder = null;
447
                }
448
            }
449
        }
450
        parent::init();
451
        Requirements::themedCSS('Order', 'ecommerce');
452
        Requirements::themedCSS('Order_Print', 'ecommerce', 'print');
453
        Requirements::themedCSS('CheckoutPage', 'ecommerce');
454
        Requirements::javascript('ecommerce/javascript/EcomPayment.js');
455
        Requirements::javascript('ecommerce/javascript/EcomPrintAndMail.js');
456
        $this->includeGoogleAnalyticsCode();
457
    }
458
459
    /**
460
     * This method exists just so that template
461
     * sets CurrentOrder variable.
462
     *
463
     * @param HTTPRequest
464
     *
465
     * @return array
466
     **/
467
    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...
468
    {
469
        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...
470
        if (isset($_REQUEST['print'])) {
471
            Requirements::clear();
472
            Requirements::themedCSS('typography', $themeBaseFolder); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
473
            Requirements::themedCSS('OrderReport', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
474
            Requirements::themedCSS('Order_Invoice', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
475
            Requirements::themedCSS('Order_Invoice_Print_Only', 'ecommerce', 'print'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
476
            Config::nest();
477
            Config::inst()->update('SSViewer', 'theme_enabled', true);
478
            $html = $this->renderWith('Invoice');
479
            Config::unnest();
480
481
            return $html;
482
        } elseif (isset($_REQUEST['packingslip'])) {
483
            Requirements::clear();
484
            Requirements::themedCSS('typography', $themeBaseFolder); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
485
            Requirements::themedCSS('OrderReport', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
486
            Requirements::themedCSS('Order_PackingSlip', 'ecommerce'); // LEAVE HERE - NOT EASY TO INCLUDE VIA TEMPLATE
487
            Config::nest();
488
            Config::inst()->update('SSViewer', 'theme_enabled', true);
489
            $html = $this->renderWith('PackingSlip');
490
            Config::unnest();
491
492
            return $html;
493
        }
494
495
        return array();
496
    }
497
498
    /**
499
     * This is an additional way to look at an order.
500
     * The order is already retrieved from the init function.
501
     *
502
     * @return array
503
     **/
504
    public function retrieveorder(SS_HTTPRequest $request)
505
    {
506
        return array();
507
    }
508
509
    /**
510
     * copies either the current order into the shopping cart.
511
     *
512
     * TO DO: untested
513
     * TO DO: what to do with old order
514
     *
515
     * @param SS_HTTPRequest
516
     *
517
     * @return array
518
     */
519
    public function copyorder(SS_HTTPRequest $request)
520
    {
521
        self::set_message(_t('CartPage.ORDERLOADED', 'Order has been loaded.'));
522
        ShoppingCart::singleton()->copyOrder($this->currentOrder->ID);
523
524
        return $this->redirect(CheckoutPage::find_link());
525
    }
526
527
    /**
528
     * Returns a dataobject set of the checkout steps if
529
     * the OrderConfirmationPage is shown as part of the checkout process
530
     * We repeat these here so that you can show the user that (s)he has reached the last step.
531
     *
532
     * @param int $number - if set, it returns that one step.
533
     */
534
    public function CheckoutSteps($number = 0)
535
    {
536
        $where = '';
537
        if ($number) {
538
            $where = "\"CheckoutPage_StepDescription\".\"ID\" = $number";
539
        }
540
        if (EcommerceConfig::get('OrderConfirmationPage_Controller', 'include_as_checkout_step')) {
541
            if ($this->currentOrder->IsInSession()) {
542
                $dos = CheckoutPage_StepDescription::get()->where($where)->sort('ID', 'ASC');
543
                if ($number) {
544
                    if ($dos && $dos->count()) {
545
                        return $dos->First();
546
                    }
547
                }
548
                $arrayList = new ArrayList(array());
549
                foreach ($dos as $do) {
550
                    $do->LinkingMode = 'link completed';
551
                    $do->Completed = 1;
552
                    $do->Link = '';
553
                    $arrayList->push($do);
554
                }
555
                $do = $this->CurrentCheckoutStep(true);
556
                if ($do) {
557
                    $arrayList->push($do);
558
                }
559
560
                return $arrayList;
561
            }
562
        }
563
    }
564
565
    /**
566
     * returns the percentage of checkout steps done (0 - 100).
567
     *
568
     * @return int
569
     */
570
    public function PercentageDone()
571
    {
572
        return 100;
573
    }
574
575
    /**
576
     * @return string
577
     */
578
    public function PaymentHeader()
579
    {
580
        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...
581
            if ($this->OrderIsCancelled()) {
582
                return $this->OrderCancelledHeader;
583
            } elseif ($this->PaymentIsPending()) {
584
                return $this->PaymentPendingHeader;
585
            } elseif ($this->IsPaid()) {
586
                return $this->PaymentSuccessfulHeader;
587
            } else {
588
                return $this->PaymentNotSuccessfulHeader;
589
            }
590
        }
591
    }
592
593
    /**
594
     * @return string | null
595
     */
596
    public function PaymentMessage()
597
    {
598
        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...
599
            if ($this->OrderIsCancelled()) {
600
                return $this->OrderCancelledMessage;
601
            } elseif ($this->PaymentIsPending()) {
602
                return $this->PaymentPendingMessage;
603
            } elseif ($this->IsPaid()) {
604
                return $this->PaymentSuccessfulMessage;
605
            } else {
606
                return $this->PaymentNotSuccessfulMessage;
607
            }
608
        }
609
    }
610
611
    /**
612
     * @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...
613
     */
614
    public function PaymentMessageType()
615
    {
616
        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...
617
            if ($this->OrderIsCancelled()) {
618
                return "bad";
619
            } elseif ($this->PaymentIsPending()) {
620
                return "warning";
621
            } elseif ($this->IsPaid()) {
622
                return "good";
623
            } else {
624
                return "bad";
625
            }
626
        }
627
    }
628
629
    /**
630
     * @return bool
631
     */
632
    public function OrderIsCancelled()
633
    {
634
        if ($order = $this->Order()) {
635
            return $order->getIsCancelled();
636
        }
637
    }
638
639
    /**
640
     * Is the Order paid?
641
     * This can be useful for choosing what header to show.
642
     *
643
     * @return bool
644
     */
645
    public function IsPaid()
646
    {
647
        if ($order = $this->Order()) {
648
            return $order->IsPaid();
649
        }
650
    }
651
652
    /**
653
     * Are there any order Payments Pending
654
     * This can be useful for choosing what header to show.
655
     *
656
     * @return bool
657
     */
658
    public function PaymentIsPending()
659
    {
660
        if ($order = $this->Order()) {
661
            return $order->PaymentIsPending();
662
        }
663
    }
664
665
    /**
666
     * Returns the form to cancel the current order,
667
     * checking to see if they can cancel their order
668
     * first of all.
669
     *
670
     * @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...
671
     */
672
    public function CancelForm()
673
    {
674
        if ($this->Order()) {
675
            if ($this->currentOrder->canCancel()) {
676
                return OrderForm_Cancel::create($this, 'CancelForm', $this->currentOrder);
677
            }
678
        }
679
        //once cancelled, you will be redirected to main page - hence we need this...
680
        if ($this->orderID) {
681
            return array();
682
        }
683
    }
684
685
    /**
686
     * Returns the form for providing feedback about current order,
687
     * checking to see if IsFeedbackEnabled is true
688
     * first of all.
689
     *
690
     * @return OrderForm_Feedback
0 ignored issues
show
Documentation introduced by
Should the return type not be OrderConfirmationPage_Controller|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...
691
     */
692
    public function FeedbackForm()
693
    {
694
        if ($this->Order()) {
695
            if ($this->IsFeedbackEnabled) {
696
                return OrderForm_Feedback::create($this, 'FeedbackForm', $this->currentOrder);
697
            }
698
        }
699
    }
700
701
    /**
702
     * show the payment form.
703
     *
704
     * @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...
705
     **/
706
    public function PaymentForm()
707
    {
708
        if ($this->currentOrder) {
709
            if ($this->currentOrder->canPay()) {
710
                Requirements::javascript('ecommerce/javascript/EcomPayment.js');
711
712
                return OrderForm_Payment::create($this, 'PaymentForm', $this->currentOrder);
713
            }
714
        }
715
716
        return array();
717
    }
718
719
    /**
720
     * Can this page only show Submitted Orders (e.g. OrderConfirmationPage) ?
721
     *
722
     * @return bool
723
     */
724
    protected function onlyShowSubmittedOrders()
725
    {
726
        return true;
727
    }
728
729
    /**
730
     * Can this page only show Unsubmitted Orders (e.g. CartPage) ?
731
     *
732
     * @return bool
733
     */
734
    protected function onlyShowUnsubmittedOrders()
735
    {
736
        return false;
737
    }
738
739
    /**
740
     * sends an order email, which can be specified in the URL
741
     * and displays a sample email
742
     * typically this link is opened in a new window.
743
     *
744
     * @param SS_HTTPRequest $request
745
     *
746
     * @return HTML
747
     **/
748
    public function sendemail(SS_HTTPRequest $request)
749
    {
750
        if ($this->currentOrder) {
751
            $subject = '';
752
            $message = '';
753
            $emailClassName = 'Order_ReceiptEmail';
754
            if (class_exists($request->param('OtherID'))) {
755
                if (is_a(singleton($request->param('OtherID')), Object::getCustomClass('Order_Email'))) {
756
                    $emailClassName = $request->param('OtherID');
757
                }
758
            }
759
            if ($statusID = intval($request->getVar('test'))) {
760
                $step = OrderStep::get()->byID($statusID);
761
                $subject = $step->EmailSubject;
762
                $message = $step->CustomerMessage;
763
                if ($step) {
764
                    $emailClassName = $step->getEmailClassName();
765
                }
766
                if ($request->getVar('send')) {
767
                    $email = filter_var($request->getVar('send'), FILTER_SANITIZE_EMAIL);
768
                    if(! $email) {
769
                        $email = true;
770
                    }
771
                    $this->currentOrder->sendEmail(
772
                        $emailClassName,
773
                        _t('Account.TEST_ONLY', '--- TEST ONLY ---') . ' ' . $subject,
774
                        $message,
775
                        $resend = true,
776
                        $adminOnlyOrToEmail = $email
777
                    );
778
                }
779
            }
780
            elseif ($request->getVar('send')) {
781
                if ($email = $this->currentOrder->getOrderEmail()) {
782
                    $step = OrderStep::get()->byID($this->currentOrder->StatusID);
0 ignored issues
show
Unused Code introduced by
$step 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...
783
                    $ecomConfig = $this->EcomConfig();
784
                    $subject = $ecomConfig->InvoiceTitle ? $ecomConfig->InvoiceTitle : _t('OrderConfirmationPage.INVOICE', 'Invoice');
785
                    $message = $ecomConfig->InvoiceMessage ? $ecomConfig->InvoiceMessage : _t('OrderConfirmationPage.MESSAGE', '<p>Thank you for your order.</p>');
786
                    $emailClassName = 'Order_InvoiceEmail';
787
                    if (
788
                        $this->currentOrder->sendEmail(
789
                            $emailClassName,
790
                            $subject,
791
                            $message,
792
                            $resend = true,
793
                            $adminOnlyOrToEmail = false
794
                        )
795
                    ) {
796
                        $message = _t('OrderConfirmationPage.RECEIPTSENT', 'An email has been sent to: ').$email.'.';
797
                    } else {
798
                        $message = _t('OrderConfirmationPage.RECEIPT_NOT_SENT', 'Email could NOT be sent to: ').$email;
799
                    }
800
                } else {
801
                    $message = _t('OrderConfirmationPage.RECEIPTNOTSENTNOEMAIL', 'No customer details found.  EMAIL NOT SENT.');
802
                }
803
            }
804
            //display same data...
805
            Requirements::clear();
806
            return $this->currentOrder->renderOrderInEmailFormat(
807
                $emailClassName,
808
                $subject,
809
                $message
810
            );
811
        } else {
812
            return _t('OrderConfirmationPage.RECEIPTNOTSENTNOORDER', 'Order could not be found.');
813
        }
814
    }
815
816
    protected function includeGoogleAnalyticsCode()
817
    {
818
        if ($this->EnableGoogleAnalytics && $this->currentOrder && Director::isLive()) {
819
            $currencyUsedObject = $this->currentOrder->CurrencyUsed();
820
            if ($currencyUsedObject) {
821
                $currencyUsedString = $currencyUsedObject->Code;
822
            }
823
            if (empty($currencyUsedString)) {
824
                $currencyUsedString = EcommerceCurrency::default_currency_code();
825
            }
826
            $js = '
827
            jQuery(document).ready(
828
                function(){
829
                    _gaq(\'require\', \'ecommerce\');
830
                    _gaq(
831
                        \'ecommerce:addTransaction\',
832
                        {
833
                            \'id\': \''.$this->currentOrder->ID.'\',
834
                            \'revenue\': \''.$this->currentOrder->getSubTotal().'\',
835
                            \'currency\': \''.$currencyUsedString.'\'
836
                        }
837
                    );
838
                    _gaq(\'ecommerce:send\');
839
                }
840
            );
841
';
842
            Requirements::customScript($js, 'GoogleAnalyticsEcommerce');
843
        }
844
    }
845
}
846