Commit 2bd1fc70 authored by Thorsten Buss's avatar Thorsten Buss

convert item conditions to collection

parent 1558f858
......@@ -248,21 +248,7 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
*/
public function addItemCondition($productId, Condition $itemCondition) {
if ($product = $this->get($productId)) {
// we need to copy first to a temporary variable to hold the conditions
// to avoid hitting this error "Indirect modification of overloaded element of Bnet\Cart\Item has no effect"
// this is due to laravel Collection instance that implements Array Access
// // see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
$itemConditionTempHolder = $product['conditions'];
if (is_array($itemConditionTempHolder)) {
array_push($itemConditionTempHolder, $itemCondition);
} else {
$itemConditionTempHolder = $itemCondition;
}
$this->update($productId, array(
'conditions' => $itemConditionTempHolder // the newly updated conditions
));
$product->conditions[$itemCondition->getName()] = $itemCondition;
}
return $this;
......@@ -410,45 +396,8 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
return false;
}
if ($this->itemHasConditions($item)) {
// NOTE:
// we do it this way, we get first conditions and store
// it in a temp variable $originalConditions, then we will modify the array there
// and after modification we will store it again on $item['conditions']
// This is because of ArrayAccess implementation
// see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
$tempConditionsHolder = $item['conditions'];
// if the item's conditions is in array format
// we will iterate through all of it and check if the name matches
// to the given name the user wants to remove, if so, remove it
if (is_array($tempConditionsHolder)) {
foreach ($tempConditionsHolder as $k => $condition) {
if ($condition->getName() == $conditionName) {
unset($tempConditionsHolder[$k]);
}
}
$item['conditions'] = $tempConditionsHolder;
}
// if the item condition is not an array, we will check if it is
// an instance of a Condition, if so, we will check if the name matches
// on the given condition name the user wants to remove, if so,
// lets just make $item['conditions'] an empty array as there's just 1 condition on it anyway
else {
if ($item['conditions'] instanceof Condition) {
if ($tempConditionsHolder->getName() == $conditionName) {
$item['conditions'] = array();
}
}
}
}
$this->update($itemId, array(
'conditions' => $item['conditions']
));
if ($this->itemHasConditions($item))
return $item->conditions->offsetUnset($conditionName);
return true;
}
......@@ -464,10 +413,7 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
return false;
}
$this->update($itemId, array(
'conditions' => array()
));
$item['conditions'] = collect([]);
return true;
}
......@@ -626,13 +572,7 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
* @return bool
*/
protected function itemHasConditions($item) {
if (!isset($item['conditions']))
return false;
if (is_array($item['conditions']))
return count($item['conditions']) > 0;
return $item['conditions'] instanceof Condition;
return !$item->conditions->isEmpty();
}
/**
......
......@@ -51,26 +51,16 @@ class CurrencyItem extends Item {
*/
public function priceWithConditions() {
$originalPrice = $this->price->amount();
$newPrice = 0;
if ($this->hasConditions()) {
if (is_array($this->conditions)) {
foreach ($this->conditions as $condition) {
if ($condition->getTarget() === 'item') {
$newPrice += $condition->applyCondition($originalPrice);
}
}
} else {
if ($this['conditions']->getTarget() === 'item') {
$newPrice = $this['conditions']->applyCondition($originalPrice);
}
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
if ($condition && $condition->getTarget() === 'item') {
return $condition->getTarget() === 'item'
? $condition->applyCondition($originalPrice)
: 0;
}
$newPrice = (int)($originalPrice + $newPrice);
$newPrice = $newPrice > 0 ? $newPrice : 0;
return new Money($newPrice, $this->currency);
}
return new Money((int)$originalPrice, $this->currency);
});
$newPrice = $this->returnPriceAboveZero($condition_price + $originalPrice);
return new Money((int)$newPrice, $this->currency);
}
/**
......@@ -80,25 +70,16 @@ class CurrencyItem extends Item {
*/
public function priceSumWithConditions() {
$originalPrice = $this->price->amount();
$newPrice = 0;
if ($this->hasConditions()) {
if (is_array($this->conditions)) {
foreach ($this->conditions as $condition) {
if ($condition->getTarget() === 'item') {
$newPrice += $condition->applyConditionWithQuantity($originalPrice, $this->quantity);
}
}
} else {
if ($this['conditions']->getTarget() === 'item') {
$newPrice = $this['conditions']->applyConditionWithQuantity($originalPrice, $this->quantity);
}
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
if ($condition && $condition->getTarget() === 'item') {
return $condition->getTarget() === 'item'
? $condition->applyConditionWithQuantity($originalPrice, $this->quantity)
: 0;
}
$newPrice += ($this->quantity * $originalPrice);
return new Money((int)($newPrice > 0 ? $newPrice : 0), $this->currency);
}
$m = new Money((int)$originalPrice, $this->currency);
return $m->multiply($this->quantity);
});
$newPrice = $this->returnPriceAboveZero($condition_price + ($this->quantity * $originalPrice));
return new Money((int)$newPrice, $this->currency);
}
}
\ No newline at end of file
......@@ -27,22 +27,8 @@ class Item extends Collection {
* @return void
*/
public function __construct($attributes) {
// make conditions as array and set target to item if not set
if (isset($attributes['conditions']) && !empty($attributes['conditions'])) {
// force conditions as array
if (!is_array($attributes['conditions']))
$attributes['conditions'] = [$attributes['conditions']];
// check/set the target
collect($attributes['conditions'])->transform(function ($condition) {
if ($condition instanceof Condition) {
if ($condition->getTarget() == 'cart')
return false;
$condition->setTarget('item');
} else
$condition['target'] = 'item';
});
}
$attributes['conditions'] = $this->prepareConditionCollection($attributes);
parent::__construct($attributes);
}
......@@ -76,13 +62,7 @@ class Item extends Collection {
* @return bool
*/
public function hasConditions() {
if (!isset($this['conditions']))
return false;
if (is_array($this['conditions']))
return count($this['conditions']) > 0;
return $this['conditions'] instanceof Condition;
return !$this->conditions || !$this->conditions->isEmpty();
}
/**
......@@ -100,21 +80,13 @@ class Item extends Collection {
*/
public function priceWithConditions() {
$originalPrice = $this->price();
$newPrice = 0;
if ($this->hasConditions()) {
if (is_array($this->conditions)) {
foreach ($this->conditions as $condition) {
if ($condition->getTarget() === 'item') {
$newPrice += $condition->applyCondition($originalPrice);
}
}
}
$newPrice = (int)($originalPrice + $newPrice);
$newPrice = $newPrice > 0 ? $newPrice : 0;
return $newPrice;
}
return $originalPrice;
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
return ($condition && $condition->getTarget() === 'item')
? $condition->applyCondition($originalPrice)
: 0;
});
return $this->returnPriceAboveZero($condition_price + ($this->quantity * $originalPrice));
}
/**
......@@ -124,21 +96,24 @@ class Item extends Collection {
*/
public function priceSumWithConditions() {
$originalPrice = $this->price();
$newPrice = 0;
if ($this->hasConditions()) {
if (is_array($this->conditions)) {
foreach ($this->conditions as $condition) {
if ($condition->getTarget() === 'item') {
$newPrice += $condition->applyConditionWithQuantity($originalPrice, $this->quantity);
}
}
}
$newPrice += ($this->quantity * $originalPrice);
return $newPrice > 0 ? $newPrice : 0;
}
return $originalPrice * $this->quantity;
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
return ($condition && $condition->getTarget() === 'item')
? $condition->applyConditionWithQuantity($originalPrice, $this->quantity)
: 0;
});
return $this->returnPriceAboveZero($condition_price + ($this->quantity * $originalPrice));
}
/**
* assert that the price is > 0
* @param $price
* @return int
*/
protected function returnPriceAboveZero($price) {
return $price > 0
? $price
: 0;
}
/**
......@@ -149,13 +124,50 @@ class Item extends Collection {
public function toArray() {
$arr = parent::toArray();
if (!empty($arr['conditions'])) {
$cond = $arr['conditions'];
unset($arr['conditions']);
foreach ($cond as $k => $v) {
$arr['conditions'][$v->getName()] = $v->toArray();
}
/** @var Collection $cond */
$cond = $this['conditions'];
$arr['conditions'] = $cond->keyBy('name')->toArray();
}
return $arr;
}
/**
* make conditions as array and set target to item if not set
* @param $attributes
* @return mixed
*/
protected function prepareConditionCollection($attributes) {
if (!isset($attributes['conditions']))
$conditions = collect([]);
elseif ($attributes['conditions'] instanceOf Condition || !is_array($attributes['conditions']))
$conditions = collect([$attributes['conditions']]);
else
$conditions = collect($attributes['conditions']);
$uniqueKeys = collect(); //list of keys to garantie uniquness
// check/set the target
$conditions = $conditions->map(function ($condition) {
if (!$condition instanceof Condition)
$condition = new Condition($condition);
// ignore target==cart conditions
if ($condition->getTarget() == 'cart')
return false;
$condition->setTarget('item'); // set item as default it not set
return $condition;
})->keyBy(function ($cond) use (&$uniqueKeys) {
// use name as key and verify that the key is unique
$key = $cond->name;
$postfix = '';
while ($uniqueKeys->contains($key . $postfix)) {
$postfix = empty($postfix) ? 1 : ($postfix + 1);
}
$uniqueKeys->push($key . $postfix);
return $key . $postfix;
});
return $conditions;
}
}
......@@ -540,7 +540,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$this->cart->removeItemCondition(456, 'SALE 5%');
// now we should have only 1 condition left on that item
$this->assertEmpty($this->cart->get(456)['conditions'], 'Item should have no condition now');
$this->assertEmpty($this->cart->get(456)->conditions, 'Item should have no condition now');
}
public function test_clear_item_conditions() {
......@@ -832,7 +832,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
'value' => '+10%'
));
$itemCondition2 = new Condition(array(
'name' => 'Test 10%',
'name' => 'Test 10% per Item',
'type' => 'sale',
'target' => 'item',
'quantity_undepended' => false,
......@@ -882,6 +882,49 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$this->assertEquals(750, $itemCondition3->applyConditionWithQuantity(0, 3), 'Quantitycondition');
$this->assertEquals(750, $itemCondition3->applyConditionWithQuantity(1000, 3), 'Quantitycondition +itemAmount');
$this->assertEquals(35250, $this->cart->subTotal(), 'match subTotal');
$this->assertEquals(35250, $this->cart->total(), 'match total');
}
public function test_two_conditions_with_same_name() {
$itemCondition = new Condition(array(
'name' => 'Test1',
'type' => 'sale',
'target' => 'item',
'quantity_undepended' => true,
'value' => '500'
));
$itemCondition1 = new Condition(array(
'name' => 'Test1',
'type' => 'sale',
'target' => 'item',
'quantity_undepended' => true,
'value' => '500'
));
$item = array(
'id' => 456,
'name' => 'Sample Item 1',
'price' => 10000,
'quantity' => 3,
'conditions' => [
$itemCondition,
$itemCondition1,
],
);
$this->cart->add($item);
$this->assertEquals(500, $itemCondition->applyCondition(0), 'condition');
$this->assertEquals(500, $itemCondition->applyConditionWithQuantity(0, 3), 'Quantitycondition');
$this->assertEquals(500, $itemCondition->applyConditionWithQuantity(1000, 3), 'Quantitycondition +itemAmount');
$this->assertEquals(500, $itemCondition1->applyCondition(0), 'condition');
$this->assertEquals(500, $itemCondition1->applyConditionWithQuantity(0, 3), 'Quantitycondition');
$this->assertEquals(500, $itemCondition1->applyConditionWithQuantity(1000, 3), 'Quantitycondition +itemAmount');
$this->assertEquals(31000, $this->cart->total(), 'match total');
}
}
......@@ -903,7 +903,7 @@ class CurrencyCartConditionTest extends PHPUnit_Framework_TestCase {
'value' => '+10%'
));
$itemCondition2 = new CurrencyCondition(array(
'name' => 'Test 10%',
'name' => 'Test 10% per Item',
'type' => 'sale',
'target' => 'item',
'quantity_undepended' => false,
......@@ -955,4 +955,45 @@ class CurrencyCartConditionTest extends PHPUnit_Framework_TestCase {
$this->assertEquals(35250, $this->cart->total()->amount(), 'match total');
}
public function test_two_conditions_with_same_name() {
$itemCondition = new CurrencyCondition(array(
'name' => 'Test1',
'type' => 'sale',
'target' => 'item',
'quantity_undepended' => true,
'value' => new Money(500)
));
$itemCondition1 = new CurrencyCondition(array(
'name' => 'Test1',
'type' => 'sale',
'target' => 'item',
'quantity_undepended' => true,
'value' => new Money(500)
));
$item = array(
'id' => 456,
'name' => 'Sample Item 1',
'price' => new Money(10000),
'quantity' => 3,
'conditions' => [
$itemCondition,
$itemCondition1,
],
);
$this->cart->add($item);
$this->assertEquals(500, $itemCondition->applyCondition(0), 'condition');
$this->assertEquals(500, $itemCondition->applyConditionWithQuantity(0, 3), 'Quantitycondition');
$this->assertEquals(500, $itemCondition->applyConditionWithQuantity(1000, 3), 'Quantitycondition +itemAmount');
$this->assertEquals(500, $itemCondition1->applyCondition(0), 'condition');
$this->assertEquals(500, $itemCondition1->applyConditionWithQuantity(0, 3), 'Quantitycondition');
$this->assertEquals(500, $itemCondition1->applyConditionWithQuantity(1000, 3), 'Quantitycondition +itemAmount');
$this->assertEquals(31000, $this->cart->total()->amount(), 'match total');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment