Completed
Push — master ( b7c5b8...080abf )
by Nicolaas
01:40
created

code/model/BuyableStockCalculatedQuantity.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
0 ignored issues
show
File has mixed line endings; this may cause incorrect results
Loading history...
2
/**
3
 *@author: Nicolaas [at] Sunny Side Up . Co . Nz
4
 *@description:
5
 * works out the quantity available for each buyable
6
 * based on the the number of items sold, recorded in BuyableStockOrderEntry,
7
 * and manual corrections, recorded in BuyableStockManualUpdate.
8
 *
9
 *
10
 **/
11
12
class BuyableStockCalculatedQuantity extends DataObject
13
{
14
    private static $db = array(
15
        "BaseQuantity" => "Int",
16
        "BuyableID" => "Int",
17
        "BuyableClassName" => "Varchar"
18
    );
19
20
    private static $has_many = array(
21
        "BuyableStockOrderEntry" => "BuyableStockOrderEntry",
22
        "BuyableStockManualUpdate" => "BuyableStockManualUpdate"
23
    );
24
25
    private static $defaults = array(
26
        "BaseQuantity" => 0
27
    );
28
29
    private static $casting = array(
30
        "Name" => "Varchar",
31
        "Buyable" => "DataObject",
32
        "UnlimitedStock" => "Boolean"
33
    );
34
35
    //MODEL ADMIN STUFF
36
    private static $searchable_fields = array(
37
        "BaseQuantity"
38
    );
39
40
    private static $field_labels = array(
41
        "BaseQuantity" => "Calculated Quantity On Hand",
42
        "BuyableID" => "Buyable ID",
43
        "LastEdited" => "Last Calculated"
44
    );
45
46
    private static $summary_fields = array(
47
        "Name",
48
        "BaseQuantity",
49
        "LastEdited"
50
    );
51
52
    private static $indexes = array(
53
        "BuyableID" => true,
54
        "BuyableClassName" => true
55
    );
56
57
    private static $default_sort = "\"BuyableClassName\", \"BaseQuantity\" DESC";
58
59
    private static $singular_name = "Stock Calculated Quantity";
60
61
    private static $plural_name = "Stock Calculated Quantities";
62
63
    private static $calculation_done = array();
64
65
    public function canCreate($member = null)
66
    {
67
        return false;
68
    }
69
70
    public function canEdit($member = null)
71
    {
72
        return false;
73
    }
74
75
    public function canDelete($member = null)
76
    {
77
        return false;
78
    }
79
80
    public function canView($member = null)
81
    {
82
        return $this->canDoAnything();
83
    }
84
85
    public function Link($action = "update")
86
    {
87
        return "/update-stock/".$action."/".$this->ID."/";
88
    }
89
90
    public function HistoryLink()
91
    {
92
        return $this->Link("history");
93
    }
94
95
    public function Buyable()
96
    {
97
        return $this->getBuyable();
98
    }
99
    public function getBuyable()
100
    {
101
        if ($this->BuyableID && class_exists($this->BuyableClassName)) {
102
            $className = $this->BuyableClassName;
103
            return $className::get()->byID($this->BuyableID);
104
        }
105
    }
106
107
    public function UnlimitedStock()
108
    {
109
        return $this->geUnlimitedStock();
110
    }
111
    public function getUnlimitedStock()
112
    {
113
        if ($buyable = $this->getBuyable()) {
114
            return $buyable->UnlimitedStock;
115
        }
116
    }
117
118
    public function Name()
119
    {
120
        return $this->getName();
121
    }
122
    public function getName()
123
    {
124
        if ($buyable = $this->getBuyable()) {
125
            return $buyable->getTitle();
126
        }
127
        return "no name";
128
    }
129
130
    protected function canDoAnything($member = null)
131
    {
132
        if ($buyable = $this->getBuyable()) {
133
            if ($buyable->canEdit($member)) {
134
                return true;
135
            }
136
        }
137
        Security::permissionFailure($this, _t('Security.PERMFAILURE', ' This page is secured and you need administrator rights to access it. Enter your credentials below and we will send you right along.'));
138
    }
139
140
    public static function get_quantity_by_buyable($buyable)
141
    {
142
        $value = 0;
143
        $item = self::get_by_buyable($buyable);
144
        if ($item) {
145
            $value = $item->calculatedBaseQuantity();
146
            if ($value < 0) {
147
                $value = 0;
148
            }
149
        }
150
        return $value;
151
    }
152
153
    public static function get_by_buyable($buyable)
154
    {
155
        $obj = BuyableStockCalculatedQuantity::get()
156
                        ->filter(
157
                            array(
158
                                'BuyableID' => $buyable->ID,
159
                                'BuyableClassName' => $buyable->ClassName
160
                            )
161
                        )
162
                        ->First();
163
        if ($obj) {
164
            //do nothing
165
        } else {
166
            $obj = new BuyableStockCalculatedQuantity();
167
            $obj->BuyableID = $buyable->ID;
168
            $obj->BuyableClassName = $buyable->ClassName;
169
        }
170
        if ($obj) {
171
            if (isset($obj->ID) && $obj->exists() && $obj->UnlimitedStock == $buyable->UnlimitedStock) {
172
                //do nothing
173
            } else {
174
                $obj->UnlimitedStock = $buyable->UnlimitedStock;
175
                //we must write here to calculate quantities
176
                $obj->write();
177
            }
178
            return $obj;
179
        }
180
        user_error("Could not find / create BuyableStockCalculatedQuantity for buyable with ID / ClassName ".$buyableID."/".$buyableClassName, E_WARNING);
181
    }
182
183
    public function calculatedBaseQuantity()
184
    {
185
        if (!$this->ID) {
186
            return 0;
187
        }
188
        $actualQuantity = $this->workoutActualQuantity();
189
        if ($actualQuantity != $this->BaseQuantity) {
190
            $this->BaseQuantity = $actualQuantity;
191
            $this->write();
192
            return $actualQuantity;
193
        } else {
194
            return $this->getField("BaseQuantity");
195
        }
196
    }
197
198
    protected function calculatedBaseQuantities($buyables = null)
199
    {
200
        if ($buyables) {
201
            foreach ($buyables as $buyable) {
202
                $buyableStockCalculatedQuantity = BuyableStockCalculatedQuantity::get_by_buyable($buyable);
203
                if ($buyableStockCalculatedQuantity) {
204
                    $buyableStockCalculatedQuantity->calculatedBaseQuantity();
205
                }
206
            }
207
        }
208
    }
209
210
    /**
211
     * TODO: change to submitted from CustomerCanEdit criteria
212
     */
213
214
215
    protected function workoutActualQuantity()
216
    {
217
        $actualQuantity = 0;
218
        if ($buyable = $this->getBuyable()) {
219
            $query = Order::get()
220
                ->where('
221
                    "OrderItem"."BuyableID" = '.(intval($this->BuyableID) - 0).'
222
                    AND
223
                    "OrderItem"."BuyableClassName" = \''.$this->BuyableClassName.'\'
224
                    AND
225
                    "OrderStep"."CustomerCanEdit" = 0
226
                    AND
227
                    "Order"."ID" <> '.ShoppingCart::current_order()->ID.'
228
                ')
229
                ->innerJoin('OrderAttribute', '"OrderAttribute"."OrderID" = "Order"."ID"')
230
                ->innerJoin('OrderItem', '"OrderAttribute"."ID" = "OrderItem"."ID"')
231
                ->innerJoin('OrderStep', '"OrderStep"."ID" = "Order"."StatusID"');
232
            $amountPerOrder = array();
233
            if($query->count()) {
234
                foreach ($query as $row) {
235
                    if(!isset($amountPerOrder[$row->OrderID])) {
236
                        $amountPerOrder[$row->OrderID] = 0;
237
                    }
238
                    $amountPerOrder[$row->OrderID] += $row->Quantity;
239
                }
240
                foreach($amountPerOrder as $orderID => $sum) {
241
                    if ($orderID && $sum) {
242
                        $buyableStockOrderEntry = BuyableStockOrderEntry::get()
243
                            ->filter(
244
                                array(
245
                                    'OrderID' => $orderID,
246
                                    'ParentID' => $this->ID
247
                                )
248
                            )
249
                            ->First();
250
                        if ($buyableStockOrderEntry) {
251
                            //do nothing
252
                        } else {
253
                            $buyableStockOrderEntry = new BuyableStockOrderEntry();
254
                            $buyableStockOrderEntry->OrderID = $orderID;
255
                            $buyableStockOrderEntry->ParentID = $this->ID;
256
                            $buyableStockOrderEntry->IncludeInCurrentCalculation = 1;
257
                            $buyableStockOrderEntry->Quantity = 0;
258
                        }
259
                        if ($buyableStockOrderEntry->Quantity != $sum) {
260
                            $buyableStockOrderEntry->Quantity = $sum;
261
                            $buyableStockOrderEntry->write();
262
                        }
263
                    }
264
                }
265
            }
266
            //find last adjustment
267
            $latestManualUpdate = BuyableStockManualUpdate::get()
268
                                                            ->filter(array('ParentID' => $this->ID))
269
                                                            ->sort(array('LastEdited' => 'DESC'))
270
                                                            ->First();
271
            //nullify order quantities that were entered before last adjustment
272
            if ($latestManualUpdate) {
273
                $latestManualUpdateQuantity = $latestManualUpdate->Quantity;
274
                DB::query("
275
                    UPDATE \"BuyableStockOrderEntry\"
276
                    SET \"IncludeInCurrentCalculation\" = 0
277
                    WHERE
278
                    \"LastEdited\" < '".$latestManualUpdate->LastEdited."'
279
                        AND
280
                        \"ParentID\" = ".$this->ID
281
                );
282
            } else {
283
                $latestManualUpdateQuantity = 0;
284
            }
285
            //work out additional purchases
286
            $orderQuantityToDeduct = BuyableStockOrderEntry::get()
287
                                        ->filter(
288
                                            array(
289
                                                'ParentID' => $this->ID,
290
                                                'IncludeInCurrentCalculation' => 1
291
                                            )
292
                                        )->sum('Quantity');
293
            if (!$orderQuantityToDeduct) {
294
                $orderQuantityToDeduct = 0;
295
            }
296
            //work out base total
297
            $actualQuantity = $latestManualUpdateQuantity - $orderQuantityToDeduct;
298
            if (isset($_GET["debug"])) {
299
                echo "<hr />";
300
                echo $this->Name;
301
                echo " | Manual SUM: ".$latestManualUpdateQuantity;
302
                echo " | Order SUM: ".$orderQuantityToDeduct;
303
                echo " | Total SUM: ".$this->BaseQuantity;
304
                echo "<hr />";
305
            }
306
        }
307
        return $actualQuantity;
308
    }
309
}
310