Skip to content

Commit dd7381f

Browse files
authored
Merge pull request #868 from HiEventsDev/develop
2 parents ca8558e + 6d81e93 commit dd7381f

File tree

50 files changed

+6309
-3334
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+6309
-3334
lines changed

backend/app/DomainObjects/Status/OrderStatus.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ enum OrderStatus
1212
case CANCELLED;
1313
case COMPLETED;
1414
case AWAITING_OFFLINE_PAYMENT;
15+
case ABANDONED;
1516

1617
public static function getHumanReadableStatus(string $status): string
1718
{
@@ -20,6 +21,7 @@ public static function getHumanReadableStatus(string $status): string
2021
self::CANCELLED->name => __('Cancelled'),
2122
self::COMPLETED->name => __('Completed'),
2223
self::AWAITING_OFFLINE_PAYMENT->name => __('Awaiting offline payment'),
24+
self::ABANDONED->name => __('Abandoned'),
2325
};
2426
}
2527
}

backend/app/Exports/AttendeesExport.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,18 @@ public function map($attendee): array
9797

9898
/** @var ProductDomainObject $ticket */
9999
$ticket = $attendee->getProduct();
100-
$ticketName = $ticket->getTitle();
101-
if ($ticket->getType() === ProductPriceType::TIERED->name) {
100+
$ticketName = $ticket?->getTitle();
101+
if ($ticket && $ticket->getType() === ProductPriceType::TIERED->name) {
102102
$ticketName .= ' - ' . $ticket
103103
->getProductPrices()
104104
->first(fn(ProductPriceDomainObject $tp) => $tp->getId() === $attendee->getProductPriceId())
105105
->getLabel();
106106
}
107107

108+
if (!$ticketName) {
109+
$ticketName = __('Unknown');
110+
}
111+
108112
$checkIns = $attendee->getCheckIns()
109113
? $attendee->getCheckIns()
110114
->map(fn($checkIn) => sprintf(
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace HiEvents\Http\Actions\Orders\Public;
4+
5+
use HiEvents\Exceptions\ResourceConflictException;
6+
use HiEvents\Exceptions\UnauthorizedException;
7+
use HiEvents\Http\Actions\BaseAction;
8+
use HiEvents\Resources\Order\OrderResourcePublic;
9+
use HiEvents\Services\Application\Handlers\Order\Public\AbandonOrderPublicHandler;
10+
use Illuminate\Http\JsonResponse;
11+
use Symfony\Component\HttpFoundation\Response;
12+
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
13+
14+
class AbandonOrderActionPublic extends BaseAction
15+
{
16+
public function __construct(
17+
private readonly AbandonOrderPublicHandler $abandonOrderPublicHandler,
18+
)
19+
{
20+
}
21+
22+
public function __invoke(int $eventId, string $orderShortId): JsonResponse
23+
{
24+
try {
25+
$order = $this->abandonOrderPublicHandler->handle($orderShortId);
26+
27+
return $this->resourceResponse(
28+
resource: OrderResourcePublic::class,
29+
data: $order,
30+
);
31+
} catch (ResourceNotFoundException $e) {
32+
return $this->errorResponse($e->getMessage(), Response::HTTP_NOT_FOUND);
33+
} catch (ResourceConflictException $e) {
34+
return $this->errorResponse($e->getMessage(), Response::HTTP_CONFLICT);
35+
} catch (UnauthorizedException $e) {
36+
return $this->errorResponse($e->getMessage(), Response::HTTP_UNAUTHORIZED);
37+
}
38+
}
39+
}

backend/app/Repository/Eloquent/OrderRepository.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function findByEventId(int $eventId, QueryParamsDTO $params): LengthAware
2525
$where = [
2626
[OrderDomainObjectAbstract::EVENT_ID, '=', $eventId],
2727
[OrderDomainObjectAbstract::STATUS, '!=', OrderStatus::RESERVED->name],
28+
[OrderDomainObjectAbstract::STATUS, '!=', OrderStatus::ABANDONED->name],
2829
];
2930

3031
if ($params->query) {
@@ -64,6 +65,7 @@ public function findByOrganizerId(int $organizerId, int $accountId, QueryParamsD
6465
{
6566
$where = [
6667
['orders.status', '!=', OrderStatus::RESERVED->name],
68+
['orders.status', '!=', OrderStatus::ABANDONED->name],
6769
];
6870

6971
if ($params->query) {

backend/app/Repository/Eloquent/ProductRepository.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,11 @@ public function hasAssociatedOrders(int $productId): bool
256256
{
257257
return $this->db->table('order_items')
258258
->join('orders', 'order_items.order_id', '=', 'orders.id')
259-
->whereIn('orders.status', [OrderStatus::COMPLETED->name, OrderStatus::CANCELLED->name])
259+
->whereIn('orders.status', [
260+
OrderStatus::COMPLETED->name,
261+
OrderStatus::CANCELLED->name,
262+
OrderStatus::AWAITING_OFFLINE_PAYMENT->name,
263+
])
260264
->where('order_items.product_id', $productId)
261265
->exists();
262266
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace HiEvents\Services\Application\Handlers\Order\Public;
4+
5+
use HiEvents\DomainObjects\Generated\OrderDomainObjectAbstract;
6+
use HiEvents\DomainObjects\OrderDomainObject;
7+
use HiEvents\DomainObjects\Status\OrderStatus;
8+
use HiEvents\Exceptions\ResourceConflictException;
9+
use HiEvents\Exceptions\UnauthorizedException;
10+
use HiEvents\Repository\Interfaces\OrderRepositoryInterface;
11+
use HiEvents\Services\Infrastructure\Session\CheckoutSessionManagementService;
12+
use Illuminate\Log\Logger;
13+
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
14+
15+
class AbandonOrderPublicHandler
16+
{
17+
public function __construct(
18+
private readonly OrderRepositoryInterface $orderRepository,
19+
private readonly CheckoutSessionManagementService $sessionService,
20+
private readonly Logger $logger,
21+
)
22+
{
23+
}
24+
25+
/**
26+
* @throws ResourceConflictException
27+
*/
28+
public function handle(string $orderShortId): OrderDomainObject
29+
{
30+
$order = $this->orderRepository->findByShortId($orderShortId);
31+
32+
if (!$order) {
33+
throw new ResourceNotFoundException(__('Order not found'));
34+
}
35+
36+
if ($order->getStatus() !== OrderStatus::RESERVED->name) {
37+
throw new ResourceConflictException(__('Order is not in a valid status to be abandoned'));
38+
}
39+
40+
if ($order->isReservedOrderExpired()) {
41+
throw new ResourceConflictException(__('Order has already expired'));
42+
}
43+
44+
$this->verifySessionId($order->getSessionId());
45+
46+
$this->orderRepository->updateFromArray($order->getId(), [
47+
OrderDomainObjectAbstract::STATUS => OrderStatus::ABANDONED->name,
48+
]);
49+
50+
$this->logger->info('Order abandoned by customer', [
51+
'order_id' => $order->getId(),
52+
'order_short_id' => $orderShortId,
53+
'event_id' => $order->getEventId(),
54+
]);
55+
56+
return $this->orderRepository->findById($order->getId());
57+
}
58+
59+
private function verifySessionId(string $orderSessionId): void
60+
{
61+
if (!$this->sessionService->verifySession($orderSessionId)) {
62+
throw new UnauthorizedException(
63+
__('Sorry, we could not verify your session. Please restart your order.')
64+
);
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)