Skip to content

Commit c31306c

Browse files
authored
Fix: Cancelling an order does not free ticket or global capacity (#468)
1 parent 7f5b802 commit c31306c

File tree

2 files changed

+87
-4
lines changed

2 files changed

+87
-4
lines changed

backend/app/Services/Domain/Order/OrderCancelService.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,14 @@ private function adjustProductQuantities(OrderDomainObject $order): void
8181
{
8282
$attendees = $this->attendeeRepository->findWhere([
8383
'order_id' => $order->getId(),
84-
'status' => AttendeeStatus::ACTIVE->name,
85-
]);
84+
])->filter(function (AttendeeDomainObject $attendee) use ($order) {
85+
if ($order->isOrderAwaitingOfflinePayment()) {
86+
return $attendee->getStatus() === AttendeeStatus::ACTIVE->name
87+
|| $attendee->getStatus() === AttendeeStatus::AWAITING_PAYMENT->name;
88+
}
89+
90+
return $attendee->getStatus() === AttendeeStatus::ACTIVE->name;
91+
});
8692

8793
$productIdCountMap = $attendees
8894
->map(fn(AttendeeDomainObject $attendee) => $attendee->getProductPriceId())->countBy();

backend/tests/Unit/Services/Domain/Order/OrderCancelServiceTest.php

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use HiEvents\Services\Infrastructure\DomainEvents\DomainEventDispatcherService;
1717
use HiEvents\Services\Infrastructure\DomainEvents\Enums\DomainEventType;
1818
use HiEvents\Services\Infrastructure\DomainEvents\Events\OrderEvent;
19-
use HiEvents\Services\Infrastructure\Webhook\WebhookDispatchService;
2019
use Illuminate\Contracts\Mail\Mailer;
2120
use Illuminate\Database\DatabaseManager;
2221
use Illuminate\Support\Collection;
@@ -64,6 +63,81 @@ public function testCancelOrder(): void
6463
$order->shouldReceive('getEventId')->andReturn(1);
6564
$order->shouldReceive('getId')->andReturn(1);
6665
$order->shouldReceive('getEmail')->andReturn('[email protected]');
66+
$order->shouldReceive('isOrderAwaitingOfflinePayment')->andReturn(false);
67+
68+
$order->shouldReceive('getLocale')->andReturn('en');
69+
70+
$attendees = new Collection([
71+
m::mock(AttendeeDomainObject::class)->shouldReceive('getproductPriceId')->andReturn(1)->mock(),
72+
m::mock(AttendeeDomainObject::class)->shouldReceive('getproductPriceId')->andReturn(2)->mock(),
73+
]);
74+
75+
$this->attendeeRepository
76+
->shouldReceive('findWhere')
77+
->once()
78+
->with([
79+
'order_id' => $order->getId(),
80+
])
81+
->andReturn($attendees);
82+
83+
$this->attendeeRepository->shouldReceive('updateWhere')->once();
84+
85+
$this->productQuantityService->shouldReceive('decreaseQuantitySold')->twice();
86+
87+
$this->orderRepository->shouldReceive('updateWhere')->once();
88+
89+
$event = new EventDomainObject();
90+
$event->setEventSettings(new EventSettingDomainObject());
91+
$this->eventRepository
92+
->shouldReceive('loadRelation')
93+
->once()
94+
->andReturnSelf()
95+
->getMock()
96+
->shouldReceive('findById')->once()->andReturn($event);
97+
98+
$this->mailer->shouldReceive('to')
99+
->once()
100+
->andReturnSelf();
101+
102+
$this->mailer->shouldReceive('locale')
103+
->once()
104+
->andReturnSelf();
105+
106+
$this->mailer->shouldReceive('send')->once()->withArgs(function ($mail) {
107+
return $mail instanceof OrderCancelled;
108+
});
109+
110+
$this->domainEventDispatcherService->shouldReceive('dispatch')
111+
->withArgs(function (OrderEvent $event) use ($order) {
112+
return $event->type === DomainEventType::ORDER_CANCELLED
113+
&& $event->orderId === $order->getId();
114+
})
115+
->once();
116+
117+
$this->databaseManager->shouldReceive('transaction')->once()->andReturnUsing(function ($callback) {
118+
$callback();
119+
});
120+
121+
$attendees->each(function ($attendee) {
122+
$attendee->shouldReceive('getStatus')->andReturn(AttendeeStatus::ACTIVE->name);
123+
});
124+
125+
try {
126+
$this->service->cancelOrder($order);
127+
} catch (Throwable $e) {
128+
$this->fail("Failed to cancel order: " . $e->getMessage());
129+
}
130+
131+
$this->assertTrue(true, "Order cancellation proceeded without throwing an exception.");
132+
}
133+
134+
public function testCancelOrderAwaitingOfflinePayment(): void
135+
{
136+
$order = m::mock(OrderDomainObject::class);
137+
$order->shouldReceive('getEventId')->andReturn(1);
138+
$order->shouldReceive('getId')->andReturn(1);
139+
$order->shouldReceive('getEmail')->andReturn('[email protected]');
140+
$order->shouldReceive('isOrderAwaitingOfflinePayment')->andReturn(true);
67141
$order->shouldReceive('getLocale')->andReturn('en');
68142

69143
$attendees = new Collection([
@@ -76,7 +150,6 @@ public function testCancelOrder(): void
76150
->once()
77151
->with([
78152
'order_id' => $order->getId(),
79-
'status' => AttendeeStatus::ACTIVE->name,
80153
])
81154
->andReturn($attendees);
82155

@@ -118,6 +191,10 @@ public function testCancelOrder(): void
118191
$callback();
119192
});
120193

194+
$attendees->each(function ($attendee) {
195+
$attendee->shouldReceive('getStatus')->andReturn(AttendeeStatus::AWAITING_PAYMENT->name);
196+
});
197+
121198
try {
122199
$this->service->cancelOrder($order);
123200
} catch (Throwable $e) {

0 commit comments

Comments
 (0)