Ticketing system — back-office and customer-facing platform
Collaborated on a complete ticketing back-office under the supervision of a colleague, with full autonomy in implementation and testing: product, ticket, customer, order, gift card management, sales/attendance statistics, and archiving.
The gift card system in particular — purchase flow, delivery logic (postal vs. electronic), shipping cost deduplication across an order, and recipient/sender data handling — was primarily my own work.
The underlying data model is tightly interdependent by necessity — cancelling a single order, for instance, cascades into ticket status changes, visit-record cleanup, and (for subscriptions) physical card deactivation, all of which had to stay consistent with each other. On the customer-facing side, I built the page templates (purchase flow, customer account area, confirmation pages), while the underlying logic — payment gateway integration, PDF ticket generation with barcodes, automated email delivery — was handled by my colleague.
- Ticketing System
- Gift card
- PHP
Code Snippet
<?php
/** * Amusement park ticketing system — gift card line item processing * (part of the order-creation flow, cart checkout). * Anonymized/condensed for portfolio purposes. * * Handles one gift-card line from the cart: creates one GiftCard record * per unit (quantity > 1 means multiple distinct cards, each with its * own code), resolves sender/recipient details with sensible defaults, * and applies shipping cost deduplication for physical cards sent to * the same address within the same order. * * Architectural Note & Self-Review (Portfolio context): * Integrated within the project's procedural order-processing pipeline. * Identified refactoring targets for future iterations: * - Encapsulate state: move logic into a dedicated `GiftCardProcessor` service to eliminate outer-scope side effects. */
if (is_string($key) && str_starts_with($key, 'giftCard')) {
if (empty($giftCardsInCart[$key]) || !is_array($giftCardsInCart[$key])) { throw new GiftCardException('Invalid cart: missing gift card data.'); }
$giftCardInput = $giftCardsInCart[$key];
$quantity = max(1, (int)($line['qty'] ?? $giftCardInput['qty'] ?? 1));
$unitAmount = (float)($giftCardInput['price'] ?? 0); $unitAmountCents = euroToCents($unitAmount);
if ($unitAmountCents <= 0) { throw new GiftCardException('Invalid gift card amount.'); }
$isPhysicalCard = ($giftCardInput['cardType'] ?? null) === GIFT_CARDS_TYPES['PHYSICAL']; $isSentToBuyer = ($giftCardInput['deliveryMethod'] ?? null) === DELIVERY_METHODS_GIFT_CARDS['SEND_TO_BUYER']; $isSentByEmail = $isSentToBuyer && ($giftCardInput['cardType'] ?? null) === GIFT_CARDS_TYPES['ELECTRONIC']; $isSentByPost = $isSentToBuyer && $isPhysicalCard;
$codeGenerator = new Code(); $codeGenerator->for = 'giftCard';
for ($i = 0; $i < $quantity; $i++) {
$codeGenerator->setNew($orderDate, ['type' => 'S', 'cat' => 'K']);
$giftCardData = [ 'orderId' => $order->getId(), 'code' => $codeGenerator->new, 'amount' => $unitAmount, 'expirationDate' => date('Y-m-d', strtotime('+2 years')), 'status' => 0, 'fromName' => $giftCardInput['giverName'] ?? ($client->getFirstName() . ' ' . $client->getLastName()), ];
if (!empty($giftCardInput['beneficiaryName'])) { $giftCardData['toName'] = $giftCardInput['beneficiaryName']; } if (!empty($giftCardInput['message'])) { $giftCardData['customMessage'] = $giftCardInput['message']; }
$giftCardData['recipientLastName'] = $giftCardInput['name'] ?? ($isSentToBuyer ? $client->getLastName() : null); $giftCardData['recipientFirstName'] = $giftCardInput['firstname'] ?? ($isSentToBuyer ? $client->getFirstName() : null); $giftCardData['recipientEmail'] = $giftCardInput['email'] ?? ($isSentByEmail ? $client->getEmail() : null); $giftCardData['recipientPostcode'] = $giftCardInput['postcode'] ?? ($isSentByPost ? $client->getPostcode() : null); $giftCardData['recipientAddress'] = $giftCardInput['address'] ?? ($isSentByPost ? $client->getAddress() : null); $giftCardData['recipientCity'] = $giftCardInput['city'] ?? ($isSentByPost ? $client->getCity() : null); $giftCardData['recipientCountry'] = $giftCardInput['country'] ?? ($isSentByPost ? $client->getCountry() : null);
$giftCardData = array_filter($giftCardData, fn($value) => $value !== null);
if ($isPhysicalCard) { $giftCardData['requiresShipping'] = true;
$destinationKey = $isSentToBuyer ? DELIVERY_METHODS_GIFT_CARDS['SEND_TO_BUYER'] : implode('|', [ (string)($giftCardInput['address'] ?? ''), (string)($giftCardInput['postcode'] ?? ''), (string)($giftCardInput['city'] ?? ''), (string)($giftCardInput['country'] ?? ''), ]);
$alreadyBilled = in_array($destinationKey, $shippingAddressesBilled, true); $giftCardData['shippingCost'] = $alreadyBilled ? 0 : SHIPPING_COST_GIFT_CARD;
if (!$alreadyBilled) { $shippingAddressesBilled[] = $destinationKey; } }
if (!$giftCard->create($giftCardData)) { throw new GiftCardException('Error creating the gift card.'); } }
$lineTotalCents = $unitAmountCents * $quantity; $orderTotalCents += $lineTotalCents; $orderTotalQty += $quantity;
$orderLineItems[] = [ 'name' => (string)($giftCardInput['title'] ?? 'Gift card'), 'qty' => $quantity, 'amount' => (string)$lineTotalCents, ];
continue;}