Replace the mock test-payment button with a real manual Swish flow
where the user sends a Swish payment with the order ID as message
and confirms via a button. Admin verifies Swish and processes manually.
Backend
- Rename OrderStatus LOOKUP_STARTED to PROCESSING (Swedish: Hanteras)
- Update V5 migration CHECK constraint from lookup_started to processing
- Rename OrderService.markAsPaid() to confirmPayment(), sets PROCESSING
instead of PAID, stop hardcoding amountPaid
- Add GET /api/payment/swish-info endpoint returning swish number and
letter price from app.payment config
- Permit /api/payment/swish-info without authentication
- Update UpdateStatusRequest regex to accept processing
- Update PaymentControllerTest for renamed method, new status, and
public swish-info endpoint test
Frontend
- Rewrite PaymentRedirect.vue: Swish number, order ID as message,
Jag har betalat button with confirmation dialog
- Add fetchSwishInfo() to api/payment.ts
- AdminPage: rename Skickade stat to Att göra (processing orders),
highlight processing rows with admin__row--todo
- OrdersPage: update status labels/badge classes for new flow
- Refactor ApiError in client.ts to property declaration syntax
- Exclude __tests__ from tsconfig.app.json and Docker builds
Tests
- Rewrite PaymentRedirect.spec.ts for Swish info, confirmation dialog,
cancel flow, and processing status
- Update OrdersPage.spec.ts with processing status test
- Update AdminDashboard.spec.ts with Att göra stat and row highlight
- Add amountPaid to ComposePage.spec.ts mock
Config
- Add SWISH_NUMBER to .env.example and docker-compose.yml
- AdminOrderResponse DTO: extends OrderResponse with email (from User
relation) and letterText fields, exposing the full order for admin review
- UpdateStatusRequest DTO: single "status" field validated against all
six OrderStatus values (pending_payment|paid|lookup_started|sent|
delivered|failed) with Swedish error messages
- OrderService.getAllOrders(): delegates to OrderRepository
.findAllByOrderByCreatedAtDesc() which uses @EntityGraph to eagerly
fetch the user relationship in a single query
- OrderService.updateOrderStatus(orderId, statusString): looks up order,
converts status string to OrderStatus enum via case-insensitive
valueOf(), saves updated entity
- AdminController /api/admin:
GET /orders → list all orders with user email (admin only)
PATCH /orders/{id}/status → update order status (admin only)
- toAdminResponse() mapper safely handles null user (empty email fallback)