1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0 |
5
|
|
|
* @copyright Metaways Infosystems GmbH, 2012 |
6
|
|
|
* @copyright Aimeos (aimeos.org), 2015-2016 |
7
|
|
|
* @package Controller |
8
|
|
|
* @subpackage Frontend |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
|
12
|
|
|
namespace Aimeos\Controller\Frontend\Basket; |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Base class for the basket frontend controller |
17
|
|
|
* |
18
|
|
|
* @package Controller |
19
|
|
|
* @subpackage Frontend |
20
|
|
|
*/ |
21
|
|
|
abstract class Base extends \Aimeos\Controller\Frontend\Base |
22
|
|
|
{ |
23
|
|
|
private $listTypeAttributes = array(); |
24
|
|
|
|
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Calculates and returns the current price for the given order product and product prices. |
28
|
|
|
* |
29
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Product\Iface $product Ordered product item |
30
|
|
|
* @param \Aimeos\MShop\Price\Item\Iface[] $prices List of price items |
31
|
|
|
* @param integer $quantity New product quantity |
32
|
|
|
* @return \Aimeos\MShop\Price\Item\Iface Price item with calculated price |
33
|
|
|
*/ |
34
|
|
|
protected function calcPrice( \Aimeos\MShop\Order\Item\Base\Product\Iface $product, array $prices, $quantity ) |
35
|
|
|
{ |
36
|
|
|
$context = $this->getContext(); |
37
|
|
|
|
38
|
|
|
if( empty( $prices ) ) |
39
|
|
|
{ |
40
|
|
|
$parentItem = $this->getDomainItem( 'product', 'product.id', $product->getProductId(), array( 'price' ) ); |
41
|
|
|
$prices = $parentItem->getRefItems( 'price', 'default' ); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
$priceManager = \Aimeos\MShop\Factory::createManager( $context, 'price' ); |
45
|
|
|
$price = $priceManager->getLowestPrice( $prices, $quantity ); |
46
|
|
|
|
47
|
|
|
foreach( $this->getAttributeItems( $product->getAttributes() ) as $attrItem ) |
48
|
|
|
{ |
49
|
|
|
$prices = $attrItem->getRefItems( 'price', 'default' ); |
50
|
|
|
|
51
|
|
|
if( count( $prices ) > 0 ) |
52
|
|
|
{ |
53
|
|
|
$attrPrice = $priceManager->getLowestPrice( $prices, $quantity ); |
54
|
|
|
$price->addItem( $attrPrice ); |
55
|
|
|
} |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
// remove product rebate of original price in favor to rebates granted for the order |
59
|
|
|
$price->setRebate( '0.00' ); |
60
|
|
|
|
61
|
|
|
return $price; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Checks if the IDs of the given items are really associated to the product. |
67
|
|
|
* |
68
|
|
|
* @param string $prodId Unique ID of the product |
69
|
|
|
* @param string $domain Domain the references must be of |
70
|
|
|
* @param integer $listTypeId ID of the list type the referenced items must be |
71
|
|
|
* @param array $refIds List of IDs that must be associated to the product |
72
|
|
|
* @throws \Aimeos\Controller\Frontend\Basket\Exception If one or more of the IDs are not associated |
73
|
|
|
*/ |
74
|
|
|
protected function checkReferences( $prodId, $domain, $listTypeId, array $refIds ) |
75
|
|
|
{ |
76
|
|
|
$productManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product' ); |
77
|
|
|
$search = $productManager->createSearch( true ); |
78
|
|
|
|
79
|
|
|
$expr = array( |
80
|
|
|
$search->compare( '==', 'product.id', $prodId ), |
81
|
|
|
$search->getConditions(), |
82
|
|
|
); |
83
|
|
|
|
84
|
|
|
if( count( $refIds ) > 0 ) |
85
|
|
|
{ |
86
|
|
|
foreach( $refIds as $key => $refId ) { |
87
|
|
|
$refIds[$key] = (string) $refId; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
$param = array( $domain, $listTypeId, $refIds ); |
91
|
|
|
$cmpfunc = $search->createFunction( 'product.contains', $param ); |
92
|
|
|
|
93
|
|
|
$expr[] = $search->compare( '==', $cmpfunc, count( $refIds ) ); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
97
|
|
|
|
98
|
|
|
if( count( $productManager->searchItems( $search, array() ) ) === 0 ) |
99
|
|
|
{ |
100
|
|
|
$msg = sprintf( 'Invalid "%1$s" references for product with ID "%2$s"', $domain, $prodId ); |
101
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Creates the order product attribute items from the given attribute IDs and updates the price item if necessary. |
108
|
|
|
* |
109
|
|
|
* @param \Aimeos\MShop\Price\Item\Iface $price Price item of the ordered product |
110
|
|
|
* @param string $prodid Unique product ID where the given attributes must be attached to |
111
|
|
|
* @param integer $quantity Number of products that should be added to the basket |
112
|
|
|
* @param array $attributeIds List of attributes IDs of the given type |
113
|
|
|
* @param string $type Attribute type |
114
|
|
|
* @param array $attributeValues Associative list of attribute IDs as keys and their codes as values |
115
|
|
|
* @return array List of items implementing \Aimeos\MShop\Order\Item\Product\Attribute\Iface |
116
|
|
|
*/ |
117
|
|
|
protected function createOrderProductAttributes( \Aimeos\MShop\Price\Item\Iface $price, $prodid, $quantity, |
118
|
|
|
array $attributeIds, $type, array $attributeValues = array() ) |
119
|
|
|
{ |
120
|
|
|
if( empty( $attributeIds ) ) { |
121
|
|
|
return array(); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$attrTypeId = $this->getProductListTypeItem( 'attribute', $type )->getId(); |
125
|
|
|
$this->checkReferences( $prodid, 'attribute', $attrTypeId, $attributeIds ); |
126
|
|
|
|
127
|
|
|
$list = array(); |
128
|
|
|
$context = $this->getContext(); |
129
|
|
|
|
130
|
|
|
$priceManager = \Aimeos\MShop\Factory::createManager( $context, 'price' ); |
131
|
|
|
$orderProductAttributeManager = \Aimeos\MShop\Factory::createManager( $context, 'order/base/product/attribute' ); |
132
|
|
|
|
133
|
|
|
foreach( $this->getAttributes( $attributeIds ) as $id => $attrItem ) |
134
|
|
|
{ |
135
|
|
|
$prices = $attrItem->getRefItems( 'price', 'default', 'default' ); |
136
|
|
|
|
137
|
|
|
if( !empty( $prices ) ) { |
138
|
|
|
$price->addItem( $priceManager->getLowestPrice( $prices, $quantity ) ); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
$item = $orderProductAttributeManager->createItem(); |
142
|
|
|
$item->copyFrom( $attrItem ); |
143
|
|
|
$item->setType( $type ); |
144
|
|
|
|
145
|
|
|
if( isset( $attributeValues[$id] ) ) { |
146
|
|
|
$item->setValue( $attributeValues[$id] ); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$list[] = $item; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
return $list; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Returns the attribute items for the given attribute IDs. |
158
|
|
|
* |
159
|
|
|
* @param array $attributeIds List of attribute IDs |
160
|
|
|
* @param string[] $domains Names of the domain items that should be fetched too |
161
|
|
|
* @return array List of items implementing \Aimeos\MShop\Attribute\Item\Iface |
162
|
|
|
* @throws \Aimeos\Controller\Frontend\Basket\Exception If the actual attribute number doesn't match the expected one |
163
|
|
|
*/ |
164
|
|
|
protected function getAttributes( array $attributeIds, array $domains = array( 'price', 'text' ) ) |
165
|
|
|
{ |
166
|
|
|
if( empty( $attributeIds ) ) { |
167
|
|
|
return array(); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
$attributeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'attribute' ); |
171
|
|
|
|
172
|
|
|
$search = $attributeManager->createSearch( true ); |
173
|
|
|
$expr = array( |
174
|
|
|
$search->compare( '==', 'attribute.id', $attributeIds ), |
175
|
|
|
$search->getConditions(), |
176
|
|
|
); |
177
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
178
|
|
|
$search->setSlice( 0, 0x7fffffff ); |
179
|
|
|
|
180
|
|
|
$attrItems = $attributeManager->searchItems( $search, $domains ); |
181
|
|
|
|
182
|
|
|
if( count( $attrItems ) !== count( $attributeIds ) ) |
183
|
|
|
{ |
184
|
|
|
$expected = implode( ',', $attributeIds ); |
185
|
|
|
$actual = implode( ',', array_keys( $attrItems ) ); |
186
|
|
|
$msg = sprintf( 'Available attribute IDs "%1$s" do not match the given attribute IDs "%2$s"', $actual, $expected ); |
187
|
|
|
|
188
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
return $attrItems; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Returns the attribute items using the given order attribute items. |
197
|
|
|
* |
198
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Product\Attribute\Item[] $orderAttributes List of order product attribute items |
199
|
|
|
* @return \Aimeos\MShop\Attribute\Item\Iface[] Associative list of attribute IDs as key and attribute items as values |
200
|
|
|
*/ |
201
|
|
|
protected function getAttributeItems( array $orderAttributes ) |
202
|
|
|
{ |
203
|
|
|
if( empty( $orderAttributes ) ) { |
204
|
|
|
return array(); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
$attributeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'attribute' ); |
208
|
|
|
$search = $attributeManager->createSearch( true ); |
209
|
|
|
$expr = array(); |
210
|
|
|
|
211
|
|
|
foreach( $orderAttributes as $item ) |
212
|
|
|
{ |
213
|
|
|
$tmp = array( |
214
|
|
|
$search->compare( '==', 'attribute.domain', 'product' ), |
215
|
|
|
$search->compare( '==', 'attribute.code', $item->getValue() ), |
216
|
|
|
$search->compare( '==', 'attribute.type.domain', 'product' ), |
217
|
|
|
$search->compare( '==', 'attribute.type.code', $item->getCode() ), |
218
|
|
|
$search->compare( '>', 'attribute.type.status', 0 ), |
219
|
|
|
$search->getConditions(), |
220
|
|
|
); |
221
|
|
|
$expr[] = $search->combine( '&&', $tmp ); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
$search->setConditions( $search->combine( '||', $expr ) ); |
225
|
|
|
return $attributeManager->searchItems( $search, array( 'price' ) ); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Retrieves the domain item specified by the given key and value. |
231
|
|
|
* |
232
|
|
|
* @param string $domain Product manager search key |
233
|
|
|
* @param string $key Domain manager search key |
234
|
|
|
* @param string $value Unique domain identifier |
235
|
|
|
* @param string[] $ref List of referenced items that should be fetched too |
236
|
|
|
* @return \Aimeos\MShop\Common\Item\Iface Domain item object |
237
|
|
|
* @throws \Aimeos\Controller\Frontend\Basket\Exception |
238
|
|
|
*/ |
239
|
|
|
protected function getDomainItem( $domain, $key, $value, array $ref ) |
240
|
|
|
{ |
241
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $domain ); |
242
|
|
|
|
243
|
|
|
$search = $manager->createSearch( true ); |
244
|
|
|
$expr = array( |
245
|
|
|
$search->compare( '==', $key, $value ), |
246
|
|
|
$search->getConditions(), |
247
|
|
|
); |
248
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
249
|
|
|
|
250
|
|
|
$result = $manager->searchItems( $search, $ref ); |
251
|
|
|
|
252
|
|
|
if( ( $item = reset( $result ) ) === false ) |
253
|
|
|
{ |
254
|
|
|
$msg = sprintf( 'No item for "%1$s" (%2$s) found', $value, $key ); |
255
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
return $item; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Returns the list type item for the given domain and code. |
264
|
|
|
* |
265
|
|
|
* @param string $domain Domain name of the list type |
266
|
|
|
* @param string $code Code of the list type |
267
|
|
|
* @return \Aimeos\MShop\Common\Item\Type\Iface List type item |
268
|
|
|
*/ |
269
|
|
|
protected function getProductListTypeItem( $domain, $code ) |
270
|
|
|
{ |
271
|
|
|
if( !isset( $this->listTypeAttributes[$domain][$code] ) ) |
272
|
|
|
{ |
273
|
|
|
$listTypeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product/lists/type' ); |
274
|
|
|
|
275
|
|
|
$listTypeSearch = $listTypeManager->createSearch( true ); |
276
|
|
|
$expr = array( |
277
|
|
|
$listTypeSearch->compare( '==', 'product.lists.type.domain', $domain ), |
278
|
|
|
$listTypeSearch->compare( '==', 'product.lists.type.code', $code ), |
279
|
|
|
$listTypeSearch->getConditions(), |
280
|
|
|
); |
281
|
|
|
$listTypeSearch->setConditions( $listTypeSearch->combine( '&&', $expr ) ); |
282
|
|
|
|
283
|
|
|
$listTypeItems = $listTypeManager->searchItems( $listTypeSearch ); |
284
|
|
|
|
285
|
|
|
if( ( $listTypeItem = reset( $listTypeItems ) ) === false ) |
286
|
|
|
{ |
287
|
|
|
$msg = sprintf( 'List type for domain "%1$s" and code "%2$s" not found', $domain, $code ); |
288
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
$this->listTypeAttributes[$domain][$code] = $listTypeItem; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
return $this->listTypeAttributes[$domain][$code]; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Returns the product variants of a selection product that match the given attributes. |
300
|
|
|
* |
301
|
|
|
* @param \Aimeos\MShop\Product\Item\Iface $productItem Product item including sub-products |
302
|
|
|
* @param array $variantAttributeIds IDs for the variant-building attributes |
303
|
|
|
* @param array $domains Names of the domain items that should be fetched too |
304
|
|
|
* @return array List of products matching the given attributes |
305
|
|
|
*/ |
306
|
|
|
protected function getProductVariants( \Aimeos\MShop\Product\Item\Iface $productItem, array $variantAttributeIds, |
307
|
|
|
array $domains = array( 'attribute', 'media', 'price', 'text' ) ) |
308
|
|
|
{ |
309
|
|
|
$subProductIds = array(); |
310
|
|
|
foreach( $productItem->getRefItems( 'product', 'default', 'default' ) as $item ) { |
311
|
|
|
$subProductIds[] = $item->getId(); |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
if( count( $subProductIds ) === 0 ) { |
315
|
|
|
return array(); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
$productManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product' ); |
319
|
|
|
$search = $productManager->createSearch( true ); |
320
|
|
|
|
321
|
|
|
$expr = array( |
322
|
|
|
$search->compare( '==', 'product.id', $subProductIds ), |
323
|
|
|
$search->getConditions(), |
324
|
|
|
); |
325
|
|
|
|
326
|
|
|
if( count( $variantAttributeIds ) > 0 ) |
327
|
|
|
{ |
328
|
|
|
foreach( $variantAttributeIds as $key => $id ) { |
329
|
|
|
$variantAttributeIds[$key] = (string) $id; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
$listTypeItem = $this->getProductListTypeItem( 'attribute', 'variant' ); |
333
|
|
|
|
334
|
|
|
$param = array( 'attribute', $listTypeItem->getId(), $variantAttributeIds ); |
335
|
|
|
$cmpfunc = $search->createFunction( 'product.contains', $param ); |
336
|
|
|
|
337
|
|
|
$expr[] = $search->compare( '==', $cmpfunc, count( $variantAttributeIds ) ); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
341
|
|
|
|
342
|
|
|
return $productManager->searchItems( $search, $domains ); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* Returns the value of an array or the default value if it's not available. |
348
|
|
|
* |
349
|
|
|
* @param array $values Associative list of key/value pairs |
350
|
|
|
* @param string $name Name of the key to return the value for |
351
|
|
|
* @param mixed $default Default value if no value is available for the given name |
352
|
|
|
* @return mixed Value from the array or default value |
353
|
|
|
*/ |
354
|
|
|
protected function getValue( array $values, $name, $default = null ) |
355
|
|
|
{ |
356
|
|
|
if( isset( $values[$name] ) ) { |
357
|
|
|
return $values[$name]; |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
return $default; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* Checks if the product is part of at least one category in the product catalog. |
366
|
|
|
* |
367
|
|
|
* @param string $prodid Unique ID of the product |
368
|
|
|
* @throws \Aimeos\Controller\Frontend\Basket\Exception If product is not associated to at least one category |
369
|
|
|
* @deprecated 2016.05 |
370
|
|
|
*/ |
371
|
|
|
protected function checkCategory( $prodid ) |
372
|
|
|
{ |
373
|
|
|
$catalogListManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog/lists' ); |
374
|
|
|
|
375
|
|
|
$search = $catalogListManager->createSearch( true ); |
376
|
|
|
$expr = array( |
377
|
|
|
$search->compare( '==', 'catalog.lists.refid', $prodid ), |
378
|
|
|
$search->getConditions() |
379
|
|
|
); |
380
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
381
|
|
|
$search->setSlice( 0, 1 ); |
382
|
|
|
|
383
|
|
|
$result = $catalogListManager->searchItems( $search ); |
384
|
|
|
|
385
|
|
|
if( reset( $result ) === false ) |
386
|
|
|
{ |
387
|
|
|
$msg = sprintf( 'Adding product with ID "%1$s" is not allowed', $prodid ); |
388
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
389
|
|
|
} |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* Edits the changed product to the basket if it's in stock. |
395
|
|
|
* |
396
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Product\Iface $orderBaseProductItem Old order product from basket |
397
|
|
|
* @param string $productId Unique ID of the product item that belongs to the order product |
398
|
|
|
* @param integer $quantity Number of products to add to the basket |
399
|
|
|
* @param array $options Associative list of options |
400
|
|
|
* @param string $warehouse Warehouse code for retrieving the stock level |
401
|
|
|
* @throws \Aimeos\Controller\Frontend\Basket\Exception If there's not enough stock available |
402
|
|
|
* @deprecated 2016.05 |
403
|
|
|
*/ |
404
|
|
|
protected function addProductInStock( \Aimeos\MShop\Order\Item\Base\Product\Iface $orderBaseProductItem, |
405
|
|
|
$productId, $quantity, array $options, $warehouse ) |
406
|
|
|
{ |
407
|
|
|
$stocklevel = null; |
408
|
|
|
if( !isset( $options['stock'] ) || $options['stock'] != false ) { |
409
|
|
|
$stocklevel = $this->getStockLevel( $productId, $warehouse ); |
|
|
|
|
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
if( $stocklevel === null || $stocklevel > 0 ) |
413
|
|
|
{ |
414
|
|
|
$position = $this->get()->addProduct( $orderBaseProductItem ); |
|
|
|
|
415
|
|
|
$orderBaseProductItem = clone $this->get()->getProduct( $position ); |
|
|
|
|
416
|
|
|
$quantity = $orderBaseProductItem->getQuantity(); |
417
|
|
|
|
418
|
|
|
if( $stocklevel > 0 && $stocklevel < $quantity ) |
419
|
|
|
{ |
420
|
|
|
$this->get()->deleteProduct( $position ); |
|
|
|
|
421
|
|
|
$orderBaseProductItem->setQuantity( $stocklevel ); |
422
|
|
|
$this->get()->addProduct( $orderBaseProductItem, $position ); |
|
|
|
|
423
|
|
|
} |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
if( $stocklevel !== null && $stocklevel < $quantity ) |
427
|
|
|
{ |
428
|
|
|
$msg = sprintf( 'There are not enough products "%1$s" in stock', $orderBaseProductItem->getName() ); |
429
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
430
|
|
|
} |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* Edits the changed product to the basket if it's in stock. |
436
|
|
|
* |
437
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Product\Iface $product Old order product from basket |
438
|
|
|
* @param \Aimeos\MShop\Product\Item\Iface $productItem Product item that belongs to the order product |
439
|
|
|
* @param integer $quantity New product quantity |
440
|
|
|
* @param integer $position Position of the old order product in the basket |
441
|
|
|
* @param array Associative list of options |
442
|
|
|
* @throws \Aimeos\Controller\Frontend\Basket\Exception If there's not enough stock available |
443
|
|
|
* @deprecated 2016.05 |
444
|
|
|
*/ |
445
|
|
|
protected function editProductInStock( \Aimeos\MShop\Order\Item\Base\Product\Iface $product, |
446
|
|
|
\Aimeos\MShop\Product\Item\Iface $productItem, $quantity, $position, array $options ) |
447
|
|
|
{ |
448
|
|
|
$stocklevel = null; |
449
|
|
|
if( !isset( $options['stock'] ) || $options['stock'] != false ) { |
450
|
|
|
$stocklevel = $this->getStockLevel( $productItem->getId(), $product->getWarehouseCode() ); |
|
|
|
|
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
$product->setQuantity( ( $stocklevel !== null && $stocklevel > 0 ? min( $stocklevel, $quantity ) : $quantity ) ); |
454
|
|
|
|
455
|
|
|
$this->get()->deleteProduct( $position ); |
|
|
|
|
456
|
|
|
|
457
|
|
|
if( $stocklevel === null || $stocklevel > 0 ) { |
458
|
|
|
$this->get()->addProduct( $product, $position ); |
|
|
|
|
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
if( $stocklevel !== null && $stocklevel < $quantity ) |
462
|
|
|
{ |
463
|
|
|
$msg = sprintf( 'There are not enough products "%1$s" in stock', $productItem->getName() ); |
464
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
465
|
|
|
} |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
|
469
|
|
|
/** |
470
|
|
|
* Returns the highest stock level for the product. |
471
|
|
|
* |
472
|
|
|
* @param string $prodid Unique ID of the product |
473
|
|
|
* @param string $warehouse Unique code of the warehouse |
474
|
|
|
* @return integer|null Number of available items in stock (null for unlimited stock) |
475
|
|
|
* @deprecated 2016.04 Use basket stock decorator instead |
476
|
|
|
*/ |
477
|
|
|
protected function getStockLevel( $prodid, $warehouse ) |
478
|
|
|
{ |
479
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'product/stock' ); |
480
|
|
|
|
481
|
|
|
$search = $manager->createSearch( true ); |
482
|
|
|
$expr = array( |
483
|
|
|
$search->compare( '==', 'product.stock.parentid', $prodid ), |
484
|
|
|
$search->getConditions(), |
485
|
|
|
$search->compare( '==', 'product.stock.warehouse.code', $warehouse ), |
486
|
|
|
); |
487
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
488
|
|
|
|
489
|
|
|
$result = $manager->searchItems( $search ); |
490
|
|
|
|
491
|
|
|
if( empty( $result ) ) |
492
|
|
|
{ |
493
|
|
|
$msg = sprintf( 'No stock for product ID "%1$s" and warehouse "%2$s" available', $prodid, $warehouse ); |
494
|
|
|
throw new \Aimeos\Controller\Frontend\Basket\Exception( $msg ); |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
$stocklevel = null; |
498
|
|
|
|
499
|
|
|
foreach( $result as $item ) |
500
|
|
|
{ |
501
|
|
|
if( ( $stock = $item->getStockLevel() ) === null ) { |
502
|
|
|
return null; |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
$stocklevel = max( (int) $stocklevel, $item->getStockLevel() ); |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
return $stocklevel; |
509
|
|
|
} |
510
|
|
|
} |
511
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.