🔄 cleanup: order with 3 key relations, and ckflow now upto speeded
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import { and, desc, eq, type Database } from "@pkg/db";
|
||||
import { checkoutFlowSession, product } from "@pkg/db/schema";
|
||||
import { getError, Logger } from "@pkg/logger";
|
||||
import { ERROR_CODES, type Result } from "@pkg/result";
|
||||
import {
|
||||
CKActionType,
|
||||
@@ -5,14 +8,11 @@ import {
|
||||
type FlowInfo,
|
||||
type PendingAction,
|
||||
} from "./data";
|
||||
import { getError, Logger } from "@pkg/logger";
|
||||
import { and, desc, eq, type Database } from "@pkg/db";
|
||||
import { checkoutFlowSession, flightTicketInfo } from "@pkg/db/schema";
|
||||
|
||||
export class CheckoutFlowRepository {
|
||||
constructor(private db: Database) {}
|
||||
|
||||
// Common method to parse and enrich flow info with ticket details
|
||||
// Common method to parse and enrich flow info with product details
|
||||
private async parseFlowInfo(
|
||||
sessionData: any,
|
||||
includeStaleness = true,
|
||||
@@ -43,48 +43,30 @@ export class CheckoutFlowRepository {
|
||||
: false;
|
||||
}
|
||||
|
||||
// Fetch ticket info if we have a ticket ID
|
||||
let ticketInfo = undefined;
|
||||
if (sessionData.ticketId) {
|
||||
// Fetch product info if we have a product ID
|
||||
let productInfo = undefined;
|
||||
if (sessionData.productId) {
|
||||
try {
|
||||
const ticketResult =
|
||||
await this.db.query.flightTicketInfo.findFirst({
|
||||
where: eq(flightTicketInfo.id, sessionData.ticketId),
|
||||
});
|
||||
|
||||
if (ticketResult) {
|
||||
ticketInfo = {
|
||||
id: ticketResult.id,
|
||||
ticketId: ticketResult.ticketId,
|
||||
departure: ticketResult.departure,
|
||||
arrival: ticketResult.arrival,
|
||||
departureDate: ticketResult.departureDate
|
||||
.toISOString()
|
||||
.split("T")[0],
|
||||
returnDate: ticketResult.returnDate
|
||||
? ticketResult.returnDate
|
||||
.toISOString()
|
||||
.split("T")[0]
|
||||
: undefined,
|
||||
flightType: ticketResult.flightType,
|
||||
cabinClass: ticketResult.cabinClass,
|
||||
priceDetails: ticketResult.priceDetails as any,
|
||||
};
|
||||
const prodResult = await this.db.query.product.findFirst({
|
||||
where: eq(product.id, sessionData.productId),
|
||||
});
|
||||
if (prodResult) {
|
||||
productInfo = { ...prodResult };
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.warn(
|
||||
"Failed to fetch ticket info for session detail",
|
||||
"Failed to fetch product info for session detail",
|
||||
err,
|
||||
);
|
||||
// Continue without ticket info - it's optional
|
||||
// Continue without product info - it's optional
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare dates for the model
|
||||
const flowInfoData = {
|
||||
...sessionData,
|
||||
ticketInfo,
|
||||
ticketId: sessionData.ticketId,
|
||||
productInfo: productInfo,
|
||||
productId: sessionData.productId,
|
||||
pendingActions: sessionData.pendingActions as any,
|
||||
personalInfo: sessionData.personalInfo as any,
|
||||
paymentInfo: sessionData.paymentInfo as any,
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { ScrollArea } from "$lib/components/ui/scroll-area";
|
||||
import type { FlowInfo } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import { CheckoutStep } from "$lib/domains/ticket/data/entities";
|
||||
import LoaderIcon from "~icons/bx/loader-alt";
|
||||
import UserIcon from "~icons/material-symbols/account-circle-full";
|
||||
import CreditCardIcon from "~icons/solar/card-2-linear";
|
||||
import QuestionMarkIcon from "~icons/solar/question-circle-linear";
|
||||
import CheckCircleIcon from "~icons/solar/check-circle-linear";
|
||||
import StopCircleIcon from "~icons/solar/stop-circle-linear";
|
||||
import ShieldAlertIcon from "~icons/solar/shield-warning-linear";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as ContextMenu from "$lib/components/ui/context-menu/index";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -21,11 +11,21 @@
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "$lib/components/ui/dialog";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { isSessionActive } from "../utils";
|
||||
import { ScrollArea } from "$lib/components/ui/scroll-area";
|
||||
import { CheckoutStep } from "$lib/domains/order/data/entities";
|
||||
import { trpcApiStore } from "$lib/stores/api";
|
||||
import type { FlowInfo } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { toast } from "svelte-sonner";
|
||||
import * as ContextMenu from "$lib/components/ui/context-menu/index";
|
||||
import LoaderIcon from "~icons/bx/loader-alt";
|
||||
import UserIcon from "~icons/material-symbols/account-circle-full";
|
||||
import CreditCardIcon from "~icons/solar/card-2-linear";
|
||||
import CheckCircleIcon from "~icons/solar/check-circle-linear";
|
||||
import QuestionMarkIcon from "~icons/solar/question-circle-linear";
|
||||
import ShieldAlertIcon from "~icons/solar/shield-warning-linear";
|
||||
import StopCircleIcon from "~icons/solar/stop-circle-linear";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
import { isSessionActive } from "../utils";
|
||||
|
||||
let {
|
||||
sessions,
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "$lib/components/ui/dialog";
|
||||
import { PaymentErrorType } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import { RadioGroup, RadioGroupItem } from "$lib/components/ui/radio-group";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "$lib/components/ui/radio-group";
|
||||
import { Textarea } from "$lib/components/ui/textarea";
|
||||
import { CKActionType } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import {
|
||||
CKActionType,
|
||||
PaymentErrorType,
|
||||
} from "@pkg/logic/domains/ckflow/data/entities";
|
||||
|
||||
let {
|
||||
open = $bindable<boolean>(false),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import { Alert, AlertDescription } from "$lib/components/ui/alert";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -9,25 +11,21 @@
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "$lib/components/ui/card";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Alert, AlertDescription } from "$lib/components/ui/alert";
|
||||
import { Separator } from "$lib/components/ui/separator";
|
||||
import { CheckoutStep } from "@pkg/logic/domains/ticket/data/entities";
|
||||
import { trpcApiStore } from "$lib/stores/api";
|
||||
import {
|
||||
CKActionType,
|
||||
type FlowInfo,
|
||||
} from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import { CheckoutStep } from "@pkg/logic/domains/order/data/enums";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { trpcApiStore } from "$lib/stores/api";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { toast } from "svelte-sonner";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import XIcon from "~icons/material-symbols/close-rounded";
|
||||
import ArrowLeftIcon from "~icons/solar/arrow-left-outline";
|
||||
import CheckCircleIcon from "~icons/solar/check-circle-broken";
|
||||
import XIcon from "~icons/material-symbols/close-rounded";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear"; // Add trash icon
|
||||
import ShieldIcon from "~icons/solar/shield-keyhole-minimalistic-broken";
|
||||
import { ckflowVM } from "../ckflow.vm.svelte";
|
||||
import { isSessionActive } from "../utils";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
// Add trash icon
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -40,7 +38,9 @@
|
||||
capitalize,
|
||||
snakeToSpacedPascal,
|
||||
} from "@pkg/logic/core/string.utils";
|
||||
import { formatCurrency } from "@pkg/logic/core/currency.utils";
|
||||
import ShieldIcon from "~icons/solar/shield-keyhole-minimalistic-broken";
|
||||
import { ckflowVM } from "../ckflow.vm.svelte";
|
||||
import { isSessionActive } from "../utils";
|
||||
import BackToPaymentDialog from "./back-to-payment-dialog.svelte";
|
||||
|
||||
let { session = $bindable() }: { session: FlowInfo } = $props();
|
||||
@@ -251,61 +251,11 @@
|
||||
|
||||
<Separator />
|
||||
|
||||
{#if session.ticketInfo}
|
||||
{#if session.productInfo}
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-lg font-medium">Booking Details</h3>
|
||||
<h3 class="text-lg font-medium">Product Details</h3>
|
||||
<div class="rounded-md border p-3">
|
||||
<div class="mb-2 flex items-center justify-between">
|
||||
<div class="font-medium">
|
||||
{session.ticketInfo.departure} → {session
|
||||
.ticketInfo.arrival}
|
||||
</div>
|
||||
<Badge variant="outline">
|
||||
{session.ticketInfo.flightType === "ONEWAY"
|
||||
? "One Way"
|
||||
: "Round Trip"}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 text-sm">
|
||||
<span class="text-muted-foreground">Departure</span>
|
||||
<span class="font-medium">
|
||||
{session.ticketInfo.departureDate}
|
||||
</span>
|
||||
|
||||
{#if session.ticketInfo.flightType !== "ONEWAY" && session.ticketInfo.returnDate}
|
||||
<span class="text-muted-foreground">Return</span>
|
||||
<span class="font-medium">
|
||||
{session.ticketInfo.returnDate}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<span class="text-muted-foreground">Cabin Class</span>
|
||||
<span class="font-medium">
|
||||
{session.ticketInfo.cabinClass}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-between border-t pt-3">
|
||||
<span class="font-medium">Original Price</span>
|
||||
<span class="text-lg font-bold text-primary">
|
||||
{formatCurrency(
|
||||
session.ticketInfo.priceDetails.basePrice ??
|
||||
0,
|
||||
session.ticketInfo.priceDetails.currency,
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<span class="font-medium">Total Price</span>
|
||||
<span class="text-lg font-bold text-primary">
|
||||
{formatCurrency(
|
||||
session.ticketInfo.priceDetails.displayPrice,
|
||||
session.ticketInfo.priceDetails.currency,
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<span>TODO: show product details here</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
<script lang="ts">
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import type { FlowInfo } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import { Separator } from "$lib/components/ui/separator";
|
||||
import {
|
||||
capitalize,
|
||||
snakeToSpacedPascal,
|
||||
} from "@pkg/logic/core/string.utils";
|
||||
import { Separator } from "$lib/components/ui/separator";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
|
||||
import type { FlowInfo } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
// Icons
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
import RestoreIcon from "~icons/solar/restart-bold";
|
||||
import CloseIcon from "~icons/solar/close-circle-linear";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -22,7 +18,9 @@
|
||||
DialogTitle,
|
||||
} from "$lib/components/ui/dialog";
|
||||
import { formatTime } from "@pkg/logic/core/date.utils";
|
||||
import { formatCurrency } from "@pkg/logic/core/currency.utils";
|
||||
import CloseIcon from "~icons/solar/close-circle-linear";
|
||||
import RestoreIcon from "~icons/solar/restart-bold";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
|
||||
let {
|
||||
session,
|
||||
@@ -116,76 +114,13 @@
|
||||
|
||||
<Separator />
|
||||
|
||||
{#if session.ticketInfo}
|
||||
{#if session.productInfo}
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-lg font-medium">Booking Details</h3>
|
||||
<h3 class="text-lg font-medium">Product Details</h3>
|
||||
<div class="rounded-md border p-3">
|
||||
<div
|
||||
class="mb-2 flex items-center justify-between"
|
||||
>
|
||||
<div class="font-medium">
|
||||
{session.ticketInfo.departure} → {session
|
||||
.ticketInfo.arrival}
|
||||
</div>
|
||||
<Badge variant="outline">
|
||||
{session.ticketInfo.flightType ===
|
||||
"ONEWAY"
|
||||
? "One Way"
|
||||
: "Round Trip"}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 text-sm">
|
||||
<span class="text-muted-foreground"
|
||||
>Departure</span
|
||||
>
|
||||
<span class="font-medium">
|
||||
{session.ticketInfo.departureDate}
|
||||
</span>
|
||||
|
||||
{#if session.ticketInfo.flightType !== "ONEWAY" && session.ticketInfo.returnDate}
|
||||
<span class="text-muted-foreground"
|
||||
>Return</span
|
||||
>
|
||||
<span class="font-medium">
|
||||
{session.ticketInfo.returnDate}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<span class="text-muted-foreground"
|
||||
>Cabin Class</span
|
||||
>
|
||||
<span class="font-medium">
|
||||
{session.ticketInfo.cabinClass}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-4 flex justify-between border-t pt-3"
|
||||
>
|
||||
<span class="font-medium">Original Price</span
|
||||
>
|
||||
<span class="text-lg font-bold text-primary">
|
||||
{formatCurrency(
|
||||
session.ticketInfo.priceDetails
|
||||
.basePrice ?? 0,
|
||||
session.ticketInfo.priceDetails
|
||||
.currency,
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-between">
|
||||
<span class="font-medium">Total Price</span>
|
||||
<span class="text-lg font-bold text-primary">
|
||||
{formatCurrency(
|
||||
session.ticketInfo.priceDetails
|
||||
.displayPrice,
|
||||
session.ticketInfo.priceDetails
|
||||
.currency,
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<span>
|
||||
TODO: SHOW THE PRODUCT INFO AT THIS PLACE
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { ScrollArea } from "$lib/components/ui/scroll-area";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import { CheckoutStep } from "$lib/domains/ticket/data/entities";
|
||||
import type { FlowInfo } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import * as ContextMenu from "$lib/components/ui/context-menu/index";
|
||||
import { isSessionActive } from "../utils";
|
||||
import { ScrollArea } from "$lib/components/ui/scroll-area";
|
||||
import { CheckoutStep } from "$lib/domains/order/data/entities";
|
||||
import type { FlowInfo } from "@pkg/logic/domains/ckflow/data/entities";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import LoaderIcon from "~icons/bx/loader-alt";
|
||||
import UserIcon from "~icons/material-symbols/account-circle-full";
|
||||
import CreditCardIcon from "~icons/solar/card-2-linear";
|
||||
import QuestionMarkIcon from "~icons/solar/question-circle-linear";
|
||||
import CheckCircleIcon from "~icons/solar/check-circle-linear";
|
||||
import StopCircleIcon from "~icons/solar/stop-circle-linear";
|
||||
import ShieldAlertIcon from "~icons/solar/shield-warning-linear";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
import QuestionMarkIcon from "~icons/solar/question-circle-linear";
|
||||
import RestoreIcon from "~icons/solar/restart-bold";
|
||||
import ShieldAlertIcon from "~icons/solar/shield-warning-linear";
|
||||
import StopCircleIcon from "~icons/solar/stop-circle-linear";
|
||||
import TrashIcon from "~icons/solar/trash-bin-trash-linear";
|
||||
import { isSessionActive } from "../utils";
|
||||
|
||||
let {
|
||||
sessions,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { capitalize } from "@pkg/logic/core/string.utils";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import {
|
||||
formatDateTime,
|
||||
formatDuration,
|
||||
formatTime,
|
||||
} from "@pkg/logic/core/date.utils";
|
||||
import XIcon from "~icons/solar/close-circle-linear";
|
||||
import CheckIcon from "~icons/solar/check-read-linear";
|
||||
import { capitalize } from "@pkg/logic/core/string.utils";
|
||||
import FlagIcon from "~icons/material-symbols/flag";
|
||||
import UserIcon from "~icons/solar/user-circle-linear";
|
||||
import ClockIcon from "~icons/solar/clock-circle-linear";
|
||||
import CardIcon from "~icons/solar/card-linear";
|
||||
import CheckIcon from "~icons/solar/check-read-linear";
|
||||
import ClockIcon from "~icons/solar/clock-circle-linear";
|
||||
import XIcon from "~icons/solar/close-circle-linear";
|
||||
import KeyIcon from "~icons/solar/key-linear";
|
||||
import UserIcon from "~icons/solar/user-circle-linear";
|
||||
import type { FlowInfo } from "../data";
|
||||
|
||||
let { session }: { session: FlowInfo } = $props();
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from "@pkg/logic/domains/order/data/entities";
|
||||
export * from "@pkg/logic/domains/order/data/enums";
|
||||
|
||||
@@ -23,7 +23,7 @@ export class OrderRepository {
|
||||
async listAllOrders(): Promise<Result<FullOrderModel[]>> {
|
||||
try {
|
||||
const res = await this.db.query.order.findMany({
|
||||
with: { customerInfo: true, product: true },
|
||||
with: { customerInfo: true, product: true, paymentInfo: true },
|
||||
});
|
||||
const out = [] as FullOrderModel[];
|
||||
for (const each of res) {
|
||||
@@ -56,7 +56,7 @@ export class OrderRepository {
|
||||
async getOrder(oid: number): Promise<Result<FullOrderModel>> {
|
||||
const out = await this.db.query.order.findFirst({
|
||||
where: eq(order.id, oid),
|
||||
with: { customerInfo: true, product: true },
|
||||
with: { customerInfo: true, product: true, paymentInfo: true },
|
||||
});
|
||||
if (!out) return {};
|
||||
const parsed = fullOrderModel.safeParse({
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
<script lang="ts">
|
||||
import Button from "$lib/components/ui/button/button.svelte";
|
||||
import LabelWrapper from "$lib/components/atoms/label-wrapper.svelte";
|
||||
import Input from "$lib/components/ui/input/input.svelte";
|
||||
import Checkbox from "$lib/components/ui/checkbox/checkbox.svelte";
|
||||
|
||||
let { order }: { order?: any } = $props();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Title from "$lib/components/atoms/title.svelte";
|
||||
import Icon from "$lib/components/atoms/icon.svelte";
|
||||
import EmailIcon from "~icons/solar/letter-broken";
|
||||
import TicketIcon from "~icons/solar/ticket-broken";
|
||||
import CreditCardIcon from "~icons/solar/card-broken";
|
||||
import Title from "$lib/components/atoms/title.svelte";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import type { FullOrderModel } from "$lib/domains/order/data/entities";
|
||||
import TicketLegsOverview from "$lib/domains/ticket/view/ticket/ticket-legs-overview.svelte";
|
||||
import CreditCardIcon from "~icons/solar/card-broken";
|
||||
import EmailIcon from "~icons/solar/letter-broken";
|
||||
import TicketIcon from "~icons/solar/ticket-broken";
|
||||
|
||||
let { order }: { order: FullOrderModel } = $props();
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import Title from "$lib/components/atoms/title.svelte";
|
||||
import { adminSiteNavMap } from "$lib/core/constants";
|
||||
import { capitalize } from "$lib/core/string.utils";
|
||||
import CinfoCard from "$lib/domains/customerinfo/view/cinfo-card.svelte";
|
||||
import type { FullOrderModel } from "$lib/domains/order/data/entities";
|
||||
import PinfoCard from "$lib/domains/passengerinfo/view/pinfo-card.svelte";
|
||||
import SuitcaseIcon from "~icons/bi/suitcase2";
|
||||
import BagIcon from "~icons/lucide/briefcase";
|
||||
import BackpackIcon from "~icons/solar/backpack-linear";
|
||||
@@ -105,14 +105,14 @@
|
||||
|
||||
{#if order.flightTicketInfo.refOIds}
|
||||
{#each order.flightTicketInfo.refOIds as refOId}
|
||||
<PinfoCard icon={PackageIcon} title="Order">
|
||||
<CinfoCard icon={PackageIcon} title="Order">
|
||||
<a
|
||||
href={`${adminSiteNavMap.orders}/${refOId}`}
|
||||
class="mt-1 inline-block font-medium text-primary hover:underline"
|
||||
>
|
||||
Reference Order #{refOId}
|
||||
</a>
|
||||
</PinfoCard>
|
||||
</CinfoCard>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { eq, type Database } from "@pkg/db";
|
||||
import { paymentDetailsModel, type PaymentDetails } from "./data";
|
||||
import type { Result } from "@pkg/result";
|
||||
import { paymentDetails } from "@pkg/db/schema";
|
||||
import { paymentInfo } from "@pkg/db/schema";
|
||||
import { Logger } from "@pkg/logger";
|
||||
import type { Result } from "@pkg/result";
|
||||
import { paymentDetailsModel, type PaymentDetails } from "./data";
|
||||
|
||||
export class PaymentInfoRepository {
|
||||
constructor(private db: Database) {}
|
||||
|
||||
async getPaymentInfo(id: number): Promise<Result<PaymentDetails>> {
|
||||
Logger.info(`Getting payment info with id ${id}`);
|
||||
const out = await this.db.query.paymentDetails.findFirst({
|
||||
where: eq(paymentDetails.id, id),
|
||||
const out = await this.db.query.paymentInfo.findFirst({
|
||||
where: eq(paymentInfo.id, id),
|
||||
});
|
||||
const parsed = paymentDetailsModel.safeParse(out);
|
||||
if (parsed.error) {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
);
|
||||
|
||||
let pii = data.data?.passengerPii;
|
||||
let paymentDetails = data.data?.paymentDetails;
|
||||
let paymentInfo = data.data?.paymentInfo;
|
||||
|
||||
const piiData = [
|
||||
{
|
||||
@@ -110,30 +110,30 @@
|
||||
];
|
||||
|
||||
// Card information
|
||||
const cardInfo = paymentDetails
|
||||
const cardInfo = paymentInfo
|
||||
? [
|
||||
{
|
||||
icon: CardUserIcon,
|
||||
title: "Cardholder Name",
|
||||
value: paymentDetails.cardholderName ?? "",
|
||||
value: paymentInfo.cardholderName ?? "",
|
||||
},
|
||||
{
|
||||
icon: CardNumberIcon,
|
||||
title: "Card Number",
|
||||
value: paymentDetails.cardNumber
|
||||
value: paymentInfo.cardNumber
|
||||
? // add spaces of 4 between each group of 4 digits
|
||||
paymentDetails.cardNumber.match(/.{1,4}/g)?.join(" ")
|
||||
paymentInfo.cardNumber.match(/.{1,4}/g)?.join(" ")
|
||||
: "",
|
||||
},
|
||||
{
|
||||
icon: CalendarCheckIcon,
|
||||
title: "Expiry Date",
|
||||
value: paymentDetails.expiry ?? "",
|
||||
value: paymentInfo.expiry ?? "",
|
||||
},
|
||||
{
|
||||
icon: LockKeyIcon,
|
||||
title: "CVV",
|
||||
value: paymentDetails.cvv ?? "",
|
||||
value: paymentInfo.cvv ?? "",
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { and, eq, type Database, isNotNull, or } from "@pkg/db";
|
||||
import { ERROR_CODES, type Result } from "$lib/core/data.types";
|
||||
import { and, eq, isNotNull, or, type Database } from "@pkg/db";
|
||||
import { order, passengerInfo } from "@pkg/db/schema";
|
||||
import { getError, Logger } from "@pkg/logger";
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
fullOrderModel,
|
||||
limitedOrderWithTicketInfoModel,
|
||||
@@ -8,9 +11,6 @@ import {
|
||||
type LimitedOrderWithTicketInfoModel,
|
||||
type NewOrderModel,
|
||||
} from "./entities";
|
||||
import { getError, Logger } from "@pkg/logger";
|
||||
import { order, passengerInfo } from "@pkg/db/schema";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
export class OrderRepository {
|
||||
private db: Database;
|
||||
@@ -122,7 +122,7 @@ export class OrderRepository {
|
||||
discountAmount: payload.discountAmount.toFixed(3),
|
||||
|
||||
flightTicketInfoId: payload.flightTicketInfoId,
|
||||
paymentDetailsId: payload.paymentDetailsId,
|
||||
paymentInfoId: payload.paymentInfoId,
|
||||
|
||||
status: OrderStatus.PENDING_FULLFILLMENT,
|
||||
pnr,
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { SessionOutcome } from "$lib/domains/ckflow/data/entities";
|
||||
import { getCKUseCases } from "$lib/domains/ckflow/domain/usecases";
|
||||
import { EmailerUseCases } from "$lib/domains/email/domain/usecases";
|
||||
import { createOrderPayloadModel } from "$lib/domains/order/data/entities";
|
||||
import { PassengerInfoRepository } from "$lib/domains/passengerinfo/data/repository";
|
||||
import { PassengerInfoController } from "$lib/domains/passengerinfo/domain/controller";
|
||||
import { PaymentInfoRepository } from "$lib/domains/paymentinfo/data/repository";
|
||||
import { PaymentInfoUseCases } from "$lib/domains/paymentinfo/domain/usecases";
|
||||
import { CheckoutStep } from "$lib/domains/ticket/data/entities";
|
||||
import { getTC } from "$lib/domains/ticket/domain/controller";
|
||||
import { createTRPCRouter, publicProcedure } from "$lib/trpc/t";
|
||||
import { db } from "@pkg/db";
|
||||
import { OrderRepository } from "../data/repository";
|
||||
import { OrderController } from "./controller";
|
||||
import { getTC } from "$lib/domains/ticket/domain/controller";
|
||||
import { getError, Logger } from "@pkg/logger";
|
||||
import { PassengerInfoController } from "$lib/domains/passengerinfo/domain/controller";
|
||||
import { PassengerInfoRepository } from "$lib/domains/passengerinfo/data/repository";
|
||||
import { PaymentInfoUseCases } from "$lib/domains/paymentinfo/domain/usecases";
|
||||
import { PaymentInfoRepository } from "$lib/domains/paymentinfo/data/repository";
|
||||
import { ERROR_CODES } from "@pkg/result";
|
||||
import { z } from "zod";
|
||||
import { getCKUseCases } from "$lib/domains/ckflow/domain/usecases";
|
||||
import { SessionOutcome } from "$lib/domains/ckflow/data/entities";
|
||||
import { CheckoutStep } from "$lib/domains/ticket/data/entities";
|
||||
import { EmailerUseCases } from "$lib/domains/email/domain/usecases";
|
||||
import { OrderRepository } from "../data/repository";
|
||||
import { OrderController } from "./controller";
|
||||
|
||||
export const orderRouter = createTRPCRouter({
|
||||
createOrder: publicProcedure
|
||||
@@ -33,7 +33,7 @@ export const orderRouter = createTRPCRouter({
|
||||
return { error: ftRes.error };
|
||||
}
|
||||
|
||||
if (!input.flightTicketId || !input.paymentDetails) {
|
||||
if (!input.flightTicketId || !input.paymentInfo) {
|
||||
return {
|
||||
error: getError({
|
||||
code: ERROR_CODES.INPUT_ERROR,
|
||||
@@ -43,7 +43,7 @@ export const orderRouter = createTRPCRouter({
|
||||
}),
|
||||
};
|
||||
}
|
||||
const pdRes = await pduc.createPaymentInfo(input.paymentDetails!);
|
||||
const pdRes = await pduc.createPaymentInfo(input.paymentInfo!);
|
||||
if (pdRes.error || !pdRes.data) {
|
||||
return { error: pdRes.error };
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export const orderRouter = createTRPCRouter({
|
||||
input.orderModel.flightTicketInfoId = ftRes.data;
|
||||
|
||||
Logger.info(`Setting payment details id ${pdRes.data}`);
|
||||
input.orderModel.paymentDetailsId = pdRes.data;
|
||||
input.orderModel.paymentInfoId = pdRes.data;
|
||||
|
||||
Logger.info("Creating order");
|
||||
const out = await oc.createOrder(input.orderModel);
|
||||
|
||||
@@ -82,7 +82,7 @@ export class PassengerInfoRepository {
|
||||
.values({
|
||||
passengerType: payload.passengerType,
|
||||
passengerPiiId: payload.passengerPiiId,
|
||||
paymentDetailsId: payload.paymentDetailsId,
|
||||
paymentInfoId: payload.paymentInfoId,
|
||||
seatSelection: payload.seatSelection,
|
||||
bagSelection: payload.bagSelection,
|
||||
agentsInfo: payload.agentsInfo,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Logger } from "@pkg/logger";
|
||||
import type { Result } from "@pkg/result";
|
||||
import type { PassengerInfo } from "../data/entities";
|
||||
import type { PassengerInfoRepository } from "../data/repository";
|
||||
import { Logger } from "@pkg/logger";
|
||||
|
||||
export class PassengerInfoController {
|
||||
repo: PassengerInfoRepository;
|
||||
@@ -14,7 +14,7 @@ export class PassengerInfoController {
|
||||
payload: PassengerInfo[],
|
||||
orderId: number,
|
||||
flightTicketInfoId?: number,
|
||||
paymentDetailsId?: number,
|
||||
paymentInfoId?: number,
|
||||
): Promise<Result<number>> {
|
||||
const made = [] as number[];
|
||||
for (const passengerInfo of payload) {
|
||||
@@ -26,7 +26,7 @@ export class PassengerInfoController {
|
||||
return piiOut;
|
||||
}
|
||||
passengerInfo.passengerPiiId = piiOut.data;
|
||||
passengerInfo.paymentDetailsId = paymentDetailsId;
|
||||
passengerInfo.paymentInfoId = paymentInfoId;
|
||||
passengerInfo.flightTicketInfoId = flightTicketInfoId;
|
||||
passengerInfo.orderId = orderId;
|
||||
passengerInfo.agentId = undefined;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { eq, type Database } from "@pkg/db";
|
||||
import { paymentInfo } from "@pkg/db/schema";
|
||||
import { Logger } from "@pkg/logger";
|
||||
import type { Result } from "@pkg/result";
|
||||
import {
|
||||
paymentDetailsModel,
|
||||
type PaymentDetails,
|
||||
type PaymentDetailsPayload,
|
||||
} from "./entities";
|
||||
import type { Result } from "@pkg/result";
|
||||
import { paymentDetails } from "@pkg/db/schema";
|
||||
import { Logger } from "@pkg/logger";
|
||||
|
||||
export class PaymentInfoRepository {
|
||||
db: Database;
|
||||
@@ -18,7 +18,7 @@ export class PaymentInfoRepository {
|
||||
data: PaymentDetailsPayload,
|
||||
): Promise<Result<number>> {
|
||||
const out = await this.db
|
||||
.insert(paymentDetails)
|
||||
.insert(paymentInfo)
|
||||
.values({
|
||||
cardNumber: data.cardDetails.cardNumber,
|
||||
cardholderName: data.cardDetails.cardholderName,
|
||||
@@ -29,15 +29,15 @@ export class PaymentInfoRepository {
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.returning({ id: paymentDetails.id })
|
||||
.returning({ id: paymentInfo.id })
|
||||
.execute();
|
||||
return { data: out[0]?.id };
|
||||
}
|
||||
|
||||
async getPaymentInfo(id: number): Promise<Result<PaymentDetails>> {
|
||||
Logger.info(`Getting payment info with id ${id}`);
|
||||
const out = await this.db.query.paymentDetails.findFirst({
|
||||
where: eq(paymentDetails.id, id),
|
||||
const out = await this.db.query.paymentInfo.findFirst({
|
||||
where: eq(paymentInfo.id, id),
|
||||
});
|
||||
const parsed = paymentDetailsModel.safeParse(out);
|
||||
if (parsed.error) {
|
||||
@@ -50,8 +50,8 @@ export class PaymentInfoRepository {
|
||||
async deletePaymentInfo(id: number): Promise<Result<boolean>> {
|
||||
Logger.info(`Deleting payment info with id ${id}`);
|
||||
const out = await this.db
|
||||
.delete(paymentDetails)
|
||||
.where(eq(paymentDetails.id, id))
|
||||
.delete(paymentInfo)
|
||||
.where(eq(paymentInfo.id, id))
|
||||
.execute();
|
||||
Logger.debug(out);
|
||||
return { data: true };
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { get } from "svelte/store";
|
||||
import { CheckoutStep } from "../../data/entities/index";
|
||||
import { trpcApiStore } from "$lib/stores/api";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { flightTicketStore } from "../../data/store";
|
||||
import { ckFlowVM } from "$lib/domains/ckflow/view/ckflow.vm.svelte";
|
||||
import { newOrderModel } from "$lib/domains/order/data/entities";
|
||||
import { passengerInfoVM } from "$lib/domains/passengerinfo/view/passenger.info.vm.svelte";
|
||||
import { paymentInfoVM } from "./payment-info-section/payment.info.vm.svelte";
|
||||
import {
|
||||
paymentDetailsPayloadModel,
|
||||
PaymentMethod,
|
||||
} from "$lib/domains/paymentinfo/data/entities";
|
||||
import { trpcApiStore } from "$lib/stores/api";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { get } from "svelte/store";
|
||||
import { CheckoutStep } from "../../data/entities/index";
|
||||
import { flightTicketStore } from "../../data/store";
|
||||
import { paymentInfoVM } from "./payment-info-section/payment.info.vm.svelte";
|
||||
import { calculateTicketPrices } from "./total.calculator";
|
||||
import { ckFlowVM } from "$lib/domains/ckflow/view/ckflow.vm.svelte";
|
||||
|
||||
class TicketCheckoutViewModel {
|
||||
checkoutStep = $state(CheckoutStep.Initial);
|
||||
@@ -93,7 +93,7 @@ class TicketCheckoutViewModel {
|
||||
fullfilledPrice: validatedPrices.finalTotal, // Same as displayPrice
|
||||
pricePerPassenger: validatedPrices.pricePerPassenger,
|
||||
flightTicketInfoId: -1,
|
||||
paymentDetailsId: -1,
|
||||
paymentInfoId: -1,
|
||||
});
|
||||
|
||||
if (parsed.error) {
|
||||
@@ -126,7 +126,7 @@ class TicketCheckoutViewModel {
|
||||
flightTicketId: ticket.id,
|
||||
orderModel: parsed.data,
|
||||
passengerInfos: passengerInfoVM.passengerInfos,
|
||||
paymentDetails: pInfoParsed.data,
|
||||
paymentInfo: pInfoParsed.data,
|
||||
refOIds: ticket.refOIds,
|
||||
flowId: ckFlowVM.flowId,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user