Commit cb952a9f authored by Thorsten Buss's avatar Thorsten Buss

* target in Condition is now optional and would be add on adding the condition to cart or item

* add LaravelLocale if \Config exists
* add CurrencyCondition for Conditions with MoneyObj
parent 86573aee
......@@ -286,7 +286,7 @@ Also, when adding conditions, the 'value' field will be the bases of calculation
$condition = new \Bnet\Cart\CartCondition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '12.5%',
'attributes' => array( // attributes field is optional
'description' => 'Value added tax',
......@@ -300,13 +300,13 @@ Cart::condition($condition);
$condition1 = new \Bnet\Cart\CartCondition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '12.5%',
));
$condition2 = new \Bnet\Cart\CartCondition(array(
'name' => 'Express Shipping $15',
'type' => 'shipping',
'target' => 'subtotal',
'target' => 'cart',
'value' => '+15',
));
Cart::condition($condition1);
......@@ -703,10 +703,15 @@ $items->each(function($item)
## Changelogs
**3.1.1
- cart is completly "Arrayable"
- condition target is optional and subtotal is changed to cart
**3.1.0
- allow to add an already created Item Object or a list of items
- add CurrencyCartServiceProvider
- change the calculation-princip of the currencyItems
- change the calculation-princip of the currencyIt
ems
**3.0.0
- the internal repesentation of amounts is now int instead of float
......
......@@ -4,12 +4,14 @@ use Bnet\Cart\Exceptions\InvalidConditionException;
use Bnet\Cart\Exceptions\InvalidItemException;
use Bnet\Cart\Helpers\Helpers;
use Bnet\Cart\Validators\ItemValidator;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
/**
* Class Cart
* @package Bnet\Cart
*/
class Cart {
class Cart implements Jsonable, \JsonSerializable, Arrayable{
/**
* the item storage
......@@ -307,7 +309,13 @@ class Cart {
return $this;
}
if (!$condition instanceof Condition) throw new InvalidConditionException('Argument 1 must be an instance of \'Bnet\Cart\CartCondition\'');
if (!$condition instanceof Condition)
throw new InvalidConditionException('Argument 1 must be an instance of \'Bnet\Cart\CartCondition\'');
// set target to cart if not set
$condition->setTarget($condition->getTarget() ?: 'cart');
if ($condition->getTarget() !== 'cart')
throw new InvalidConditionException('target have to be cart for cart conditions');
$conditions = $this->getConditions();
......@@ -504,7 +512,7 @@ class Cart {
if (!$conditions->count()) return $subTotal;
$conditions->each(function ($cond) use ($subTotal, &$newTotal, &$process) {
if ($cond->getTarget() === 'subtotal') {
if ($cond->getTarget() === 'cart') {
($process > 0) ? $toBeCalculated = $newTotal : $toBeCalculated = $subTotal;
$newTotal = $cond->applyCondition($toBeCalculated);
......@@ -672,4 +680,76 @@ class Cart {
return $item;
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray() {
return [
'items' => $this->items()->toArray(),
'conditions' => $this->getConditions()->toArray()
];
}
/**
* Get the evaluated contents of the object.
*
* @return string
*/
public function render() {
$items = '';
/** @var Item $item */
foreach ($this->items()->all() as $item) {
$items .= "\n <tr>
<td>{$item->quantity}</td><td>{$item->name}</td><td>{$item->price}</td><td>{$item->priceSum()}</td>
</tr>";
}
return <<<EOF
<table class="cart">
<thead>
<tr>
<td>Qty.</td><td>Name</td><td>Price</td><td>Sum</td>
</tr>
</thead>
<tbody>
$items
</tbody>
</table>
EOF;
}
/**
* __toString.
*
* @return string
*/
public function __toString() {
return $this->render();
}
/**
* Convert the object to its JSON representation.
*
* @param int $options
* @return string
*/
public function toJson($options = 0) {
return json_encode($this->toArray(), $options);
}
/**
* Specify data which should be serialized to JSON
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
function jsonSerialize() {
return $this->toArray();
}
}
<?php namespace Bnet\Cart;
<?php
namespace Bnet\Cart;
use Bnet\Cart\Exceptions\InvalidConditionException;
use Bnet\Cart\Helpers\Helpers;
use Bnet\Cart\Validators\ConditionValidator;
use Illuminate\Support\Collection;
/**
* Created by PhpStorm.
* User: darryl
* Date: 1/15/2015
* Time: 9:02 PM
* Class Condition
* @package Bnet\Cart
*/
class Condition {
class Condition extends Collection {
/**
* List of validation rules for the condition
* @var array
*/
private $args;
protected $rules = [
'name' => 'required',
'type' => 'required|string',
'target' => 'sometimes|required|in:item,cart',
'value' => 'required|string',
];
/**
* the parsed raw value of the condition
*
* @var
*/
private $parsedRawValue;
protected $parsedRawValue;
/**
* @param array $args (name, type, target, value)
* @throws InvalidConditionException
*/
public function __construct(array $args) {
$this->args = $args;
parent::__construct($args);
if (Helpers::isMultiArray($args)) {
Throw new InvalidConditionException('Multi dimensional array is not supported.');
} else {
$this->validate($this->args);
$this->validate($this->items);
}
}
......@@ -44,7 +50,14 @@ class Condition {
* @return mixed
*/
public function getTarget() {
return $this->args['target'];
return $this->get('target');
}
/**
* @param $target
*/
public function setTarget($target) {
$this->items['target'] = $target;
}
/**
......@@ -53,7 +66,7 @@ class Condition {
* @return mixed
*/
public function getName() {
return $this->args['name'];
return $this->get('name');
}
/**
......@@ -62,7 +75,7 @@ class Condition {
* @return mixed
*/
public function getType() {
return $this->args['type'];
return $this->get('type');
}
/**
......@@ -71,7 +84,7 @@ class Condition {
* @return array
*/
public function getAttributes() {
return (isset($this->args['attributes'])) ? $this->args['attributes'] : array();
return (isset($this->items['attributes'])) ? $this->items['attributes'] : array();
}
/**
......@@ -80,7 +93,7 @@ class Condition {
* @return mixed
*/
public function getValue() {
return $this->args['value'];
return $this->get('value');
}
/**
......@@ -119,23 +132,13 @@ class Condition {
// percentage, whether to add or subtract it to the total/subtotal/price
// if we can't find any plus/minus sign, we will assume it as plus sign
if ($this->valueIsPercentage($conditionValue)) {
if ($this->valueIsToBeSubtracted($conditionValue)) {
$value = Helpers::normalizePercentage($this->cleanValue($conditionValue));
$this->parsedRawValue = $totalOrSubTotalOrPrice * ($value / 100);
$value = Helpers::normalizePercentage($this->cleanValue($conditionValue));
$this->parsedRawValue = $totalOrSubTotalOrPrice * ($value / 100);
if ($this->valueIsToBeSubtracted($conditionValue)) {
$result = Helpers::intval($totalOrSubTotalOrPrice - $this->parsedRawValue);
} else if ($this->valueIsToBeAdded($conditionValue)) {
$value = Helpers::normalizePercentage($this->cleanValue($conditionValue));
$this->parsedRawValue = $totalOrSubTotalOrPrice * ($value / 100);
$result = Helpers::intval($totalOrSubTotalOrPrice + $this->parsedRawValue);
} else {
$value = Helpers::normalizePercentage($conditionValue);
$this->parsedRawValue = $totalOrSubTotalOrPrice * ($value / 100);
$result = Helpers::intval($totalOrSubTotalOrPrice + $this->parsedRawValue);
}
}
......@@ -143,17 +146,12 @@ class Condition {
// if the value has no percent sign on it, the operation will not be a percentage
// next is we will check if it has a minus/plus sign so then we can just deduct it to total/subtotal/price
else {
if ($this->valueIsToBeSubtracted($conditionValue)) {
$this->parsedRawValue = Helpers::normalizePrice($this->cleanValue($conditionValue));
$result = Helpers::intval($totalOrSubTotalOrPrice - $this->parsedRawValue);
} else if ($this->valueIsToBeAdded($conditionValue)) {
$this->parsedRawValue = Helpers::normalizePrice($this->cleanValue($conditionValue));
$this->parsedRawValue = Helpers::normalizePrice($this->cleanValue($conditionValue));
$result = Helpers::intval($totalOrSubTotalOrPrice + $this->parsedRawValue);
if ($this->valueIsToBeSubtracted($conditionValue)) {
$result = Helpers::intval($totalOrSubTotalOrPrice - $this->parsedRawValue);
} else {
$this->parsedRawValue = Helpers::normalizePrice($conditionValue);
$result = Helpers::intval($totalOrSubTotalOrPrice + $this->parsedRawValue);
}
}
......@@ -209,17 +207,21 @@ class Condition {
* @throws InvalidConditionException
*/
protected function validate($args) {
$rules = array(
'name' => 'required',
'type' => 'required',
'target' => 'required',
'value' => 'required',
);
$validator = ConditionValidator::make($args, $rules);
$validator = ConditionValidator::make($args, $this->rules);
if ($validator->fails()) {
throw new InvalidConditionException($validator->messages()->first());
}
}
/**
* map the $porperty to the function
* @param $name
* @return mixed|null
*/
public function __get($name) {
if ($this->has($name)) return $this->get($name);
return null;
}
}
\ No newline at end of file
......@@ -61,7 +61,7 @@ class CurrencyCart extends Cart {
$process = 0;
$this->getConditions()->each(function ($cond) use ($subTotal, &$newTotal, &$process) {
if ($cond->getTarget() === 'subtotal') {
if ($cond->getTarget() === 'cart') {
($process > 0) ? $toBeCalculated = $newTotal : $toBeCalculated = $subTotal;
$newTotal = $cond->applyCondition($toBeCalculated);
$process++;
......
<?php
/**
* User: thorsten
* Date: 27.07.16
* Time: 09:39
*/
namespace Bnet\Cart;
use Bnet\Cart\Helpers\Helpers;
use Bnet\Money\Money;
class CurrencyCondition extends Condition {
/**
* CurrencyCondition constructor.
* @param array $args
*/
public function __construct(array $args) {
// remove the "string" validator from the value field
$this->rules['value'] = 'required';
parent::__construct($args);
}
/**
* apply condition
*
* @param $totalOrSubTotalOrPrice
* @param $conditionValue
* @return int
*/
protected function apply($totalOrSubTotalOrPrice, $conditionValue) {
if ($conditionValue instanceof Money) {
$this->parsedRawValue = $conditionValue->amount();
$result = Helpers::intval($totalOrSubTotalOrPrice + $this->parsedRawValue);
// Do not allow items with negative prices.
return $result < 0 ? 0 : $result;
}
return parent::apply($totalOrSubTotalOrPrice, $conditionValue);
}
}
\ No newline at end of file
......@@ -27,6 +27,18 @@ 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']))
if (!is_array($attributes['conditions']))
$attributes['conditions'] = [$attributes['conditions']];
collect($attributes['conditions'])->transform(function($condition) {
if ($condition instanceof Condition) {
if ($condition->getTarget() == 'cart')
return false;
$condition->setTarget('item');
} else
$condition['target'] = 'item';
});
parent::__construct($attributes);
}
......@@ -40,6 +52,11 @@ class Item extends Collection {
return $this->price() * $this->quantity;
}
/**
* return property
* @param $name
* @return mixed|null
*/
public function __get($name) {
if ($this->has($name)) return $this->get($name);
return null;
......@@ -106,4 +123,22 @@ class Item extends Collection {
public function priceSumWithConditions() {
return $this->priceWithConditions() * $this->quantity;
}
/**
* Get the collection of items as a plain array.
*
* @return array
*/
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();
}
}
return $arr;
}
}
......@@ -15,8 +15,8 @@ abstract class Validator {
public static function instance() {
if (!static::$factory) {
// $translator = new Translator(\Config::get('app.locale'));
$translator = new Translator('en');
$locale = class_exists('\Config') ? \Config::get('app.locale') : 'en';
$translator = new Translator($locale);
static::$factory = new Factory($translator);
}
......
......@@ -84,7 +84,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition = new Condition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '12.5%',
));
......@@ -106,13 +106,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition1 = new Condition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '12.5%',
));
$condition2 = new Condition(array(
'name' => 'Express Shipping $15',
'type' => 'shipping',
'target' => 'subtotal',
'target' => 'cart',
'value' => '+1500',
));
......@@ -135,13 +135,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition1 = new Condition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '12.5%',
));
$condition2 = new Condition(array(
'name' => 'Express Shipping $15',
'type' => 'shipping',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-1500',
));
......@@ -164,13 +164,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition1 = new Condition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-12.5%',
));
$condition2 = new Condition(array(
'name' => 'Express Shipping $15',
'type' => 'shipping',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-1500',
));
......@@ -193,13 +193,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition1 = new Condition(array(
'name' => 'VAT 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-12.5%',
));
$condition2 = new Condition(array(
'name' => 'Express Shipping $15',
'type' => 'shipping',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-1500',
));
......@@ -221,13 +221,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition1 = new Condition(array(
'name' => 'COUPON LESS 12.5%',
'type' => 'tax',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-12.5%',
));
$condition2 = new Condition(array(
'name' => 'Express Shipping $15',
'type' => 'shipping',
'target' => 'subtotal',
'target' => 'cart',
'value' => '+1500',
));
......@@ -245,7 +245,6 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'tax',
'target' => 'item',
'value' => '-5%',
));
......@@ -309,7 +308,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$itemCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
)); // --> this should not be included in calculation
$itemCondition2 = new Condition(array(
......@@ -327,7 +326,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$itemCondition4 = new Condition(array(
'name' => 'MISC 2',
'type' => 'misc2',
'target' => 'subtotal',
'target' => 'cart',
'value' => '+10%',
));// --> this should not be included in calculation
......@@ -410,13 +409,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$itemCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
));
$itemCondition2 = new Condition(array(
'name' => 'Item Gift Pack 2500',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-2500',
));
......@@ -436,7 +435,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$condition = $this->cart->getCondition($itemCondition1->getName());
$this->assertEquals($condition->getName(), 'SALE 5%');
$this->assertEquals($condition->getTarget(), 'subtotal');
$this->assertEquals($condition->getTarget(), 'cart');
$this->assertEquals($condition->getType(), 'sale');
$this->assertEquals($condition->getValue(), '-5%');
}
......@@ -445,13 +444,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$itemCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
));
$itemCondition2 = new Condition(array(
'name' => 'Item Gift Pack 2500',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-2500',
));
......@@ -587,13 +586,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$itemCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
));
$itemCondition2 = new Condition(array(
'name' => 'Item Gift Pack 2500',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-2500',
));
......@@ -623,13 +622,13 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$cartCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
));
$cartCondition2 = new Condition(array(
'name' => 'Item Gift Pack 2500',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-25',
));
......@@ -665,19 +664,19 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$cartCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
));
$cartCondition2 = new Condition(array(
'name' => 'Item Gift Pack 2500',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-2500',
));
$cartCondition3 = new Condition(array(
'name' => 'Item Less 8%',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-8%',
));
......@@ -711,19 +710,19 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$cartCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
));
$cartCondition2 = new Condition(array(
'name' => 'Item Gift Pack 20',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-2500',
));
$cartCondition3 = new Condition(array(
'name' => 'Item Less 8%',
'type' => 'promo',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-8%',
));
......@@ -749,7 +748,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$cartCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%'
));
......@@ -779,7 +778,7 @@ class CartConditionTest extends PHPUnit_Framework_TestCase {
$cartCondition1 = new Condition(array(
'name' => 'SALE 5%',
'type' => 'sale',
'target' => 'subtotal',
'target' => 'cart',
'value' => '-5%',
'attributes' => array(
'description' => 'october fest promo sale',
......
......@@ -7,6 +7,7 @@
*/
use Bnet\Cart\Cart;
use Bnet\Cart\Condition;
use Mockery as m;
require_once __DIR__ . '/helpers/SessionMock.php';
......@@ -472,4 +473,130 @@ class CartTest extends PHPUnit_Framework_TestCase {
$this->assertInternalType("int", $this->cart->totalQuantity(), 'Return type should be INT');
$this->assertEquals(4, $this->cart->totalQuantity(), 'Cart\'s quantity should be 4.');
}
public function testToArray() {
$items = [
456 => [
'id' => 456,
'name' => 'Sample Item 1',
'price' => \Bnet\Money\MoneyGross::fromNet(12345, 19),
'quantity' => 3,
'attributes' => [
'asdf'=> 'tt'
]
], 568 => [
'id' => 568,
'name' => 'Sample Item 2',
'price' => new \Bnet\Money\Money(6925),
'quantity' => 1,
],
];
$this->cart->add($items);
$items[456]['conditions'] = [];
$items[456]['price'] = [
'amount' => 14691,
'number' => 146.91,
'format' => '€146,91',
'currency' => 'EUR',
'price_net' => 12345,
'price_gross' => 14691,
'tax' => 19
];