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

code/model/BuyableStockCalculatedQuantity.php (1 issue)

Internal.LineEndings.Mixed

Coding Style Informational

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