import { notFound } from "next/navigation"; import Link from "next/link"; import { prisma } from "@/lib/prisma"; import { BackLink } from "@/components/back-link"; import { formatPrice, formatDate } from "@/lib/format"; import { updateOrderStatusAction, updateShipmentTrackingAction, createDhlLabelAction, deleteOrderAction, } from "../../actions"; import { ConfirmForm } from "@/components/confirm-form"; import { OrderStatusForm } from "@/components/order-status-form"; import { checkOrderDeletable } from "@/lib/order-delete"; import { getLocale } from "@/i18n/locale"; import { getDictionary } from "@/i18n/get-dictionary"; import { isDhlConfigured } from "@/lib/dhl"; import { OrderStatusBadge, OrderStatusTimeline } from "@/components/account-ui"; import { Button } from "@/components/ui"; export default async function AdminOrderDetailPage(props: PageProps<"/admin/bestellungen/[id]">) { const t = getDictionary(await getLocale()); const statusLabels = t.orderStatusBadge; const { id } = await props.params; const order = await prisma.order.findUnique({ where: { id }, include: { items: { include: { product: { select: { slug: true } }, batch: { select: { code: true } } } }, payment: true, shipment: true, pickup: true, invoice: { include: { cancellation: { select: { number: true } } } }, customer: { select: { email: true, firstName: true, lastName: true } }, discountCode: { select: { code: true } }, }, }); if (!order) notFound(); const dhlConfigured = isDhlConfigured(); // Dieselbe Regel, die deleteOrderAction serverseitig durchsetzt — geteilt // ueber lib/order-delete.ts, damit Anzeige und Durchsetzung nicht // auseinanderlaufen koennen. const isDeletable = checkOrderDeletable({ status: order.status, hasPayment: order.payment !== null, hasInvoice: order.invoice !== null, }).deletable; return (

{order.orderNumber}

{formatDate(order.createdAt)}

{/* Wo steht die Bestellung? Dieselbe Waben-Zeitleiste wie im Kundenkonto. */}
{order.giftMessage ? (

{t.adminOrderDetailPage.giftHeading}

{order.giftMessage}

) : null}

{t.adminOrderDetailPage.customerHeading}

{order.firstName} {order.lastName}

{order.email}

{order.phone ?

{order.phone}

: null} {order.customer ? (

{t.adminOrderDetailPage.registeredAccount}

) : (

{t.adminOrderDetailPage.guestOrder}

)}

{order.fulfillmentMethod === "VERSAND" ? t.adminOrderDetailPage.shippingAddressHeading : t.adminOrderDetailPage.pickupHeading}

{order.fulfillmentMethod === "VERSAND" ? ( <>

{order.street}

{order.zip} {order.city}

{/* Nur bei Packstation-Lieferung: ohne die Postnummer laesst sich keine Versandmarke erstellen, und ohne Anzeige hier waere nicht nachvollziehbar, warum DHL sie ablehnt. */} {order.packstationNumber ? (

{t.adminOrderDetailPage.postNumberLabel}: {order.postNumber ?? "—"}

) : null}

{order.shipment?.shippedAt ? t.adminOrderDetailPage.shippedOn(formatDate(order.shipment.shippedAt)) : t.adminOrderDetailPage.notShippedYet}

) : (

{order.pickup?.pickedUpAt ? t.adminOrderDetailPage.pickedUpOn(formatDate(order.pickup.pickedUpAt)) : order.pickup?.readyAt ? t.adminOrderDetailPage.readySince(formatDate(order.pickup.readyAt)) : t.adminOrderDetailPage.notPickedUpYet}

)}
{order.fulfillmentMethod === "VERSAND" && order.payment?.status === "SUCCEEDED" ? (

{t.adminOrderDetailPage.dhlHeading}

{order.shipment?.trackingNumber ? (

{t.adminOrderDetailPage.dhlAlreadyCreated(order.shipment.trackingNumber)}

) : dhlConfigured ? (
) : (

{t.adminOrderDetailPage.dhlNotConfigured}

)}
) : null} {order.fulfillmentMethod === "VERSAND" ? (

{t.adminOrderDetailPage.trackingHeading}

) : null}

{t.adminOrderDetailPage.itemsHeading}

{order.items.map((item) => ( ))}
{t.adminOrderDetailPage.colProduct} {t.adminOrderDetailPage.colBatch} {t.adminOrderDetailPage.colQuantity} {t.adminOrderDetailPage.colTotal}
{item.productName} {" "} ({item.weightGrams} g) {item.batch?.code ?? "—"} {item.quantity} {formatPrice(item.totalCents, order.currency)}
{t.adminOrderDetailPage.subtotalLabel} {formatPrice(order.subtotalCents, order.currency)}
{t.adminOrderDetailPage.shippingLabel} {order.shippingCents === 0 ? t.adminOrderDetailPage.freeShipping : formatPrice(order.shippingCents, order.currency)}
{order.discountCents > 0 ? (
{t.adminOrderDetailPage.discountLabel}{order.discountCode ? ` (${order.discountCode.code})` : ""} −{formatPrice(order.discountCents, order.currency)}
) : null}
{t.adminOrderDetailPage.totalLabel} {formatPrice(order.totalCents, order.currency)}

{t.adminOrderDetailPage.paymentHeading}

{order.payment ? ( <>

{order.payment.status}

{formatPrice(order.payment.amountCents, order.payment.currency)}

{order.payment.paidAt ? (

{t.adminOrderDetailPage.paidOn(formatDate(order.payment.paidAt))}

) : null} ) : (

{t.adminOrderDetailPage.noPaymentYet}

)}

{t.adminOrderDetailPage.invoiceHeading}

{order.invoice ? (
{order.invoice.invoiceNumber} {t.adminOrderDetailPage.downloadPdf} {order.invoice.cancellation && ( <> {t.invoicePage.cancellationTitle} {order.invoice.cancellation.number} {t.adminOrderDetailPage.downloadPdf} )}
) : (

{t.adminOrderDetailPage.noInvoiceYet}

)}
{/* Dieselben drei Bedingungen prueft deleteOrderAction noch einmal serverseitig. Das hier ist reine Anzeige: ein Knopf, den man nicht sieht, ist keine Sicherheitsgrenze (siehe requireAdmin in actions/_shared.ts). Steht am Seitenende, damit man nicht aus Versehen daraufklickt, waehrend man oben den Status setzt. */}

{t.adminOrderDetailPage.deleteHeading}

{isDeletable ? ( <>

{t.adminOrderDetailPage.deleteHint}

) : (

{t.adminOrderDetailPage.deleteBlocked}

)}
); }