Order   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Test Coverage

Coverage 40%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 28
eloc 136
c 1
b 0
f 0
dl 0
loc 357
rs 10
ccs 42
cts 105
cp 0.4

14 Methods

Rating   Name   Duplication   Size   Complexity  
A canEdit() 0 3 1
A providePermissions() 0 4 1
A onBeforeWrite() 0 4 1
A canCreate() 0 3 1
A canDelete() 0 3 1
A fieldLabels() 0 18 1
A getDecryptedResponse() 0 7 2
A parseOrder() 0 12 2
A parseOrderInfo() 0 14 2
A ReceiptLink() 0 3 1
A getReceiptLink() 0 8 1
B parseOrderDetails() 0 54 8
A canView() 0 3 1
A parseOrderCustomer() 0 31 5
1
<?php
2
3
namespace Dynamic\FoxyStripe\Model;
4
5
use Dynamic\FoxyStripe\Page\ProductPage;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Forms\DateField;
8
use SilverStripe\ORM\DataObject;
9
use SilverStripe\ORM\FieldType\DBHTMLVarchar;
10
use SilverStripe\Security\Member;
11
use SilverStripe\Security\Permission;
12
use SilverStripe\Security\PermissionProvider;
13
use SilverStripe\Security\Security;
14
15
/**
16
 * Class Order
17
 * @package Dynamic\FoxyStripe\Model
18
 *
19
 * @property \SilverStripe\ORM\FieldType\DBInt Order_ID
20
 * @property \SilverStripe\ORM\FieldType\DBDatetime TransactionDate
21
 * @property \SilverStripe\ORM\FieldType\DBCurrency ProductTotal
22
 * @property \SilverStripe\ORM\FieldType\DBCurrency TaxTotal
23
 * @property \SilverStripe\ORM\FieldType\DBCurrency ShippingTotal
24
 * @property \SilverStripe\ORM\FieldType\DBCurrency OrderTotal
25
 * @property \SilverStripe\ORM\FieldType\DBVarchar ReceiptURL
26
 * @property \SilverStripe\ORM\FieldType\DBVarchar OrderStatus
27
 * @property \SilverStripe\ORM\FieldType\DBVarchar Response
28
 *
29
 * @property int MemberID
30
 * @method Member Member
31
 *
32
 * @method \SilverStripe\ORM\HasManyList Details
33
 */
34
class Order extends DataObject implements PermissionProvider
35
{
36
    /**
37
     * @var array
38
     */
39
    private static $db = array(
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
40
        'Order_ID' => 'Int',
41
        'TransactionDate' => 'DBDatetime',
42
        'ProductTotal' => 'Currency',
43
        'TaxTotal' => 'Currency',
44
        'ShippingTotal' => 'Currency',
45
        'OrderTotal' => 'Currency',
46
        'ReceiptURL' => 'Varchar(255)',
47
        'OrderStatus' => 'Varchar(255)',
48
        'Response' => 'Text',
49
    );
50
51
    /**
52
     * @var array
53
     */
54
    private static $has_one = array(
0 ignored issues
show
introduced by
The private property $has_one is not used, and could be removed.
Loading history...
55
        'Member' => Member::class,
56
    );
57
58
    /**
59
     * @var array
60
     */
61
    private static $has_many = array(
0 ignored issues
show
introduced by
The private property $has_many is not used, and could be removed.
Loading history...
62
        'Details' => OrderDetail::class,
63
    );
64
65
    /**
66
     * @var string
67
     */
68
    private static $singular_name = 'Order';
0 ignored issues
show
introduced by
The private property $singular_name is not used, and could be removed.
Loading history...
69
70
    /**
71
     * @var string
72
     */
73
    private static $plural_name = 'Orders';
0 ignored issues
show
introduced by
The private property $plural_name is not used, and could be removed.
Loading history...
74
75
    /**
76
     * @var string
77
     */
78
    private static $description = 'Orders from FoxyCart Datafeed';
0 ignored issues
show
introduced by
The private property $description is not used, and could be removed.
Loading history...
79
80
    /**
81
     * @var string
82
     */
83
    private static $default_sort = 'TransactionDate DESC, ID DESC';
0 ignored issues
show
introduced by
The private property $default_sort is not used, and could be removed.
Loading history...
84
85
    /**
86
     * @var array
87
     */
88
    private static $summary_fields = array(
0 ignored issues
show
introduced by
The private property $summary_fields is not used, and could be removed.
Loading history...
89
        'Order_ID',
90
        'TransactionDate.Nice',
91
        'Member.Name',
92
        'ProductTotal.Nice',
93
        'ShippingTotal.Nice',
94
        'TaxTotal.Nice',
95
        'OrderTotal.Nice',
96
        'ReceiptLink',
97
    );
98
99
    /**
100
     * @var array
101
     */
102
    private static $searchable_fields = array(
0 ignored issues
show
introduced by
The private property $searchable_fields is not used, and could be removed.
Loading history...
103
        'Order_ID',
104
        'TransactionDate' => array(
105
            'field' => DateField::class,
106
            'filter' => 'PartialMatchFilter',
107
        ),
108
        'Member.ID',
109
        'OrderTotal',
110
        'Details.ProductID',
111
    );
112
113
    /**
114
     * @var array
115
     */
116
    private static $casting = array(
0 ignored issues
show
introduced by
The private property $casting is not used, and could be removed.
Loading history...
117
        'ReceiptLink' => 'HTMLVarchar',
118
    );
119
120
    /**
121
     * @var array
122
     */
123
    private static $indexes = array(
0 ignored issues
show
introduced by
The private property $indexes is not used, and could be removed.
Loading history...
124
        'Order_ID' => true, // make unique
125
    );
126
127
    /**
128
     * @var string
129
     */
130
    private static $table_name = 'Order';
0 ignored issues
show
introduced by
The private property $table_name is not used, and could be removed.
Loading history...
131
132
    /**
133
     * @param bool $includerelations
134
     *
135
     * @return array|string
136
     */
137 1
    public function fieldLabels($includerelations = true)
138
    {
139 1
        $labels = parent::fieldLabels();
140
141 1
        $labels['Order_ID'] = _t('Order.Order_ID', 'Order ID#');
142 1
        $labels['TransactionDate'] = _t('Order.TransactionDate', 'Date');
143 1
        $labels['TransactionDate.NiceUS'] = _t('Order.TransactionDate', 'Date');
144 1
        $labels['Member.Name'] = _t('Order.MemberName', 'Customer');
145 1
        $labels['Member.ID'] = _t('Order.MemberName', 'Customer');
146 1
        $labels['ProductTotal.Nice'] = _t('Order.ProductTotal', 'Sub Total');
147 1
        $labels['TaxTotal.Nice'] = _t('Order.TaxTotal', 'Tax');
148 1
        $labels['ShippingTotal.Nice'] = _t('Order.ShippingTotal', 'Shipping');
149 1
        $labels['OrderTotal'] = _t('Order.OrderTotal', 'Total');
150 1
        $labels['OrderTotal.Nice'] = _t('Order.OrderTotal', 'Total');
151 1
        $labels['ReceiptLink'] = _t('Order.ReceiptLink', 'Invoice');
152 1
        $labels['Details.ProductID'] = _t('Order.Details.ProductID', 'Product');
153
154 1
        return $labels;
155
    }
156
157
    /**
158
     * @return mixed
159
     */
160 1
    public function ReceiptLink()
161
    {
162 1
        return $this->getReceiptLink();
163
    }
164
165
    /**
166
     * @return mixed
167
     */
168 1
    public function getReceiptLink()
169
    {
170 1
        $obj = DBHTMLVarchar::create();
171 1
        $obj->setValue(
172 1
            '<a href="'.$this->ReceiptURL.'" target="_blank" class="cms-panel-link action external-link">view</a>'
173
        );
174
175 1
        return $obj;
176
    }
177
178
    /**
179
     * @return bool|string
180
     */
181 9
    public function getDecryptedResponse()
182
    {
183 9
        $decrypted = urldecode($this->Response);
184 9
        if (FoxyCart::getStoreKey()) {
185
            return \rc4crypt::decrypt(FoxyCart::getStoreKey(), $decrypted);
0 ignored issues
show
Bug introduced by
It seems like Dynamic\FoxyStripe\Model\FoxyCart::getStoreKey() can also be of type false; however, parameter $pwd of rc4crypt::decrypt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

185
            return \rc4crypt::decrypt(/** @scrutinizer ignore-type */ FoxyCart::getStoreKey(), $decrypted);
Loading history...
186
        }
187 9
        return false;
188
    }
189
190
    /**
191
     * @throws \SilverStripe\ORM\ValidationException
192
     */
193 9
    public function onBeforeWrite()
194
    {
195 9
        $this->parseOrder();
196 9
        parent::onBeforeWrite();
197
    }
198
199
    /**
200
     * @return bool
201
     *
202
     * @throws \SilverStripe\ORM\ValidationException
203
     */
204 9
    public function parseOrder()
205
    {
206 9
        if ($this->getDecryptedResponse()) {
207
            $response = new \SimpleXMLElement($this->getDecryptedResponse());
208
209
            $this->parseOrderInfo($response);
210
            $this->parseOrderCustomer($response);
211
            $this->parseOrderDetails($response);
212
213
            return true;
214
        } else {
215 9
            return false;
216
        }
217
    }
218
219
    /**
220
     * @param $response
221
     */
222
    public function parseOrderInfo($response)
223
    {
224
        foreach ($response->transactions->transaction as $transaction) {
225
            // Record transaction data from FoxyCart Datafeed:
226
            $this->Store_ID = (int) $transaction->store_id;
0 ignored issues
show
Bug Best Practice introduced by
The property Store_ID does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
227
            $this->TransactionDate = (string) $transaction->transaction_date;
0 ignored issues
show
Documentation Bug introduced by
It seems like (string)$transaction->transaction_date of type string is incompatible with the declared type SilverStripe\ORM\FieldType\DBDatetime of property $TransactionDate.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
228
            $this->ProductTotal = (float) $transaction->product_total;
0 ignored issues
show
Documentation Bug introduced by
It seems like (double)$transaction->product_total of type double is incompatible with the declared type SilverStripe\ORM\FieldType\DBCurrency of property $ProductTotal.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
229
            $this->TaxTotal = (float) $transaction->tax_total;
0 ignored issues
show
Documentation Bug introduced by
It seems like (double)$transaction->tax_total of type double is incompatible with the declared type SilverStripe\ORM\FieldType\DBCurrency of property $TaxTotal.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
230
            $this->ShippingTotal = (float) $transaction->shipping_total;
0 ignored issues
show
Documentation Bug introduced by
It seems like (double)$transaction->shipping_total of type double is incompatible with the declared type SilverStripe\ORM\FieldType\DBCurrency of property $ShippingTotal.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
231
            $this->OrderTotal = (float) $transaction->order_total;
0 ignored issues
show
Documentation Bug introduced by
It seems like (double)$transaction->order_total of type double is incompatible with the declared type SilverStripe\ORM\FieldType\DBCurrency of property $OrderTotal.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
232
            $this->ReceiptURL = (string) $transaction->receipt_url;
0 ignored issues
show
Documentation Bug introduced by
It seems like (string)$transaction->receipt_url of type string is incompatible with the declared type SilverStripe\ORM\FieldType\DBVarchar of property $ReceiptURL.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
233
            $this->OrderStatus = (string) $transaction->status;
0 ignored issues
show
Documentation Bug introduced by
It seems like (string)$transaction->status of type string is incompatible with the declared type SilverStripe\ORM\FieldType\DBVarchar of property $OrderStatus.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
234
235
            $this->extend('handleOrderInfo', $order, $response);
236
        }
237
    }
238
239
    /**
240
     * @param $response
241
     * @throws \SilverStripe\ORM\ValidationException
242
     */
243
    public function parseOrderCustomer($response)
244
    {
245
        foreach ($response->transactions->transaction as $transaction) {
246
            // if not a guest transaction in FoxyCart
247
            if (isset($transaction->customer_email) && $transaction->is_anonymous == 0) {
248
                // if Customer is existing member, associate with current order
249
                if (Member::get()->filter('Email', $transaction->customer_email)->First()) {
250
                    $customer = Member::get()->filter('Email', $transaction->customer_email)->First();
251
                    // if new customer, create account with data from FoxyCart
252
                } else {
253
                    // set PasswordEncryption to 'none' so imported, encrypted password is not encrypted again
254
                    Config::modify()->set(Security::class, 'password_encryption_algorithm', 'none');
255
256
                    // create new Member, set password info from FoxyCart
257
                    $customer = Member::create();
258
                    $customer->Customer_ID = (int) $transaction->customer_id;
259
                    $customer->FirstName = (string) $transaction->customer_first_name;
260
                    $customer->Surname = (string) $transaction->customer_last_name;
261
                    $customer->Email = (string) $transaction->customer_email;
262
                    $customer->Password = (string) $transaction->customer_password;
263
                    $customer->Salt = (string) $transaction->customer_password_salt;
264
                    $customer->PasswordEncryption = 'none';
265
266
                    // record member record
267
                    $customer->write();
268
                }
269
270
                // set Order MemberID
271
                $this->MemberID = $customer->ID;
272
273
                $this->extend('handleOrderCustomer', $order, $response, $customer);
274
            }
275
        }
276
    }
277
278
    /**
279
     * @param $response
280
     *
281
     * @throws \SilverStripe\ORM\ValidationException
282
     */
283
    public function parseOrderDetails($response)
284
    {
285
286
        // remove previous OrderDetails and OrderOptions so we don't end up with duplicates
287
        foreach ($this->Details() as $detail) {
288
            /** @var OrderOption $orderOption */
289
            foreach ($detail->OrderOptions() as $orderOption) {
290
                $orderOption->delete();
291
            }
292
            $detail->delete();
293
        }
294
295
        foreach ($response->transactions->transaction as $transaction) {
296
            // Associate ProductPages, Options, Quantity with Order
297
            foreach ($transaction->transaction_details->transaction_detail as $detail) {
298
                $OrderDetail = OrderDetail::create();
299
300
                $OrderDetail->Quantity = (int) $detail->product_quantity;
301
                $OrderDetail->ProductName = (string) $detail->product_name;
302
                $OrderDetail->ProductCode = (string) $detail->product_code;
303
                $OrderDetail->ProductImage = (string) $detail->image;
304
                $OrderDetail->ProductCategory = (string) $detail->category_code;
305
                $priceModifier = 0;
306
307
                // parse OrderOptions
308
                foreach ($detail->transaction_detail_options->transaction_detail_option as $option) {
309
                    // Find product via product_id custom variable
310
                    if ($option->product_option_name == 'product_id') {
311
                        // if product is found, set relation to OrderDetail
312
                        $OrderProduct = ProductPage::get()->byID((int) $option->product_option_value);
313
                        if ($OrderProduct) {
314
                            $OrderDetail->ProductID = $OrderProduct->ID;
315
                        }
316
                    } else {
317
                        $OrderOption = OrderOption::create();
318
                        $OrderOption->Name = (string) $option->product_option_name;
319
                        $OrderOption->Value = (string) $option->product_option_value;
320
                        $OrderOption->write();
321
                        $OrderDetail->OrderOptions()->add($OrderOption);
322
323
                        $priceModifier += $option->price_mod;
324
                    }
325
                }
326
327
                $OrderDetail->Price = (float) $detail->product_price + (float) $priceModifier;
328
329
                // extend OrderDetail parsing, allowing for recording custom fields from FoxyCart
330
                $this->extend('handleOrderItem', $order, $response, $OrderDetail);
331
332
                // write
333
                $OrderDetail->write();
334
335
                // associate with this order
336
                $this->Details()->add($OrderDetail);
337
            }
338
        }
339
    }
340
341
    /**
342
     * @param bool $member
343
     *
344
     * @return bool|int
345
     */
346 10
    public function canView($member = null)
347
    {
348 10
        return Permission::check('Product_ORDERS', 'any', $member);
0 ignored issues
show
Bug introduced by
It seems like $member can also be of type boolean; however, parameter $member of SilverStripe\Security\Permission::check() does only seem to accept SilverStripe\Security\Member|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

348
        return Permission::check('Product_ORDERS', 'any', /** @scrutinizer ignore-type */ $member);
Loading history...
349
    }
350
351
    /**
352
     * @param null $member
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $member is correct as it would always require null to be passed?
Loading history...
353
     *
354
     * @return bool
355
     */
356 1
    public function canEdit($member = null)
357
    {
358 1
        return false;
359
        //return Permission::check('Product_ORDERS', 'any', $member);
360
    }
361
362
    /**
363
     * @param null $member
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $member is correct as it would always require null to be passed?
Loading history...
364
     *
365
     * @return bool
366
     */
367 1
    public function canDelete($member = null)
368
    {
369 1
        return false;
370
        //return Permission::check('Product_ORDERS', 'any', $member);
371
    }
372
373
    /**
374
     * @param null  $member
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $member is correct as it would always require null to be passed?
Loading history...
375
     * @param array $context
376
     *
377
     * @return bool
378
     */
379 1
    public function canCreate($member = null, $context = [])
380
    {
381 1
        return false;
382
    }
383
384
    /**
385
     * @return array
386
     */
387 1
    public function providePermissions()
388
    {
389
        return array(
390 1
            'Product_ORDERS' => 'Allow user to manage Orders and related objects',
391
        );
392
    }
393
}
394