Skip to content

Commit

Permalink
Prevent from refund free order
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamKasp committed Jan 31, 2020
1 parent d20f724 commit 33e78ad
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 70 deletions.
28 changes: 28 additions & 0 deletions features/being_unable_to_refund_free_order.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@refunds
Feature: Being unable to refund a free order
In order to give back money to the customer only if it is possible
As an Administrator
I want not to be able to generate a refund for a free order

Background:
Given the store operates on a single green channel in "United States"
And the store has a free product "Witcher Sword"
And the store ships everywhere for free for all channels
And the store allows paying with "Space money"
And there is a customer "Lucifer Morningstar" that placed an order "#0000001"
And the customer bought 3 "Witcher Sword" products
And the customer "Lucifer Morningstar" addressed it to "Seaside Fwy", "90802" "Los Angeles" in the "United States" with identical billing address
And the customer chose "Free" shipping method
And this order is already paid
And I am logged in as an administrator

@ui
Scenario: Being unable to refund a free order
When I view the summary of the order "#0000001"
Then I should not see refunds button

@ui
Scenario: Not being able to open refund page when order is free
When I try to refund some units of order "#0000001"
Then I should be redirected to the order "#0000001" show page
And I should be notified that I cannot refund a free order
26 changes: 0 additions & 26 deletions features/preventing_from_refund_free_order.feature

This file was deleted.

2 changes: 1 addition & 1 deletion features/refunding_single_order_unit.feature
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Feature: Refunding a single order unit
@ui
Scenario: Not being able to see refunds button
When I view the summary of the order "#00000022"
Then I should not be able to see refunds button
Then I should not see refunds button

@ui
Scenario: Being able to choose only offline payment methods
Expand Down
42 changes: 39 additions & 3 deletions spec/Checker/OrderRefundingAvailabilityCheckerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,68 @@ function it_implements_order_refunding_availability_checker_interface(): void
$this->shouldImplement(OrderRefundingAvailabilityCheckerInterface::class);
}

function it_returns_true_if_order_is_paid(
function it_returns_true_if_order_is_paid_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PAID);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(true);
}

function it_returns_true_if_order_is_partialy_refunded(
function it_returns_true_if_order_is_partially_refunded_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PARTIALLY_REFUNDED);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(true);
}

function it_returns_false_if_order_is_in_other_state(
function it_returns_false_if_order_is_in_other_state_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(false);
}

function it_returns_false_if_order_is_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PAID);
$order->getTotal()->willReturn(0);

$this('00000007')->shouldReturn(false);
}

function it_returns_false_if_order_is_partially_refunded_and_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PARTIALLY_REFUNDED);
$order->getTotal()->willReturn(0);

$this('00000007')->shouldReturn(false);
}

function it_returns_false_if_order_is_in_other_state_and_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT);
$order->getTotal()->willReturn(0);

$this('00000007')->shouldReturn(false);
}
Expand Down
46 changes: 42 additions & 4 deletions spec/Checker/OrderRefundsListAvailabilityCheckerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,80 @@ function it_implements_order_refunding_availability_checker_interface(): void
$this->shouldImplement(OrderRefundingAvailabilityCheckerInterface::class);
}

function it_returns_true_if_order_is_paid(
function it_returns_true_if_order_is_paid_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PAID);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(true);
}

function it_returns_true_if_order_is_refunded(
function it_returns_true_if_order_is_refunded_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_REFUNDED);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(true);
}

function it_returns_true_if_order_is_partialy_refunded(
function it_returns_true_if_order_is_partially_refunded_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PARTIALLY_REFUNDED);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(true);
}

function it_returns_false_if_order_is_in_other_state(
function it_returns_false_if_order_is_in_other_state_and_not_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT);
$order->getTotal()->willReturn(100);

$this('00000007')->shouldReturn(false);
}


function it_returns_false_if_order_is_paid_and_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PAID);
$order->getTotal()->willReturn(0);

$this('00000007')->shouldReturn(false);
}

function it_returns_false_if_order_is_refunded_and_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_REFUNDED);
$order->getTotal()->willReturn(0);

$this('00000007')->shouldReturn(false);
}

function it_returns_false_if_order_is_in_other_state_and_free(
OrderRepositoryInterface $orderRepository,
OrderInterface $order
): void {
$orderRepository->findOneByNumber('00000007')->willReturn($order);
$order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT);
$order->getTotal()->willReturn(0);

$this('00000007')->shouldReturn(false);
}
Expand Down
10 changes: 7 additions & 3 deletions src/Action/Admin/OrderRefundsListAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ public function __invoke(Request $request): Response
$order = $this->orderRepository->findOneByNumber($request->attributes->get('orderNumber'));

if (!$this->orderRefundsListAvailabilityChecker->__invoke($request->attributes->get('orderNumber'))) {
return $this->redirectToReferer($order);
if ($order->getTotal() === 0) {
return $this->redirectToReferer($order, 'sylius_refund.free_order_should_not_be_refund');
}

return $this->redirectToReferer($order, 'sylius_refund.order_should_be_paid');
}

return new Response(
Expand All @@ -68,9 +72,9 @@ public function __invoke(Request $request): Response
);
}

private function redirectToReferer(OrderInterface $order): Response
private function redirectToReferer(OrderInterface $order, string $message): Response
{
$this->session->getFlashBag()->add('error', 'sylius_refund.order_should_be_paid');
$this->session->getFlashBag()->add('error', $message);

return new RedirectResponse($this->router->generate('sylius_admin_order_show', ['id' => $order->getId()]));
}
Expand Down
5 changes: 3 additions & 2 deletions src/Checker/OrderRefundingAvailabilityChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public function __invoke(string $orderNumber): bool

return in_array(
$order->getPaymentState(),
[OrderPaymentStates::STATE_PAID, OrderPaymentStates::STATE_PARTIALLY_REFUNDED]
);
[OrderPaymentStates::STATE_PAID, OrderPaymentStates::STATE_PARTIALLY_REFUNDED]) &&
$order->getTotal() !== 0
;
}
}
5 changes: 3 additions & 2 deletions src/Checker/OrderRefundsListAvailabilityChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public function __invoke(string $orderNumber): bool

return in_array(
$order->getPaymentState(),
[OrderPaymentStates::STATE_PAID, OrderPaymentStates::STATE_PARTIALLY_REFUNDED, OrderPaymentStates::STATE_REFUNDED]
);
[OrderPaymentStates::STATE_PAID, OrderPaymentStates::STATE_PARTIALLY_REFUNDED, OrderPaymentStates::STATE_REFUNDED]) &&
$order->getTotal() !== 0
;
}
}
3 changes: 2 additions & 1 deletion src/Resources/translations/flashes.en.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
sylius_refund:
at_least_one_unit_should_be_selected_to_refund: 'At least one unit should be selected to refund'
error_occurred: 'Unexpected error occurred'
free_order_should_not_be_refund: 'You cannot refund a free order'
order_should_be_paid: 'Order should be paid for the units to could be refunded'
refund_amount_must_be_greater: 'Refund amount must be greater than 0'
refund_amount_must_be_less: 'You cannot refund more money than the refunded unit total'
Expand All @@ -8,4 +10,3 @@ sylius_refund:
resend_credit_memo_success: 'Selected credit memo has been successfully resent'
unit_refund_exceeded: 'You cannot refund more money than the order unit total'
units_successfully_refunded: 'Selected order units have been successfully refunded'
error_occurred: 'Unexpected error occurred'
44 changes: 23 additions & 21 deletions src/Resources/views/_paymentMethod.html.twig
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
{% set original_payment_method = order.payments.first().method %}
{% if order.payments.first() %}
{% set original_payment_method = order.payments.first().method %}

<div class="ui hidden divider"></div>
<div class="ui hidden divider"></div>

<div class="ui stackable grid">
<div class="two column row">
<div class="ui form column">
<div class="field">
<label for="payment-methods">{{ 'sylius.ui.payment_method'|trans }}</label>
<select id="payment-methods" name="sylius_refund_payment_method" class="ui fluid selection dropdown">
{% for payment_method in payment_methods %}
<option value="{{ payment_method.id }}" {{ (payment_method.code == original_payment_method.code) ? 'selected="selected"' : '' }}>
{{ payment_method.name }}
</option>
{% endfor %}
</select>
<small>{{ 'sylius.ui.original_payment_method'|trans }}: <strong>{{ original_payment_method }}</strong></small>
<div class="ui stackable grid">
<div class="two column row">
<div class="ui form column">
<div class="field">
<label for="payment-methods">{{ 'sylius.ui.payment_method'|trans }}</label>
<select id="payment-methods" name="sylius_refund_payment_method" class="ui fluid selection dropdown">
{% for payment_method in payment_methods %}
<option value="{{ payment_method.id }}" {{ (payment_method.code == original_payment_method.code) ? 'selected="selected"' : '' }}>
{{ payment_method.name }}
</option>
{% endfor %}
</select>
<small>{{ 'sylius.ui.original_payment_method'|trans }}: <strong>{{ original_payment_method }}</strong></small>
</div>
</div>
</div>
<div class="ui form column">
<div class="field">
<label for="sylius-refund-comment">{{ 'sylius.ui.comment'|trans }}</label>
<textarea rows="3" name="sylius_refund_comment" id="sylius-refund-comment"></textarea>
<div class="ui form column">
<div class="field">
<label for="sylius-refund-comment">{{ 'sylius.ui.comment'|trans }}</label>
<textarea rows="3" name="sylius_refund_comment" id="sylius-refund-comment"></textarea>
</div>
</div>
</div>
</div>
</div>
{% endif %}
12 changes: 6 additions & 6 deletions tests/Behat/Context/Ui/ManagingOrdersContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ public function shouldBeNotifiedThatTheOrderShouldBePaid(): void
}

/**
* @Then I should not be able to see refunds button
* @Then I should not see refunds button
*/
public function shouldNotBeAbleToSeeRefundsButton(): void
public function iShouldNotSeeRefundsButton(): void
{
Assert::false($this->showPage->hasRefundsButton());
}
Expand Down Expand Up @@ -112,16 +112,16 @@ public function thisOrderSPaymentStateShouldBe(OrderInterface $order, string $or
*/
public function iShouldBeRedirectedToTheOrderShowPage(OrderInterface $order): void
{
$this->showPage->isOpen(['id' => $order->getId()]);
Assert::true($this->showPage->isOpen(['id' => $order->getId()]));
}

/**
* @Then I should be notified that I cannot refund free order
* @Then I should be notified that I cannot refund a free order
*/
public function iShouldBeNotifiedThatICannotRefundFreeOrder(): void
public function iShouldBeNotifiedThatICannotRefundAFreeOrder(): void
{
$this->notificationChecker->checkNotification(
'You can not refund free order',
'You cannot refund a free order',
NotificationType::failure()
);
}
Expand Down
4 changes: 4 additions & 0 deletions tests/Behat/Resources/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,9 @@
<service id="Tests\Sylius\RefundPlugin\Behat\Services\Provider\MessagesProvider">
<argument>%kernel.cache_dir%/spool</argument>
</service>

<service id="Tests\Sylius\RefundPlugin\Behat\Context\Setup\ProductContext">
<argument type="service" id="sylius.behat.context.setup.product" />
</service>
</services>
</container>
3 changes: 2 additions & 1 deletion tests/Behat/Resources/suites.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ default:
- sylius.behat.context.setup.taxation
- sylius.behat.context.setup.zone

- Tests\Sylius\RefundPlugin\Behat\Context\Setup\RefundingContext
- Tests\Sylius\RefundPlugin\Behat\Context\Setup\OrderContext
- Tests\Sylius\RefundPlugin\Behat\Context\Setup\ProductContext
- Tests\Sylius\RefundPlugin\Behat\Context\Setup\RefundingContext

- sylius.behat.context.ui.admin.managing_orders

Expand Down

0 comments on commit 33e78ad

Please sign in to comment.