mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
Merge pull request #4876 from lchrusciel/promotion-feature
[Admin] Promotions start and end date validation
This commit is contained in:
commit
4cc16020e2
18 changed files with 341 additions and 5 deletions
|
|
@ -19,6 +19,7 @@
|
|||
<parameter key="sylius.behat.context.transform.coupon.class">Sylius\Behat\Context\Transform\CouponContext</parameter>
|
||||
<parameter key="sylius.behat.context.transform.currency.class">Sylius\Behat\Context\Transform\CurrencyContext</parameter>
|
||||
<parameter key="sylius.behat.context.transform.customer.class">Sylius\Behat\Context\Transform\CustomerContext</parameter>
|
||||
<parameter key="sylius.behat.context.transform.date_time.class">Sylius\Behat\Context\Transform\DateTimeContext</parameter>
|
||||
<parameter key="sylius.behat.context.transform.lexical.class">Sylius\Behat\Context\Transform\LexicalContext</parameter>
|
||||
<parameter key="sylius.behat.context.transform.locale.class">Sylius\Behat\Context\Transform\LocaleContext</parameter>
|
||||
<parameter key="sylius.behat.context.transform.payment.class">Sylius\Behat\Context\Transform\PaymentContext</parameter>
|
||||
|
|
@ -73,6 +74,10 @@
|
|||
<tag name="sylius.behat.context" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.behat.context.transform.date_time" class="%sylius.behat.context.transform.date_time.class%" scope="scenario">
|
||||
<tag name="sylius.behat.context" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.behat.context.transform.lexical" class="%sylius.behat.context.transform.lexical.class%" scope="scenario">
|
||||
<tag name="sylius.behat.context" />
|
||||
</service>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ default:
|
|||
|
||||
- sylius.behat.context.transform.addressing
|
||||
- sylius.behat.context.transform.customer
|
||||
- sylius.behat.context.transform.date_time
|
||||
- sylius.behat.context.transform.lexical
|
||||
- sylius.behat.context.transform.payment
|
||||
- sylius.behat.context.transform.product
|
||||
|
|
|
|||
|
|
@ -56,3 +56,13 @@ Feature: Adding a new promotion
|
|||
And I add it
|
||||
Then I should be notified that it has been successfully created
|
||||
And the "Full metal promotion" promotion should be applicable for the "France" channel
|
||||
|
||||
@ui
|
||||
Scenario: Adding a promotion with start and end date
|
||||
Given I want to create a new promotion
|
||||
When I specify its code as "FULL_METAL_PROMOTION"
|
||||
And I name it "Full metal promotion"
|
||||
And I specify that it should starts at "21.04.2017"
|
||||
And I specify that it should ends at "21.05.2017"
|
||||
And I add it
|
||||
Then I should be notified that it has been successfully created
|
||||
|
|
|
|||
|
|
@ -45,3 +45,12 @@ Feature: Editing promotion
|
|||
And I save my changes
|
||||
Then I should be notified that it has been successfully edited
|
||||
And the "Christmas sale" promotion should be applicable for the "France" channel
|
||||
|
||||
@ui
|
||||
Scenario: Adding a promotion with start and end date
|
||||
Given I want to modify a "Christmas sale" promotion
|
||||
And I specify that it should starts at "12.12.2017"
|
||||
And I specify that it should ends at "24.12.2017"
|
||||
And I save my changes
|
||||
Then I should be notified that it has been successfully edited
|
||||
And the "Christmas sale" promotion should be applicable from "12.12.2017" to "24.12.2017"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,16 @@ Feature: Promotion validation
|
|||
Then I should be notified that name is required
|
||||
And promotion with code "no_vat_promotion" should not be added
|
||||
|
||||
@ui
|
||||
Scenario: Adding a promotion with start date set up after ends date
|
||||
Given I want to create a new promotion
|
||||
When I specify its code as "FULL_METAL_PROMOTION"
|
||||
And I name it "Full metal promotion"
|
||||
And I specify that it should starts at "24.12.2017"
|
||||
And I specify that it should ends at "12.12.2017"
|
||||
And I try to add it
|
||||
Then I should be notified that promotion cannot end before it starts
|
||||
|
||||
@ui
|
||||
Scenario: Trying to remove name from existing promotion
|
||||
Given there is a promotion "Christmas sale"
|
||||
|
|
@ -34,3 +44,12 @@ Feature: Promotion validation
|
|||
And I try to save my changes
|
||||
Then I should be notified that name is required
|
||||
And this promotion should still be named "Christmas sale"
|
||||
|
||||
@ui
|
||||
Scenario: Trying to add start later then ends date for existing promotion
|
||||
Given there is a promotion "Christmas sale"
|
||||
And I want to modify this promotion
|
||||
And I specify that it should starts at "24.12.2017"
|
||||
And I specify that it should ends at "12.12.2017"
|
||||
And I try to save my changes
|
||||
Then I should be notified that promotion cannot end before it starts
|
||||
|
|
|
|||
30
src/Sylius/Behat/Context/Transform/DateTimeContext.php
Normal file
30
src/Sylius/Behat/Context/Transform/DateTimeContext.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Behat\Context\Transform;
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
|
||||
/**
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
*/
|
||||
final class DateTimeContext implements Context
|
||||
{
|
||||
/**
|
||||
* @Transform :date
|
||||
* @Transform :startsDate
|
||||
* @Transform :endsDate
|
||||
*/
|
||||
public function getDate($date)
|
||||
{
|
||||
return new \DateTime($date);
|
||||
}
|
||||
}
|
||||
|
|
@ -393,6 +393,57 @@ final class ManagingPromotionsContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify that it should starts at :date
|
||||
*/
|
||||
public function iSpecifyThatItShouldStartAt(\DateTime $date)
|
||||
{
|
||||
$currentPage = $this->currentPageResolver->getCurrentPageWithForm($this->createPage, $this->updatePage);
|
||||
|
||||
$currentPage->setStartsAt($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify that it should ends at :date
|
||||
*/
|
||||
public function iSpecifyThatItShouldEndsAt(\DateTime $date)
|
||||
{
|
||||
$currentPage = $this->currentPageResolver->getCurrentPageWithForm($this->createPage, $this->updatePage);
|
||||
|
||||
$currentPage->setEndsAt($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the :promotion promotion should be applicable from :startsDate to :endsDate
|
||||
*/
|
||||
public function thePromotionShouldBeApplicableFromTo(PromotionInterface $promotion, \DateTime $startsDate, \DateTime $endsDate)
|
||||
{
|
||||
$this->iWantToModifyAPromotion($promotion);
|
||||
|
||||
Assert::true(
|
||||
$this->updatePage->hasStartsAt($startsDate),
|
||||
sprintf('Promotion %s should starts at %s, but it isn\'t.', $promotion->getName(), date('D, d M Y H:i:s', $startsDate->getTimestamp()))
|
||||
);
|
||||
|
||||
Assert::true(
|
||||
$this->updatePage->hasEndsAt($endsDate),
|
||||
sprintf('Promotion %s should ends at %s, but it isn\'t.', $promotion->getName(), date('D, d M Y H:i:s', $endsDate->getTimestamp()))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that promotion cannot end before it starts
|
||||
*/
|
||||
public function iShouldBeNotifiedThatPromotionCannotEndBeforeItsEvenStart()
|
||||
{
|
||||
$currentPage = $this->currentPageResolver->getCurrentPageWithForm($this->createPage, $this->updatePage);
|
||||
|
||||
Assert::true(
|
||||
$currentPage->checkValidationMessageFor('ends_at', 'End date cannot be set prior start date.'),
|
||||
'Start date was set after ends date, but it should not be possible.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element
|
||||
* @param string $expectedMessage
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use Sylius\Behat\Page\Admin\Crud\CreatePage as BaseCreatePage;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Łuksaz Zalewski <mateusz.zalewski@lakion.com>
|
||||
*/
|
||||
class CreatePage extends BaseCreatePage implements CreatePageInterface
|
||||
{
|
||||
|
|
@ -99,12 +100,35 @@ class CreatePage extends BaseCreatePage implements CreatePageInterface
|
|||
$this->getDocument()->checkField($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStartsAt(\DateTime $dateTime)
|
||||
{
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
|
||||
$this->getDocument()->fillField('sylius_promotion_startsAt_date', date('Y-m-d', $timestamp));
|
||||
$this->getDocument()->fillField('sylius_promotion_startsAt_time', date('H:i', $timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setEndsAt(\DateTime $dateTime)
|
||||
{
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
|
||||
$this->getDocument()->fillField('sylius_promotion_endsAt_date', date('Y-m-d', $timestamp));
|
||||
$this->getDocument()->fillField('sylius_promotion_endsAt_time', date('H:i', $timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefinedElements()
|
||||
{
|
||||
return [
|
||||
'starts_at' => '#sylius_promotion_startsAt',
|
||||
'actions' => '#sylius_promotion_actions',
|
||||
'code' => '#sylius_promotion_code',
|
||||
'name' => '#sylius_promotion_name',
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Sylius\Behat\Page\Admin\Crud\CreatePageInterface as BaseCreatePageInterface;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
*/
|
||||
interface CreatePageInterface extends BaseCreatePageInterface
|
||||
{
|
||||
|
|
@ -77,4 +78,14 @@ interface CreatePageInterface extends BaseCreatePageInterface
|
|||
* @param string $name
|
||||
*/
|
||||
public function checkChannel($name);
|
||||
|
||||
/**
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setStartsAt(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setEndsAt(\DateTime $dateTime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
*/
|
||||
class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
|
||||
{
|
||||
|
|
@ -56,6 +57,50 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
|
|||
$this->getDocument()->checkField($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStartsAt(\DateTime $dateTime)
|
||||
{
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
|
||||
$this->getDocument()->fillField('sylius_promotion_startsAt_date', date('Y-m-d', $timestamp));
|
||||
$this->getDocument()->fillField('sylius_promotion_startsAt_time', date('H:i', $timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setEndsAt(\DateTime $dateTime)
|
||||
{
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
|
||||
$this->getDocument()->fillField('sylius_promotion_endsAt_date', date('Y-m-d', $timestamp));
|
||||
$this->getDocument()->fillField('sylius_promotion_endsAt_time', date('H:i', $timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasStartsAt(\DateTime $dateTime)
|
||||
{
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
|
||||
return $this->getElement('starts_at_date')->getValue() === date('Y-m-d', $timestamp)
|
||||
&& $this->getElement('starts_at_time')->getValue() === date('H:i', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasEndsAt(\DateTime $dateTime)
|
||||
{
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
|
||||
return $this->getElement('ends_at_date')->getValue() === date('Y-m-d', $timestamp)
|
||||
&& $this->getElement('ends_at_time')->getValue() === date('H:i', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
@ -75,6 +120,11 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
|
|||
'exclusive' => '#sylius_promotion_exclusive',
|
||||
'name' => '#sylius_promotion_name',
|
||||
'usage_limit' => '#sylius_promotion_usageLimit',
|
||||
'starts_at' => '#sylius_promotion_startsAt',
|
||||
'starts_at_date' => '#sylius_promotion_startsAt_date',
|
||||
'starts_at_time' => '#sylius_promotion_startsAt_time',
|
||||
'ends_at_date' => '#sylius_promotion_endsAt_date',
|
||||
'ends_at_time' => '#sylius_promotion_endsAt_time',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface as BaseUpdatePageInterface;
|
|||
|
||||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
*/
|
||||
interface UpdatePageInterface extends BaseUpdatePageInterface
|
||||
{
|
||||
|
|
@ -48,4 +49,24 @@ interface UpdatePageInterface extends BaseUpdatePageInterface
|
|||
* @param string $name
|
||||
*/
|
||||
public function checkChannel($name);
|
||||
|
||||
/**
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setStartsAt(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setEndsAt(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasStartsAt(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasEndsAt(\DateTime $dateTime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
{{ form_row(form.code) }}
|
||||
{{ form_row(form.name) }}
|
||||
</div>
|
||||
<div class="ui two column grid">
|
||||
<div class="two field">
|
||||
<div class="column">
|
||||
{{ form_row(form.usageLimit) }}
|
||||
{{ form_row(form.exclusive) }}
|
||||
|
|
@ -19,6 +19,10 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
{{ form_row(form.startsAt) }}
|
||||
{{ form_row(form.endsAt) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui segment">
|
||||
<h4 class="ui dividing header">{{ 'sylius.ui.promotion_configuration'|trans }}</h4>
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ class PromotionType extends AbstractResourceType
|
|||
])
|
||||
->add('startsAt', 'datetime', [
|
||||
'label' => 'sylius.form.promotion.starts_at',
|
||||
'empty_value' => /* @Ignore */ ['year' => '-', 'month' => '-', 'day' => '-'],
|
||||
'time_widget' => 'text',
|
||||
'date_widget' => 'single_text',
|
||||
'time_widget' => 'single_text',
|
||||
])
|
||||
->add('endsAt', 'datetime', [
|
||||
'label' => 'sylius.form.promotion.ends_at',
|
||||
'empty_value' => /* @Ignore */ ['year' => '-', 'month' => '-', 'day' => '-'],
|
||||
'time_widget' => 'text',
|
||||
'date_widget' => 'single_text',
|
||||
'time_widget' => 'single_text',
|
||||
])
|
||||
->add('couponBased', 'checkbox', [
|
||||
'label' => 'sylius.form.promotion.coupon_based',
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
<parameter key="sylius.form.type.promotion_coupon_to_code.class">Sylius\Bundle\PromotionBundle\Form\Type\CouponToCodeType</parameter>
|
||||
<parameter key="sylius.form.type.promotion_coupon_generate_instruction.class">Sylius\Bundle\PromotionBundle\Form\Type\CouponGenerateInstructionType</parameter>
|
||||
<parameter key="sylius.form.transformer.promotion_coupon_to_code.class">Sylius\Bundle\PromotionBundle\Form\DataTransformer\CouponToCodeTransformer</parameter>
|
||||
|
||||
<parameter key="sylius.validator.date_range.class">Sylius\Bundle\PromotionBundle\Validator\PromotionDateRangeValidator</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
|
|
@ -144,6 +146,10 @@
|
|||
<argument type="service" id="sylius.repository.promotion_coupon" />
|
||||
<argument type="service" id="sylius.manager.promotion_coupon" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.validator.date_range" class="%sylius.validator.date_range.class%">
|
||||
<tag name="validator.constraint_validator" alias="sylius_promotion_date_range_validator" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@
|
|||
<option name="message">sylius.promotion.code.unique</option>
|
||||
<option name="groups">sylius</option>
|
||||
</constraint>
|
||||
<constraint name="Sylius\Bundle\PromotionBundle\Validator\Constraints\PromotionDateRange">
|
||||
<option name="message">sylius.promotion.startsAt.end_date_cannot_be_set_prior_start_date</option>
|
||||
<option name="groups">sylius</option>
|
||||
</constraint>
|
||||
<property name="code">
|
||||
<constraint name="NotBlank">
|
||||
<option name="message">sylius.promotion.code.not_blank</option>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ sylius:
|
|||
max_length: Promotion name must not be longer than 1 character.|Promotion name must not be longer than {{ limit }} characters.
|
||||
min_length: Promotion name must be at least 1 character long.|Promotion name must be at least {{ limit }} characters long.
|
||||
not_blank: Please enter promotion name.
|
||||
endsAt:
|
||||
end_date_cannot_be_set_prior_start_date: End date cannot be set prior start date.
|
||||
promotion_coupon:
|
||||
code:
|
||||
max_length: Coupon code must not be longer than 1 character.|Coupon code must not be longer than {{ limit }} characters.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\PromotionBundle\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
*/
|
||||
class PromotionDateRange extends Constraint
|
||||
{
|
||||
public $message = 'sylius.promotion.startsAt.end_date_cannot_be_set_prior_start_date';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTargets()
|
||||
{
|
||||
return [self::CLASS_CONSTRAINT];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validatedBy()
|
||||
{
|
||||
return 'sylius_promotion_date_range_validator';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Bundle\PromotionBundle\Validator;
|
||||
|
||||
use Sylius\Component\Promotion\Model\PromotionInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
*/
|
||||
class PromotionDateRangeValidator extends ConstraintValidator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param Constraint $constraint
|
||||
*/
|
||||
public function validate($value, Constraint $constraint)
|
||||
{
|
||||
if (null === $value) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert::isInstanceOf(
|
||||
$value,
|
||||
PromotionInterface::class
|
||||
);
|
||||
|
||||
if (null === $value->getStartsAt() || null === $value->getEndsAt()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($value->getStartsAt()->getTimestamp() > $value->getEndsAt()->getTimestamp()) {
|
||||
$this->context->buildViolation($constraint->message)
|
||||
->atPath('endsAt')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue