Skip to content
This repository was archived by the owner on Oct 24, 2023. It is now read-only.

Commit 5207c2b

Browse files
author
Jens Schulze
committed
feat(CartDiscount): support multi buy discounts
Closes #353
1 parent a82d290 commit 5207c2b

File tree

7 files changed

+265
-2
lines changed

7 files changed

+265
-2
lines changed

src/Core/Model/CartDiscount/CartDiscountTarget.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,51 @@
1717
*/
1818
class CartDiscountTarget extends JsonObject
1919
{
20+
const TARGET_TYPE = '';
2021
const TYPE_LINE_ITEMS = 'lineItems';
2122

23+
/**
24+
* @inheritDoc
25+
*/
26+
public function __construct(array $data = [], $context = null)
27+
{
28+
if (static::TARGET_TYPE != '' && !isset($data[static::TYPE])) {
29+
$data[static::TYPE] = static::TARGET_TYPE;
30+
}
31+
parent::__construct($data, $context);
32+
}
33+
34+
2235
public function fieldDefinitions()
2336
{
2437
return [
2538
'type' => [static::TYPE => 'string'],
2639
'predicate' => [static::TYPE => 'string'],
2740
];
2841
}
42+
43+
/**
44+
* @inheritDoc
45+
*/
46+
public static function fromArray(array $data, $context = null)
47+
{
48+
if (get_called_class() === CartDiscountTarget::class && isset($data[static::TYPE])) {
49+
$className = static::targetType($data[static::TYPE]);
50+
if (class_exists($className)) {
51+
return new $className($data, $context);
52+
}
53+
}
54+
return new static($data, $context);
55+
}
56+
57+
protected static function targetType($typeId)
58+
{
59+
$types = [
60+
LineItemsTarget::TARGET_TYPE => LineItemsTarget::class,
61+
CustomLineItemsTarget::TARGET_TYPE => CustomLineItemsTarget::class,
62+
ShippingCostTarget::TARGET_TYPE => ShippingCostTarget::class,
63+
MultiBuyLineItemsTarget::TARGET_TYPE => MultiBuyLineItemsTarget::class,
64+
];
65+
return isset($types[$typeId]) ? $types[$typeId] : CartDiscountTarget::class;
66+
}
2967
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* @author @jayS-de <jens.schulze@commercetools.de>
4+
*/
5+
6+
namespace Commercetools\Core\Model\CartDiscount;
7+
8+
/**
9+
* @package Commercetools\Core\Model\CartDiscount
10+
*
11+
* @method string getType()
12+
* @method CustomLineItemsTarget setType(string $type = null)
13+
* @method string getPredicate()
14+
* @method CustomLineItemsTarget setPredicate(string $predicate = null)
15+
*/
16+
class CustomLineItemsTarget extends CartDiscountTarget
17+
{
18+
const TARGET_TYPE = 'customLineItems';
19+
20+
public static function ofPredicate($predicate, $context = null)
21+
{
22+
return static::of($context)->setPredicate($predicate);
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* @author @jayS-de <jens.schulze@commercetools.de>
4+
*/
5+
6+
namespace Commercetools\Core\Model\CartDiscount;
7+
8+
/**
9+
* @package Commercetools\Core\Model\CartDiscount
10+
*
11+
* @method string getType()
12+
* @method LineItemsTarget setType(string $type = null)
13+
* @method string getPredicate()
14+
* @method LineItemsTarget setPredicate(string $predicate = null)
15+
*/
16+
class LineItemsTarget extends CartDiscountTarget
17+
{
18+
const TARGET_TYPE = 'lineItems';
19+
20+
public static function ofPredicate($predicate, $context = null)
21+
{
22+
return static::of($context)->setPredicate($predicate);
23+
}
24+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/**
3+
* @author @jayS-de <jens.schulze@commercetools.de>
4+
*/
5+
6+
namespace Commercetools\Core\Model\CartDiscount;
7+
8+
/**
9+
* @package Commercetools\Core\Model\CartDiscount
10+
*
11+
* @method string getType()
12+
* @method MultiBuyLineItemsTarget setType(string $type = null)
13+
* @method string getPredicate()
14+
* @method MultiBuyLineItemsTarget setPredicate(string $predicate = null)
15+
* @method int getTriggerQuantity()
16+
* @method MultiBuyLineItemsTarget setTriggerQuantity(int $triggerQuantity = null)
17+
* @method int getDiscountedQuantity()
18+
* @method MultiBuyLineItemsTarget setDiscountedQuantity(int $discountedQuantity = null)
19+
* @method int getMaxOccurrence()
20+
* @method MultiBuyLineItemsTarget setMaxOccurrence(int $maxOccurrence = null)
21+
* @method string getSelectionMode()
22+
* @method MultiBuyLineItemsTarget setSelectionMode(string $selectionMode = null)
23+
*/
24+
class MultiBuyLineItemsTarget extends CartDiscountTarget
25+
{
26+
const TARGET_TYPE = 'multiBuyLineItems';
27+
const MODE_CHEAPEST = 'Cheapest';
28+
const MODE_MOST_EXPENSIVE = 'MostExpensive';
29+
30+
public function fieldDefinitions()
31+
{
32+
return [
33+
'type' => [static::TYPE => 'string'],
34+
'predicate' => [static::TYPE => 'string'],
35+
'triggerQuantity' => [static::TYPE => 'int'],
36+
'discountedQuantity' => [static::TYPE => 'int'],
37+
'maxOccurrence' => [static::TYPE => 'int'],
38+
'selectionMode' => [static::TYPE => 'string'],
39+
];
40+
}
41+
42+
public static function ofPredicateTriggerDiscountedAndMode(
43+
$predicate,
44+
$triggerQuantity,
45+
$discountedQuantity,
46+
$selectionMode,
47+
$context = null
48+
) {
49+
return static::of($context)
50+
->setPredicate($predicate)
51+
->setTriggerQuantity($triggerQuantity)
52+
->setDiscountedQuantity($discountedQuantity)
53+
->setSelectionMode($selectionMode);
54+
}
55+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* @author @jayS-de <jens.schulze@commercetools.de>
4+
*/
5+
6+
namespace Commercetools\Core\Model\CartDiscount;
7+
8+
/**
9+
* @package Commercetools\Core\Model\CartDiscount
10+
*
11+
* @method string getType()
12+
* @method ShippingCostTarget setType(string $type = null)
13+
* @method string getPredicate()
14+
* @method ShippingCostTarget setPredicate(string $predicate = null)
15+
*/
16+
class ShippingCostTarget extends CartDiscountTarget
17+
{
18+
const TARGET_TYPE = 'shipping';
19+
}

tests/integration/Cart/CartUpdateRequestTest.php

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
use Commercetools\Core\Model\Cart\LineItemCollection;
1818
use Commercetools\Core\Model\Cart\LineItemDraft;
1919
use Commercetools\Core\Model\Cart\LineItemDraftCollection;
20+
use Commercetools\Core\Model\CartDiscount\AbsoluteCartDiscountValue;
2021
use Commercetools\Core\Model\CartDiscount\CartDiscountDraft;
2122
use Commercetools\Core\Model\CartDiscount\CartDiscountTarget;
2223
use Commercetools\Core\Model\CartDiscount\CartDiscountValue;
24+
use Commercetools\Core\Model\CartDiscount\LineItemsTarget;
25+
use Commercetools\Core\Model\CartDiscount\MultiBuyLineItemsTarget;
26+
use Commercetools\Core\Model\CartDiscount\RelativeCartDiscountValue;
2327
use Commercetools\Core\Model\Common\Address;
2428
use Commercetools\Core\Model\Common\LocalizedString;
2529
use Commercetools\Core\Model\Common\Money;
@@ -1185,11 +1189,11 @@ public function testDiscountCodeCustomPredicate()
11851189

11861190
$draft = CartDiscountDraft::ofNameValuePredicateTargetOrderActiveAndDiscountCode(
11871191
LocalizedString::ofLangAndText('en', 'test-' . $this->getTestRun() . '-discount'),
1188-
CartDiscountValue::of()->setType('absolute')->setMoney(
1192+
AbsoluteCartDiscountValue::of()->setMoney(
11891193
MoneyCollection::of()->add(Money::ofCurrencyAndAmount('EUR', 100))
11901194
),
11911195
'custom(testField = "' . $this->getTestRun() . '")',
1192-
CartDiscountTarget::of()->setType('lineItems')->setPredicate('1=1'),
1196+
LineItemsTarget::of()->setPredicate('1=1'),
11931197
'0.9' . trim((string)mt_rand(1, 1000), '0'),
11941198
true,
11951199
true
@@ -1218,6 +1222,58 @@ public function testDiscountCodeCustomPredicate()
12181222
);
12191223
}
12201224

1225+
public function testMultiBuyDiscount()
1226+
{
1227+
$draft = $this->getDraft();
1228+
$draft->setLineItems(
1229+
LineItemDraftCollection::of()
1230+
->add(LineItemDraft::of()->setProductId($this->getProduct()->getId())->setVariantId(1)->setQuantity(3))
1231+
);
1232+
1233+
$cart = $this->createCart($draft);
1234+
1235+
$draft = CartDiscountDraft::ofNameValuePredicateTargetOrderActiveAndDiscountCode(
1236+
LocalizedString::ofLangAndText('en', 'test-' . $this->getTestRun() . '-discount'),
1237+
RelativeCartDiscountValue::of()->setPermyriad(10000),
1238+
'1=1',
1239+
MultiBuyLineItemsTarget::ofPredicateTriggerDiscountedAndMode(
1240+
'1=1',
1241+
3,
1242+
1,
1243+
MultiBuyLineItemsTarget::MODE_CHEAPEST
1244+
),
1245+
'0.9' . trim((string)mt_rand(1, 1000), '0'),
1246+
true,
1247+
true
1248+
);
1249+
$request = CartDiscountCreateRequest::ofDraft($draft);
1250+
$response = $request->executeWithClient($this->getClient());
1251+
$this->cartDiscount = $request->mapResponse($response);
1252+
1253+
$discountCode = $this->getDiscountCode();
1254+
1255+
$request = CartUpdateRequest::ofIdAndVersion($cart->getId(), $cart->getVersion())
1256+
->addAction(CartAddDiscountCodeAction::ofCode($discountCode->getCode()))
1257+
;
1258+
$response = $request->executeWithClient($this->getClient());
1259+
$cart = $request->mapResponse($response);
1260+
$this->deleteRequest->setVersion($cart->getVersion());
1261+
1262+
$this->assertSame($discountCode->getId(), $cart->getDiscountCodes()->current()->getDiscountCode()->getId());
1263+
1264+
$this->assertSame(
1265+
$this->cartDiscount->getId(),
1266+
$cart->getLineItems()->current()
1267+
->getDiscountedPricePerQuantity()->current()
1268+
->getDiscountedPrice()->getIncludedDiscounts()->current()
1269+
->getDiscount()->getId()
1270+
);
1271+
$this->assertSame(
1272+
$cart->getLineItems()->current()->getPrice()->getValue()->getCentAmount() * 2,
1273+
$cart->getLineItems()->current()->getTotalPrice()->getCentAmount()
1274+
);
1275+
}
1276+
12211277
public function testDiscountCodeCustomLineItemPredicate()
12221278
{
12231279
$type = $this->getType('key-' . $this->getTestRun(), 'line-item');
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
/**
3+
* @author @jayS-de <jens.schulze@commercetools.de>
4+
*/
5+
6+
namespace Commercetools\Core\Model\CartDiscount;
7+
8+
9+
class CartDiscountTargetTest extends \PHPUnit\Framework\TestCase
10+
{
11+
/**
12+
* @dataProvider getTargetsProvider
13+
*/
14+
public function testFromArray($expectedClass, $type)
15+
{
16+
$data = [];
17+
if (!is_null($type)) {
18+
$data['type'] = $type;
19+
}
20+
$target = CartDiscountTarget::fromArray($data);
21+
$this->assertInstanceOf($expectedClass, $target);
22+
$this->assertSame($type, $target->getType());
23+
}
24+
25+
/**
26+
* @dataProvider getTargetsProvider
27+
*/
28+
public function testOf($class, $type)
29+
{
30+
/**
31+
* @var CartDiscountTarget $target
32+
*/
33+
$target = $class::of();
34+
$this->assertSame($type, $target->getType());
35+
}
36+
37+
public function getTargetsProvider()
38+
{
39+
return [
40+
CartDiscountTarget::class => [CartDiscountTarget::class, null],
41+
LineItemsTarget::class => [LineItemsTarget::class, 'lineItems'],
42+
CustomLineItemsTarget::class => [CustomLineItemsTarget::class, 'customLineItems'],
43+
ShippingCostTarget::class => [ShippingCostTarget::class, 'shipping'],
44+
MultiBuyLineItemsTarget::class => [MultiBuyLineItemsTarget::class, 'multiBuyLineItems'],
45+
];
46+
}
47+
}

0 commit comments

Comments
 (0)