1 <?php
2
3 class ProductVariation extends DataObject {
4 static $db = array(
5 'Title' => 'Varchar(200)',
6 'MenuTitle' => 'Varchar(200)',
7
8 'PriceType' => "Enum('own,delta,percent')",
9
10 'BasePriceDelta' => 'CatalogPrice',
11 'CostPriceDelta' => 'CatalogPrice',
12
13 'BasePricePercent' => 'Float',
14 'CostPricePercent' => 'Float',
15
16 'BasePriceOwn' => 'CatalogPrice',
17 'CostPriceOwn' => 'CatalogPrice',
18
19 'VariationPrice' => 'CatalogPrice',
20
21 'Available' => 'Boolean',
22 'AllowPurchase' => 'Boolean',
23
24 'ImportID' => 'Varchar(100)',
25 'SKU' => 'Varchar',
26
27 'Quantity' => 'Int',
28 'Sort' => 'Int',
29 );
30
31 static $has_one = array(
32 'Product' => 'Product',
33 );
34
35 static $has_many = array(
36 'ParamValues' => 'ProductParamValue',
37 );
38
39 static $searchable_fields = array('Title', 'Available', 'AllowPurchase', 'Quantity', 'VariationPrice');
40
41 static $summary_fields = array('Title', 'Available', 'AllowPurchase', 'Quantity', 'CostPrice', 'BasePrice', 'VariationPrice');
42
43 static $default_sort = "Sort";
44
45 function fieldLabels() {
46 $labels = parent::fieldLabels();
47 $labels['CostPrice'] = $labels['CostPriceOwn'];
48 $labels['BasePrice'] = $labels['BasePriceOwn'];
49 return $labels;
50 }
51
52 function getCMSFields() {
53 $fields = parent::getCMSFields();
54 $tab = $fields->findOrMakeTab('Root.Main');
55 $fields->removeByName('VariationPrice');
56
57 $fields->removeByName('ParamValues');
58 $fields->removeByName('PriceType');
59
60 $bp = $fields->dataFieldByName('BasePriceOwn');
61 $cp = $fields->dataFieldByName('CostPriceOwn');
62 $pf = new FieldGroup($bp, $cp);
63 $fields->removeByName('BasePriceOwn');
64 $fields->removeByName('CostPriceOwn');
65
66 $bpd = $fields->dataFieldByName('BasePriceDelta');
67 $cpd = $fields->dataFieldByName('CostPriceDelta');
68 $pfd = new FieldGroup($bpd, $cpd);
69 $fields->removeByName('BasePriceDelta');
70 $fields->removeByName('CostPriceDelta');
71
72 $bpp = $fields->dataFieldByName('BasePricePercent');
73 $cpp = $fields->dataFieldByName('CostPricePercent');
74 $pfp = new FieldGroup($bpp, $cpp);
75 $fields->removeByName('BasePricePercent');
76 $fields->removeByName('CostPricePercent');
77
78 $tab->insertBefore($type = new SelectionGroup('PriceType', array(
79 'own//' . _t('ProductVariation.PriceType_own', 'Price Type Own') => $pf,
80 'delta//' . _t('ProductVariation.PriceType_delta', 'Price Type Currency Diff') => $pfd,
81 'percent//' . _t('ProductVariation.PriceType_percent', 'Price Type Percents Diff') => $pfp,
82 )), 'Available');
83
84 if ($this->ProductID && $this->ID && $categoryParams = $this->Product()->Parent()->getVariationCatalogParams()) {
85 foreach($categoryParams as $categoryParam) {
86 if ($categoryParam->Type == 'bool') {
87 $tab->push(new ProductParamValue_BoolValueField('ParamValues', $categoryParam, $this->ID, 'ProductVariationID'));
88 } else {
89 if ($categoryParam->MultiValues) {
90 if ($categoryParam->PossibleValuesList()) {
91 $tab->push(new ProductParamValue_MultiValueSetField('ParamValues', $categoryParam, $this->ID, 'ProductVariationID'));
92 } else {
93 $tab->push(new LiteralField('ParamTitle', "<h4>{$categoryParam->Title}</h4>"));
94 $rate = new ProductParamValue();
95 $fieldList = array(
96 "Value" => $rate->fieldLabel('Value'),
97 );
98 $fieldTypes = array(
99 'Value' => 'TextField',
100 );
101 $ctf = new TableField("ParamValues", "ProductParamValue", $fieldList, $fieldTypes, 'ProductParamID', $categoryParam->ID);
102 $params = new DataObjectSet();
103 if ($allParamValues = DataObject::get('ProductParamValue', "ProductParamID = {$categoryParam->ID} AND ProductID = {$this->ID}")) {
104 $params = $allParamValues;
105 }
106 $ctf->setCustomSourceItems($params);
107 $tab->push($ctf);
108 }
109 } else {
110 if ($categoryParam->PossibleValuesList()) {
111 $tab->push(new ProductParamValue_MultiValueField('ParamValues', $categoryParam, $this->ID, 'ProductVariationID'));
112 } else {
113 $tab->push(new ProductParamValue_ValueField('ParamValues', $categoryParam, $this->ID, 'ProductVariationID'));
114 }
115 }
116 }
117
118 }
119 }
120 return $fields;
121 }
122
123 function OrderButtonTitle() {
124 if ($this->MenuTitle) {
125 return $this->MenuTitle;
126 }
127 return $this->Title;
128 }
129
130
131 function IsVariation() {
132 return true;
133 }
134
135 function getPhoto() {
136 return $this->Product()->Photo();
137 }
138
139 function getBasePrice() {
140 $price = 0;
141 if ($this->ProductID && ($product = $this->Product())) {
142 switch ($this->PriceType) {
143 case 'own':
144 $price = $this->BasePriceOwn;
145 break;
146 case 'delta':
147 $price = $product->BasePrice + $this->BasePriceDelta;
148 break;
149 case 'percent':
150 $price = $product->BasePrice + $product->BasePrice / 100 * $this->BasePricePercent;
151 break;
152 }
153 }
154 return $price;
155 }
156
157 function getCostPrice() {
158 $price = 0;
159 if ($this->ProductID && ($product = $this->Product())) {
160 switch ($this->PriceType) {
161 case 'own':
162 $price = $this->CostPriceOwn;
163 break;
164 case 'delta':
165 if ((int)$product->CostPrice) {
166 $price = $product->CostPrice + $this->CostPriceDelta;
167 }
168 break;
169 case 'percent':
170 if ((int)$product->CostPrice) {
171 $price = $product->CostPrice + $product->CostPrice / 100 * $this->CostPricePercent;
172 }
173 break;
174 }
175 }
176 return $price;
177 }
178
179 function NiceBasePrice() {
180 return DBField::create('CatalogPrice', $this->getBasePrice());
181 }
182
183 function NiceCostPrice() {
184 return DBField::create('CatalogPrice', $this->getCostPrice());
185 }
186
187 function Price($onlyreal=false) {
188 $real = $this->VariationPrice;
189 $client = $real;
190 $delta = 0;
191 $percent = 0;
192 if ($this->CostPrice == 0) {
193
194 $member = Member::currentUser();
195 if ($member){
196 if ($member->hasMethod('getPersonalDiscount') && $percent < $member->getPersonalDiscount()) {
197 $percent = $member->getPersonalDiscount();
198 }
199
200 if ($groups = $member->Groups()) {
201 foreach ($groups as $g) {
202 if ($g->hasMethod('Discount') && $percent < $g->Discount()) {
203 $percent = $g->Discount();
204 }
205 }
206 }
207 }
208 $this->extend('updateDiscount', $percent);
209 }
210 $sc = SiteConfig::current_site_config();
211 $ceil = $sc->CatalogDiscountCeil;
212 if ($ceil) {
213 $real = ceil($real);
214 $client = ceil($client);
215 $decimal = 0;
216 }
217 if ($percent) {
218 $delta = ($ceil) ? ceil(($real / 100) * $percent) : round(($real / 100) * $percent, 2);
219 $client = $real - $delta;
220 }
221 if ($onlyreal) {
222 return $client;
223 }
224 return new ArrayData(array(
225 'Real' => DBField::create('CatalogPrice', $real),
226 'Client' => DBField::create('CatalogPrice', $client),
227 'Delta' => DBField::create('CatalogPrice', $delta),
228 'Percent' => $percent,
229 'Discount' => ($percent > 0) ? 1 : 0,
230 'Currency' => $sc->CatalogCurrency,
231 ));
232
233 return DBField::create('CatalogPrice', ($this->CostPrice > 0) ? $this->CostPrice : $this->BasePrice);
234 }
235 236 237 238 239
240
241 function onBeforeWrite() {
242 parent::onBeforeWrite();
243 $this->VariationPrice = ($this->CostPrice > 0) ? $this->CostPrice : $this->BasePrice;
244 245 246 247 248 249
250 }
251
252 function onAfterDelete() {
253 parent::onAfterDelete();
254
255 DB::Query("DELETE FROM `ProductParamValue` WHERE ProductVariationID = {$this->ID}");
256 }
257
258
259 function ParamValue($title) {
260 if ($product = $this->Product()) {
261 $join = "JOIN ProductParam ON ProductParam.ID = ProductParamValue.ProductParamID";
262 if ($product->Parent()->OwnParams) {
263 $join .= " JOIN Catalog_EnabledParams ON ProductParam.ID = Catalog_EnabledParams.ProductParamID AND Catalog_EnabledParams.CatalogID = {$product->ParentID}";
264 }
265 $title = Convert::raw2sql($title);
266 $value = DataObject::get('ProductParamValue', "ProductVariationID = {$this->ID} AND ProductParam.TechTitle = '{$title}' ", "", $join);
267 if ($value) {
268 return $value->First();
269 }
270 }
271 return false;
272 }
273
274 275 276 277 278
279 function orderButtonClass() {
280 if (!$this->AllowPurchase) {
281 return false;
282 }
283 if ($this->VariationPrice == 0) {
284 if (Product::$order_empty_price)
285 return Product::$empty_order_button_class;
286 return false;
287 }
288 $class = Product::$order_button_class;
289 $this->extend('updateOrderButtonClass', $class);
290 return $class;
291 }
292
293 294 295 296 297
298 function OrderButton() {
299 $buttonClass = $this->orderButtonClass();
300 if (!$buttonClass)
301 return false;
302 return new $buttonClass($this->ProductID, $this->ID);
303 }
304
305 306 307 308 309
310 function OrderButtonWithNum() {
311 if ($button = $this->OrderButton()) {
312 return $button->WithNum();
313 }
314 return false;
315 }
316
317 function OrderButtonLink() {
318 return $this->Product()->VariationOrderButtonLink($this->ID);
319 }
320
321 function PurchaseStatus() {
322 if (!$this->Available && !$this->AllowPurchase) {
323 return 'NoOrder';
324 }
325 if (!$this->Available && $this->AllowPurchase) {
326 return 'PreOrder';
327 }
328 if ($this->Available && !$this->AllowPurchase) {
329 return 'NoOrder';
330 }
331 if ($this->Available && $this->AllowPurchase) {
332 return 'InStock';
333 }
334 return 'NoOrder';
335 }
336
337 function PurchaseStatusTitle() {
338 return _t('ProductVariation.PurchaseStatus_' . $this->PurchaseStatus());
339 }
340
341 function canOrder() {
342 if (in_array($this->PurchaseStatus(), array('PreOrder', 'InStock'))) {
343 return true;
344 }
345 return false;
346 }
347
348 function VariationInfo() {
349 $info = array();
350 $info['Title'] = $this->Title;
351 $info['Available'] = (bool)$this->Available;
352 $info['AllowPurchase'] = (bool)$this->AllowPurchase;
353 $info['SKU'] = $this->SKU;
354 $info['Quantity'] = (int)$this->Quantity;
355 $info['CostPrice'] = (float)$this->getCostPrice();
356 $info['BasePrice'] = (float)$this->getBasePrice();
357 $info['Price'] = (float)$this->Price(1);
358 return $info;
359 }
360
361
362 function AttributeProxy(){
363 $do = new DataObject();
364 if($this->ParamValues()->exists()){
365 foreach($this->ParamValues() as $value){
366 $do->{'Val'.$value->TechTitle} = $value->Value;
367 }
368 }
369 return $do;
370 }
371
372 }
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-