mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-05 20:57:12 +00:00
Merge c2de78c937 into fc1a487a4f
This commit is contained in:
commit
6a9202fcfc
10 changed files with 353 additions and 55 deletions
|
|
@ -21,7 +21,7 @@ use Sylius\Behat\Context\Api\Resources;
|
|||
use Sylius\Behat\Service\SharedStorageInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class PromotionContext implements Context
|
||||
final readonly class PromotionContext implements Context
|
||||
{
|
||||
public function __construct(
|
||||
private ApiClientInterface $client,
|
||||
|
|
@ -34,7 +34,11 @@ final class PromotionContext implements Context
|
|||
#[When('I remove coupon from my cart')]
|
||||
public function iUseCouponWithCode(?string $couponCode = null): void
|
||||
{
|
||||
$this->useCouponCode($couponCode);
|
||||
$this->client
|
||||
->buildUpdateRequest(Resources::ORDERS, $this->getCartTokenValue())
|
||||
->setRequestData(['couponCode' => $couponCode])
|
||||
->update()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,23 +48,22 @@ final class PromotionContext implements Context
|
|||
{
|
||||
$response = $this->client->getLastResponse();
|
||||
|
||||
$availableErrors = [
|
||||
'couponCode: Coupon code is invalid.',
|
||||
'couponCode: Coupon code has expired.',
|
||||
'couponCode: Coupon code is not valid for this order.',
|
||||
];
|
||||
|
||||
Assert::same($response->getStatusCode(), 422);
|
||||
Assert::same($this->responseChecker->getError($response), 'couponCode: Coupon code is invalid.');
|
||||
Assert::inArray($this->responseChecker->getError($response), $availableErrors);
|
||||
}
|
||||
|
||||
private function getCartTokenValue(): ?string
|
||||
private function getCartTokenValue(): string
|
||||
{
|
||||
if ($this->sharedStorage->has('cart_token')) {
|
||||
return $this->sharedStorage->get('cart_token');
|
||||
if (!$this->sharedStorage->has('cart_token')) {
|
||||
throw new \RuntimeException('There is no cart token set in shared storage.');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function useCouponCode(?string $couponCode): void
|
||||
{
|
||||
$this->client->buildUpdateRequest(Resources::ORDERS, $this->getCartTokenValue());
|
||||
$this->client->setRequestData(['couponCode' => $couponCode]);
|
||||
$this->client->update();
|
||||
return $this->sharedStorage->get('cart_token');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,11 @@ use Symfony\Component\Validator\Constraint;
|
|||
#[\Attribute]
|
||||
final class PromotionCouponEligibility extends Constraint
|
||||
{
|
||||
/** @var string */
|
||||
public $message = 'sylius.promotion_coupon.is_invalid';
|
||||
public string $invalid = 'sylius.promotion_coupon.is_invalid';
|
||||
|
||||
public string $expired = 'sylius.promotion_coupon.expired';
|
||||
|
||||
public string $ineligible = 'sylius.promotion_coupon.ineligible';
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,10 +25,14 @@ use Webmozart\Assert\Assert;
|
|||
|
||||
final class PromotionCouponEligibilityValidator extends ConstraintValidator
|
||||
{
|
||||
/**
|
||||
* @param PromotionCouponRepositoryInterface<PromotionCouponInterface> $promotionCouponRepository
|
||||
* @param OrderRepositoryInterface<OrderInterface> $orderRepository
|
||||
*/
|
||||
public function __construct(
|
||||
private PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
private OrderRepositoryInterface $orderRepository,
|
||||
private AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
private readonly PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
private readonly OrderRepositoryInterface $orderRepository,
|
||||
private readonly AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -43,29 +47,44 @@ final class PromotionCouponEligibilityValidator extends ConstraintValidator
|
|||
return;
|
||||
}
|
||||
|
||||
/** @var PromotionCouponInterface|null $promotionCoupon */
|
||||
$promotionCoupon = $this->promotionCouponRepository->findOneBy(['code' => $value->couponCode]);
|
||||
|
||||
if (!$promotionCoupon instanceof PromotionCouponInterface) {
|
||||
$this->context
|
||||
->buildViolation($constraint->message)
|
||||
->atPath('couponCode')
|
||||
->addViolation()
|
||||
;
|
||||
if ($promotionCoupon === null) {
|
||||
$this->addViolation($constraint->invalid, 'COUPON_INVALID');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var OrderInterface $cart */
|
||||
$expirationDate = $promotionCoupon->getExpiresAt();
|
||||
|
||||
if ($expirationDate !== null && $expirationDate < new \DateTime()) {
|
||||
$this->addViolation($constraint->expired, 'COUPON_EXPIRED');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var OrderInterface|null $cart */
|
||||
$cart = $this->orderRepository->findCartByTokenValue($value->orderTokenValue);
|
||||
|
||||
if ($cart === null) {
|
||||
throw new \InvalidArgumentException('Cart with given token supposed to exist at this point.');
|
||||
}
|
||||
|
||||
$cart->setPromotionCoupon($promotionCoupon);
|
||||
|
||||
if (!$this->appliedCouponEligibilityChecker->isEligible($promotionCoupon, $cart)) {
|
||||
$this->context
|
||||
->buildViolation($constraint->message)
|
||||
->atPath('couponCode')
|
||||
->addViolation()
|
||||
;
|
||||
$this->addViolation($constraint->ineligible, 'PROMOTION_INELIGIBLE');
|
||||
}
|
||||
}
|
||||
|
||||
private function addViolation(string $message, string $code): void
|
||||
{
|
||||
$this->context
|
||||
->buildViolation($message)
|
||||
->atPath('couponCode')
|
||||
->setCode($code)
|
||||
->addViolation()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,18 +54,87 @@ final class PromotionCouponEligibilityValidatorSpec extends ObjectBehavior
|
|||
;
|
||||
}
|
||||
|
||||
function it_does_not_add_violation_if_promotion_coupon_is_eligible(
|
||||
function it_does_not_add_violation_if_coupon_code_was_not_provided(
|
||||
PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
ExecutionContextInterface $executionContext,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new UpdateCart(orderTokenValue: 'token', couponCode: null);
|
||||
$constraint = new PromotionCouponEligibility();
|
||||
|
||||
$promotionCouponRepository->findOneBy(Argument::any())->shouldNotBeCalled();
|
||||
$orderRepository->findCartByTokenValue(Argument::any())->shouldNotBeCalled();
|
||||
$appliedCouponEligibilityChecker->isEligible(Argument::cetera())->shouldNotBeCalled();
|
||||
$executionContext->buildViolation(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_adds_violation_if_coupon_code_was_provided_but_it_does_not_exist(
|
||||
PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
ExecutionContextInterface $executionContext,
|
||||
ConstraintViolationBuilderInterface $constraintViolationBuilder,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new UpdateCart(orderTokenValue: 'token', couponCode: 'couponCode');
|
||||
$constraint = new PromotionCouponEligibility();
|
||||
|
||||
$promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn(null);
|
||||
$orderRepository->findCartByTokenValue('token')->shouldNotBeCalled();
|
||||
$appliedCouponEligibilityChecker->isEligible(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$executionContext->buildViolation($constraint->invalid)->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->atPath('couponCode')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->setCode('COUPON_INVALID')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->addViolation()->shouldBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_adds_violation_if_coupon_code_was_provided_but_it_is_expired(
|
||||
PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
ConstraintViolationBuilderInterface $constraintViolationBuilder,
|
||||
ExecutionContextInterface $executionContext,
|
||||
PromotionCouponInterface $promotionCoupon,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new UpdateCart(orderTokenValue: 'token', couponCode: 'couponCode');
|
||||
$constraint = new PromotionCouponEligibility();
|
||||
|
||||
$promotionCoupon->getExpiresAt()->willReturn(new \DateTime('-1 day'));
|
||||
$promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn($promotionCoupon);
|
||||
$orderRepository->findCartByTokenValue('token')->shouldNotBeCalled();
|
||||
$appliedCouponEligibilityChecker->isEligible(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$executionContext->buildViolation($constraint->expired)->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->atPath('couponCode')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->setCode('COUPON_EXPIRED')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->addViolation()->shouldBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_does_not_add_violation_if_promotion_with_given_coupon_is_eligible(
|
||||
PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
PromotionCouponInterface $promotionCoupon,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
OrderInterface $cart,
|
||||
ExecutionContextInterface $executionContext,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
$constraint = new PromotionCouponEligibility();
|
||||
|
||||
$value = new UpdateCart(couponCode: 'couponCode', orderTokenValue: 'token');
|
||||
$value = new UpdateCart(orderTokenValue: 'token', couponCode: 'couponCode');
|
||||
|
||||
$promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn($promotionCoupon);
|
||||
$orderRepository->findCartByTokenValue('token')->willReturn($cart);
|
||||
|
|
@ -79,21 +148,21 @@ final class PromotionCouponEligibilityValidatorSpec extends ObjectBehavior
|
|||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_adds_violation_if_promotion_coupon_is_not_eligible(
|
||||
function it_adds_violation_if_promotion_with_given_coupon_is_not_eligible(
|
||||
PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
PromotionCouponInterface $promotionCoupon,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
OrderInterface $cart,
|
||||
ExecutionContextInterface $executionContext,
|
||||
ConstraintViolationBuilderInterface $constraintViolationBuilder,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new UpdateCart(orderTokenValue: 'token', couponCode: 'couponCode');
|
||||
$constraint = new PromotionCouponEligibility();
|
||||
$constraint->message = 'message';
|
||||
|
||||
$value = new UpdateCart(couponCode: 'couponCode', orderTokenValue: 'token');
|
||||
|
||||
$promotionCoupon->getExpiresAt()->willReturn(null);
|
||||
$promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn($promotionCoupon);
|
||||
$orderRepository->findCartByTokenValue('token')->willReturn($cart);
|
||||
|
||||
|
|
@ -101,33 +170,35 @@ final class PromotionCouponEligibilityValidatorSpec extends ObjectBehavior
|
|||
|
||||
$appliedCouponEligibilityChecker->isEligible($promotionCoupon, $cart)->willReturn(false);
|
||||
|
||||
$executionContext->buildViolation($constraint->message)->willReturn($constraintViolationBuilder);
|
||||
$executionContext->buildViolation($constraint->ineligible)->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->atPath('couponCode')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->setCode('PROMOTION_INELIGIBLE')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->addViolation()->shouldBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_adds_violation_if_promotion_coupon_is_not_instance_of_promotion_coupon_interface(
|
||||
function it_throws_an_exception_if_cart_with_given_token_does_not_exist(
|
||||
PromotionCouponRepositoryInterface $promotionCouponRepository,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker,
|
||||
PromotionCouponInterface $promotionCoupon,
|
||||
ExecutionContextInterface $executionContext,
|
||||
ConstraintViolationBuilderInterface $constraintViolationBuilder,
|
||||
): void {
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$value = new UpdateCart(orderTokenValue: 'token', couponCode: 'couponCode');
|
||||
$constraint = new PromotionCouponEligibility();
|
||||
$constraint->message = 'message';
|
||||
|
||||
$value = new UpdateCart(couponCode: 'couponCode', orderTokenValue: 'token');
|
||||
$promotionCoupon->getExpiresAt()->willReturn(null);
|
||||
$promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn($promotionCoupon);
|
||||
$appliedCouponEligibilityChecker->isEligible(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$promotionCouponRepository->findOneBy(['code' => 'couponCode'])->willReturn(null);
|
||||
$orderRepository->findCartByTokenValue('token')->willReturn(null);
|
||||
|
||||
$executionContext->buildViolation($constraint->message)->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->atPath('couponCode')->willReturn($constraintViolationBuilder);
|
||||
$constraintViolationBuilder->addViolation()->shouldBeCalled();
|
||||
|
||||
$orderRepository->findCartByTokenValue('token')->shouldNotBeCalled();
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', [$value, $constraint])
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ sylius:
|
|||
not_blank: Please enter coupon code.
|
||||
regex: Coupon code can only be comprised of letters, numbers, dashes and underscores.
|
||||
unique: This coupon already exists.
|
||||
expired: Coupon code has expired.
|
||||
ineligible: Coupon code is not valid for this order.
|
||||
is_invalid: Coupon code is invalid.
|
||||
promotion:
|
||||
not_blank: Please provide a promotion for this coupon.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,17 @@ Sylius\Component\Core\Model\Product:
|
|||
code: 'CAP'
|
||||
channels: ['@channel_web']
|
||||
currentLocale: 'en_US'
|
||||
product_socks:
|
||||
code: 'SOCKS'
|
||||
channels: ['@channel_web']
|
||||
|
||||
Sylius\Component\Core\Model\ProductVariant:
|
||||
product_variant_cap_blue:
|
||||
code: 'CAP_BLUE'
|
||||
product: '@product_cap'
|
||||
currentLocale: 'en_US'
|
||||
channelPricings:
|
||||
WEB: '@channel_pricing_cap_blue_web'
|
||||
|
||||
Sylius\Component\Core\Model\ChannelPricing:
|
||||
channel_pricing_cap_blue_web:
|
||||
channelCode: 'WEB'
|
||||
price: 2000
|
||||
originalPrice: 3000
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
Sylius\Component\Core\Model\Promotion:
|
||||
promotion_active:
|
||||
code: 'promotion_active'
|
||||
name: 'Active promotion with expired coupon'
|
||||
description: 'This promotion is active but the coupon has already expired'
|
||||
channels: ['@channel_web']
|
||||
priority: 1
|
||||
exclusive: true
|
||||
appliesToDiscounted: false
|
||||
usageLimit: 1
|
||||
used: 0
|
||||
couponBased: true
|
||||
translations:
|
||||
- '@promotion_active_en'
|
||||
|
||||
Sylius\Component\Promotion\Model\PromotionTranslation:
|
||||
promotion_active_en:
|
||||
locale: 'en_US'
|
||||
label: 'Active promotion with expired coupon'
|
||||
translatable: '@promotion_active'
|
||||
|
||||
Sylius\Component\Core\Model\PromotionCoupon:
|
||||
promotion_coupon_expired:
|
||||
code: 'PROMOTION_COUPON_EXPIRED'
|
||||
usageLimit: null
|
||||
perCustomerUsageLimit: null
|
||||
reusableFromCancelledOrders: false
|
||||
promotion: '@promotion_active'
|
||||
expiresAt: <dateTimeBetween('-2 month', '-1 month')>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
Sylius\Component\Core\Model\Promotion:
|
||||
promotion_ended:
|
||||
code: 'promotion_ended'
|
||||
name: 'Ended promotion with valid coupon'
|
||||
description: 'This promotion has already ended but the coupon is still valid'
|
||||
channels: ['@channel_web']
|
||||
priority: 1
|
||||
exclusive: true
|
||||
appliesToDiscounted: false
|
||||
usageLimit: 1
|
||||
used: 0
|
||||
couponBased: true
|
||||
endsAt: <dateTimeBetween('-1 month', '-1 day')>
|
||||
translations:
|
||||
- '@promotion_ended_en'
|
||||
|
||||
Sylius\Component\Promotion\Model\PromotionTranslation:
|
||||
promotion_ended_en:
|
||||
locale: 'en_US'
|
||||
label: 'Ended promotion with valid coupon'
|
||||
translatable: '@promotion_ended'
|
||||
|
||||
Sylius\Component\Core\Model\PromotionCoupon:
|
||||
promotion_coupon_valid:
|
||||
code: 'PROMOTION_COUPON_VALID'
|
||||
usageLimit: null
|
||||
perCustomerUsageLimit: null
|
||||
reusableFromCancelledOrders: false
|
||||
promotion: '@promotion_ended'
|
||||
expiresAt: <dateTimeBetween('+1 month', '+2 month')>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
Sylius\Component\Core\Model\Promotion:
|
||||
promotion_ineligible:
|
||||
code: 'promotion_ineligible'
|
||||
name: 'Ineligible promotion'
|
||||
description: 'This promotion is not eligible for the cart that contains more than 10 items'
|
||||
channels: ['@channel_web']
|
||||
priority: 1
|
||||
exclusive: true
|
||||
appliesToDiscounted: false
|
||||
usageLimit: 1
|
||||
used: 0
|
||||
couponBased: true
|
||||
translations:
|
||||
- '@promotion_ineligible_en'
|
||||
|
||||
Sylius\Component\Promotion\Model\PromotionTranslation:
|
||||
promotion_ineligible_en:
|
||||
locale: 'en_US'
|
||||
label: 'Ineligible'
|
||||
translatable: '@promotion_ineligible'
|
||||
|
||||
Sylius\Component\Core\Model\PromotionCoupon:
|
||||
promotion_coupon_ineligible:
|
||||
code: 'ELIGIBLE_COUPON_WITH_INELIGIBLE_PROMOTION'
|
||||
usageLimit: null
|
||||
perCustomerUsageLimit: null
|
||||
reusableFromCancelledOrders: false
|
||||
promotion: '@promotion_ineligible'
|
||||
|
||||
Sylius\Component\Promotion\Model\PromotionRule:
|
||||
promotion_rule_cart_quantity_more_than_10:
|
||||
type: "cart_quantity"
|
||||
promotion: "@promotion_ineligible"
|
||||
configuration:
|
||||
count: 5
|
||||
|
||||
Sylius\Component\Promotion\Model\PromotionAction:
|
||||
promotion_action_unit_fixed_discount_100:
|
||||
type: "unit_fixed_discount"
|
||||
promotion: "@promotion_ineligible"
|
||||
configuration:
|
||||
WEB:
|
||||
amount: 100
|
||||
|
|
@ -24,6 +24,7 @@ final class CartTest extends JsonApiTestCase
|
|||
protected function setUp(): void
|
||||
{
|
||||
$this->setUpOrderPlacer();
|
||||
$this->setUpDefaultPutHeaders();
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
|
@ -598,6 +599,93 @@ final class CartTest extends JsonApiTestCase
|
|||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_apply_invalid_coupon_code(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles([
|
||||
'promotion/channel.yaml',
|
||||
'promotion/product.yaml',
|
||||
]);
|
||||
|
||||
$tokenValue = $this->pickUpCart();
|
||||
$this->addItemToCart('CAP_BLUE', 1, $tokenValue);
|
||||
|
||||
$this->requestPut(
|
||||
uri: sprintf('/api/v2/shop/orders/%s', $tokenValue),
|
||||
body: ['couponCode' => 'INVALID'],
|
||||
);
|
||||
|
||||
$this->assertResponseViolations($this->client->getResponse(), [
|
||||
['propertyPath' => 'couponCode', 'message' => 'Coupon code is invalid.'],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_apply_expired_coupon_code(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles([
|
||||
'promotion/channel.yaml',
|
||||
'promotion/product.yaml',
|
||||
'promotion/promotion_coupon_expired.yaml',
|
||||
]);
|
||||
|
||||
$tokenValue = $this->pickUpCart();
|
||||
$this->addItemToCart('CAP_BLUE', 1, $tokenValue);
|
||||
|
||||
$this->requestPut(
|
||||
uri: sprintf('/api/v2/shop/orders/%s', $tokenValue),
|
||||
body: ['couponCode' => 'PROMOTION_COUPON_EXPIRED'],
|
||||
);
|
||||
|
||||
$this->assertResponseViolations($this->client->getResponse(), [
|
||||
['propertyPath' => 'couponCode', 'message' => 'Coupon code has expired.'],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_apply_a_valid_coupon_code_of_ended_promotion(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles([
|
||||
'promotion/channel.yaml',
|
||||
'promotion/promotion_ended_with_valid_coupon.yaml',
|
||||
'promotion/product.yaml',
|
||||
]);
|
||||
|
||||
$tokenValue = $this->pickUpCart();
|
||||
$this->addItemToCart('CAP_BLUE', 1, $tokenValue);
|
||||
|
||||
$this->requestPut(
|
||||
uri: sprintf('/api/v2/shop/orders/%s', $tokenValue),
|
||||
body: ['couponCode' => 'PROMOTION_COUPON_VALID'],
|
||||
);
|
||||
|
||||
$this->assertResponseViolations($this->client->getResponse(), [
|
||||
['propertyPath' => 'couponCode', 'message' => 'Coupon code is not valid for this order.'],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_apply_valid_coupon_with_ineligible_promotion(): void
|
||||
{
|
||||
$this->loadFixturesFromFiles([
|
||||
'promotion/channel.yaml',
|
||||
'promotion/promotion_ineligible.yaml',
|
||||
'promotion/product.yaml',
|
||||
]);
|
||||
|
||||
$tokenValue = $this->pickUpCart();
|
||||
$this->addItemToCart('CAP_BLUE', 1, $tokenValue);
|
||||
|
||||
$this->requestPut(
|
||||
uri: sprintf('/api/v2/shop/orders/%s', $tokenValue),
|
||||
body: ['couponCode' => 'ELIGIBLE_COUPON_WITH_INELIGIBLE_PROMOTION'],
|
||||
);
|
||||
|
||||
$this->assertResponseViolations($this->client->getResponse(), [
|
||||
['propertyPath' => 'couponCode', 'message' => 'Coupon code is not valid for this order.'],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_deletes_cart(): void
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue