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
Bug
introduced
by
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 |