Completed
Push — master ( ce2dd0...10a6ac )
by Nicolaas
04:02
created

code/model/process/OrderProcessQueue.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * This class provides a bunch of Meta Objects
4
 * that do not interact with the object at hand, but rather with the datalist as a whole.
5
 *
6
 */
7
8
class OrderProcessQueue extends DataObject
9
{
10
    private static $db = array(
11
        'DeferTimeInSeconds' => 'Int',
12
        'InProcess' => 'Boolean'
13
    );
14
15
    private static $has_one = array(
16
        'Order' => 'Order',
17
        'OrderStep' => 'OrderStep'
18
    );
19
20
    private static $indexes = array(
21
        'Created' => true,
22
        'DeferTimeInSeconds' => true
23
    );
24
25
    private static $casting = array(
26
        'ToBeProcessedAt' => 'SS_Datetime',
27
        'HasBeenInQueueSince' => 'SS_Datetime'
28
    );
29
30
    private static $default_sort = array(
31
        'Created' => 'DESC'
32
    );
33
34
    /**
35
     * standard SS variable.
36
     *
37
     * @var array
38
     */
39
    private static $summary_fields = array(
40
        'Order.Title' => 'Order',
41
        'Order.Status.Title' => 'Current Step',
42
        'ToBeProcessedAt.Nice' => 'To be processed at',
43
        'ToBeProcessedAt.Ago' => 'That is ...',
44
        'HasBeenInQueueForSince.Nice' => 'Added to queue ...',
45
        'InProcess.Nice' => 'Currently Running'
46
    );
47
48
    /**
49
     * standard SS variable.
50
     *
51
     * @var array
52
     */
53
    private static $searchable_fields = array(
54
        'OrderID' => array(
55
            'field' => 'NumericField',
56
            'title' => 'Order Number',
57
        )
58
    );
59
60
61
    /**
62
     * Standard SS method.
63
     *
64
     * @param Member $member
65
     *
66
     * @return bool
67
     */
68
    public function canCreate($member = null)
69
    {
70
        return false;
71
    }
72
73
    /**
74
     * Standard SS method.
75
     *
76
     * @param Member $member
77
     *
78
     * @return bool
79
     */
80
    public function canView($member = null)
81
    {
82
        if (! $member) {
83
            $member = Member::currentUser();
84
        }
85
        $extended = $this->extendedCan(__FUNCTION__, $member);
86
        if ($extended !== null) {
87
            return $extended;
88
        }
89
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
90
            return true;
91
        }
92
        //is the member is a shop assistant they can always view it
93
        if (EcommerceRole::current_member_is_shop_assistant($member)) {
94
            return true;
95
        }
96
97
        return parent::canView($member);
98
    }
99
100
    /**
101
     * Standard SS method.
102
     *
103
     * @param Member $member
104
     *
105
     * @return bool
106
     */
107
    public function canEdit($member = null)
108
    {
109
        return false;
110
    }
111
112
    /**
113
     * Standard SS method
114
     * Queues can be deleted if needed.
115
     *
116
     * @param Member $member
117
     *
118
     * @return bool
119
     */
120
    public function canDelete($member = null)
121
    {
122
        return parent::canDelete($member);
123
    }
124
125
    /**
126
     * standard SS variable.
127
     *
128
     * @var string
129
     */
130
    private static $singular_name = 'Order To Be Processed';
131
    public function i18n_singular_name()
132
    {
133
        return _t('OrderProcessQueue.SINGULAR_NAME', 'Order In Queue');
134
    }
135
136
    /**
137
     * standard SS variable.
138
     *
139
     * @var string
140
     */
141
    private static $plural_name = 'Orders to be Processed';
142
    public function i18n_plural_name()
143
    {
144
        return _t('OrderProcessQueue.PLURAL_NAME', 'Orders In Queue');
145
    }
146
147
148
    /**
149
     * META METHOD: Add an order to the job list.
150
     * If the order already exists, it will update the seconds and the creation  time.
151
     *
152
     * @param Order $order
153
     * @param Int   $deferInSeconds
154
     */
155
    public function AddOrderToQueue($order, $deferTimeInSeconds)
156
    {
157
        if(!$order || ! $order->ID) {
158
            user_error('No real order provided.')
159
        }
0 ignored issues
show
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected '}'
Loading history...
160
        $filter = array('OrderID' => $order->ID);
161
        $existingEntry = OrderProcessQueue::get()->filter($filter)->first();
162
        $filter['Created'] = SS_Datetime::now()->Rfc2822();
163
        $filter['DeferTimeInSeconds'] = $deferTimeInSeconds;
164
        if (! $existingEntry) {
165
            $existingEntry = OrderProcessQueue::create($filter);
166
            $existingEntry->OrderStepID = $order->StatusID;
167
        } else {
168
            foreach ($filter as $field => $value) {
169
                $existingEntry->$field = $value;
170
            }
171
        }
172
        $existingEntry->write();
173
174
        return $existingEntry;
175
    }
176
177
    /**
178
     * META METHOD
179
     * processes the order ...
180
     * returns TRUE if SUCCESSFUL and a message if unsuccessful ...
181
     *
182
     *
183
     * @param  Order $order optional
184
     * @return boolean | string
185
     */
186
    public function process($order = null)
187
    {
188
        //find variables
189
        if( ! $order) {
190
            $order = $this->Order();
191
            $myQueueObject = $this;
192
        } else {
193
            $myQueueObject = $this->getQueueObject($order);
194
        }
195
        //delete if order is gone ...
196
        if($order) {
197
            //if order has moved already ... delete
198
            if(
199
                $this->OrderStepID > 0
200
                && (int)$order->StatusID !== (int)$myQueueObject->OrderStepID
201
            ) {
202
                $message = 'Order has already moved on.';
203
                $myQueueObject->delete();
204
            } else {
205
                if($myQueueObject) {
206
                    if ($myQueueObject->isReadyToGo()) {
207
                        $oldOrderStatusID = $order->StatusID;
208
                        $myQueueObject->InProcess = true;
209
                        $myQueueObject->write();
210
                        $order->tryToFinaliseOrder(
211
                            $tryAgain = false,
212
                            $fromOrderQueue = true
213
                        );
214
                        $newOrderStatusID = $order->StatusID;
215
                        if($oldOrderStatusID != $newOrderStatusID) {
216
                            $myQueueObject->delete();
217
                            return true;
218
                        } else {
219
                            $message = 'Attempt to move order was not successful.';
220
                            $myQueueObject->InProcess = false;
221
                            $myQueueObject->write();
222
                        }
223
                    } else  {
224
                        $message = 'Minimum order queue time has not been passed.';
225
                    }
226
227
                } else {
228
                    $message = 'Could not find queue object.';
229
                }
230
            }
231
        } else {
232
            $message = 'Can not find order.';
233
            $myQueueObject->delete();
234
        }
235
        return $message;
236
    }
237
238
    /**
239
     * META METHOD: returns the queue object if it exists
240
     *
241
     * @param  Order $order
242
     *
243
     * @return null |   OrderProcessQueue
244
     */
245
    public function getQueueObject($order)
246
    {
247
        $filter = array('OrderID' => $order->ID);
248
249
        return OrderProcessQueue::get()->filter($filter)->first();
250
    }
251
252
    /**
253
     * META METHOD: Once you are done, you can remove the item like this ...
254
     *
255
     * @param  Order $order
256
     */
257
    public function removeOrderFromQueue($order)
258
    {
259
        $queueEntries = OrderProcessQueue::get()->filter(array('OrderID' => $order->ID));
260
        foreach($queueEntries as $queueEntry) {
261
            $queueEntry->delete();
262
        }
263
    }
264
265
    /**
266
     * META METHOD: returns a list of orders to be processed
267
     * @param int $id force this Order to be processed
268
     * @param int $limit total number of orders that can be retrieved at any one time
269
     *
270
     * @return DataList (of orders)
271
     */
272
    public function OrdersToBeProcessed($id = 0, $limit = 9999)
273
    {
274
275
        //we sort the order randomly so that we get a nice mixture
276
        //not always the same ones holding up the process
277
        $sql = '
278
            SELECT "OrderID"
279
            FROM "OrderProcessQueue"
280
            WHERE
281
                "InProcess" = 0
282
                AND
283
                (UNIX_TIMESTAMP("Created") + "DeferTimeInSeconds") < '.time().'
284
            ORDER BY RAND() DESC
285
            LIMIT '.$limit.';
286
        ';
287
        $rows = DB::query($sql);
288
        $orderIDs = array($id => $id);
289
        foreach ($rows as $row) {
290
            $orderIDs[$row['OrderID']] = $row['OrderID'];
291
        }
292
293
        return Order::get()
294
            ->filter(array('ID' => $orderIDs))
295
            ->sort('RAND()');
296
    }
297
298
    /**
299
     * META METHOD: all orders with a queue object
300
     * @param int $id force this Order to be processed
301
     * @param int $limit total number of orders that can be retrieved at any one time
302
     *
303
     * @return DataList (of orders)
304
     */
305
    public function AllOrdersInQueue($limit = 9999)
306
    {
307
308
        return Order::get()
309
            ->filter(array('ID' => OrderProcessQueue::get()->column('OrderID')))
310
            ->sort('RAND()')
311
            ->limit($limit);
312
    }
313
314
    /**
315
     * META METHOD: returns a list of orders NOT YET to be processed
316
     * @param int $limit total number of orders that can be retrieved at any one time
317
     *
318
     * @return DataList (of orders)
319
     */
320
    public function OrdersInQueueThatAreNotReady($limit = 9999)
321
    {
322
323
        //we sort the order randomly so that we get a nice mixture
324
        //not always the same ones holding up the process
325
        $sql = '
326
            SELECT "OrderID"
327
            FROM "OrderProcessQueue"
328
            WHERE
329
                (UNIX_TIMESTAMP("Created") + "DeferTimeInSeconds") >= '.time().'
330
            ORDER BY RAND() DESC
331
            LIMIT '.$limit.';
332
        ';
333
        $rows = DB::query($sql);
334
        $orderIDs = array(0 => 0);
335
        foreach ($rows as $row) {
336
            $orderIDs[$row['OrderID']] = $row['OrderID'];
337
        }
338
339
        return Order::get()
340
            ->filter(array('ID' => $orderIDs))
341
            ->sort('RAND()');
342
    }
343
344
    /**
345
     * non-database method of working out if an Order is ready to go.
346
     *
347
     * @return bool
348
     */
349
    public function isReadyToGo()
350
    {
351
        return (strtotime($this->Created) + $this->DeferTimeInSeconds) < time();
352
    }
353
354
    /**
355
     *
356
     * casted variable
357
     * @return SS_DateTime
358
     */
359
    public function ToBeProcessedAt()
360
    {
361
        return $this->getToBeProcessedAt();
362
    }
363
364
    /**
365
     *
366
     * casted variable
367
     * @return SS_DateTime
368
     */
369
    public function getToBeProcessedAt()
370
    {
371
        return DBField::create_field('SS_Datetime', (strtotime($this->Created) + $this->DeferTimeInSeconds));
372
    }
373
374
375
    /**
376
     *
377
     * casted variable
378
     * @return SS_DateTime
379
     */
380
    public function HasBeenInQueueForSince()
381
    {
382
        return $this->getHasBeenInQueueForSince();
383
    }
384
385
    /**
386
     *
387
     * casted variable
388
     * @return SS_DateTime
389
     */
390
    public function getHasBeenInQueueForSince()
391
    {
392
        return DBField::create_field('SS_Datetime', (strtotime($this->Created)));
393
    }
394
395
396
    /**
397
     * CMS Fields
398
     * @return FieldList
399
     */
400
    public function getCMSFields()
401
    {
402
        $fields = parent::getCMSFields();
403
        if($this->exists()) {
404
            $fields->addFieldToTab(
405
                'Root.Main',
406
                ReadonlyField::create(
407
                    'HasBeenInQueueForSinceCompilations',
408
                    _t('OrderProcessQueue.SINCE', 'In the queue since'),
409
                    $this->getHasBeenInQueueForSince()->Nice() . ' - ' . $this->getHasBeenInQueueForSince()->Ago()
410
                ),
411
                'DeferTimeInSeconds'
412
            );
413
            $fields->addFieldToTab(
414
                'Root.Main',
415
                ReadonlyField::create(
416
                    'ToBeProcessedAtCompilations',
417
                    _t('OrderProcessQueue.TO_BE_PROCESSED', 'To Be Processed'),
418
                    $this->getToBeProcessedAt()->Nice() . ' - ' . $this->getToBeProcessedAt()->Ago()
419
                ),
420
                'InProcess'
421
            );
422
            $fields->addFieldToTab(
423
                'Root.Main',
424
                LiteralField::create(
425
                    'processQueueNow',
426
                    '<h2>
427
                        <a href="/dev/tasks/EcommerceTaskProcessOrderQueue/?id='.$this->OrderID.'" target="_blank">'.
428
                            _t('OrderProcessQueue.PROCESS', 'Process now').
429
                        '</a>
430
                    </h2>'
431
                )
432
            );
433
            $fields->replaceField(
434
                'OrderID',
435
                CMSEditLinkField::create(
436
                    'OrderID',
437
                    'Order',
438
                    $this->Order()
439
                )
440
            );
441
        }
442
        return $fields;
443
    }
444
445
    public function requireDefaultRecords()
446
    {
447
        parent::requireDefaultRecords();
448
        $errors = OrderProcessQueue::get()->filter(array('OrderID' => 0));
449
        foreach($errors as $error) {
450
            DB::alteration_message(' DELETING ROGUE OrderProcessQueue', 'deleted');
451
            $error->delete();
452
        }
453
    }
454
455
}
456