Commit 6b9035e3 authored by Thorsten Buss's avatar Thorsten Buss

* add type specific condition calculation (ex.: only the sum of delivery_type)

* add some sum calculations to the cart
* FIX: use accidently quantity in Item::priceWithConditions()
* FIX: return Money instead of int in CurrencyCart::totalTaxAmount
* require 0.1.13 MOneyDatatype
parent 2d770210
......@@ -15,7 +15,7 @@
"illuminate/validation": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x",
"illuminate/translation": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x",
"illuminate/session": "5.0.x|5.1.x|5.2.x|5.3.x|5.4.x",
"bnet/money-datatype": "^0.1"
"bnet/money-datatype": "~0.1.13"
},
"require-dev": {
"mockery/mockery": "~0.9",
......
......@@ -333,10 +333,19 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
/**
* get conditions applied on the cart
*
* @param bool $withItemConditions
* @return Conditions
*/
public function getConditions() {
return new Conditions($this->session->get($this->sessionKeyCartConditions));
public function getConditions($withItemConditions = false) {
$conditions = new Conditions($this->session->get($this->sessionKeyCartConditions));
if ($withItemConditions) {
$this->items()->each(function (Item $item) use (&$conditions) {
$item->conditions->each(function (AdditionalFee $condition) use (&$conditions) {
$conditions->push($condition);
});
});
}
return $conditions;
}
/**
......@@ -353,7 +362,7 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
* check if condition exists on the cart by its name
*
* @param $conditionName
* @return Condition
* @return Boolean
*/
public function hasCondition($conditionName) {
return $this->getConditions()->has($conditionName);
......@@ -365,10 +374,11 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
* specifically on an per item bases
*
* @param $type
* @param bool $withItemConditions
* @return Conditions
*/
public function getConditionsByType($type) {
return $this->getConditions()->filter(function (Condition $condition) use ($type) {
public function getConditionsByType($type, $withItemConditions = false) {
return $this->getConditions($withItemConditions)->filter(function (Condition $condition) use ($type) {
return $condition->getType() == $type;
});
}
......@@ -380,10 +390,12 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
* specifically on an per item bases
*
* @param $type
* @param bool $withItemConditions
* @return $this
*/
public function removeConditionsByType($type) {
$this->getConditionsByType($type)->each(function ($condition) {
public function removeConditionsByType($type, $withItemConditions = false) {
$this->getConditionsByType($type, $withItemConditions)->each(function ($condition) {
/** @var Condition $condition */
$this->removeCartCondition($condition->getName());
});
}
......@@ -464,30 +476,68 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
}
/**
* get cart sub total
* get cart sub total - items WITH conditions WITHOUT cart conditions
*
* @param null|string $only_with_condition_type Only with this conditionType
* @return int
*/
public function subTotal() {
$sum = $this->items()->sum(function (Item $item) {
return $item->priceSumWithConditions();
public function subTotal($only_with_condition_type = null) {
$sum = $this->items()->sum(function (Item $item) use($only_with_condition_type) {
return $item->priceSumWithConditions($only_with_condition_type);
});
return Helpers::intval($sum);
}
/**
* the new total in which conditions are already applied
* cart totel WITH cart conditions and WITH item conditions
*
* @param null|string $only_with_condition_type Only with this conditionType
* @return int
*/
public function total($only_with_condition_type = null) {
$subTotal = $this->subTotal($only_with_condition_type);
if ($this->getConditions($only_with_condition_type)->isEmpty())
return $subTotal;
$condTotal = $this->getConditions($only_with_condition_type)->sum(function ($cond) use ($subTotal) {
/** @var Condition $cond */
return $cond->getTarget() === 'cart'
? $cond->applyCondition($subTotal)
: 0;
});
return $subTotal + $condTotal;
}
/**
* get totalItems WITH conditions WITHOUT item price
* @param null|string $type type of conditions to calc only
* @return int
*/
public function total() {
if ($this->getConditions()->isEmpty())
return $this->subTotal();
public function totalItemsOnlyConditions($type = null) {
$sum = $this->items()->sum(function (Item $item) use ($type) {
return $item->priceSumOnlyConditions($type);
});
return Helpers::intval($sum);
}
$subTotal = $this->subTotal();
$condTotal = $this->getConditions()->sum(function ($cond) use ($subTotal) {
/**
* cart totel WITH cart conditions and WITH item conditions
*
* @param null|string $type Only with this conditionType
* @return int
*/
public function totalOnlyConditions($type = null) {
$subTotal = $this->totalItemsOnlyConditions($type);
if ($this->getConditions($type)->isEmpty())
return $subTotal;
$condTotal = $this->getConditions($type)->sum(function ($cond) use ($subTotal) {
/** @var Condition $cond */
return $cond->getTarget() === 'cart'
? $cond->applyCondition($subTotal)
: 0;
......@@ -496,6 +546,29 @@ class Cart implements Jsonable, \JsonSerializable, Arrayable{
return $subTotal + $condTotal;
}
/**
* get cart sub total - items WITH conditions and WITHOUT cart conditions
* alias for subTotal
* @param null|string $only_with_condition_type Only with this conditionType
* @return int
*/
public function totalItems($only_with_condition_type = null) {
return $this->subTotal($only_with_condition_type);
}
/**
* get cart sub total - items WITHOUT conditions and WITHOUT cart conditions
*
* @return int
*/
public function totalItemsWithoutConditions() {
$sum = $this->items()->sum(function (Item $item) {
return $item->priceSum();
});
return Helpers::intval($sum);
}
/**
* get total quantity of items in the cart
*
......
......@@ -36,30 +36,34 @@ class CurrencyCart extends Cart {
}
/**
* get cart sub total
* get cart sub total - items WITH conditions WITHOUT cart conditions
*
* @param null|string $only_with_condition_type Only with this conditionType
* @return Money
*/
public function subTotal() {
$sum = $this->items()->sum(function (CurrencyItem $item) {
return $item->priceSumWithConditions()->amount();
public function subTotal($only_with_condition_type = null) {
$sum = $this->items()->sum(function (CurrencyItem $item) use ($only_with_condition_type) {
return $item->priceSumWithConditions($only_with_condition_type)->amount();
});
return new Money($sum, $this->currency);
}
/**
* the new total in which conditions are already applied
* cart totel WITH cart conditions and WITH item conditions
*
* @param null|string $only_with_condition_type Only with this conditionType
* @return Money
*/
public function total() {
if ($this->getConditions()->isEmpty())
return $this->subTotal();
public function total($only_with_condition_type = null) {
$subTotal = $this->subTotal($only_with_condition_type);
if ($this->getConditions($only_with_condition_type)->isEmpty())
return $subTotal;
$subTotal = $this->subTotal()->amount();
$subTotal = $subTotal->amount();
$condTotal = $this->getConditions()->sum(function ($cond) use ($subTotal) {
$condTotal = $this->getConditions($only_with_condition_type)->sum(function ($cond) use ($subTotal) {
/** @var Condition $cond */
return $cond->getTarget() === 'cart'
? $cond->applyCondition($subTotal)
: 0;
......@@ -68,10 +72,71 @@ class CurrencyCart extends Cart {
return new Money((int)($subTotal + $condTotal), $this->currency);
}
/**
* get totalItems WITH conditions WITHOUT item price
* @param null|string $type type of conditions to calc only
* @return Money
*/
public function totalItemsOnlyConditions($type = null) {
return new Money(parent::totalItemsOnlyConditions($type), $this->currency);
}
/**
* cart totel WITH cart conditions and WITH item conditions
*
* @param null|string $type Only with this conditionType
* @return Money
*/
public function totalOnlyConditions($type = null) {
$subTotal = $this->totalItemsOnlyConditions($type);
if ($this->getConditions($type)->isEmpty())
return $subTotal;
$subTotal = $subTotal->amount();
$condTotal = $this->getConditions($type)->sum(function ($cond) use ($subTotal) {
/** @var Condition $cond */
return $cond->getTarget() === 'cart'
? $cond->applyCondition($subTotal)
: 0;
});
return new Money((int)($subTotal + $condTotal), $this->currency);
}
/**
* get cart sub total - items WITHOUT conditions and WITHOUT cart conditions
*
* @return Money
*/
public function totalItemsWithoutConditions() {
$sum = $this->items()->sum(function (Item $item) {
return $item->priceSum();
});
return new Money($sum, $this->currency);
}
/**
* get cart sub total - items WITH conditions and WITHOUT cart conditions
* alias for subTotal
* @param null|string $only_with_condition_type Only with this conditionType
* @return Money
*/
public function totalItems($only_with_condition_type = null) {
return $this->subTotal($only_with_condition_type);
}
/**
* return the total tax amount
* @return Money
*/
public function totalTaxAmount() {
return $this->items()->sum(function(CurrencyItem $item) {
$sum = $this->items()->sum(function(CurrencyItem $item) {
return $item->taxAmountWithConditions();
});
return new Money($sum, $this->currency);
}
/**
......
......@@ -36,6 +36,15 @@ class CurrencyItem extends Item {
parent::__construct($attributes);
}
/**
* return the price amount for this item
* @return Money
*/
public function price() {
return $this->price;
}
/**
* get the sum of price
*
......@@ -48,17 +57,18 @@ class CurrencyItem extends Item {
/**
* get the single price in which conditions are already applied
*
* @param null|string $type only sum with conditions for this $type
* @return Money
*/
public function priceWithConditions() {
public function priceWithConditions($type = null) {
$originalPrice = $this->price->amount();
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
if ($condition && $condition->getTarget() === 'item') {
return $condition->getTarget() === 'item'
? $condition->applyCondition($originalPrice)
: 0;
}
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice, $type) {
/** @var Condition $condition */
return ($condition && $condition->getTarget() === 'item'
&& (is_null($type) || $type == $condition->getType()))
? $condition->applyCondition($originalPrice)
: 0;
});
$newPrice = $this->returnPriceAboveZero($condition_price + $originalPrice);
return new Money((int)$newPrice, $this->currency);
......@@ -67,22 +77,42 @@ class CurrencyItem extends Item {
/**
* get the sum of price in which conditions are already applied
*
* @param null|string $type only sum with conditions for this $type
* @return Money
*/
public function priceSumWithConditions() {
public function priceSumWithConditions($type = null) {
$originalPrice = $this->price->amount();
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
if ($condition && $condition->getTarget() === 'item') {
return $condition->getTarget() === 'item'
? $condition->applyConditionWithQuantity($originalPrice, $this->quantity)
: 0;
}
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice, $type) {
/** @var Condition $condition */
return ($condition && $condition->getTarget() === 'item'
&& (is_null($type) || $type == $condition->getType()))
? $condition->applyConditionWithQuantity($originalPrice, $this->quantity)
: 0;
});
$newPrice = $this->returnPriceAboveZero($condition_price + ($this->quantity * $originalPrice));
return new Money((int)$newPrice, $this->currency);
}
/**
* return the price of the conditions without the item price
* @param null|string $type only sum with conditions for this $type
* @return Money
*/
public function priceOnlyConditions($type = null) {
return $this->priceWithConditions($type)->subtract($this->price());
}
/**
* return the price of the conditions SUM without the item priceSUM
* @param null|string $type only sum with conditions for this $type
* @return Money
*/
public function priceSumOnlyConditions($type = null) {
return $this->priceSumWithConditions($type)->subtract($this->priceSum());
}
/**
* @return int
*/
......@@ -92,6 +122,7 @@ class CurrencyItem extends Item {
/* get the tax for the item */
if ($this->price->hasTax()) {
/** @var TaxedMoney $taxed_price */
$taxed_price = $this->price;
$tax = $taxed_price->taxAmountOnly();
$item_price = $taxed_price->amountWithoutTax();
......
......@@ -76,29 +76,53 @@ class Item extends Collection {
/**
* get the single price in which conditions are already applied
*
* @param null|string $type only sum with conditions for this $type
* @return mixed|null
*/
public function priceWithConditions() {
public function priceWithConditions($type = null) {
$originalPrice = $this->price();
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
return ($condition && $condition->getTarget() === 'item')
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice, $type) {
/** @var Condition $condition */
return ($condition && $condition->getTarget() === 'item'
&& (is_null($type) || $type == $condition->getType()))
? $condition->applyCondition($originalPrice)
: 0;
});
return $this->returnPriceAboveZero($condition_price + ($this->quantity * $originalPrice));
return $this->returnPriceAboveZero($condition_price + $originalPrice);
}
/**
* return the price of the conditions without the item price
* @param null|string $type only sum with conditions for this $type
* @return mixed|null
*/
public function priceOnlyConditions($type = null) {
return $this->priceWithConditions($type) - $this->price();
}
/**
* return the price of the conditions SUM without the item priceSUM
* @param null|string $type only sum with conditions for this $type
* @return mixed|null
*/
public function priceSumOnlyConditions($type = null) {
return $this->priceSumWithConditions($type) - $this->priceSum();
}
/**
* get the sum of price in which conditions are already applied
*
* @param null|string $type only sum with conditions for this $type
* @return mixed|null
*/
public function priceSumWithConditions() {
public function priceSumWithConditions($type = null) {
$originalPrice = $this->price();
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice) {
return ($condition && $condition->getTarget() === 'item')
$condition_price = $this->conditions->sum(function ($condition) use ($originalPrice, $type) {
/** @var Condition $condition */
return ($condition && $condition->getTarget() === 'item'
&& (is_null($type) || $type == $condition->getType()))
? $condition->applyConditionWithQuantity($originalPrice, $this->quantity)
: 0;
});
......@@ -158,7 +182,7 @@ class Item extends Collection {
return $condition;
})->keyBy(function ($cond) use (&$uniqueKeys) {
// use name as key and verify that the key is unique
$key = $cond->name;
$key = @$cond->name ?: 'unknown';
$postfix = '';
while ($uniqueKeys->contains($key . $postfix)) {
$postfix = empty($postfix) ? 1 : ($postfix + 1);
......
......@@ -260,6 +260,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$this->cart->add($item);
$this->assertEquals(95, $this->cart->get(456)->priceSumWithConditions());
$this->assertEquals(-5, $this->cart->get(456)->priceSumOnlyConditions());
$this->assertEquals(95, $this->cart->subTotal());
}
......@@ -287,15 +288,26 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
'id' => 456,
'name' => 'Sample Item 1',
'price' => 10000,
'quantity' => 1,
'quantity' => 2,
'attributes' => array(),
'conditions' => [$itemCondition1, $itemCondition2, $itemCondition3]
);
$this->cart->add($item);
$this->assertEquals(8000, $this->cart->get(456)->priceSumWithConditions(), 'Item subtotal with 1 item should be 80');
$this->assertEquals(8000, $this->cart->subTotal(), 'Cart subtotal with 1 item should be 80');
$this->assertEquals(16000, $this->cart->get(456)->priceSumWithConditions(), 'Item subtotal with 1 item should be 80');
$this->assertEquals(-4000, $this->cart->get(456)->priceSumOnlyConditions(), 'Item subtotal with 1 item should be 80');
$this->assertEquals(15000, $this->cart->get(456)->priceSumWithConditions('promo'));
$this->assertEquals(-5000, $this->cart->get(456)->priceSumOnlyConditions('promo'));
$this->assertEquals(19000, $this->cart->get(456)->priceSumWithConditions('sale'));
$this->assertEquals(-1000, $this->cart->get(456)->priceSumOnlyConditions('sale'));
$this->assertEquals(9500, $this->cart->get(456)->priceWithConditions('sale'));
$this->assertEquals(-500, $this->cart->get(456)->priceOnlyConditions('sale'));
$this->assertEquals(16000, $this->cart->subTotal(), 'Cart subtotal with 1 item should be 80');
}
public function test_add_item_with_multiple_item_conditions_with_one_condition_wrong_target() {
......@@ -342,6 +354,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$this->cart->add($item);
$this->assertEquals(8500, $this->cart->get(456)->priceSumWithConditions(), 'Cart subtotal with 1 item should be 85');
$this->assertEquals(-1500, $this->cart->get(456)->priceSumOnlyConditions(), 'Cart subtotal with 1 item should be 85');
$this->assertEquals(8500, $this->cart->subTotal(), 'Cart subtotal with 1 item should be 85');
}
......
......@@ -511,6 +511,6 @@ class CurrencyCartTest extends PHPUnit_Framework_TestCase {
];
$this->cart->add($items);
$this->assertEquals(1800, $this->cart->totalTaxAmount());
$this->assertEquals(1800, $this->cart->totalTaxAmount()->value());
}
}
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