refund roadmap pr-1 and pr-2
This commit is contained in:
@@ -6,7 +6,11 @@
|
|||||||
"Bash(Get-ChildItem -Path \"c:\\\\development\\\\DIOS\\\\weekly-project\\\\setrip\" -Force)",
|
"Bash(Get-ChildItem -Path \"c:\\\\development\\\\DIOS\\\\weekly-project\\\\setrip\" -Force)",
|
||||||
"Bash(Select-Object Name, PSIsContainer)",
|
"Bash(Select-Object Name, PSIsContainer)",
|
||||||
"Bash(npx tsc *)",
|
"Bash(npx tsc *)",
|
||||||
"Bash(echo \"exitcode=$?\")"
|
"Bash(echo \"exitcode=$?\")",
|
||||||
|
"PowerShell(npx prisma generate 2>&1)",
|
||||||
|
"PowerShell(npx tsc --noEmit 2>&1)",
|
||||||
|
"PowerShell(npx eslint server/services/refund.service.ts server/repositories/refund.repo.ts features/refund app/admin/refunds 2>&1)",
|
||||||
|
"PowerShell(npx eslint server lib features app 2>&1)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
## Forbidden
|
## Forbidden
|
||||||
|
|
||||||
- Jangan query database langsung di component
|
- Jangan query database langsung di component
|
||||||
- Jangan buat arsitektur over-engineered
|
- Jangan buat arsitektur over-engineered, tidak apa apa jika lebih baik untuk performance dan struktur yang baik
|
||||||
- Jangan menambahkan dependency tanpa kebutuhan jelas
|
- Jangan menambahkan dependency tanpa kebutuhan jelas, tambahkan jika memang dibutuhkan dan gunakan dependency yang aman
|
||||||
|
|
||||||
## Output Style
|
## Output Style
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Admin · Refund Manual",
|
||||||
|
description:
|
||||||
|
"Halaman admin untuk meninjau laporan refund dari peserta dan organizer.",
|
||||||
|
alternates: { canonical: "/admin/refunds" },
|
||||||
|
robots: { index: false, follow: false },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AdminRefundsLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { getServerSession } from "next-auth";
|
||||||
|
import { authOptions } from "@/lib/auth";
|
||||||
|
import { isAdminEmail } from "@/lib/admin";
|
||||||
|
import { refundRepo } from "@/server/repositories/refund.repo";
|
||||||
|
import { CreateRefundForm } from "@/features/refund/components/create-refund-form";
|
||||||
|
import {
|
||||||
|
RefundReviewCard,
|
||||||
|
type RefundCardData,
|
||||||
|
} from "@/features/refund/components/refund-review-card";
|
||||||
|
|
||||||
|
type Tab = "PENDING" | "APPROVED" | "REJECTED" | "SUCCEEDED" | "FAILED";
|
||||||
|
|
||||||
|
const TABS: { key: Tab; label: string }[] = [
|
||||||
|
{ key: "PENDING", label: "Pending" },
|
||||||
|
{ key: "APPROVED", label: "Disetujui" },
|
||||||
|
{ key: "SUCCEEDED", label: "Selesai" },
|
||||||
|
{ key: "REJECTED", label: "Ditolak" },
|
||||||
|
{ key: "FAILED", label: "Gagal" },
|
||||||
|
];
|
||||||
|
|
||||||
|
interface PageProps {
|
||||||
|
searchParams: Promise<{ tab?: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function AdminRefundsPage({ searchParams }: PageProps) {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session?.user) redirect("/login?callbackUrl=/admin/refunds");
|
||||||
|
if (!isAdminEmail(session.user.email)) {
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-2xl px-4 py-12 text-center">
|
||||||
|
<p className="text-sm text-neutral-600">
|
||||||
|
Halaman ini hanya untuk admin SeTrip.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = await searchParams;
|
||||||
|
const tab: Tab = TABS.some((t) => t.key === params.tab)
|
||||||
|
? (params.tab as Tab)
|
||||||
|
: "PENDING";
|
||||||
|
|
||||||
|
const rows = await refundRepo.listByStatus(tab);
|
||||||
|
const items: RefundCardData[] = rows.map((r) => ({
|
||||||
|
id: r.id,
|
||||||
|
amount: r.amount,
|
||||||
|
currency: r.currency,
|
||||||
|
reason: r.reason,
|
||||||
|
reportedBy: r.reportedBy,
|
||||||
|
reportNote: r.reportNote,
|
||||||
|
initiatedBy: r.initiatedBy,
|
||||||
|
status: r.status,
|
||||||
|
adminNote: r.adminNote,
|
||||||
|
createdAt: r.createdAt,
|
||||||
|
reviewedAt: r.reviewedAt,
|
||||||
|
succeededAt: r.succeededAt,
|
||||||
|
failedAt: r.failedAt,
|
||||||
|
reviewedBy: r.reviewedBy,
|
||||||
|
booking: {
|
||||||
|
id: r.booking.id,
|
||||||
|
amount: r.booking.amount,
|
||||||
|
status: r.booking.status,
|
||||||
|
trip: {
|
||||||
|
id: r.booking.trip.id,
|
||||||
|
title: r.booking.trip.title,
|
||||||
|
date: r.booking.trip.date,
|
||||||
|
},
|
||||||
|
user: r.booking.user,
|
||||||
|
payments: r.booking.payments.map((p) => ({
|
||||||
|
id: p.id,
|
||||||
|
provider: p.provider,
|
||||||
|
method: p.method,
|
||||||
|
amount: p.amount,
|
||||||
|
status: p.status,
|
||||||
|
paidAt: p.paidAt,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-4xl px-4 py-8 sm:py-12">
|
||||||
|
<header className="mb-6">
|
||||||
|
<h1 className="text-2xl font-bold text-neutral-900 sm:text-3xl">
|
||||||
|
Review Refund Manual
|
||||||
|
</h1>
|
||||||
|
<p className="mt-1 text-sm text-neutral-500">
|
||||||
|
Tinjau laporan refund dari peserta dan organizer. Setiap refund harus
|
||||||
|
melalui approval admin sebelum dieksekusi.
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<CreateRefundForm />
|
||||||
|
|
||||||
|
<div className="mb-6 flex flex-wrap gap-2">
|
||||||
|
{TABS.map((t) => (
|
||||||
|
<a
|
||||||
|
key={t.key}
|
||||||
|
href={`/admin/refunds?tab=${t.key}`}
|
||||||
|
className={`rounded-full px-4 py-1.5 text-sm font-semibold transition-colors ${
|
||||||
|
tab === t.key
|
||||||
|
? "bg-primary-600 text-white"
|
||||||
|
: "bg-neutral-100 text-neutral-600 hover:bg-neutral-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{t.label}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{items.length === 0 ? (
|
||||||
|
<div className="rounded-2xl border border-dashed border-neutral-300 bg-white p-10 text-center">
|
||||||
|
<p className="text-sm text-neutral-500">
|
||||||
|
Tidak ada refund pada status ini.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-4">
|
||||||
|
{items.map((r) => (
|
||||||
|
<RefundReviewCard key={r.id} refund={r} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -75,3 +75,15 @@ export type Booking = Prisma.BookingModel
|
|||||||
* (di Phase MIDTRANS nanti). Untuk MANUAL biasanya cukup 1 Payment.
|
* (di Phase MIDTRANS nanti). Untuk MANUAL biasanya cukup 1 Payment.
|
||||||
*/
|
*/
|
||||||
export type Payment = Prisma.PaymentModel
|
export type Payment = Prisma.PaymentModel
|
||||||
|
/**
|
||||||
|
* Model Refund
|
||||||
|
* Refund = financial event terpisah dari Booking. Satu Booking bisa punya
|
||||||
|
* banyak Refund (partial, multi-tahap). Setiap row auditable: kapan dibuat,
|
||||||
|
* siapa melaporkan, siapa approve, kapan SUCCEEDED. Never delete — kalau
|
||||||
|
* gagal, set status=FAILED + alasan.
|
||||||
|
*
|
||||||
|
* Di MVP refund dimasukkan admin secara manual berdasarkan laporan dari
|
||||||
|
* peserta atau organizer (via WhatsApp/email). Phase berikutnya akan
|
||||||
|
* menambah self-service flow dari user dan organizer.
|
||||||
|
*/
|
||||||
|
export type Refund = Prisma.RefundModel
|
||||||
|
|||||||
@@ -99,3 +99,15 @@ export type Booking = Prisma.BookingModel
|
|||||||
* (di Phase MIDTRANS nanti). Untuk MANUAL biasanya cukup 1 Payment.
|
* (di Phase MIDTRANS nanti). Untuk MANUAL biasanya cukup 1 Payment.
|
||||||
*/
|
*/
|
||||||
export type Payment = Prisma.PaymentModel
|
export type Payment = Prisma.PaymentModel
|
||||||
|
/**
|
||||||
|
* Model Refund
|
||||||
|
* Refund = financial event terpisah dari Booking. Satu Booking bisa punya
|
||||||
|
* banyak Refund (partial, multi-tahap). Setiap row auditable: kapan dibuat,
|
||||||
|
* siapa melaporkan, siapa approve, kapan SUCCEEDED. Never delete — kalau
|
||||||
|
* gagal, set status=FAILED + alasan.
|
||||||
|
*
|
||||||
|
* Di MVP refund dimasukkan admin secara manual berdasarkan laporan dari
|
||||||
|
* peserta atau organizer (via WhatsApp/email). Phase berikutnya akan
|
||||||
|
* menambah self-service flow dari user dan organizer.
|
||||||
|
*/
|
||||||
|
export type Refund = Prisma.RefundModel
|
||||||
|
|||||||
@@ -389,6 +389,74 @@ export type JsonNullableWithAggregatesFilterBase<$PrismaModel = never> = {
|
|||||||
_max?: Prisma.NestedJsonNullableFilter<$PrismaModel>
|
_max?: Prisma.NestedJsonNullableFilter<$PrismaModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EnumRefundReasonFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReason | Prisma.EnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReasonFilter<$PrismaModel> | $Enums.RefundReason
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundReporterFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReporter | Prisma.EnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReporterFilter<$PrismaModel> | $Enums.RefundReporter
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundInitiatorFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundInitiator | Prisma.EnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundInitiatorFilter<$PrismaModel> | $Enums.RefundInitiator
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundStatusFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundStatus | Prisma.EnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundStatusFilter<$PrismaModel> | $Enums.RefundStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundReasonWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReason | Prisma.EnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReasonWithAggregatesFilter<$PrismaModel> | $Enums.RefundReason
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundReasonFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundReasonFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundReporterWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReporter | Prisma.EnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReporterWithAggregatesFilter<$PrismaModel> | $Enums.RefundReporter
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundReporterFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundReporterFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundInitiatorWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundInitiator | Prisma.EnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundInitiatorWithAggregatesFilter<$PrismaModel> | $Enums.RefundInitiator
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundInitiatorFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundInitiatorFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumRefundStatusWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundStatus | Prisma.EnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundStatusWithAggregatesFilter<$PrismaModel> | $Enums.RefundStatus
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundStatusFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundStatusFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type NestedStringFilter<$PrismaModel = never> = {
|
export type NestedStringFilter<$PrismaModel = never> = {
|
||||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||||
@@ -750,4 +818,72 @@ export type NestedJsonNullableFilterBase<$PrismaModel = never> = {
|
|||||||
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundReasonFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReason | Prisma.EnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReasonFilter<$PrismaModel> | $Enums.RefundReason
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundReporterFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReporter | Prisma.EnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReporterFilter<$PrismaModel> | $Enums.RefundReporter
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundInitiatorFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundInitiator | Prisma.EnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundInitiatorFilter<$PrismaModel> | $Enums.RefundInitiator
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundStatusFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundStatus | Prisma.EnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundStatusFilter<$PrismaModel> | $Enums.RefundStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundReasonWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReason | Prisma.EnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReason[] | Prisma.ListEnumRefundReasonFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReasonWithAggregatesFilter<$PrismaModel> | $Enums.RefundReason
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundReasonFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundReasonFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundReporterWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundReporter | Prisma.EnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundReporter[] | Prisma.ListEnumRefundReporterFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundReporterWithAggregatesFilter<$PrismaModel> | $Enums.RefundReporter
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundReporterFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundReporterFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundInitiatorWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundInitiator | Prisma.EnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundInitiator[] | Prisma.ListEnumRefundInitiatorFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundInitiatorWithAggregatesFilter<$PrismaModel> | $Enums.RefundInitiator
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundInitiatorFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundInitiatorFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumRefundStatusWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.RefundStatus | Prisma.EnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
notIn?: $Enums.RefundStatus[] | Prisma.ListEnumRefundStatusFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedEnumRefundStatusWithAggregatesFilter<$PrismaModel> | $Enums.RefundStatus
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumRefundStatusFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumRefundStatusFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export const BookingStatus = {
|
|||||||
PAID: 'PAID',
|
PAID: 'PAID',
|
||||||
CANCELLED: 'CANCELLED',
|
CANCELLED: 'CANCELLED',
|
||||||
REFUNDED: 'REFUNDED',
|
REFUNDED: 'REFUNDED',
|
||||||
|
PARTIALLY_REFUNDED: 'PARTIALLY_REFUNDED',
|
||||||
EXPIRED: 'EXPIRED'
|
EXPIRED: 'EXPIRED'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
@@ -93,3 +94,45 @@ export const PaymentStatus = {
|
|||||||
} as const
|
} as const
|
||||||
|
|
||||||
export type PaymentStatus = (typeof PaymentStatus)[keyof typeof PaymentStatus]
|
export type PaymentStatus = (typeof PaymentStatus)[keyof typeof PaymentStatus]
|
||||||
|
|
||||||
|
|
||||||
|
export const RefundReason = {
|
||||||
|
USER_CANCELLATION: 'USER_CANCELLATION',
|
||||||
|
ORGANIZER_CANCELLED: 'ORGANIZER_CANCELLED',
|
||||||
|
TRIP_ISSUE: 'TRIP_ISSUE',
|
||||||
|
ADMIN_ADJUSTMENT: 'ADMIN_ADJUSTMENT',
|
||||||
|
DISPUTE_RESOLVED: 'DISPUTE_RESOLVED',
|
||||||
|
OTHER: 'OTHER'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RefundReason = (typeof RefundReason)[keyof typeof RefundReason]
|
||||||
|
|
||||||
|
|
||||||
|
export const RefundStatus = {
|
||||||
|
PENDING: 'PENDING',
|
||||||
|
APPROVED: 'APPROVED',
|
||||||
|
REJECTED: 'REJECTED',
|
||||||
|
PROCESSING: 'PROCESSING',
|
||||||
|
SUCCEEDED: 'SUCCEEDED',
|
||||||
|
FAILED: 'FAILED'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RefundStatus = (typeof RefundStatus)[keyof typeof RefundStatus]
|
||||||
|
|
||||||
|
|
||||||
|
export const RefundInitiator = {
|
||||||
|
USER: 'USER',
|
||||||
|
ORGANIZER: 'ORGANIZER',
|
||||||
|
SYSTEM: 'SYSTEM',
|
||||||
|
ADMIN: 'ADMIN'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RefundInitiator = (typeof RefundInitiator)[keyof typeof RefundInitiator]
|
||||||
|
|
||||||
|
|
||||||
|
export const RefundReporter = {
|
||||||
|
PARTICIPANT: 'PARTICIPANT',
|
||||||
|
ORGANIZER: 'ORGANIZER'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RefundReporter = (typeof RefundReporter)[keyof typeof RefundReporter]
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -393,7 +393,8 @@ export const ModelName = {
|
|||||||
TripImage: 'TripImage',
|
TripImage: 'TripImage',
|
||||||
TripParticipant: 'TripParticipant',
|
TripParticipant: 'TripParticipant',
|
||||||
Booking: 'Booking',
|
Booking: 'Booking',
|
||||||
Payment: 'Payment'
|
Payment: 'Payment',
|
||||||
|
Refund: 'Refund'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||||
@@ -409,7 +410,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
omit: GlobalOmitOptions
|
omit: GlobalOmitOptions
|
||||||
}
|
}
|
||||||
meta: {
|
meta: {
|
||||||
modelProps: "user" | "userProfile" | "account" | "organizerVerification" | "trip" | "tripReview" | "tripImage" | "tripParticipant" | "booking" | "payment"
|
modelProps: "user" | "userProfile" | "account" | "organizerVerification" | "trip" | "tripReview" | "tripImage" | "tripParticipant" | "booking" | "payment" | "refund"
|
||||||
txIsolationLevel: TransactionIsolationLevel
|
txIsolationLevel: TransactionIsolationLevel
|
||||||
}
|
}
|
||||||
model: {
|
model: {
|
||||||
@@ -1153,6 +1154,80 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Refund: {
|
||||||
|
payload: Prisma.$RefundPayload<ExtArgs>
|
||||||
|
fields: Prisma.RefundFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.RefundFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.RefundFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.RefundFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.RefundFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.RefundFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.RefundCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.RefundCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
createManyAndReturn: {
|
||||||
|
args: Prisma.RefundCreateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>[]
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.RefundDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.RefundUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.RefundDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.RefundUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateManyAndReturn: {
|
||||||
|
args: Prisma.RefundUpdateManyAndReturnArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>[]
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.RefundUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$RefundPayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.RefundAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateRefund>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.RefundGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.RefundGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.RefundCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.RefundCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} & {
|
} & {
|
||||||
other: {
|
other: {
|
||||||
@@ -1365,6 +1440,31 @@ export const PaymentScalarFieldEnum = {
|
|||||||
export type PaymentScalarFieldEnum = (typeof PaymentScalarFieldEnum)[keyof typeof PaymentScalarFieldEnum]
|
export type PaymentScalarFieldEnum = (typeof PaymentScalarFieldEnum)[keyof typeof PaymentScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const RefundScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
bookingId: 'bookingId',
|
||||||
|
paymentId: 'paymentId',
|
||||||
|
amount: 'amount',
|
||||||
|
currency: 'currency',
|
||||||
|
reason: 'reason',
|
||||||
|
reportedBy: 'reportedBy',
|
||||||
|
reportNote: 'reportNote',
|
||||||
|
initiatedBy: 'initiatedBy',
|
||||||
|
status: 'status',
|
||||||
|
idempotencyKey: 'idempotencyKey',
|
||||||
|
adminNote: 'adminNote',
|
||||||
|
reviewedById: 'reviewedById',
|
||||||
|
reviewedAt: 'reviewedAt',
|
||||||
|
succeededAt: 'succeededAt',
|
||||||
|
failedAt: 'failedAt',
|
||||||
|
externalRefundId: 'externalRefundId',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RefundScalarFieldEnum = (typeof RefundScalarFieldEnum)[keyof typeof RefundScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const SortOrder = {
|
export const SortOrder = {
|
||||||
asc: 'asc',
|
asc: 'asc',
|
||||||
desc: 'desc'
|
desc: 'desc'
|
||||||
@@ -1587,6 +1687,62 @@ export type EnumQueryModeFieldRefInput<$PrismaModel> = FieldRefInputType<$Prisma
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundReason'
|
||||||
|
*/
|
||||||
|
export type EnumRefundReasonFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundReason'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundReason[]'
|
||||||
|
*/
|
||||||
|
export type ListEnumRefundReasonFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundReason[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundReporter'
|
||||||
|
*/
|
||||||
|
export type EnumRefundReporterFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundReporter'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundReporter[]'
|
||||||
|
*/
|
||||||
|
export type ListEnumRefundReporterFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundReporter[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundInitiator'
|
||||||
|
*/
|
||||||
|
export type EnumRefundInitiatorFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundInitiator'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundInitiator[]'
|
||||||
|
*/
|
||||||
|
export type ListEnumRefundInitiatorFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundInitiator[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundStatus'
|
||||||
|
*/
|
||||||
|
export type EnumRefundStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundStatus'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'RefundStatus[]'
|
||||||
|
*/
|
||||||
|
export type ListEnumRefundStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RefundStatus[]'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to a field of type 'Float'
|
* Reference to a field of type 'Float'
|
||||||
*/
|
*/
|
||||||
@@ -1720,6 +1876,7 @@ export type GlobalOmitConfig = {
|
|||||||
tripParticipant?: Prisma.TripParticipantOmit
|
tripParticipant?: Prisma.TripParticipantOmit
|
||||||
booking?: Prisma.BookingOmit
|
booking?: Prisma.BookingOmit
|
||||||
payment?: Prisma.PaymentOmit
|
payment?: Prisma.PaymentOmit
|
||||||
|
refund?: Prisma.RefundOmit
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Types for Logging */
|
/* Types for Logging */
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ export const ModelName = {
|
|||||||
TripImage: 'TripImage',
|
TripImage: 'TripImage',
|
||||||
TripParticipant: 'TripParticipant',
|
TripParticipant: 'TripParticipant',
|
||||||
Booking: 'Booking',
|
Booking: 'Booking',
|
||||||
Payment: 'Payment'
|
Payment: 'Payment',
|
||||||
|
Refund: 'Refund'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||||
@@ -252,6 +253,31 @@ export const PaymentScalarFieldEnum = {
|
|||||||
export type PaymentScalarFieldEnum = (typeof PaymentScalarFieldEnum)[keyof typeof PaymentScalarFieldEnum]
|
export type PaymentScalarFieldEnum = (typeof PaymentScalarFieldEnum)[keyof typeof PaymentScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const RefundScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
bookingId: 'bookingId',
|
||||||
|
paymentId: 'paymentId',
|
||||||
|
amount: 'amount',
|
||||||
|
currency: 'currency',
|
||||||
|
reason: 'reason',
|
||||||
|
reportedBy: 'reportedBy',
|
||||||
|
reportNote: 'reportNote',
|
||||||
|
initiatedBy: 'initiatedBy',
|
||||||
|
status: 'status',
|
||||||
|
idempotencyKey: 'idempotencyKey',
|
||||||
|
adminNote: 'adminNote',
|
||||||
|
reviewedById: 'reviewedById',
|
||||||
|
reviewedAt: 'reviewedAt',
|
||||||
|
succeededAt: 'succeededAt',
|
||||||
|
failedAt: 'failedAt',
|
||||||
|
externalRefundId: 'externalRefundId',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type RefundScalarFieldEnum = (typeof RefundScalarFieldEnum)[keyof typeof RefundScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const SortOrder = {
|
export const SortOrder = {
|
||||||
asc: 'asc',
|
asc: 'asc',
|
||||||
desc: 'desc'
|
desc: 'desc'
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ export type * from './models/TripImage'
|
|||||||
export type * from './models/TripParticipant'
|
export type * from './models/TripParticipant'
|
||||||
export type * from './models/Booking'
|
export type * from './models/Booking'
|
||||||
export type * from './models/Payment'
|
export type * from './models/Payment'
|
||||||
|
export type * from './models/Refund'
|
||||||
export type * from './commonInputTypes'
|
export type * from './commonInputTypes'
|
||||||
@@ -257,6 +257,7 @@ export type BookingWhereInput = {
|
|||||||
user?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
|
user?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
|
||||||
participant?: Prisma.XOR<Prisma.TripParticipantScalarRelationFilter, Prisma.TripParticipantWhereInput>
|
participant?: Prisma.XOR<Prisma.TripParticipantScalarRelationFilter, Prisma.TripParticipantWhereInput>
|
||||||
payments?: Prisma.PaymentListRelationFilter
|
payments?: Prisma.PaymentListRelationFilter
|
||||||
|
refunds?: Prisma.RefundListRelationFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingOrderByWithRelationInput = {
|
export type BookingOrderByWithRelationInput = {
|
||||||
@@ -273,6 +274,7 @@ export type BookingOrderByWithRelationInput = {
|
|||||||
user?: Prisma.UserOrderByWithRelationInput
|
user?: Prisma.UserOrderByWithRelationInput
|
||||||
participant?: Prisma.TripParticipantOrderByWithRelationInput
|
participant?: Prisma.TripParticipantOrderByWithRelationInput
|
||||||
payments?: Prisma.PaymentOrderByRelationAggregateInput
|
payments?: Prisma.PaymentOrderByRelationAggregateInput
|
||||||
|
refunds?: Prisma.RefundOrderByRelationAggregateInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingWhereUniqueInput = Prisma.AtLeast<{
|
export type BookingWhereUniqueInput = Prisma.AtLeast<{
|
||||||
@@ -293,6 +295,7 @@ export type BookingWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
user?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
|
user?: Prisma.XOR<Prisma.UserScalarRelationFilter, Prisma.UserWhereInput>
|
||||||
participant?: Prisma.XOR<Prisma.TripParticipantScalarRelationFilter, Prisma.TripParticipantWhereInput>
|
participant?: Prisma.XOR<Prisma.TripParticipantScalarRelationFilter, Prisma.TripParticipantWhereInput>
|
||||||
payments?: Prisma.PaymentListRelationFilter
|
payments?: Prisma.PaymentListRelationFilter
|
||||||
|
refunds?: Prisma.RefundListRelationFilter
|
||||||
}, "id" | "participantId" | "tripId_userId">
|
}, "id" | "participantId" | "tripId_userId">
|
||||||
|
|
||||||
export type BookingOrderByWithAggregationInput = {
|
export type BookingOrderByWithAggregationInput = {
|
||||||
@@ -338,6 +341,7 @@ export type BookingCreateInput = {
|
|||||||
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
||||||
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
||||||
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedCreateInput = {
|
export type BookingUncheckedCreateInput = {
|
||||||
@@ -351,6 +355,7 @@ export type BookingUncheckedCreateInput = {
|
|||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUpdateInput = {
|
export type BookingUpdateInput = {
|
||||||
@@ -364,6 +369,7 @@ export type BookingUpdateInput = {
|
|||||||
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
||||||
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateInput = {
|
export type BookingUncheckedUpdateInput = {
|
||||||
@@ -377,6 +383,7 @@ export type BookingUncheckedUpdateInput = {
|
|||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateManyInput = {
|
export type BookingCreateManyInput = {
|
||||||
@@ -615,6 +622,20 @@ export type BookingUpdateOneRequiredWithoutPaymentsNestedInput = {
|
|||||||
update?: Prisma.XOR<Prisma.XOR<Prisma.BookingUpdateToOneWithWhereWithoutPaymentsInput, Prisma.BookingUpdateWithoutPaymentsInput>, Prisma.BookingUncheckedUpdateWithoutPaymentsInput>
|
update?: Prisma.XOR<Prisma.XOR<Prisma.BookingUpdateToOneWithWhereWithoutPaymentsInput, Prisma.BookingUpdateWithoutPaymentsInput>, Prisma.BookingUncheckedUpdateWithoutPaymentsInput>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type BookingCreateNestedOneWithoutRefundsInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.BookingCreateWithoutRefundsInput, Prisma.BookingUncheckedCreateWithoutRefundsInput>
|
||||||
|
connectOrCreate?: Prisma.BookingCreateOrConnectWithoutRefundsInput
|
||||||
|
connect?: Prisma.BookingWhereUniqueInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingUpdateOneRequiredWithoutRefundsNestedInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.BookingCreateWithoutRefundsInput, Prisma.BookingUncheckedCreateWithoutRefundsInput>
|
||||||
|
connectOrCreate?: Prisma.BookingCreateOrConnectWithoutRefundsInput
|
||||||
|
upsert?: Prisma.BookingUpsertWithoutRefundsInput
|
||||||
|
connect?: Prisma.BookingWhereUniqueInput
|
||||||
|
update?: Prisma.XOR<Prisma.XOR<Prisma.BookingUpdateToOneWithWhereWithoutRefundsInput, Prisma.BookingUpdateWithoutRefundsInput>, Prisma.BookingUncheckedUpdateWithoutRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
export type BookingCreateWithoutUserInput = {
|
export type BookingCreateWithoutUserInput = {
|
||||||
id?: string
|
id?: string
|
||||||
amount: number
|
amount: number
|
||||||
@@ -625,6 +646,7 @@ export type BookingCreateWithoutUserInput = {
|
|||||||
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
||||||
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
||||||
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedCreateWithoutUserInput = {
|
export type BookingUncheckedCreateWithoutUserInput = {
|
||||||
@@ -637,6 +659,7 @@ export type BookingUncheckedCreateWithoutUserInput = {
|
|||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateOrConnectWithoutUserInput = {
|
export type BookingCreateOrConnectWithoutUserInput = {
|
||||||
@@ -690,6 +713,7 @@ export type BookingCreateWithoutTripInput = {
|
|||||||
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
||||||
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
||||||
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedCreateWithoutTripInput = {
|
export type BookingUncheckedCreateWithoutTripInput = {
|
||||||
@@ -702,6 +726,7 @@ export type BookingUncheckedCreateWithoutTripInput = {
|
|||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateOrConnectWithoutTripInput = {
|
export type BookingCreateOrConnectWithoutTripInput = {
|
||||||
@@ -740,6 +765,7 @@ export type BookingCreateWithoutParticipantInput = {
|
|||||||
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
||||||
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
||||||
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedCreateWithoutParticipantInput = {
|
export type BookingUncheckedCreateWithoutParticipantInput = {
|
||||||
@@ -752,6 +778,7 @@ export type BookingUncheckedCreateWithoutParticipantInput = {
|
|||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateOrConnectWithoutParticipantInput = {
|
export type BookingCreateOrConnectWithoutParticipantInput = {
|
||||||
@@ -780,6 +807,7 @@ export type BookingUpdateWithoutParticipantInput = {
|
|||||||
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateWithoutParticipantInput = {
|
export type BookingUncheckedUpdateWithoutParticipantInput = {
|
||||||
@@ -792,6 +820,7 @@ export type BookingUncheckedUpdateWithoutParticipantInput = {
|
|||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateWithoutPaymentsInput = {
|
export type BookingCreateWithoutPaymentsInput = {
|
||||||
@@ -804,6 +833,7 @@ export type BookingCreateWithoutPaymentsInput = {
|
|||||||
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
||||||
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
||||||
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedCreateWithoutPaymentsInput = {
|
export type BookingUncheckedCreateWithoutPaymentsInput = {
|
||||||
@@ -816,6 +846,7 @@ export type BookingUncheckedCreateWithoutPaymentsInput = {
|
|||||||
status?: $Enums.BookingStatus
|
status?: $Enums.BookingStatus
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutBookingInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateOrConnectWithoutPaymentsInput = {
|
export type BookingCreateOrConnectWithoutPaymentsInput = {
|
||||||
@@ -844,6 +875,7 @@ export type BookingUpdateWithoutPaymentsInput = {
|
|||||||
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateWithoutPaymentsInput = {
|
export type BookingUncheckedUpdateWithoutPaymentsInput = {
|
||||||
@@ -856,6 +888,75 @@ export type BookingUncheckedUpdateWithoutPaymentsInput = {
|
|||||||
status?: Prisma.EnumBookingStatusFieldUpdateOperationsInput | $Enums.BookingStatus
|
status?: Prisma.EnumBookingStatusFieldUpdateOperationsInput | $Enums.BookingStatus
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingCreateWithoutRefundsInput = {
|
||||||
|
id?: string
|
||||||
|
amount: number
|
||||||
|
currency?: string
|
||||||
|
status?: $Enums.BookingStatus
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
trip: Prisma.TripCreateNestedOneWithoutBookingsInput
|
||||||
|
user: Prisma.UserCreateNestedOneWithoutBookingsInput
|
||||||
|
participant: Prisma.TripParticipantCreateNestedOneWithoutBookingInput
|
||||||
|
payments?: Prisma.PaymentCreateNestedManyWithoutBookingInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingUncheckedCreateWithoutRefundsInput = {
|
||||||
|
id?: string
|
||||||
|
tripId: string
|
||||||
|
userId: string
|
||||||
|
participantId: string
|
||||||
|
amount: number
|
||||||
|
currency?: string
|
||||||
|
status?: $Enums.BookingStatus
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
payments?: Prisma.PaymentUncheckedCreateNestedManyWithoutBookingInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingCreateOrConnectWithoutRefundsInput = {
|
||||||
|
where: Prisma.BookingWhereUniqueInput
|
||||||
|
create: Prisma.XOR<Prisma.BookingCreateWithoutRefundsInput, Prisma.BookingUncheckedCreateWithoutRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingUpsertWithoutRefundsInput = {
|
||||||
|
update: Prisma.XOR<Prisma.BookingUpdateWithoutRefundsInput, Prisma.BookingUncheckedUpdateWithoutRefundsInput>
|
||||||
|
create: Prisma.XOR<Prisma.BookingCreateWithoutRefundsInput, Prisma.BookingUncheckedCreateWithoutRefundsInput>
|
||||||
|
where?: Prisma.BookingWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingUpdateToOneWithWhereWithoutRefundsInput = {
|
||||||
|
where?: Prisma.BookingWhereInput
|
||||||
|
data: Prisma.XOR<Prisma.BookingUpdateWithoutRefundsInput, Prisma.BookingUncheckedUpdateWithoutRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingUpdateWithoutRefundsInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
amount?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
|
currency?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
status?: Prisma.EnumBookingStatusFieldUpdateOperationsInput | $Enums.BookingStatus
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
|
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
|
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
||||||
|
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BookingUncheckedUpdateWithoutRefundsInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
tripId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
participantId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
amount?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
|
currency?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
status?: Prisma.EnumBookingStatusFieldUpdateOperationsInput | $Enums.BookingStatus
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCreateManyUserInput = {
|
export type BookingCreateManyUserInput = {
|
||||||
@@ -879,6 +980,7 @@ export type BookingUpdateWithoutUserInput = {
|
|||||||
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
trip?: Prisma.TripUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
||||||
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateWithoutUserInput = {
|
export type BookingUncheckedUpdateWithoutUserInput = {
|
||||||
@@ -891,6 +993,7 @@ export type BookingUncheckedUpdateWithoutUserInput = {
|
|||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateManyWithoutUserInput = {
|
export type BookingUncheckedUpdateManyWithoutUserInput = {
|
||||||
@@ -925,6 +1028,7 @@ export type BookingUpdateWithoutTripInput = {
|
|||||||
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
user?: Prisma.UserUpdateOneRequiredWithoutBookingsNestedInput
|
||||||
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
participant?: Prisma.TripParticipantUpdateOneRequiredWithoutBookingNestedInput
|
||||||
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateWithoutTripInput = {
|
export type BookingUncheckedUpdateWithoutTripInput = {
|
||||||
@@ -937,6 +1041,7 @@ export type BookingUncheckedUpdateWithoutTripInput = {
|
|||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
payments?: Prisma.PaymentUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutBookingNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingUncheckedUpdateManyWithoutTripInput = {
|
export type BookingUncheckedUpdateManyWithoutTripInput = {
|
||||||
@@ -957,10 +1062,12 @@ export type BookingUncheckedUpdateManyWithoutTripInput = {
|
|||||||
|
|
||||||
export type BookingCountOutputType = {
|
export type BookingCountOutputType = {
|
||||||
payments: number
|
payments: number
|
||||||
|
refunds: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type BookingCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
payments?: boolean | BookingCountOutputTypeCountPaymentsArgs
|
payments?: boolean | BookingCountOutputTypeCountPaymentsArgs
|
||||||
|
refunds?: boolean | BookingCountOutputTypeCountRefundsArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -980,6 +1087,13 @@ export type BookingCountOutputTypeCountPaymentsArgs<ExtArgs extends runtime.Type
|
|||||||
where?: Prisma.PaymentWhereInput
|
where?: Prisma.PaymentWhereInput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingCountOutputType without action
|
||||||
|
*/
|
||||||
|
export type BookingCountOutputTypeCountRefundsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
where?: Prisma.RefundWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type BookingSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type BookingSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
id?: boolean
|
id?: boolean
|
||||||
@@ -995,6 +1109,7 @@ export type BookingSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
|||||||
user?: boolean | Prisma.UserDefaultArgs<ExtArgs>
|
user?: boolean | Prisma.UserDefaultArgs<ExtArgs>
|
||||||
participant?: boolean | Prisma.TripParticipantDefaultArgs<ExtArgs>
|
participant?: boolean | Prisma.TripParticipantDefaultArgs<ExtArgs>
|
||||||
payments?: boolean | Prisma.Booking$paymentsArgs<ExtArgs>
|
payments?: boolean | Prisma.Booking$paymentsArgs<ExtArgs>
|
||||||
|
refunds?: boolean | Prisma.Booking$refundsArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.BookingCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.BookingCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["booking"]>
|
}, ExtArgs["result"]["booking"]>
|
||||||
|
|
||||||
@@ -1046,6 +1161,7 @@ export type BookingInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
|||||||
user?: boolean | Prisma.UserDefaultArgs<ExtArgs>
|
user?: boolean | Prisma.UserDefaultArgs<ExtArgs>
|
||||||
participant?: boolean | Prisma.TripParticipantDefaultArgs<ExtArgs>
|
participant?: boolean | Prisma.TripParticipantDefaultArgs<ExtArgs>
|
||||||
payments?: boolean | Prisma.Booking$paymentsArgs<ExtArgs>
|
payments?: boolean | Prisma.Booking$paymentsArgs<ExtArgs>
|
||||||
|
refunds?: boolean | Prisma.Booking$refundsArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.BookingCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.BookingCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}
|
}
|
||||||
export type BookingIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type BookingIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
@@ -1066,6 +1182,7 @@ export type $BookingPayload<ExtArgs extends runtime.Types.Extensions.InternalArg
|
|||||||
user: Prisma.$UserPayload<ExtArgs>
|
user: Prisma.$UserPayload<ExtArgs>
|
||||||
participant: Prisma.$TripParticipantPayload<ExtArgs>
|
participant: Prisma.$TripParticipantPayload<ExtArgs>
|
||||||
payments: Prisma.$PaymentPayload<ExtArgs>[]
|
payments: Prisma.$PaymentPayload<ExtArgs>[]
|
||||||
|
refunds: Prisma.$RefundPayload<ExtArgs>[]
|
||||||
}
|
}
|
||||||
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
||||||
id: string
|
id: string
|
||||||
@@ -1475,6 +1592,7 @@ export interface Prisma__BookingClient<T, Null = never, ExtArgs extends runtime.
|
|||||||
user<T extends Prisma.UserDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.UserDefaultArgs<ExtArgs>>): Prisma.Prisma__UserClient<runtime.Types.Result.GetResult<Prisma.$UserPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
|
user<T extends Prisma.UserDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.UserDefaultArgs<ExtArgs>>): Prisma.Prisma__UserClient<runtime.Types.Result.GetResult<Prisma.$UserPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
|
||||||
participant<T extends Prisma.TripParticipantDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.TripParticipantDefaultArgs<ExtArgs>>): Prisma.Prisma__TripParticipantClient<runtime.Types.Result.GetResult<Prisma.$TripParticipantPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
|
participant<T extends Prisma.TripParticipantDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.TripParticipantDefaultArgs<ExtArgs>>): Prisma.Prisma__TripParticipantClient<runtime.Types.Result.GetResult<Prisma.$TripParticipantPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
|
||||||
payments<T extends Prisma.Booking$paymentsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Booking$paymentsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$PaymentPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
payments<T extends Prisma.Booking$paymentsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Booking$paymentsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$PaymentPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
|
refunds<T extends Prisma.Booking$refundsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Booking$refundsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$RefundPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
/**
|
/**
|
||||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||||
@@ -1937,6 +2055,30 @@ export type Booking$paymentsArgs<ExtArgs extends runtime.Types.Extensions.Intern
|
|||||||
distinct?: Prisma.PaymentScalarFieldEnum | Prisma.PaymentScalarFieldEnum[]
|
distinct?: Prisma.PaymentScalarFieldEnum | Prisma.PaymentScalarFieldEnum[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Booking.refunds
|
||||||
|
*/
|
||||||
|
export type Booking$refundsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
/**
|
||||||
|
* Select specific fields to fetch from the Refund
|
||||||
|
*/
|
||||||
|
select?: Prisma.RefundSelect<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Omit specific fields from the Refund
|
||||||
|
*/
|
||||||
|
omit?: Prisma.RefundOmit<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Choose, which related nodes to fetch as well
|
||||||
|
*/
|
||||||
|
include?: Prisma.RefundInclude<ExtArgs> | null
|
||||||
|
where?: Prisma.RefundWhereInput
|
||||||
|
orderBy?: Prisma.RefundOrderByWithRelationInput | Prisma.RefundOrderByWithRelationInput[]
|
||||||
|
cursor?: Prisma.RefundWhereUniqueInput
|
||||||
|
take?: number
|
||||||
|
skip?: number
|
||||||
|
distinct?: Prisma.RefundScalarFieldEnum | Prisma.RefundScalarFieldEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Booking without action
|
* Booking without action
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ export type PaymentWhereInput = {
|
|||||||
createdAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
||||||
booking?: Prisma.XOR<Prisma.BookingScalarRelationFilter, Prisma.BookingWhereInput>
|
booking?: Prisma.XOR<Prisma.BookingScalarRelationFilter, Prisma.BookingWhereInput>
|
||||||
|
refunds?: Prisma.RefundListRelationFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentOrderByWithRelationInput = {
|
export type PaymentOrderByWithRelationInput = {
|
||||||
@@ -322,6 +323,7 @@ export type PaymentOrderByWithRelationInput = {
|
|||||||
createdAt?: Prisma.SortOrder
|
createdAt?: Prisma.SortOrder
|
||||||
updatedAt?: Prisma.SortOrder
|
updatedAt?: Prisma.SortOrder
|
||||||
booking?: Prisma.BookingOrderByWithRelationInput
|
booking?: Prisma.BookingOrderByWithRelationInput
|
||||||
|
refunds?: Prisma.RefundOrderByRelationAggregateInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentWhereUniqueInput = Prisma.AtLeast<{
|
export type PaymentWhereUniqueInput = Prisma.AtLeast<{
|
||||||
@@ -345,6 +347,7 @@ export type PaymentWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
createdAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
createdAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
||||||
booking?: Prisma.XOR<Prisma.BookingScalarRelationFilter, Prisma.BookingWhereInput>
|
booking?: Prisma.XOR<Prisma.BookingScalarRelationFilter, Prisma.BookingWhereInput>
|
||||||
|
refunds?: Prisma.RefundListRelationFilter
|
||||||
}, "id" | "externalOrderId">
|
}, "id" | "externalOrderId">
|
||||||
|
|
||||||
export type PaymentOrderByWithAggregationInput = {
|
export type PaymentOrderByWithAggregationInput = {
|
||||||
@@ -410,6 +413,7 @@ export type PaymentCreateInput = {
|
|||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
booking: Prisma.BookingCreateNestedOneWithoutPaymentsInput
|
booking: Prisma.BookingCreateNestedOneWithoutPaymentsInput
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutPaymentInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentUncheckedCreateInput = {
|
export type PaymentUncheckedCreateInput = {
|
||||||
@@ -429,6 +433,7 @@ export type PaymentUncheckedCreateInput = {
|
|||||||
rejectionReason?: string | null
|
rejectionReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutPaymentInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentUpdateInput = {
|
export type PaymentUpdateInput = {
|
||||||
@@ -448,6 +453,7 @@ export type PaymentUpdateInput = {
|
|||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
booking?: Prisma.BookingUpdateOneRequiredWithoutPaymentsNestedInput
|
booking?: Prisma.BookingUpdateOneRequiredWithoutPaymentsNestedInput
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutPaymentNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentUncheckedUpdateInput = {
|
export type PaymentUncheckedUpdateInput = {
|
||||||
@@ -467,6 +473,7 @@ export type PaymentUncheckedUpdateInput = {
|
|||||||
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutPaymentNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentCreateManyInput = {
|
export type PaymentCreateManyInput = {
|
||||||
@@ -598,6 +605,11 @@ export type PaymentSumOrderByAggregateInput = {
|
|||||||
amount?: Prisma.SortOrder
|
amount?: Prisma.SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PaymentNullableScalarRelationFilter = {
|
||||||
|
is?: Prisma.PaymentWhereInput | null
|
||||||
|
isNot?: Prisma.PaymentWhereInput | null
|
||||||
|
}
|
||||||
|
|
||||||
export type PaymentCreateNestedManyWithoutBookingInput = {
|
export type PaymentCreateNestedManyWithoutBookingInput = {
|
||||||
create?: Prisma.XOR<Prisma.PaymentCreateWithoutBookingInput, Prisma.PaymentUncheckedCreateWithoutBookingInput> | Prisma.PaymentCreateWithoutBookingInput[] | Prisma.PaymentUncheckedCreateWithoutBookingInput[]
|
create?: Prisma.XOR<Prisma.PaymentCreateWithoutBookingInput, Prisma.PaymentUncheckedCreateWithoutBookingInput> | Prisma.PaymentCreateWithoutBookingInput[] | Prisma.PaymentUncheckedCreateWithoutBookingInput[]
|
||||||
connectOrCreate?: Prisma.PaymentCreateOrConnectWithoutBookingInput | Prisma.PaymentCreateOrConnectWithoutBookingInput[]
|
connectOrCreate?: Prisma.PaymentCreateOrConnectWithoutBookingInput | Prisma.PaymentCreateOrConnectWithoutBookingInput[]
|
||||||
@@ -648,6 +660,22 @@ export type EnumPaymentStatusFieldUpdateOperationsInput = {
|
|||||||
set?: $Enums.PaymentStatus
|
set?: $Enums.PaymentStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PaymentCreateNestedOneWithoutRefundsInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.PaymentCreateWithoutRefundsInput, Prisma.PaymentUncheckedCreateWithoutRefundsInput>
|
||||||
|
connectOrCreate?: Prisma.PaymentCreateOrConnectWithoutRefundsInput
|
||||||
|
connect?: Prisma.PaymentWhereUniqueInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentUpdateOneWithoutRefundsNestedInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.PaymentCreateWithoutRefundsInput, Prisma.PaymentUncheckedCreateWithoutRefundsInput>
|
||||||
|
connectOrCreate?: Prisma.PaymentCreateOrConnectWithoutRefundsInput
|
||||||
|
upsert?: Prisma.PaymentUpsertWithoutRefundsInput
|
||||||
|
disconnect?: Prisma.PaymentWhereInput | boolean
|
||||||
|
delete?: Prisma.PaymentWhereInput | boolean
|
||||||
|
connect?: Prisma.PaymentWhereUniqueInput
|
||||||
|
update?: Prisma.XOR<Prisma.XOR<Prisma.PaymentUpdateToOneWithWhereWithoutRefundsInput, Prisma.PaymentUpdateWithoutRefundsInput>, Prisma.PaymentUncheckedUpdateWithoutRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
export type PaymentCreateWithoutBookingInput = {
|
export type PaymentCreateWithoutBookingInput = {
|
||||||
id?: string
|
id?: string
|
||||||
provider: $Enums.PaymentProvider
|
provider: $Enums.PaymentProvider
|
||||||
@@ -664,6 +692,7 @@ export type PaymentCreateWithoutBookingInput = {
|
|||||||
rejectionReason?: string | null
|
rejectionReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
refunds?: Prisma.RefundCreateNestedManyWithoutPaymentInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentUncheckedCreateWithoutBookingInput = {
|
export type PaymentUncheckedCreateWithoutBookingInput = {
|
||||||
@@ -682,6 +711,7 @@ export type PaymentUncheckedCreateWithoutBookingInput = {
|
|||||||
rejectionReason?: string | null
|
rejectionReason?: string | null
|
||||||
createdAt?: Date | string
|
createdAt?: Date | string
|
||||||
updatedAt?: Date | string
|
updatedAt?: Date | string
|
||||||
|
refunds?: Prisma.RefundUncheckedCreateNestedManyWithoutPaymentInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentCreateOrConnectWithoutBookingInput = {
|
export type PaymentCreateOrConnectWithoutBookingInput = {
|
||||||
@@ -732,6 +762,98 @@ export type PaymentScalarWhereInput = {
|
|||||||
updatedAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
updatedAt?: Prisma.DateTimeFilter<"Payment"> | Date | string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PaymentCreateWithoutRefundsInput = {
|
||||||
|
id?: string
|
||||||
|
provider: $Enums.PaymentProvider
|
||||||
|
externalOrderId: string
|
||||||
|
externalTxId?: string | null
|
||||||
|
method?: string | null
|
||||||
|
amount: number
|
||||||
|
status?: $Enums.PaymentStatus
|
||||||
|
rawCallback?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
||||||
|
snapToken?: string | null
|
||||||
|
expiresAt?: Date | string | null
|
||||||
|
paidAt?: Date | string | null
|
||||||
|
failedAt?: Date | string | null
|
||||||
|
rejectionReason?: string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
booking: Prisma.BookingCreateNestedOneWithoutPaymentsInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentUncheckedCreateWithoutRefundsInput = {
|
||||||
|
id?: string
|
||||||
|
bookingId: string
|
||||||
|
provider: $Enums.PaymentProvider
|
||||||
|
externalOrderId: string
|
||||||
|
externalTxId?: string | null
|
||||||
|
method?: string | null
|
||||||
|
amount: number
|
||||||
|
status?: $Enums.PaymentStatus
|
||||||
|
rawCallback?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
||||||
|
snapToken?: string | null
|
||||||
|
expiresAt?: Date | string | null
|
||||||
|
paidAt?: Date | string | null
|
||||||
|
failedAt?: Date | string | null
|
||||||
|
rejectionReason?: string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentCreateOrConnectWithoutRefundsInput = {
|
||||||
|
where: Prisma.PaymentWhereUniqueInput
|
||||||
|
create: Prisma.XOR<Prisma.PaymentCreateWithoutRefundsInput, Prisma.PaymentUncheckedCreateWithoutRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentUpsertWithoutRefundsInput = {
|
||||||
|
update: Prisma.XOR<Prisma.PaymentUpdateWithoutRefundsInput, Prisma.PaymentUncheckedUpdateWithoutRefundsInput>
|
||||||
|
create: Prisma.XOR<Prisma.PaymentCreateWithoutRefundsInput, Prisma.PaymentUncheckedCreateWithoutRefundsInput>
|
||||||
|
where?: Prisma.PaymentWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentUpdateToOneWithWhereWithoutRefundsInput = {
|
||||||
|
where?: Prisma.PaymentWhereInput
|
||||||
|
data: Prisma.XOR<Prisma.PaymentUpdateWithoutRefundsInput, Prisma.PaymentUncheckedUpdateWithoutRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentUpdateWithoutRefundsInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
provider?: Prisma.EnumPaymentProviderFieldUpdateOperationsInput | $Enums.PaymentProvider
|
||||||
|
externalOrderId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
externalTxId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
method?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
amount?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
|
status?: Prisma.EnumPaymentStatusFieldUpdateOperationsInput | $Enums.PaymentStatus
|
||||||
|
rawCallback?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
||||||
|
snapToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
expiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
paidAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
failedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
booking?: Prisma.BookingUpdateOneRequiredWithoutPaymentsNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentUncheckedUpdateWithoutRefundsInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
bookingId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
provider?: Prisma.EnumPaymentProviderFieldUpdateOperationsInput | $Enums.PaymentProvider
|
||||||
|
externalOrderId?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
externalTxId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
method?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
amount?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
|
status?: Prisma.EnumPaymentStatusFieldUpdateOperationsInput | $Enums.PaymentStatus
|
||||||
|
rawCallback?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
||||||
|
snapToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
expiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
paidAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
failedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
}
|
||||||
|
|
||||||
export type PaymentCreateManyBookingInput = {
|
export type PaymentCreateManyBookingInput = {
|
||||||
id?: string
|
id?: string
|
||||||
provider: $Enums.PaymentProvider
|
provider: $Enums.PaymentProvider
|
||||||
@@ -766,6 +888,7 @@ export type PaymentUpdateWithoutBookingInput = {
|
|||||||
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
refunds?: Prisma.RefundUpdateManyWithoutPaymentNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentUncheckedUpdateWithoutBookingInput = {
|
export type PaymentUncheckedUpdateWithoutBookingInput = {
|
||||||
@@ -784,6 +907,7 @@ export type PaymentUncheckedUpdateWithoutBookingInput = {
|
|||||||
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
rejectionReason?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
refunds?: Prisma.RefundUncheckedUpdateManyWithoutPaymentNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentUncheckedUpdateManyWithoutBookingInput = {
|
export type PaymentUncheckedUpdateManyWithoutBookingInput = {
|
||||||
@@ -805,6 +929,35 @@ export type PaymentUncheckedUpdateManyWithoutBookingInput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count Type PaymentCountOutputType
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type PaymentCountOutputType = {
|
||||||
|
refunds: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaymentCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
refunds?: boolean | PaymentCountOutputTypeCountRefundsArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PaymentCountOutputType without action
|
||||||
|
*/
|
||||||
|
export type PaymentCountOutputTypeDefaultArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
/**
|
||||||
|
* Select specific fields to fetch from the PaymentCountOutputType
|
||||||
|
*/
|
||||||
|
select?: Prisma.PaymentCountOutputTypeSelect<ExtArgs> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PaymentCountOutputType without action
|
||||||
|
*/
|
||||||
|
export type PaymentCountOutputTypeCountRefundsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
where?: Prisma.RefundWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type PaymentSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type PaymentSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
id?: boolean
|
id?: boolean
|
||||||
@@ -824,6 +977,8 @@ export type PaymentSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
|||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
updatedAt?: boolean
|
updatedAt?: boolean
|
||||||
booking?: boolean | Prisma.BookingDefaultArgs<ExtArgs>
|
booking?: boolean | Prisma.BookingDefaultArgs<ExtArgs>
|
||||||
|
refunds?: boolean | Prisma.Payment$refundsArgs<ExtArgs>
|
||||||
|
_count?: boolean | Prisma.PaymentCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["payment"]>
|
}, ExtArgs["result"]["payment"]>
|
||||||
|
|
||||||
export type PaymentSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type PaymentSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
@@ -888,6 +1043,8 @@ export type PaymentSelectScalar = {
|
|||||||
export type PaymentOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "bookingId" | "provider" | "externalOrderId" | "externalTxId" | "method" | "amount" | "status" | "rawCallback" | "snapToken" | "expiresAt" | "paidAt" | "failedAt" | "rejectionReason" | "createdAt" | "updatedAt", ExtArgs["result"]["payment"]>
|
export type PaymentOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "bookingId" | "provider" | "externalOrderId" | "externalTxId" | "method" | "amount" | "status" | "rawCallback" | "snapToken" | "expiresAt" | "paidAt" | "failedAt" | "rejectionReason" | "createdAt" | "updatedAt", ExtArgs["result"]["payment"]>
|
||||||
export type PaymentInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type PaymentInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
booking?: boolean | Prisma.BookingDefaultArgs<ExtArgs>
|
booking?: boolean | Prisma.BookingDefaultArgs<ExtArgs>
|
||||||
|
refunds?: boolean | Prisma.Payment$refundsArgs<ExtArgs>
|
||||||
|
_count?: boolean | Prisma.PaymentCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}
|
}
|
||||||
export type PaymentIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type PaymentIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
booking?: boolean | Prisma.BookingDefaultArgs<ExtArgs>
|
booking?: boolean | Prisma.BookingDefaultArgs<ExtArgs>
|
||||||
@@ -900,6 +1057,7 @@ export type $PaymentPayload<ExtArgs extends runtime.Types.Extensions.InternalArg
|
|||||||
name: "Payment"
|
name: "Payment"
|
||||||
objects: {
|
objects: {
|
||||||
booking: Prisma.$BookingPayload<ExtArgs>
|
booking: Prisma.$BookingPayload<ExtArgs>
|
||||||
|
refunds: Prisma.$RefundPayload<ExtArgs>[]
|
||||||
}
|
}
|
||||||
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
||||||
id: string
|
id: string
|
||||||
@@ -1332,6 +1490,7 @@ readonly fields: PaymentFieldRefs;
|
|||||||
export interface Prisma__PaymentClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> {
|
export interface Prisma__PaymentClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> {
|
||||||
readonly [Symbol.toStringTag]: "PrismaPromise"
|
readonly [Symbol.toStringTag]: "PrismaPromise"
|
||||||
booking<T extends Prisma.BookingDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.BookingDefaultArgs<ExtArgs>>): Prisma.Prisma__BookingClient<runtime.Types.Result.GetResult<Prisma.$BookingPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
|
booking<T extends Prisma.BookingDefaultArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.BookingDefaultArgs<ExtArgs>>): Prisma.Prisma__BookingClient<runtime.Types.Result.GetResult<Prisma.$BookingPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions>
|
||||||
|
refunds<T extends Prisma.Payment$refundsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Payment$refundsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$RefundPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
/**
|
/**
|
||||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||||
@@ -1777,6 +1936,30 @@ export type PaymentDeleteManyArgs<ExtArgs extends runtime.Types.Extensions.Inter
|
|||||||
limit?: number
|
limit?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment.refunds
|
||||||
|
*/
|
||||||
|
export type Payment$refundsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
/**
|
||||||
|
* Select specific fields to fetch from the Refund
|
||||||
|
*/
|
||||||
|
select?: Prisma.RefundSelect<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Omit specific fields from the Refund
|
||||||
|
*/
|
||||||
|
omit?: Prisma.RefundOmit<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Choose, which related nodes to fetch as well
|
||||||
|
*/
|
||||||
|
include?: Prisma.RefundInclude<ExtArgs> | null
|
||||||
|
where?: Prisma.RefundWhereInput
|
||||||
|
orderBy?: Prisma.RefundOrderByWithRelationInput | Prisma.RefundOrderByWithRelationInput[]
|
||||||
|
cursor?: Prisma.RefundWhereUniqueInput
|
||||||
|
take?: number
|
||||||
|
skip?: number
|
||||||
|
distinct?: Prisma.RefundScalarFieldEnum | Prisma.RefundScalarFieldEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment without action
|
* Payment without action
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -229,6 +229,7 @@ export type UserWhereInput = {
|
|||||||
bookings?: Prisma.BookingListRelationFilter
|
bookings?: Prisma.BookingListRelationFilter
|
||||||
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
||||||
|
reviewedRefunds?: Prisma.RefundListRelationFilter
|
||||||
profile?: Prisma.XOR<Prisma.UserProfileNullableScalarRelationFilter, Prisma.UserProfileWhereInput> | null
|
profile?: Prisma.XOR<Prisma.UserProfileNullableScalarRelationFilter, Prisma.UserProfileWhereInput> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,6 +251,7 @@ export type UserOrderByWithRelationInput = {
|
|||||||
bookings?: Prisma.BookingOrderByRelationAggregateInput
|
bookings?: Prisma.BookingOrderByRelationAggregateInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationOrderByWithRelationInput
|
organizerVerification?: Prisma.OrganizerVerificationOrderByWithRelationInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationOrderByRelationAggregateInput
|
reviewedVerifications?: Prisma.OrganizerVerificationOrderByRelationAggregateInput
|
||||||
|
reviewedRefunds?: Prisma.RefundOrderByRelationAggregateInput
|
||||||
profile?: Prisma.UserProfileOrderByWithRelationInput
|
profile?: Prisma.UserProfileOrderByWithRelationInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +276,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
bookings?: Prisma.BookingListRelationFilter
|
bookings?: Prisma.BookingListRelationFilter
|
||||||
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
organizerVerification?: Prisma.XOR<Prisma.OrganizerVerificationNullableScalarRelationFilter, Prisma.OrganizerVerificationWhereInput> | null
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
reviewedVerifications?: Prisma.OrganizerVerificationListRelationFilter
|
||||||
|
reviewedRefunds?: Prisma.RefundListRelationFilter
|
||||||
profile?: Prisma.XOR<Prisma.UserProfileNullableScalarRelationFilter, Prisma.UserProfileWhereInput> | null
|
profile?: Prisma.XOR<Prisma.UserProfileNullableScalarRelationFilter, Prisma.UserProfileWhereInput> | null
|
||||||
}, "id" | "email">
|
}, "id" | "email">
|
||||||
|
|
||||||
@@ -327,6 +330,7 @@ export type UserCreateInput = {
|
|||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,6 +352,7 @@ export type UserUncheckedCreateInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,6 +374,7 @@ export type UserUpdateInput = {
|
|||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,6 +396,7 @@ export type UserUncheckedUpdateInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,6 +622,22 @@ export type UserUpdateOneRequiredWithoutBookingsNestedInput = {
|
|||||||
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutBookingsInput, Prisma.UserUpdateWithoutBookingsInput>, Prisma.UserUncheckedUpdateWithoutBookingsInput>
|
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutBookingsInput, Prisma.UserUpdateWithoutBookingsInput>, Prisma.UserUncheckedUpdateWithoutBookingsInput>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UserCreateNestedOneWithoutReviewedRefundsInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.UserCreateWithoutReviewedRefundsInput, Prisma.UserUncheckedCreateWithoutReviewedRefundsInput>
|
||||||
|
connectOrCreate?: Prisma.UserCreateOrConnectWithoutReviewedRefundsInput
|
||||||
|
connect?: Prisma.UserWhereUniqueInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpdateOneWithoutReviewedRefundsNestedInput = {
|
||||||
|
create?: Prisma.XOR<Prisma.UserCreateWithoutReviewedRefundsInput, Prisma.UserUncheckedCreateWithoutReviewedRefundsInput>
|
||||||
|
connectOrCreate?: Prisma.UserCreateOrConnectWithoutReviewedRefundsInput
|
||||||
|
upsert?: Prisma.UserUpsertWithoutReviewedRefundsInput
|
||||||
|
disconnect?: Prisma.UserWhereInput | boolean
|
||||||
|
delete?: Prisma.UserWhereInput | boolean
|
||||||
|
connect?: Prisma.UserWhereUniqueInput
|
||||||
|
update?: Prisma.XOR<Prisma.XOR<Prisma.UserUpdateToOneWithWhereWithoutReviewedRefundsInput, Prisma.UserUpdateWithoutReviewedRefundsInput>, Prisma.UserUncheckedUpdateWithoutReviewedRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutProfileInput = {
|
export type UserCreateWithoutProfileInput = {
|
||||||
id?: string
|
id?: string
|
||||||
name: string
|
name: string
|
||||||
@@ -633,6 +656,7 @@ export type UserCreateWithoutProfileInput = {
|
|||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedCreateWithoutProfileInput = {
|
export type UserUncheckedCreateWithoutProfileInput = {
|
||||||
@@ -653,6 +677,7 @@ export type UserUncheckedCreateWithoutProfileInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutProfileInput = {
|
export type UserCreateOrConnectWithoutProfileInput = {
|
||||||
@@ -689,6 +714,7 @@ export type UserUpdateWithoutProfileInput = {
|
|||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserUncheckedUpdateWithoutProfileInput = {
|
export type UserUncheckedUpdateWithoutProfileInput = {
|
||||||
@@ -709,6 +735,7 @@ export type UserUncheckedUpdateWithoutProfileInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCreateWithoutAccountsInput = {
|
export type UserCreateWithoutAccountsInput = {
|
||||||
@@ -728,6 +755,7 @@ export type UserCreateWithoutAccountsInput = {
|
|||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,6 +776,7 @@ export type UserUncheckedCreateWithoutAccountsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -784,6 +813,7 @@ export type UserUpdateWithoutAccountsInput = {
|
|||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,6 +834,7 @@ export type UserUncheckedUpdateWithoutAccountsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,6 +855,7 @@ export type UserCreateWithoutOrganizerVerificationInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,6 +876,7 @@ export type UserUncheckedCreateWithoutOrganizerVerificationInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,6 +902,7 @@ export type UserCreateWithoutReviewedVerificationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -889,6 +923,7 @@ export type UserUncheckedCreateWithoutReviewedVerificationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -925,6 +960,7 @@ export type UserUpdateWithoutOrganizerVerificationInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -945,6 +981,7 @@ export type UserUncheckedUpdateWithoutOrganizerVerificationInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -976,6 +1013,7 @@ export type UserUpdateWithoutReviewedVerificationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,6 +1034,7 @@ export type UserUncheckedUpdateWithoutReviewedVerificationsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,6 +1055,7 @@ export type UserCreateWithoutTripsInput = {
|
|||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1036,6 +1076,7 @@ export type UserUncheckedCreateWithoutTripsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,6 +1113,7 @@ export type UserUpdateWithoutTripsInput = {
|
|||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,6 +1134,7 @@ export type UserUncheckedUpdateWithoutTripsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1112,6 +1155,7 @@ export type UserCreateWithoutTripReviewsInput = {
|
|||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1132,6 +1176,7 @@ export type UserUncheckedCreateWithoutTripReviewsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,6 +1213,7 @@ export type UserUpdateWithoutTripReviewsInput = {
|
|||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1188,6 +1234,7 @@ export type UserUncheckedUpdateWithoutTripReviewsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,6 +1255,7 @@ export type UserCreateWithoutParticipationsInput = {
|
|||||||
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1228,6 +1276,7 @@ export type UserUncheckedCreateWithoutParticipationsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1264,6 +1313,7 @@ export type UserUpdateWithoutParticipationsInput = {
|
|||||||
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1284,6 +1334,7 @@ export type UserUncheckedUpdateWithoutParticipationsInput = {
|
|||||||
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1304,6 +1355,7 @@ export type UserCreateWithoutBookingsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1324,6 +1376,7 @@ export type UserUncheckedCreateWithoutBookingsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,6 +1413,7 @@ export type UserUpdateWithoutBookingsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,6 +1434,107 @@ export type UserUncheckedUpdateWithoutBookingsInput = {
|
|||||||
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
reviewedRefunds?: Prisma.RefundUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserCreateWithoutReviewedRefundsInput = {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
password?: string | null
|
||||||
|
image?: string | null
|
||||||
|
emailVerified?: Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: boolean
|
||||||
|
acceptedAt?: Date | string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
accounts?: Prisma.AccountCreateNestedManyWithoutUserInput
|
||||||
|
trips?: Prisma.TripCreateNestedManyWithoutOrganizerInput
|
||||||
|
participations?: Prisma.TripParticipantCreateNestedManyWithoutUserInput
|
||||||
|
tripReviews?: Prisma.TripReviewCreateNestedManyWithoutUserInput
|
||||||
|
bookings?: Prisma.BookingCreateNestedManyWithoutUserInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationCreateNestedOneWithoutUserInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileCreateNestedOneWithoutUserInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUncheckedCreateWithoutReviewedRefundsInput = {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
password?: string | null
|
||||||
|
image?: string | null
|
||||||
|
emailVerified?: Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: boolean
|
||||||
|
acceptedAt?: Date | string | null
|
||||||
|
createdAt?: Date | string
|
||||||
|
updatedAt?: Date | string
|
||||||
|
accounts?: Prisma.AccountUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
trips?: Prisma.TripUncheckedCreateNestedManyWithoutOrganizerInput
|
||||||
|
participations?: Prisma.TripParticipantUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
tripReviews?: Prisma.TripReviewUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
bookings?: Prisma.BookingUncheckedCreateNestedManyWithoutUserInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedCreateNestedOneWithoutUserInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedCreateNestedManyWithoutReviewedByInput
|
||||||
|
profile?: Prisma.UserProfileUncheckedCreateNestedOneWithoutUserInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserCreateOrConnectWithoutReviewedRefundsInput = {
|
||||||
|
where: Prisma.UserWhereUniqueInput
|
||||||
|
create: Prisma.XOR<Prisma.UserCreateWithoutReviewedRefundsInput, Prisma.UserUncheckedCreateWithoutReviewedRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpsertWithoutReviewedRefundsInput = {
|
||||||
|
update: Prisma.XOR<Prisma.UserUpdateWithoutReviewedRefundsInput, Prisma.UserUncheckedUpdateWithoutReviewedRefundsInput>
|
||||||
|
create: Prisma.XOR<Prisma.UserCreateWithoutReviewedRefundsInput, Prisma.UserUncheckedCreateWithoutReviewedRefundsInput>
|
||||||
|
where?: Prisma.UserWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpdateToOneWithWhereWithoutReviewedRefundsInput = {
|
||||||
|
where?: Prisma.UserWhereInput
|
||||||
|
data: Prisma.XOR<Prisma.UserUpdateWithoutReviewedRefundsInput, Prisma.UserUncheckedUpdateWithoutReviewedRefundsInput>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUpdateWithoutReviewedRefundsInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
accounts?: Prisma.AccountUpdateManyWithoutUserNestedInput
|
||||||
|
trips?: Prisma.TripUpdateManyWithoutOrganizerNestedInput
|
||||||
|
participations?: Prisma.TripParticipantUpdateManyWithoutUserNestedInput
|
||||||
|
tripReviews?: Prisma.TripReviewUpdateManyWithoutUserNestedInput
|
||||||
|
bookings?: Prisma.BookingUpdateManyWithoutUserNestedInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationUpdateOneWithoutUserNestedInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationUpdateManyWithoutReviewedByNestedInput
|
||||||
|
profile?: Prisma.UserProfileUpdateOneWithoutUserNestedInput
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserUncheckedUpdateWithoutReviewedRefundsInput = {
|
||||||
|
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
email?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
password?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
|
emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
acceptedTermsAndPrivacy?: Prisma.BoolFieldUpdateOperationsInput | boolean
|
||||||
|
acceptedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
||||||
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
|
accounts?: Prisma.AccountUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
trips?: Prisma.TripUncheckedUpdateManyWithoutOrganizerNestedInput
|
||||||
|
participations?: Prisma.TripParticipantUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
tripReviews?: Prisma.TripReviewUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
bookings?: Prisma.BookingUncheckedUpdateManyWithoutUserNestedInput
|
||||||
|
organizerVerification?: Prisma.OrganizerVerificationUncheckedUpdateOneWithoutUserNestedInput
|
||||||
|
reviewedVerifications?: Prisma.OrganizerVerificationUncheckedUpdateManyWithoutReviewedByNestedInput
|
||||||
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
profile?: Prisma.UserProfileUncheckedUpdateOneWithoutUserNestedInput
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1395,6 +1550,7 @@ export type UserCountOutputType = {
|
|||||||
tripReviews: number
|
tripReviews: number
|
||||||
bookings: number
|
bookings: number
|
||||||
reviewedVerifications: number
|
reviewedVerifications: number
|
||||||
|
reviewedRefunds: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type UserCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
@@ -1404,6 +1560,7 @@ export type UserCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.I
|
|||||||
tripReviews?: boolean | UserCountOutputTypeCountTripReviewsArgs
|
tripReviews?: boolean | UserCountOutputTypeCountTripReviewsArgs
|
||||||
bookings?: boolean | UserCountOutputTypeCountBookingsArgs
|
bookings?: boolean | UserCountOutputTypeCountBookingsArgs
|
||||||
reviewedVerifications?: boolean | UserCountOutputTypeCountReviewedVerificationsArgs
|
reviewedVerifications?: boolean | UserCountOutputTypeCountReviewedVerificationsArgs
|
||||||
|
reviewedRefunds?: boolean | UserCountOutputTypeCountReviewedRefundsArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1458,6 +1615,13 @@ export type UserCountOutputTypeCountReviewedVerificationsArgs<ExtArgs extends ru
|
|||||||
where?: Prisma.OrganizerVerificationWhereInput
|
where?: Prisma.OrganizerVerificationWhereInput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserCountOutputType without action
|
||||||
|
*/
|
||||||
|
export type UserCountOutputTypeCountReviewedRefundsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
where?: Prisma.RefundWhereInput
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
id?: boolean
|
id?: boolean
|
||||||
@@ -1477,6 +1641,7 @@ export type UserSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
|
|||||||
bookings?: boolean | Prisma.User$bookingsArgs<ExtArgs>
|
bookings?: boolean | Prisma.User$bookingsArgs<ExtArgs>
|
||||||
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
||||||
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
||||||
|
reviewedRefunds?: boolean | Prisma.User$reviewedRefundsArgs<ExtArgs>
|
||||||
profile?: boolean | Prisma.User$profileArgs<ExtArgs>
|
profile?: boolean | Prisma.User$profileArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}, ExtArgs["result"]["user"]>
|
}, ExtArgs["result"]["user"]>
|
||||||
@@ -1529,6 +1694,7 @@ export type UserInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
bookings?: boolean | Prisma.User$bookingsArgs<ExtArgs>
|
bookings?: boolean | Prisma.User$bookingsArgs<ExtArgs>
|
||||||
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
organizerVerification?: boolean | Prisma.User$organizerVerificationArgs<ExtArgs>
|
||||||
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
reviewedVerifications?: boolean | Prisma.User$reviewedVerificationsArgs<ExtArgs>
|
||||||
|
reviewedRefunds?: boolean | Prisma.User$reviewedRefundsArgs<ExtArgs>
|
||||||
profile?: boolean | Prisma.User$profileArgs<ExtArgs>
|
profile?: boolean | Prisma.User$profileArgs<ExtArgs>
|
||||||
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
_count?: boolean | Prisma.UserCountOutputTypeDefaultArgs<ExtArgs>
|
||||||
}
|
}
|
||||||
@@ -1545,6 +1711,7 @@ export type $UserPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
bookings: Prisma.$BookingPayload<ExtArgs>[]
|
bookings: Prisma.$BookingPayload<ExtArgs>[]
|
||||||
organizerVerification: Prisma.$OrganizerVerificationPayload<ExtArgs> | null
|
organizerVerification: Prisma.$OrganizerVerificationPayload<ExtArgs> | null
|
||||||
reviewedVerifications: Prisma.$OrganizerVerificationPayload<ExtArgs>[]
|
reviewedVerifications: Prisma.$OrganizerVerificationPayload<ExtArgs>[]
|
||||||
|
reviewedRefunds: Prisma.$RefundPayload<ExtArgs>[]
|
||||||
profile: Prisma.$UserProfilePayload<ExtArgs> | null
|
profile: Prisma.$UserProfilePayload<ExtArgs> | null
|
||||||
}
|
}
|
||||||
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
||||||
@@ -1971,6 +2138,7 @@ export interface Prisma__UserClient<T, Null = never, ExtArgs extends runtime.Typ
|
|||||||
bookings<T extends Prisma.User$bookingsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$bookingsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$BookingPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
bookings<T extends Prisma.User$bookingsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$bookingsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$BookingPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
organizerVerification<T extends Prisma.User$organizerVerificationArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$organizerVerificationArgs<ExtArgs>>): Prisma.Prisma__OrganizerVerificationClient<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
organizerVerification<T extends Prisma.User$organizerVerificationArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$organizerVerificationArgs<ExtArgs>>): Prisma.Prisma__OrganizerVerificationClient<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
||||||
reviewedVerifications<T extends Prisma.User$reviewedVerificationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$reviewedVerificationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
reviewedVerifications<T extends Prisma.User$reviewedVerificationsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$reviewedVerificationsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$OrganizerVerificationPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
|
reviewedRefunds<T extends Prisma.User$reviewedRefundsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$reviewedRefundsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$RefundPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||||
profile<T extends Prisma.User$profileArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$profileArgs<ExtArgs>>): Prisma.Prisma__UserProfileClient<runtime.Types.Result.GetResult<Prisma.$UserProfilePayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
profile<T extends Prisma.User$profileArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.User$profileArgs<ExtArgs>>): Prisma.Prisma__UserProfileClient<runtime.Types.Result.GetResult<Prisma.$UserProfilePayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
|
||||||
/**
|
/**
|
||||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||||
@@ -2566,6 +2734,30 @@ export type User$reviewedVerificationsArgs<ExtArgs extends runtime.Types.Extensi
|
|||||||
distinct?: Prisma.OrganizerVerificationScalarFieldEnum | Prisma.OrganizerVerificationScalarFieldEnum[]
|
distinct?: Prisma.OrganizerVerificationScalarFieldEnum | Prisma.OrganizerVerificationScalarFieldEnum[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User.reviewedRefunds
|
||||||
|
*/
|
||||||
|
export type User$reviewedRefundsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
|
/**
|
||||||
|
* Select specific fields to fetch from the Refund
|
||||||
|
*/
|
||||||
|
select?: Prisma.RefundSelect<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Omit specific fields from the Refund
|
||||||
|
*/
|
||||||
|
omit?: Prisma.RefundOmit<ExtArgs> | null
|
||||||
|
/**
|
||||||
|
* Choose, which related nodes to fetch as well
|
||||||
|
*/
|
||||||
|
include?: Prisma.RefundInclude<ExtArgs> | null
|
||||||
|
where?: Prisma.RefundWhereInput
|
||||||
|
orderBy?: Prisma.RefundOrderByWithRelationInput | Prisma.RefundOrderByWithRelationInput[]
|
||||||
|
cursor?: Prisma.RefundWhereUniqueInput
|
||||||
|
take?: number
|
||||||
|
skip?: number
|
||||||
|
distinct?: Prisma.RefundScalarFieldEnum | Prisma.RefundScalarFieldEnum[]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User.profile
|
* User.profile
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,17 +6,21 @@ import Image from "next/image";
|
|||||||
import { authOptions } from "@/lib/auth";
|
import { authOptions } from "@/lib/auth";
|
||||||
import { tripService } from "@/server/services/trip.service";
|
import { tripService } from "@/server/services/trip.service";
|
||||||
import { bookingService } from "@/server/services/booking.service";
|
import { bookingService } from "@/server/services/booking.service";
|
||||||
|
import { bookingRepo } from "@/server/repositories/booking.repo";
|
||||||
import { trustService } from "@/server/services/trust.service";
|
import { trustService } from "@/server/services/trust.service";
|
||||||
import { formatRupiah } from "@/lib/utils";
|
import { formatRupiah } from "@/lib/utils";
|
||||||
import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
|
import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
|
||||||
import { siteConfig, siteUrl, absoluteUrl } from "@/lib/site";
|
import { siteConfig, siteUrl, absoluteUrl } from "@/lib/site";
|
||||||
import { JoinTripButton } from "@/features/trip/components/join-trip-button";
|
import { JoinTripButton } from "@/features/trip/components/join-trip-button";
|
||||||
|
import { CancelTripButton } from "@/features/trip/components/cancel-trip-button";
|
||||||
|
import { CancelBookingButton } from "@/features/booking/components/cancel-booking-button";
|
||||||
import { OrganizerJoinRequests } from "@/features/trip/components/organizer-join-requests";
|
import { OrganizerJoinRequests } from "@/features/trip/components/organizer-join-requests";
|
||||||
import { OrganizerTrustPanel } from "@/features/trip/components/organizer-trust-panel";
|
import { OrganizerTrustPanel } from "@/features/trip/components/organizer-trust-panel";
|
||||||
import { TripProgramBlock } from "@/features/trip/components/trip-program-block";
|
import { TripProgramBlock } from "@/features/trip/components/trip-program-block";
|
||||||
import { OrganizerPaymentQueue } from "@/features/booking/components/organizer-payment-queue";
|
import { OrganizerPaymentQueue } from "@/features/booking/components/organizer-payment-queue";
|
||||||
import { ImageGallery } from "@/features/trip/components/image-gallery";
|
import { ImageGallery } from "@/features/trip/components/image-gallery";
|
||||||
import { TripReviewSection } from "@/features/review/components/trip-review-section";
|
import { TripReviewSection } from "@/features/review/components/trip-review-section";
|
||||||
|
import { RefundPolicySection } from "@/features/refund/components/refund-policy-section";
|
||||||
import { categoryMeta } from "@/lib/activity-category";
|
import { categoryMeta } from "@/lib/activity-category";
|
||||||
import { vibeMeta } from "@/lib/vibe";
|
import { vibeMeta } from "@/lib/vibe";
|
||||||
import { isFreeTrip } from "@/lib/trip-pricing";
|
import { isFreeTrip } from "@/lib/trip-pricing";
|
||||||
@@ -24,6 +28,7 @@ import {
|
|||||||
isPastTripLastDayForReview,
|
isPastTripLastDayForReview,
|
||||||
isTripDepartureDayPast,
|
isTripDepartureDayPast,
|
||||||
} from "@/lib/trip-dates";
|
} from "@/lib/trip-dates";
|
||||||
|
import { previewRefund } from "@/lib/refund-policy";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params,
|
params,
|
||||||
@@ -137,6 +142,31 @@ export default async function TripDetailPage({
|
|||||||
? await bookingService.getAwaitingManualForTrip(trip.id)
|
? await bookingService.getAwaitingManualForTrip(trip.id)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
// Booking peserta saat ini — dipakai untuk render CancelBookingButton vs
|
||||||
|
// tombol "Batal Ikut" biasa. Hanya untuk non-organizer yang ikut trip.
|
||||||
|
const myBooking =
|
||||||
|
session?.user && !isOrganizer && currentParticipation
|
||||||
|
? await bookingService.getByTripAndUser(trip.id, session.user.id)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Untuk CancelTripButton: jumlah booking PAID/PARTIALLY_REFUNDED (yang akan
|
||||||
|
// auto-refund). Hanya dihitung saat organizer mengakses trip yang masih
|
||||||
|
// bisa dibatalkan.
|
||||||
|
const canOrganizerCancel =
|
||||||
|
isOrganizer &&
|
||||||
|
(trip.status === "OPEN" || trip.status === "FULL") &&
|
||||||
|
!isDeparturePast;
|
||||||
|
const paidBookingCount = canOrganizerCancel
|
||||||
|
? await bookingRepo.countSettledForTrip(trip.id)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
// Preview refund untuk CancelBookingButton (server-side supaya konsisten
|
||||||
|
// dengan service yang juga pakai policy yang sama).
|
||||||
|
const refundPreview =
|
||||||
|
myBooking && myBooking.status === "PAID" && !isDeparturePast
|
||||||
|
? previewRefund(myBooking.amount, trip.date)
|
||||||
|
: null;
|
||||||
|
|
||||||
const catMeta = categoryMeta(trip.category);
|
const catMeta = categoryMeta(trip.category);
|
||||||
|
|
||||||
const tripUrl = absoluteUrl(`/trips/${trip.id}`);
|
const tripUrl = absoluteUrl(`/trips/${trip.id}`);
|
||||||
@@ -480,8 +510,33 @@ export default async function TripDetailPage({
|
|||||||
isFull={spotsLeft <= 0}
|
isFull={spotsLeft <= 0}
|
||||||
tripStatus={trip.status}
|
tripStatus={trip.status}
|
||||||
isDeparturePast={isDeparturePast}
|
isDeparturePast={isDeparturePast}
|
||||||
|
hideCancelButton={!!refundPreview}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Peserta PAID: cancel + request refund (lewat policy default). */}
|
||||||
|
{refundPreview && (
|
||||||
|
<CancelBookingButton
|
||||||
|
tripId={trip.id}
|
||||||
|
preview={{
|
||||||
|
days: refundPreview.days,
|
||||||
|
refundAmount: refundPreview.refundAmount,
|
||||||
|
bookingAmount: refundPreview.bookingAmount,
|
||||||
|
tierLabel: refundPreview.tier.label,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Organizer: batalkan trip (auto-refund peserta PAID). */}
|
||||||
|
{canOrganizerCancel && (
|
||||||
|
<CancelTripButton
|
||||||
|
tripId={trip.id}
|
||||||
|
paidParticipantCount={paidBookingCount}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Kebijakan refund — transparency sebelum user cancel. */}
|
||||||
|
{!tripIsFree && <RefundPolicySection />}
|
||||||
|
|
||||||
<TripReviewSection
|
<TripReviewSection
|
||||||
tripId={trip.id}
|
tripId={trip.id}
|
||||||
reviews={trip.reviews.map((r) => ({
|
reviews={trip.reviews.map((r) => ({
|
||||||
|
|||||||
@@ -158,7 +158,14 @@ function FreeTripSection({
|
|||||||
bookingStatus,
|
bookingStatus,
|
||||||
}: {
|
}: {
|
||||||
tripId: string;
|
tripId: string;
|
||||||
bookingStatus: "PENDING" | "AWAITING_PAY" | "PAID" | "CANCELLED" | "REFUNDED" | "EXPIRED";
|
bookingStatus:
|
||||||
|
| "PENDING"
|
||||||
|
| "AWAITING_PAY"
|
||||||
|
| "PAID"
|
||||||
|
| "CANCELLED"
|
||||||
|
| "REFUNDED"
|
||||||
|
| "PARTIALLY_REFUNDED"
|
||||||
|
| "EXPIRED";
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<section className="rounded-2xl border border-emerald-200 bg-emerald-50/60 p-6 text-center shadow-sm sm:p-8">
|
<section className="rounded-2xl border border-emerald-200 bg-emerald-50/60 p-6 text-center shadow-sm sm:p-8">
|
||||||
@@ -208,7 +215,14 @@ async function PaidTripSection({
|
|||||||
organizerId: string;
|
organizerId: string;
|
||||||
organizerName: string;
|
organizerName: string;
|
||||||
price: number;
|
price: number;
|
||||||
bookingStatus: "PENDING" | "AWAITING_PAY" | "PAID" | "CANCELLED" | "REFUNDED" | "EXPIRED";
|
bookingStatus:
|
||||||
|
| "PENDING"
|
||||||
|
| "AWAITING_PAY"
|
||||||
|
| "PAID"
|
||||||
|
| "CANCELLED"
|
||||||
|
| "REFUNDED"
|
||||||
|
| "PARTIALLY_REFUNDED"
|
||||||
|
| "EXPIRED";
|
||||||
paymentMarkedAt: Date | null;
|
paymentMarkedAt: Date | null;
|
||||||
paymentPaidAt: Date | null;
|
paymentPaidAt: Date | null;
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { authOptions } from "@/lib/auth";
|
|||||||
import { tripService } from "@/server/services/trip.service";
|
import { tripService } from "@/server/services/trip.service";
|
||||||
import { paymentService } from "@/server/services/payment.service";
|
import { paymentService } from "@/server/services/payment.service";
|
||||||
import { bookingService } from "@/server/services/booking.service";
|
import { bookingService } from "@/server/services/booking.service";
|
||||||
|
import { refundService } from "@/server/services/refund.service";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
|
|
||||||
export async function markParticipantPaidAction(tripId: string) {
|
export async function markParticipantPaidAction(tripId: string) {
|
||||||
@@ -94,3 +95,45 @@ export async function confirmParticipantPaymentAction(
|
|||||||
return { error: (err as Error).message };
|
return { error: (err as Error).message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peserta cancel booking PAID dengan refund request. Server menghitung
|
||||||
|
* nominal refund pakai policy default (lib/refund-policy.ts) — client
|
||||||
|
* cuma kirim bookingId untuk cegah tampering.
|
||||||
|
*/
|
||||||
|
export async function cancelBookingWithRefundAction(tripId: string) {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session?.user) {
|
||||||
|
return { error: "Kamu harus login terlebih dahulu" };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const booking = await bookingService.getByTripAndUser(
|
||||||
|
tripId,
|
||||||
|
session.user.id
|
||||||
|
);
|
||||||
|
if (!booking) {
|
||||||
|
return { error: "Kamu tidak terdaftar di trip ini" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await refundService.requestUserCancellation({
|
||||||
|
bookingId: booking.id,
|
||||||
|
userId: session.user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
revalidatePath(`/trips/${tripId}`);
|
||||||
|
revalidatePath("/trips");
|
||||||
|
revalidatePath("/");
|
||||||
|
revalidatePath("/profile");
|
||||||
|
revalidatePath("/admin/refunds");
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true as const,
|
||||||
|
kind: result.kind,
|
||||||
|
refundAmount: result.refundAmount,
|
||||||
|
days: result.days,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return { error: (err as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { cancelBookingWithRefundAction } from "@/features/booking/actions";
|
||||||
|
import { formatRupiah } from "@/lib/utils";
|
||||||
|
|
||||||
|
interface CancelBookingButtonProps {
|
||||||
|
tripId: string;
|
||||||
|
/** Hasil preview server-side (dihitung di trip detail page). */
|
||||||
|
preview: {
|
||||||
|
days: number;
|
||||||
|
refundAmount: number;
|
||||||
|
bookingAmount: number;
|
||||||
|
tierLabel: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerResult =
|
||||||
|
| { kind: "REFUND_PENDING"; refundAmount: number; days: number }
|
||||||
|
| { kind: "CANCELLED_NO_REFUND"; days: number };
|
||||||
|
|
||||||
|
export function CancelBookingButton({ tripId, preview }: CancelBookingButtonProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [result, setResult] = useState<ServerResult | null>(null);
|
||||||
|
|
||||||
|
async function handleConfirm() {
|
||||||
|
setLoading(true);
|
||||||
|
setError("");
|
||||||
|
const res = await cancelBookingWithRefundAction(tripId);
|
||||||
|
setLoading(false);
|
||||||
|
if ("error" in res) {
|
||||||
|
setError(res.error ?? "Terjadi kesalahan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setResult({
|
||||||
|
kind: res.kind,
|
||||||
|
refundAmount: res.refundAmount,
|
||||||
|
days: res.days,
|
||||||
|
} as ServerResult);
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.kind === "REFUND_PENDING") {
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-900">
|
||||||
|
<p className="font-semibold">Request refund dibuat.</p>
|
||||||
|
<p className="mt-1 text-xs">
|
||||||
|
Refund <span className="font-bold">{formatRupiah(result.refundAmount)}</span>{" "}
|
||||||
|
menunggu review admin. Setelah disetujui dan ditransfer manual, slot
|
||||||
|
kamu di trip akan otomatis dibebaskan.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result?.kind === "CANCELLED_NO_REFUND") {
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border border-neutral-200 bg-neutral-50 p-4 text-sm text-neutral-700">
|
||||||
|
<p className="font-semibold">Booking dibatalkan.</p>
|
||||||
|
<p className="mt-1 text-xs">
|
||||||
|
Pembatalan di H-{result.days} berada di luar window refund — tidak
|
||||||
|
ada nominal yang dikembalikan.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
className="w-full rounded-xl border-2 border-red-200 py-3 text-sm font-bold text-red-600 transition-colors hover:bg-red-50"
|
||||||
|
>
|
||||||
|
Cancel & Request Refund
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const percentage = preview.bookingAmount
|
||||||
|
? Math.floor((preview.refundAmount * 100) / preview.bookingAmount)
|
||||||
|
: 0;
|
||||||
|
const noRefund = preview.refundAmount === 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-3 rounded-2xl border-2 border-red-200 bg-red-50 p-4 text-sm">
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-red-900">Cancel booking?</p>
|
||||||
|
<p className="mt-1 text-xs text-red-800/80">
|
||||||
|
Kamu cancel di <span className="font-semibold">H-{preview.days}</span>{" "}
|
||||||
|
dari tanggal berangkat.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="rounded-xl border border-red-200 bg-white p-3">
|
||||||
|
<p className="text-xs font-semibold uppercase tracking-wide text-neutral-500">
|
||||||
|
Estimasi refund (sesuai policy)
|
||||||
|
</p>
|
||||||
|
<p className="mt-1 text-lg font-bold text-neutral-900">
|
||||||
|
{formatRupiah(preview.refundAmount)}
|
||||||
|
{!noRefund && (
|
||||||
|
<span className="ml-2 text-xs font-medium text-neutral-500">
|
||||||
|
({percentage}% dari {formatRupiah(preview.bookingAmount)})
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<p className="mt-1 text-[11px] text-neutral-500">
|
||||||
|
Tier: {preview.tierLabel}
|
||||||
|
</p>
|
||||||
|
{noRefund ? (
|
||||||
|
<p className="mt-2 text-xs text-red-700">
|
||||||
|
⚠️ Di luar window refund — uang tidak dikembalikan. Booking akan
|
||||||
|
di-cancel langsung.
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p className="mt-2 text-xs text-neutral-600">
|
||||||
|
Refund akan masuk antrian review admin. Setelah disetujui & uang
|
||||||
|
ditransfer, booking otomatis ditandai{" "}
|
||||||
|
{percentage === 100 ? "REFUNDED" : "PARTIALLY_REFUNDED"}.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="rounded-lg bg-white px-3 py-2 text-xs font-medium text-red-700">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleConfirm}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl bg-red-600 px-4 py-2 text-sm font-bold text-white hover:bg-red-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{loading
|
||||||
|
? "Memproses…"
|
||||||
|
: noRefund
|
||||||
|
? "Konfirmasi Cancel"
|
||||||
|
: "Konfirmasi & Request Refund"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
setError("");
|
||||||
|
}}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-medium text-red-700 hover:bg-red-100 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { getServerSession } from "next-auth";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { authOptions } from "@/lib/auth";
|
||||||
|
import { isAdminEmail } from "@/lib/admin";
|
||||||
|
import { refundService } from "@/server/services/refund.service";
|
||||||
|
import { createRefundSchema, refundDecisionSchema } from "./schemas";
|
||||||
|
|
||||||
|
async function requireAdmin() {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session?.user || !isAdminEmail(session.user.email)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return session.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createRefundAction(formData: FormData) {
|
||||||
|
const admin = await requireAdmin();
|
||||||
|
if (!admin) return { error: "Tidak memiliki akses admin" };
|
||||||
|
|
||||||
|
const parsed = createRefundSchema.safeParse({
|
||||||
|
bookingId: formData.get("bookingId") as string,
|
||||||
|
reason: formData.get("reason") as string,
|
||||||
|
reportedBy: formData.get("reportedBy") as string,
|
||||||
|
reportNote: formData.get("reportNote") as string,
|
||||||
|
amount: (formData.get("amount") as string) || undefined,
|
||||||
|
});
|
||||||
|
if (!parsed.success) {
|
||||||
|
return { error: parsed.error.issues[0].message };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await refundService.requestRefund({
|
||||||
|
bookingId: parsed.data.bookingId,
|
||||||
|
reason: parsed.data.reason,
|
||||||
|
reportedBy: parsed.data.reportedBy,
|
||||||
|
reportNote: parsed.data.reportNote,
|
||||||
|
amount: parsed.data.amount,
|
||||||
|
initiatedByAdminId: admin.id,
|
||||||
|
});
|
||||||
|
revalidatePath("/admin/refunds");
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
return { error: (err as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function decideRefundAction(formData: FormData) {
|
||||||
|
const admin = await requireAdmin();
|
||||||
|
if (!admin) return { error: "Tidak memiliki akses admin" };
|
||||||
|
|
||||||
|
const parsed = refundDecisionSchema.safeParse({
|
||||||
|
refundId: formData.get("refundId") as string,
|
||||||
|
decision: formData.get("decision") as string,
|
||||||
|
adminNote: (formData.get("adminNote") as string) || undefined,
|
||||||
|
});
|
||||||
|
if (!parsed.success) {
|
||||||
|
return { error: parsed.error.issues[0].message };
|
||||||
|
}
|
||||||
|
|
||||||
|
const { refundId, decision, adminNote } = parsed.data;
|
||||||
|
const needsNote = decision === "REJECT" || decision === "SUCCEEDED" || decision === "FAILED";
|
||||||
|
if (needsNote && (!adminNote || !adminNote.trim())) {
|
||||||
|
return { error: "Catatan/alasan admin wajib diisi untuk tindakan ini" };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (decision === "APPROVE") {
|
||||||
|
await refundService.approveRefund({
|
||||||
|
refundId,
|
||||||
|
adminId: admin.id,
|
||||||
|
adminNote,
|
||||||
|
});
|
||||||
|
} else if (decision === "REJECT") {
|
||||||
|
await refundService.rejectRefund({
|
||||||
|
refundId,
|
||||||
|
adminId: admin.id,
|
||||||
|
adminNote: adminNote!,
|
||||||
|
});
|
||||||
|
} else if (decision === "SUCCEEDED") {
|
||||||
|
await refundService.markSucceededManual({
|
||||||
|
refundId,
|
||||||
|
adminId: admin.id,
|
||||||
|
adminNote: adminNote!,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await refundService.markFailed({
|
||||||
|
refundId,
|
||||||
|
adminId: admin.id,
|
||||||
|
adminNote: adminNote!,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
revalidatePath("/admin/refunds");
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
return { error: (err as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { createRefundAction } from "@/features/refund/actions";
|
||||||
|
|
||||||
|
const REASON_OPTIONS = [
|
||||||
|
{ value: "USER_CANCELLATION", label: "Peserta cancel sendiri" },
|
||||||
|
{ value: "ORGANIZER_CANCELLED", label: "Organizer batalkan trip" },
|
||||||
|
{ value: "TRIP_ISSUE", label: "Masalah saat/setelah trip" },
|
||||||
|
{ value: "ADMIN_ADJUSTMENT", label: "Penyesuaian admin" },
|
||||||
|
{ value: "DISPUTE_RESOLVED", label: "Hasil dispute / chargeback" },
|
||||||
|
{ value: "OTHER", label: "Lain-lain" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const REPORTER_OPTIONS = [
|
||||||
|
{ value: "PARTICIPANT", label: "Peserta" },
|
||||||
|
{ value: "ORGANIZER", label: "Organizer" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function CreateRefundForm() {
|
||||||
|
const router = useRouter();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||||
|
e.preventDefault();
|
||||||
|
setError("");
|
||||||
|
setLoading(true);
|
||||||
|
const fd = new FormData(e.currentTarget);
|
||||||
|
const result = await createRefundAction(fd);
|
||||||
|
setLoading(false);
|
||||||
|
if (result.error) {
|
||||||
|
setError(result.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(e.target as HTMLFormElement).reset();
|
||||||
|
setOpen(false);
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
return (
|
||||||
|
<div className="mb-6 flex justify-end">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-semibold text-white hover:bg-primary-700"
|
||||||
|
>
|
||||||
|
+ Catat Laporan Refund
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
className="mb-6 space-y-4 rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm sm:p-6"
|
||||||
|
>
|
||||||
|
<header className="flex items-start justify-between gap-3 border-b border-neutral-100 pb-3">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-base font-bold text-neutral-900">
|
||||||
|
Catat Laporan Refund Manual
|
||||||
|
</h2>
|
||||||
|
<p className="mt-0.5 text-xs text-neutral-500">
|
||||||
|
Masukkan laporan yang diterima dari peserta atau organizer (via
|
||||||
|
WhatsApp/email). Refund akan masuk antrian PENDING untuk di-review.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
setError("");
|
||||||
|
}}
|
||||||
|
className="rounded-lg px-2 py-1 text-xs font-medium text-neutral-500 hover:bg-neutral-100"
|
||||||
|
>
|
||||||
|
Tutup
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
<Field label="Booking ID" required>
|
||||||
|
<input
|
||||||
|
name="bookingId"
|
||||||
|
required
|
||||||
|
placeholder="cuid booking yang dilaporkan"
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm font-mono focus:bg-white"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field label="Pelapor" required>
|
||||||
|
<select
|
||||||
|
name="reportedBy"
|
||||||
|
required
|
||||||
|
defaultValue=""
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm focus:bg-white"
|
||||||
|
>
|
||||||
|
<option value="" disabled>
|
||||||
|
Pilih pelapor
|
||||||
|
</option>
|
||||||
|
{REPORTER_OPTIONS.map((o) => (
|
||||||
|
<option key={o.value} value={o.value}>
|
||||||
|
{o.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field label="Alasan" required>
|
||||||
|
<select
|
||||||
|
name="reason"
|
||||||
|
required
|
||||||
|
defaultValue=""
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm focus:bg-white"
|
||||||
|
>
|
||||||
|
<option value="" disabled>
|
||||||
|
Pilih alasan
|
||||||
|
</option>
|
||||||
|
{REASON_OPTIONS.map((o) => (
|
||||||
|
<option key={o.value} value={o.value}>
|
||||||
|
{o.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field
|
||||||
|
label="Nominal (IDR)"
|
||||||
|
hint="Kosongkan untuk full remaining"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
name="amount"
|
||||||
|
inputMode="numeric"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
placeholder="mis. 500000"
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm focus:bg-white"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Field label="Isi laporan" required>
|
||||||
|
<textarea
|
||||||
|
name="reportNote"
|
||||||
|
required
|
||||||
|
rows={3}
|
||||||
|
placeholder="Salin/ringkas laporan dari peserta/organizer"
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm focus:bg-white"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-2 border-t border-neutral-100 pt-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
setError("");
|
||||||
|
}}
|
||||||
|
className="rounded-xl border border-neutral-200 px-4 py-2 text-sm font-medium text-neutral-600 hover:bg-neutral-50"
|
||||||
|
>
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{loading ? "Menyimpan…" : "Simpan Laporan"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Field({
|
||||||
|
label,
|
||||||
|
hint,
|
||||||
|
required,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
hint?: string;
|
||||||
|
required?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<label className="block">
|
||||||
|
<div className="mb-1 flex items-baseline justify-between gap-2">
|
||||||
|
<span className="text-xs font-semibold uppercase tracking-wide text-neutral-600">
|
||||||
|
{label}
|
||||||
|
{required && <span className="text-red-500"> *</span>}
|
||||||
|
</span>
|
||||||
|
{hint && <span className="text-xs text-neutral-400">{hint}</span>}
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { getRefundPolicyTiers } from "@/lib/refund-policy";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display kebijakan refund default di trip detail. Sumber tier:
|
||||||
|
* lib/refund-policy.ts. Compact agar tidak mendominasi page.
|
||||||
|
*/
|
||||||
|
export function RefundPolicySection() {
|
||||||
|
const tiers = getRefundPolicyTiers();
|
||||||
|
return (
|
||||||
|
<details className="rounded-xl border border-neutral-200 bg-neutral-50/60 p-3 text-xs sm:text-sm">
|
||||||
|
<summary className="cursor-pointer select-none font-semibold text-neutral-700">
|
||||||
|
🛟 Kebijakan refund saat peserta cancel
|
||||||
|
</summary>
|
||||||
|
<div className="mt-2 space-y-2 text-neutral-600">
|
||||||
|
<p className="text-[11px] text-neutral-500 sm:text-xs">
|
||||||
|
Kebijakan ini berlaku saat <strong>peserta</strong> cancel booking
|
||||||
|
yang sudah lunas. Kalau <strong>organizer</strong> membatalkan trip,
|
||||||
|
peserta yang sudah bayar selalu dapat refund 100%.
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-1">
|
||||||
|
{tiers.map((t) => (
|
||||||
|
<li key={t.minDaysBefore} className="flex items-baseline gap-2">
|
||||||
|
<span
|
||||||
|
className={`inline-flex min-w-[3rem] justify-center rounded-full px-2 py-0.5 text-[10px] font-bold ${
|
||||||
|
t.refundPercentage >= 80
|
||||||
|
? "bg-primary-100 text-primary-700"
|
||||||
|
: t.refundPercentage >= 50
|
||||||
|
? "bg-amber-100 text-amber-700"
|
||||||
|
: "bg-red-100 text-red-700"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{t.refundPercentage}%
|
||||||
|
</span>
|
||||||
|
<span>{t.label}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<p className="text-[11px] text-neutral-500 sm:text-xs">
|
||||||
|
Refund diproses manual oleh admin SeTrip — perlu 1–3 hari kerja
|
||||||
|
setelah disetujui untuk uang masuk ke rekening kamu.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,378 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { decideRefundAction } from "@/features/refund/actions";
|
||||||
|
import { formatRupiah } from "@/lib/utils";
|
||||||
|
|
||||||
|
type RefundStatus =
|
||||||
|
| "PENDING"
|
||||||
|
| "APPROVED"
|
||||||
|
| "REJECTED"
|
||||||
|
| "PROCESSING"
|
||||||
|
| "SUCCEEDED"
|
||||||
|
| "FAILED";
|
||||||
|
|
||||||
|
type Decision = "APPROVE" | "REJECT" | "SUCCEEDED" | "FAILED";
|
||||||
|
|
||||||
|
export type RefundCardData = {
|
||||||
|
id: string;
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
reason: string;
|
||||||
|
reportedBy: "PARTICIPANT" | "ORGANIZER";
|
||||||
|
reportNote: string;
|
||||||
|
initiatedBy: string;
|
||||||
|
status: RefundStatus;
|
||||||
|
adminNote: string | null;
|
||||||
|
createdAt: Date;
|
||||||
|
reviewedAt: Date | null;
|
||||||
|
succeededAt: Date | null;
|
||||||
|
failedAt: Date | null;
|
||||||
|
reviewedBy: { id: string; name: string; email: string } | null;
|
||||||
|
booking: {
|
||||||
|
id: string;
|
||||||
|
amount: number;
|
||||||
|
status: string;
|
||||||
|
trip: { id: string; title: string; date: Date };
|
||||||
|
user: { id: string; name: string; email: string };
|
||||||
|
payments: {
|
||||||
|
id: string;
|
||||||
|
provider: string;
|
||||||
|
method: string | null;
|
||||||
|
amount: number;
|
||||||
|
status: string;
|
||||||
|
paidAt: Date | null;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatDate(d: Date): string {
|
||||||
|
return new Date(d).toLocaleString("id-ID", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const REASON_LABEL: Record<string, string> = {
|
||||||
|
USER_CANCELLATION: "Peserta cancel",
|
||||||
|
ORGANIZER_CANCELLED: "Organizer batalkan",
|
||||||
|
TRIP_ISSUE: "Masalah trip",
|
||||||
|
ADMIN_ADJUSTMENT: "Penyesuaian admin",
|
||||||
|
DISPUTE_RESOLVED: "Dispute resolved",
|
||||||
|
OTHER: "Lain-lain",
|
||||||
|
};
|
||||||
|
|
||||||
|
export function RefundReviewCard({ refund }: { refund: RefundCardData }) {
|
||||||
|
const router = useRouter();
|
||||||
|
const [openAction, setOpenAction] = useState<Decision | null>(null);
|
||||||
|
const [note, setNote] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const paidPayment = refund.booking.payments.find(
|
||||||
|
(p) => p.status === "PAID" || p.status === "REFUNDED"
|
||||||
|
);
|
||||||
|
|
||||||
|
async function submit(decision: Decision) {
|
||||||
|
setError("");
|
||||||
|
setLoading(true);
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.set("refundId", refund.id);
|
||||||
|
fd.set("decision", decision);
|
||||||
|
if (note.trim()) fd.set("adminNote", note);
|
||||||
|
const result = await decideRefundAction(fd);
|
||||||
|
setLoading(false);
|
||||||
|
if (result.error) {
|
||||||
|
setError(result.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setOpenAction(null);
|
||||||
|
setNote("");
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className="rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm sm:p-6">
|
||||||
|
<header className="flex flex-wrap items-start justify-between gap-3 border-b border-neutral-100 pb-4">
|
||||||
|
<div className="min-w-0">
|
||||||
|
<h3 className="truncate text-base font-bold text-neutral-900">
|
||||||
|
{refund.booking.trip.title}
|
||||||
|
</h3>
|
||||||
|
<p className="mt-0.5 text-xs text-neutral-500">
|
||||||
|
Dilaporkan {formatDate(refund.createdAt)} oleh{" "}
|
||||||
|
<span className="font-semibold">
|
||||||
|
{refund.reportedBy === "PARTICIPANT" ? "Peserta" : "Organizer"}
|
||||||
|
</span>
|
||||||
|
{" · "}
|
||||||
|
<span className="font-mono">{refund.id.slice(0, 8)}…</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<StatusPill status={refund.status} />
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="mt-4 grid gap-4 sm:grid-cols-2">
|
||||||
|
<Field
|
||||||
|
label="Peserta booking"
|
||||||
|
value={`${refund.booking.user.name} · ${refund.booking.user.email}`}
|
||||||
|
/>
|
||||||
|
<Field label="Booking ID" value={refund.booking.id} mono />
|
||||||
|
<Field
|
||||||
|
label="Tanggal trip"
|
||||||
|
value={formatDate(refund.booking.trip.date)}
|
||||||
|
/>
|
||||||
|
<Field
|
||||||
|
label="Alasan"
|
||||||
|
value={REASON_LABEL[refund.reason] ?? refund.reason}
|
||||||
|
/>
|
||||||
|
<Field
|
||||||
|
label="Nominal refund"
|
||||||
|
value={`${formatRupiah(refund.amount)} ${refund.currency !== "IDR" ? `(${refund.currency})` : ""}`}
|
||||||
|
highlight
|
||||||
|
/>
|
||||||
|
<Field
|
||||||
|
label="Total dibayar"
|
||||||
|
value={
|
||||||
|
paidPayment
|
||||||
|
? `${formatRupiah(paidPayment.amount)} · ${paidPayment.provider} ${paidPayment.method ?? ""}`
|
||||||
|
: "—"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 rounded-xl bg-neutral-50 p-3 text-sm text-neutral-700">
|
||||||
|
<p className="mb-1 text-xs font-semibold uppercase tracking-wide text-neutral-500">
|
||||||
|
Isi laporan
|
||||||
|
</p>
|
||||||
|
<p className="whitespace-pre-wrap">{refund.reportNote}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{refund.adminNote && (
|
||||||
|
<div className="mt-3 rounded-xl bg-blue-50 p-3 text-sm text-blue-800">
|
||||||
|
<p className="mb-1 text-xs font-semibold uppercase tracking-wide text-blue-600">
|
||||||
|
Catatan admin
|
||||||
|
</p>
|
||||||
|
<p className="whitespace-pre-wrap">{refund.adminNote}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{refund.reviewedBy && refund.reviewedAt && (
|
||||||
|
<p className="mt-3 text-xs text-neutral-500">
|
||||||
|
Diproses oleh {refund.reviewedBy.name} pada{" "}
|
||||||
|
{formatDate(refund.reviewedAt)}
|
||||||
|
{refund.succeededAt && ` · uang keluar ${formatDate(refund.succeededAt)}`}
|
||||||
|
{refund.failedAt && ` · gagal ${formatDate(refund.failedAt)}`}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(refund.status === "PENDING" || refund.status === "APPROVED") && (
|
||||||
|
<div className="mt-5 border-t border-neutral-100 pt-4">
|
||||||
|
{error && (
|
||||||
|
<div className="mb-3 rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{openAction ? (
|
||||||
|
<ActionForm
|
||||||
|
decision={openAction}
|
||||||
|
note={note}
|
||||||
|
setNote={setNote}
|
||||||
|
loading={loading}
|
||||||
|
onCancel={() => {
|
||||||
|
setOpenAction(null);
|
||||||
|
setNote("");
|
||||||
|
setError("");
|
||||||
|
}}
|
||||||
|
onConfirm={() => submit(openAction)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{refund.status === "PENDING" && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpenAction("APPROVE")}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
✅ Setujui
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpenAction("REJECT")}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
❌ Tolak
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{refund.status === "APPROVED" && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpenAction("SUCCEEDED")}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl bg-primary-600 px-4 py-2 text-sm font-bold text-white hover:bg-primary-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
💸 Tandai sudah ditransfer
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpenAction("FAILED")}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-bold text-red-600 hover:bg-red-50 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
⚠️ Tandai gagal
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ActionForm({
|
||||||
|
decision,
|
||||||
|
note,
|
||||||
|
setNote,
|
||||||
|
loading,
|
||||||
|
onCancel,
|
||||||
|
onConfirm,
|
||||||
|
}: {
|
||||||
|
decision: Decision;
|
||||||
|
note: string;
|
||||||
|
setNote: (v: string) => void;
|
||||||
|
loading: boolean;
|
||||||
|
onCancel: () => void;
|
||||||
|
onConfirm: () => void;
|
||||||
|
}) {
|
||||||
|
const cfg = {
|
||||||
|
APPROVE: {
|
||||||
|
label: "Setujui Refund",
|
||||||
|
placeholder: "Catatan untuk approval (opsional)",
|
||||||
|
required: false,
|
||||||
|
btnLabel: "Konfirmasi Setuju",
|
||||||
|
btnClass: "bg-primary-600 hover:bg-primary-700",
|
||||||
|
},
|
||||||
|
REJECT: {
|
||||||
|
label: "Tolak Refund",
|
||||||
|
placeholder: "Alasan penolakan (wajib)",
|
||||||
|
required: true,
|
||||||
|
btnLabel: "Konfirmasi Tolak",
|
||||||
|
btnClass: "bg-red-600 hover:bg-red-700",
|
||||||
|
},
|
||||||
|
SUCCEEDED: {
|
||||||
|
label: "Tandai Sudah Transfer",
|
||||||
|
placeholder: "Referensi transfer / nomor mutasi bank (wajib)",
|
||||||
|
required: true,
|
||||||
|
btnLabel: "Tandai SUCCEEDED",
|
||||||
|
btnClass: "bg-primary-600 hover:bg-primary-700",
|
||||||
|
},
|
||||||
|
FAILED: {
|
||||||
|
label: "Tandai Gagal",
|
||||||
|
placeholder: "Alasan gagal (wajib)",
|
||||||
|
required: true,
|
||||||
|
btnLabel: "Tandai FAILED",
|
||||||
|
btnClass: "bg-red-600 hover:bg-red-700",
|
||||||
|
},
|
||||||
|
}[decision];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p className="text-xs font-semibold uppercase tracking-wide text-neutral-600">
|
||||||
|
{cfg.label}
|
||||||
|
</p>
|
||||||
|
<textarea
|
||||||
|
value={note}
|
||||||
|
onChange={(e) => setNote(e.target.value)}
|
||||||
|
rows={2}
|
||||||
|
placeholder={cfg.placeholder}
|
||||||
|
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm focus:bg-white"
|
||||||
|
/>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onConfirm}
|
||||||
|
disabled={loading || (cfg.required && !note.trim())}
|
||||||
|
className={`rounded-xl px-4 py-2 text-sm font-bold text-white disabled:opacity-50 ${cfg.btnClass}`}
|
||||||
|
>
|
||||||
|
{loading ? "Memproses…" : cfg.btnLabel}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onCancel}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl border border-neutral-200 bg-white px-4 py-2 text-sm font-medium text-neutral-600 hover:bg-neutral-50 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Field({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
mono,
|
||||||
|
highlight,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
mono?: boolean;
|
||||||
|
highlight?: boolean;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p className="text-xs font-semibold uppercase tracking-wide text-neutral-500">
|
||||||
|
{label}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className={`mt-0.5 text-sm ${mono ? "font-mono" : ""} ${
|
||||||
|
highlight ? "font-bold text-primary-700" : "text-neutral-800"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function StatusPill({ status }: { status: RefundStatus }) {
|
||||||
|
const cfg: Record<RefundStatus, { label: string; cls: string }> = {
|
||||||
|
PENDING: {
|
||||||
|
label: "Pending Review",
|
||||||
|
cls: "bg-amber-50 text-amber-700 ring-amber-200",
|
||||||
|
},
|
||||||
|
APPROVED: {
|
||||||
|
label: "Disetujui",
|
||||||
|
cls: "bg-blue-50 text-blue-700 ring-blue-200",
|
||||||
|
},
|
||||||
|
REJECTED: { label: "Ditolak", cls: "bg-red-50 text-red-700 ring-red-200" },
|
||||||
|
PROCESSING: {
|
||||||
|
label: "Diproses",
|
||||||
|
cls: "bg-violet-50 text-violet-700 ring-violet-200",
|
||||||
|
},
|
||||||
|
SUCCEEDED: {
|
||||||
|
label: "Selesai",
|
||||||
|
cls: "bg-primary-50 text-primary-700 ring-primary-200",
|
||||||
|
},
|
||||||
|
FAILED: { label: "Gagal", cls: "bg-red-50 text-red-700 ring-red-200" },
|
||||||
|
};
|
||||||
|
const c = cfg[status];
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold ring-1 ${c.cls}`}
|
||||||
|
>
|
||||||
|
{c.label}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
import { LIMITS } from "@/lib/limits";
|
||||||
|
|
||||||
|
const reasonValues = [
|
||||||
|
"USER_CANCELLATION",
|
||||||
|
"ORGANIZER_CANCELLED",
|
||||||
|
"TRIP_ISSUE",
|
||||||
|
"ADMIN_ADJUSTMENT",
|
||||||
|
"DISPUTE_RESOLVED",
|
||||||
|
"OTHER",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const reporterValues = ["PARTICIPANT", "ORGANIZER"] as const;
|
||||||
|
|
||||||
|
const refundNote = z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(3, "Isi catatan minimal 3 karakter")
|
||||||
|
.max(
|
||||||
|
LIMITS.MAX_REFUND_NOTE_LENGTH,
|
||||||
|
`Catatan maksimal ${LIMITS.MAX_REFUND_NOTE_LENGTH} karakter`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const createRefundSchema = z.object({
|
||||||
|
bookingId: z.string().trim().min(1, "Booking ID wajib"),
|
||||||
|
reason: z.enum(reasonValues, { error: "Alasan tidak valid" }),
|
||||||
|
reportedBy: z.enum(reporterValues, { error: "Pelapor tidak valid" }),
|
||||||
|
reportNote: refundNote,
|
||||||
|
/** Kosong = full remaining. Angka positif (IDR) untuk partial. */
|
||||||
|
amount: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.optional()
|
||||||
|
.transform((v) => (v && v.length > 0 ? Number(v.replace(/[^\d]/g, "")) : undefined))
|
||||||
|
.refine(
|
||||||
|
(n) => n === undefined || (Number.isInteger(n) && n > 0),
|
||||||
|
"Nominal harus bilangan bulat positif"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const refundDecisionSchema = z.object({
|
||||||
|
refundId: z.string().trim().min(1, "Refund ID wajib"),
|
||||||
|
decision: z.enum(["APPROVE", "REJECT", "SUCCEEDED", "FAILED"], {
|
||||||
|
error: "Keputusan tidak valid",
|
||||||
|
}),
|
||||||
|
adminNote: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.max(
|
||||||
|
LIMITS.MAX_REFUND_NOTE_LENGTH,
|
||||||
|
`Catatan maksimal ${LIMITS.MAX_REFUND_NOTE_LENGTH} karakter`
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CreateRefundInput = z.infer<typeof createRefundSchema>;
|
||||||
|
export type RefundDecisionInput = z.infer<typeof refundDecisionSchema>;
|
||||||
@@ -180,3 +180,27 @@ export async function rejectParticipantAction(
|
|||||||
return { error: (err as Error).message };
|
return { error: (err as Error).message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function cancelTripAction(tripId: string) {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session?.user) {
|
||||||
|
return { error: "Kamu harus login terlebih dahulu" };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await tripService.closeTrip(tripId, session.user.id);
|
||||||
|
revalidatePath(`/trips/${tripId}`);
|
||||||
|
revalidatePath("/trips");
|
||||||
|
revalidatePath("/");
|
||||||
|
revalidatePath("/profile");
|
||||||
|
revalidatePath("/admin/refunds");
|
||||||
|
return {
|
||||||
|
success: true as const,
|
||||||
|
refundCount: result.refundsCreated.length,
|
||||||
|
cancelledCount: result.cancelledBookings.length,
|
||||||
|
skippedCount: result.skippedBookings.length,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return { error: (err as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { cancelTripAction } from "@/features/trip/actions";
|
||||||
|
|
||||||
|
interface CancelTripButtonProps {
|
||||||
|
tripId: string;
|
||||||
|
/** Jumlah peserta dengan booking PAID — preview impact. */
|
||||||
|
paidParticipantCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CancelTripButton({
|
||||||
|
tripId,
|
||||||
|
paidParticipantCount,
|
||||||
|
}: CancelTripButtonProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [confirmText, setConfirmText] = useState("");
|
||||||
|
const [result, setResult] = useState<
|
||||||
|
| { refundCount: number; cancelledCount: number; skippedCount: number }
|
||||||
|
| null
|
||||||
|
>(null);
|
||||||
|
|
||||||
|
async function handleConfirm() {
|
||||||
|
setLoading(true);
|
||||||
|
setError("");
|
||||||
|
const res = await cancelTripAction(tripId);
|
||||||
|
setLoading(false);
|
||||||
|
if ("error" in res) {
|
||||||
|
setError(res.error ?? "Terjadi kesalahan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setResult({
|
||||||
|
refundCount: res.refundCount,
|
||||||
|
cancelledCount: res.cancelledCount,
|
||||||
|
skippedCount: res.skippedCount,
|
||||||
|
});
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-900">
|
||||||
|
<p className="font-semibold">Trip dibatalkan.</p>
|
||||||
|
<ul className="mt-2 list-inside list-disc space-y-0.5 text-xs">
|
||||||
|
<li>{result.refundCount} refund dibuat (menunggu admin transfer)</li>
|
||||||
|
<li>
|
||||||
|
{result.cancelledCount} booking belum-bayar di-cancel langsung
|
||||||
|
</li>
|
||||||
|
{result.skippedCount > 0 && (
|
||||||
|
<li>
|
||||||
|
{result.skippedCount} booking di-skip (sudah punya refund aktif —
|
||||||
|
admin akan handle manual)
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
className="w-full rounded-xl border-2 border-red-200 py-3 text-sm font-bold text-red-600 transition-colors hover:bg-red-50"
|
||||||
|
>
|
||||||
|
Batalkan Trip
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const requireConfirm = paidParticipantCount > 0;
|
||||||
|
const canSubmit = !requireConfirm || confirmText.trim() === "BATAL";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-3 rounded-2xl border-2 border-red-200 bg-red-50 p-4 text-sm">
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-red-900">Yakin batalkan trip ini?</p>
|
||||||
|
<p className="mt-1 text-xs text-red-800/80">
|
||||||
|
Aksi ini <span className="font-semibold">tidak bisa di-undo</span>.
|
||||||
|
Trip akan ditandai CLOSED dan semua peserta dibatalkan.
|
||||||
|
{paidParticipantCount > 0 && (
|
||||||
|
<>
|
||||||
|
{" "}Sistem akan otomatis membuat{" "}
|
||||||
|
<span className="font-bold">
|
||||||
|
{paidParticipantCount} refund
|
||||||
|
</span>{" "}
|
||||||
|
full amount untuk peserta yang sudah membayar — admin SeTrip akan
|
||||||
|
memproses transfer.
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{requireConfirm && (
|
||||||
|
<label className="block">
|
||||||
|
<span className="text-xs font-semibold uppercase tracking-wide text-red-700">
|
||||||
|
Ketik <span className="font-mono">BATAL</span> untuk konfirmasi
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
value={confirmText}
|
||||||
|
onChange={(e) => setConfirmText(e.target.value)}
|
||||||
|
placeholder="BATAL"
|
||||||
|
className="mt-1 w-full rounded-xl border border-red-300 bg-white px-3 py-2 font-mono text-sm focus:border-red-500 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="rounded-lg bg-white px-3 py-2 text-xs font-medium text-red-700">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleConfirm}
|
||||||
|
disabled={loading || !canSubmit}
|
||||||
|
className="rounded-xl bg-red-600 px-4 py-2 text-sm font-bold text-white hover:bg-red-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{loading ? "Memproses…" : "Ya, Batalkan Trip"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
setConfirmText("");
|
||||||
|
setError("");
|
||||||
|
}}
|
||||||
|
disabled={loading}
|
||||||
|
className="rounded-xl border border-red-200 bg-white px-4 py-2 text-sm font-medium text-red-700 hover:bg-red-100 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -23,6 +23,9 @@ interface JoinTripButtonProps {
|
|||||||
tripStatus: string;
|
tripStatus: string;
|
||||||
/** Tanggal berangkat trip sudah lewat */
|
/** Tanggal berangkat trip sudah lewat */
|
||||||
isDeparturePast?: boolean;
|
isDeparturePast?: boolean;
|
||||||
|
/** Sembunyikan tombol cancel — dipakai saat booking PAID dan parent
|
||||||
|
* menampilkan CancelBookingButton (refund flow) di tempat terpisah. */
|
||||||
|
hideCancelButton?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function JoinTripButton({
|
export function JoinTripButton({
|
||||||
@@ -36,6 +39,7 @@ export function JoinTripButton({
|
|||||||
isFull,
|
isFull,
|
||||||
tripStatus,
|
tripStatus,
|
||||||
isDeparturePast,
|
isDeparturePast,
|
||||||
|
hideCancelButton,
|
||||||
}: JoinTripButtonProps) {
|
}: JoinTripButtonProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -163,13 +167,15 @@ export function JoinTripButton({
|
|||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{isJoined ? (
|
{isJoined ? (
|
||||||
<button
|
hideCancelButton ? null : (
|
||||||
onClick={handleCancel}
|
<button
|
||||||
disabled={loading}
|
onClick={handleCancel}
|
||||||
className="w-full rounded-xl border-2 border-red-200 py-3 text-sm font-bold text-red-600 transition-colors hover:bg-red-50 disabled:opacity-50"
|
disabled={loading}
|
||||||
>
|
className="w-full rounded-xl border-2 border-red-200 py-3 text-sm font-bold text-red-600 transition-colors hover:bg-red-50 disabled:opacity-50"
|
||||||
{loading ? "Memproses..." : "Batal Ikut"}
|
>
|
||||||
</button>
|
{loading ? "Memproses..." : "Batal Ikut"}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={handleJoin}
|
onClick={handleJoin}
|
||||||
|
|||||||
@@ -31,4 +31,6 @@ export const LIMITS = {
|
|||||||
MAX_BANK_ACCOUNT_NUMBER_LENGTH: 32,
|
MAX_BANK_ACCOUNT_NUMBER_LENGTH: 32,
|
||||||
MAX_REJECTION_REASON_LENGTH: 500,
|
MAX_REJECTION_REASON_LENGTH: 500,
|
||||||
NIK_LENGTH: 16,
|
NIK_LENGTH: 16,
|
||||||
|
/** Catatan laporan dari peserta/organizer + catatan admin pada refund. */
|
||||||
|
MAX_REFUND_NOTE_LENGTH: 1000,
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* Refund policy hardcoded untuk MVP (PR-R3). Akan jadi data-driven di PR-R5.
|
||||||
|
*
|
||||||
|
* Aturan: hitung persentase refund berdasarkan jarak hari ke tanggal berangkat
|
||||||
|
* (UTC calendar day). Selalu integer rupiah — pakai Math.floor supaya tidak
|
||||||
|
* ada sub-rupiah dan total refund tidak pernah melebihi nominal yang dibayar.
|
||||||
|
*
|
||||||
|
* Tier:
|
||||||
|
* - ≥7 hari sebelum berangkat → 80% refund (organizer ambil 20% admin fee)
|
||||||
|
* - 3–6 hari sebelum berangkat → 50% refund
|
||||||
|
* - <3 hari sebelum berangkat / sudah lewat → 0% (tidak ada refund)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { utcStartOfDay } from "@/lib/trip-dates";
|
||||||
|
|
||||||
|
export interface RefundTier {
|
||||||
|
/** Minimum jumlah hari sebelum berangkat untuk tier ini. */
|
||||||
|
minDaysBefore: number;
|
||||||
|
/** Persentase nominal yang di-refund (0–100). */
|
||||||
|
refundPercentage: number;
|
||||||
|
/** Label untuk UI. */
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIERS: RefundTier[] = [
|
||||||
|
{ minDaysBefore: 7, refundPercentage: 80, label: "≥ 7 hari sebelum berangkat" },
|
||||||
|
{ minDaysBefore: 3, refundPercentage: 50, label: "3–6 hari sebelum berangkat" },
|
||||||
|
{ minDaysBefore: 0, refundPercentage: 0, label: "Kurang dari 3 hari / sudah lewat" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getRefundPolicyTiers(): RefundTier[] {
|
||||||
|
return TIERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jumlah hari kalender UTC dari sekarang ke tanggal berangkat. Negative kalau
|
||||||
|
* tanggal sudah lewat. Pakai start-of-day UTC supaya jam tidak mempengaruhi.
|
||||||
|
*/
|
||||||
|
export function daysUntilDeparture(
|
||||||
|
departureDate: Date,
|
||||||
|
now: Date = new Date()
|
||||||
|
): number {
|
||||||
|
const todayMs = utcStartOfDay(now).getTime();
|
||||||
|
const depMs = utcStartOfDay(departureDate).getTime();
|
||||||
|
const oneDayMs = 24 * 60 * 60 * 1000;
|
||||||
|
return Math.floor((depMs - todayMs) / oneDayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tier aktif untuk jumlah hari yang diberikan. */
|
||||||
|
export function getTierForDays(days: number): RefundTier {
|
||||||
|
for (const tier of TIERS) {
|
||||||
|
if (days >= tier.minDaysBefore) {
|
||||||
|
return tier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TIERS[TIERS.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hitung nominal refund (IDR integer) berdasarkan harga booking dan jarak ke
|
||||||
|
* tanggal berangkat. Floor supaya tidak pernah > bookingAmount.
|
||||||
|
*/
|
||||||
|
export function calculateRefundAmount(
|
||||||
|
bookingAmount: number,
|
||||||
|
days: number
|
||||||
|
): number {
|
||||||
|
if (bookingAmount <= 0) return 0;
|
||||||
|
const tier = getTierForDays(days);
|
||||||
|
return Math.floor((bookingAmount * tier.refundPercentage) / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RefundPreview {
|
||||||
|
days: number;
|
||||||
|
tier: RefundTier;
|
||||||
|
refundAmount: number;
|
||||||
|
bookingAmount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Bundle lengkap untuk display di UI — preview cancel booking. */
|
||||||
|
export function previewRefund(
|
||||||
|
bookingAmount: number,
|
||||||
|
departureDate: Date,
|
||||||
|
now: Date = new Date()
|
||||||
|
): RefundPreview {
|
||||||
|
const days = daysUntilDeparture(departureDate, now);
|
||||||
|
const tier = getTierForDays(days);
|
||||||
|
return {
|
||||||
|
days,
|
||||||
|
tier,
|
||||||
|
refundAmount: calculateRefundAmount(bookingAmount, days),
|
||||||
|
bookingAmount,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "BookingStatus" ADD VALUE 'PARTIALLY_REFUNDED';
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "RefundReason" AS ENUM ('USER_CANCELLATION', 'ORGANIZER_CANCELLED', 'TRIP_ISSUE', 'ADMIN_ADJUSTMENT', 'DISPUTE_RESOLVED', 'OTHER');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "RefundStatus" AS ENUM ('PENDING', 'APPROVED', 'REJECTED', 'PROCESSING', 'SUCCEEDED', 'FAILED');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "RefundInitiator" AS ENUM ('USER', 'ORGANIZER', 'SYSTEM', 'ADMIN');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "RefundReporter" AS ENUM ('PARTICIPANT', 'ORGANIZER');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Refund" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"bookingId" TEXT NOT NULL,
|
||||||
|
"paymentId" TEXT,
|
||||||
|
"amount" INTEGER NOT NULL,
|
||||||
|
"currency" TEXT NOT NULL DEFAULT 'IDR',
|
||||||
|
"reason" "RefundReason" NOT NULL,
|
||||||
|
"reportedBy" "RefundReporter" NOT NULL,
|
||||||
|
"reportNote" TEXT NOT NULL,
|
||||||
|
"initiatedBy" "RefundInitiator" NOT NULL DEFAULT 'ADMIN',
|
||||||
|
"status" "RefundStatus" NOT NULL DEFAULT 'PENDING',
|
||||||
|
"idempotencyKey" TEXT NOT NULL,
|
||||||
|
"adminNote" TEXT,
|
||||||
|
"reviewedById" TEXT,
|
||||||
|
"reviewedAt" TIMESTAMP(3),
|
||||||
|
"succeededAt" TIMESTAMP(3),
|
||||||
|
"failedAt" TIMESTAMP(3),
|
||||||
|
"externalRefundId" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Refund_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Refund_idempotencyKey_key" ON "Refund"("idempotencyKey");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Refund_bookingId_status_idx" ON "Refund"("bookingId", "status");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Refund_status_createdAt_idx" ON "Refund"("status", "createdAt");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Refund" ADD CONSTRAINT "Refund_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Refund" ADD CONSTRAINT "Refund_paymentId_fkey" FOREIGN KEY ("paymentId") REFERENCES "Payment"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Refund" ADD CONSTRAINT "Refund_reviewedById_fkey" FOREIGN KEY ("reviewedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
@@ -32,6 +32,8 @@ model User {
|
|||||||
organizerVerification OrganizerVerification? @relation("OrganizerVerificationOwner")
|
organizerVerification OrganizerVerification? @relation("OrganizerVerificationOwner")
|
||||||
reviewedVerifications OrganizerVerification[] @relation("OrganizerVerificationReviewer")
|
reviewedVerifications OrganizerVerification[] @relation("OrganizerVerificationReviewer")
|
||||||
|
|
||||||
|
reviewedRefunds Refund[] @relation("RefundReviewer")
|
||||||
|
|
||||||
profile UserProfile?
|
profile UserProfile?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,6 +260,7 @@ model Booking {
|
|||||||
status BookingStatus @default(PENDING)
|
status BookingStatus @default(PENDING)
|
||||||
|
|
||||||
payments Payment[]
|
payments Payment[]
|
||||||
|
refunds Refund[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
@@ -275,6 +278,7 @@ enum BookingStatus {
|
|||||||
PAID
|
PAID
|
||||||
CANCELLED
|
CANCELLED
|
||||||
REFUNDED
|
REFUNDED
|
||||||
|
PARTIALLY_REFUNDED
|
||||||
EXPIRED
|
EXPIRED
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +311,8 @@ model Payment {
|
|||||||
failedAt DateTime?
|
failedAt DateTime?
|
||||||
rejectionReason String?
|
rejectionReason String?
|
||||||
|
|
||||||
|
refunds Refund[]
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
@@ -328,3 +334,105 @@ enum PaymentStatus {
|
|||||||
CANCELLED
|
CANCELLED
|
||||||
REFUNDED
|
REFUNDED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refund = financial event terpisah dari Booking. Satu Booking bisa punya
|
||||||
|
/// banyak Refund (partial, multi-tahap). Setiap row auditable: kapan dibuat,
|
||||||
|
/// siapa melaporkan, siapa approve, kapan SUCCEEDED. Never delete — kalau
|
||||||
|
/// gagal, set status=FAILED + alasan.
|
||||||
|
///
|
||||||
|
/// Di MVP refund dimasukkan admin secara manual berdasarkan laporan dari
|
||||||
|
/// peserta atau organizer (via WhatsApp/email). Phase berikutnya akan
|
||||||
|
/// menambah self-service flow dari user dan organizer.
|
||||||
|
model Refund {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
bookingId String
|
||||||
|
booking Booking @relation(fields: [bookingId], references: [id], onDelete: Restrict)
|
||||||
|
|
||||||
|
/// Payment yang di-refund. Opsional di MVP (manual transfer bisa tidak
|
||||||
|
/// terikat ke Payment row tertentu); wajib saat integrasi Midtrans (R-4).
|
||||||
|
paymentId String?
|
||||||
|
payment Payment? @relation(fields: [paymentId], references: [id], onDelete: Restrict)
|
||||||
|
|
||||||
|
/// Nominal refund dalam satuan terkecil (IDR rupiah, integer). Boleh < total
|
||||||
|
/// payment untuk partial. Service layer enforce SUM(SUCCEEDED) <= payment.amount.
|
||||||
|
amount Int
|
||||||
|
currency String @default("IDR")
|
||||||
|
|
||||||
|
reason RefundReason
|
||||||
|
|
||||||
|
/// Siapa yang melaporkan kebutuhan refund ini ke admin.
|
||||||
|
reportedBy RefundReporter
|
||||||
|
/// Isi laporan dari peserta/organizer yang admin terima (mis. WA, email).
|
||||||
|
reportNote String
|
||||||
|
|
||||||
|
/// Pihak yang membuat record di sistem. Di MVP selalu ADMIN; saat self-service
|
||||||
|
/// nanti USER/ORGANIZER, dan SYSTEM untuk auto-trigger dari trip dibatalkan.
|
||||||
|
initiatedBy RefundInitiator @default(ADMIN)
|
||||||
|
|
||||||
|
status RefundStatus @default(PENDING)
|
||||||
|
|
||||||
|
/// Idempotency key, dipakai saat panggil Midtrans Refund API di R-4. Generate
|
||||||
|
/// sekali saat create supaya retry gateway tidak double-refund.
|
||||||
|
idempotencyKey String @unique
|
||||||
|
|
||||||
|
/// Catatan admin: alasan tolak, referensi transfer manual, dst. Bebas teks.
|
||||||
|
adminNote String?
|
||||||
|
|
||||||
|
/// Admin yang terakhir mengubah status (approve/reject/mark-succeeded/failed).
|
||||||
|
reviewedById String?
|
||||||
|
reviewedBy User? @relation("RefundReviewer", fields: [reviewedById], references: [id], onDelete: SetNull)
|
||||||
|
reviewedAt DateTime?
|
||||||
|
|
||||||
|
succeededAt DateTime?
|
||||||
|
failedAt DateTime?
|
||||||
|
|
||||||
|
/// ID refund di gateway (mis. Midtrans refund_id). Kosong untuk manual transfer.
|
||||||
|
externalRefundId String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([bookingId, status])
|
||||||
|
@@index([status, createdAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RefundReason {
|
||||||
|
/// Peserta cancel booking sendiri (mengikuti refund window policy).
|
||||||
|
USER_CANCELLATION
|
||||||
|
/// Organizer membatalkan trip — peserta dapat full refund.
|
||||||
|
ORGANIZER_CANCELLED
|
||||||
|
/// Masalah saat/setelah trip (mis. itinerary tidak sesuai).
|
||||||
|
TRIP_ISSUE
|
||||||
|
/// Penyesuaian dari admin (kompensasi, koreksi nominal, dll.).
|
||||||
|
ADMIN_ADJUSTMENT
|
||||||
|
/// Hasil resolusi dispute / chargeback bank.
|
||||||
|
DISPUTE_RESOLVED
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RefundStatus {
|
||||||
|
/// Baru dilaporkan, menunggu review admin.
|
||||||
|
PENDING
|
||||||
|
/// Admin sudah setujui, siap dieksekusi (manual transfer / gateway).
|
||||||
|
APPROVED
|
||||||
|
/// Admin tolak (alasan di `adminNote`).
|
||||||
|
REJECTED
|
||||||
|
/// (R-4) Request sudah dikirim ke gateway, menunggu callback.
|
||||||
|
PROCESSING
|
||||||
|
/// Uang sudah keluar dari kas Setrip / merchant gateway.
|
||||||
|
SUCCEEDED
|
||||||
|
/// Eksekusi gagal (alasan di `adminNote`). Record tidak dihapus.
|
||||||
|
FAILED
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RefundInitiator {
|
||||||
|
USER
|
||||||
|
ORGANIZER
|
||||||
|
SYSTEM
|
||||||
|
ADMIN
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RefundReporter {
|
||||||
|
PARTICIPANT
|
||||||
|
ORGANIZER
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,4 +71,17 @@ export const bookingRepo = {
|
|||||||
data: { status },
|
data: { status },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jumlah booking PAID/PARTIALLY_REFUNDED di trip. Dipakai untuk preview
|
||||||
|
* dampak cancel-trip (berapa peserta yang akan dapat auto-refund).
|
||||||
|
*/
|
||||||
|
async countSettledForTrip(tripId: string) {
|
||||||
|
return prisma.booking.count({
|
||||||
|
where: {
|
||||||
|
tripId,
|
||||||
|
status: { in: ["PAID", "PARTIALLY_REFUNDED"] },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { Prisma } from "@/app/generated/prisma/client";
|
||||||
|
|
||||||
|
const refundListInclude = {
|
||||||
|
booking: {
|
||||||
|
include: {
|
||||||
|
trip: { select: { id: true, title: true, date: true, organizerId: true } },
|
||||||
|
user: { select: { id: true, name: true, email: true, image: true } },
|
||||||
|
payments: {
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
provider: true,
|
||||||
|
method: true,
|
||||||
|
amount: true,
|
||||||
|
status: true,
|
||||||
|
paidAt: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
provider: true,
|
||||||
|
method: true,
|
||||||
|
amount: true,
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reviewedBy: { select: { id: true, name: true, email: true } },
|
||||||
|
} satisfies Prisma.RefundInclude;
|
||||||
|
|
||||||
|
export const refundRepo = {
|
||||||
|
async findById(id: string) {
|
||||||
|
return prisma.refund.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include: refundListInclude,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async listByStatus(
|
||||||
|
status?: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED"
|
||||||
|
) {
|
||||||
|
return prisma.refund.findMany({
|
||||||
|
where: status ? { status } : undefined,
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
include: refundListInclude,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async listByBooking(bookingId: string) {
|
||||||
|
return prisma.refund.findMany({
|
||||||
|
where: { bookingId },
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Total nominal yang sudah SUCCEEDED untuk satu booking. Dipakai service untuk
|
||||||
|
* validasi `SUM(SUCCEEDED) + new.amount <= payment.amount`. */
|
||||||
|
async sumSucceededAmount(bookingId: string, tx?: Prisma.TransactionClient): Promise<number> {
|
||||||
|
const client = tx ?? prisma;
|
||||||
|
const agg = await client.refund.aggregate({
|
||||||
|
where: { bookingId, status: "SUCCEEDED" },
|
||||||
|
_sum: { amount: true },
|
||||||
|
});
|
||||||
|
return agg._sum.amount ?? 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Pending + approved + processing — refund yang "in-flight" (belum settled).
|
||||||
|
* Dipakai untuk cek apakah booking masih punya refund aktif. */
|
||||||
|
async hasActiveRefund(bookingId: string, tx?: Prisma.TransactionClient): Promise<boolean> {
|
||||||
|
const client = tx ?? prisma;
|
||||||
|
const count = await client.refund.count({
|
||||||
|
where: {
|
||||||
|
bookingId,
|
||||||
|
status: { in: ["PENDING", "APPROVED", "PROCESSING"] },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return count > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
async create(
|
||||||
|
data: Pick<
|
||||||
|
Prisma.RefundUncheckedCreateInput,
|
||||||
|
| "bookingId"
|
||||||
|
| "paymentId"
|
||||||
|
| "amount"
|
||||||
|
| "reason"
|
||||||
|
| "reportedBy"
|
||||||
|
| "reportNote"
|
||||||
|
| "initiatedBy"
|
||||||
|
| "idempotencyKey"
|
||||||
|
>,
|
||||||
|
tx?: Prisma.TransactionClient
|
||||||
|
) {
|
||||||
|
const client = tx ?? prisma;
|
||||||
|
return client.refund.create({ data });
|
||||||
|
},
|
||||||
|
|
||||||
|
async update(
|
||||||
|
id: string,
|
||||||
|
data: Prisma.RefundUncheckedUpdateInput,
|
||||||
|
tx?: Prisma.TransactionClient
|
||||||
|
) {
|
||||||
|
const client = tx ?? prisma;
|
||||||
|
return client.refund.update({ where: { id }, data });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RefundWithRelations = Awaited<ReturnType<typeof refundRepo.findById>>;
|
||||||
@@ -0,0 +1,502 @@
|
|||||||
|
import { randomBytes } from "crypto";
|
||||||
|
import { Prisma } from "@/app/generated/prisma/client";
|
||||||
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { refundRepo } from "@/server/repositories/refund.repo";
|
||||||
|
import { calculateRefundAmount, daysUntilDeparture } from "@/lib/refund-policy";
|
||||||
|
import { isTripDepartureDayPast } from "@/lib/trip-dates";
|
||||||
|
|
||||||
|
const SERIAL_TX_ATTEMPTS = 6;
|
||||||
|
|
||||||
|
function isSerializationConflict(err: unknown): boolean {
|
||||||
|
return (
|
||||||
|
typeof err === "object" &&
|
||||||
|
err !== null &&
|
||||||
|
"code" in err &&
|
||||||
|
(err as { code: string }).code === "P2034"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runSerializable<T>(fn: (tx: Prisma.TransactionClient) => Promise<T>): Promise<T> {
|
||||||
|
let lastErr: unknown;
|
||||||
|
for (let attempt = 0; attempt < SERIAL_TX_ATTEMPTS; attempt++) {
|
||||||
|
try {
|
||||||
|
return await prisma.$transaction(fn, {
|
||||||
|
isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
|
||||||
|
maxWait: 5000,
|
||||||
|
timeout: 15000,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
lastErr = e;
|
||||||
|
if (isSerializationConflict(e) && attempt < SERIAL_TX_ATTEMPTS - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw lastErr instanceof Error
|
||||||
|
? lastErr
|
||||||
|
: new Error("Gagal memproses refund. Coba lagi sebentar.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function newIdempotencyKey(): string {
|
||||||
|
return `refund_${randomBytes(16).toString("hex")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestRefundInput = {
|
||||||
|
bookingId: string;
|
||||||
|
reason:
|
||||||
|
| "USER_CANCELLATION"
|
||||||
|
| "ORGANIZER_CANCELLED"
|
||||||
|
| "TRIP_ISSUE"
|
||||||
|
| "ADMIN_ADJUSTMENT"
|
||||||
|
| "DISPUTE_RESOLVED"
|
||||||
|
| "OTHER";
|
||||||
|
reportedBy: "PARTICIPANT" | "ORGANIZER";
|
||||||
|
reportNote: string;
|
||||||
|
/** Nominal refund (IDR). Kalau tidak diisi → service akan pakai sisa
|
||||||
|
* refundable amount (payment.amount - sudah-di-refund). */
|
||||||
|
amount?: number;
|
||||||
|
/** Admin yang memasukkan laporan ke sistem. */
|
||||||
|
initiatedByAdminId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const refundService = {
|
||||||
|
/**
|
||||||
|
* Admin mencatat laporan refund dari peserta atau organizer ke sistem.
|
||||||
|
* Status awal: PENDING. Belum mengubah Booking/Payment status.
|
||||||
|
*
|
||||||
|
* Idempotency: kalau booking masih punya refund PENDING/APPROVED/PROCESSING,
|
||||||
|
* tolak — admin harus selesaikan yang lama dulu (reject atau succeeded).
|
||||||
|
*/
|
||||||
|
async requestRefund(input: RequestRefundInput) {
|
||||||
|
return runSerializable(async (tx) => {
|
||||||
|
const booking = await tx.booking.findUnique({
|
||||||
|
where: { id: input.bookingId },
|
||||||
|
include: {
|
||||||
|
payments: {
|
||||||
|
where: { status: "PAID" },
|
||||||
|
orderBy: { paidAt: "desc" },
|
||||||
|
take: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!booking) {
|
||||||
|
throw new Error("Booking tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (booking.amount <= 0) {
|
||||||
|
throw new Error("Booking gratis — tidak ada nominal untuk di-refund");
|
||||||
|
}
|
||||||
|
if (booking.status === "CANCELLED" || booking.status === "EXPIRED") {
|
||||||
|
throw new Error(
|
||||||
|
"Booking sudah dibatalkan/expired — tidak ada pembayaran untuk di-refund"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (booking.status === "REFUNDED") {
|
||||||
|
throw new Error("Booking sudah refund penuh");
|
||||||
|
}
|
||||||
|
|
||||||
|
const paidPayment = booking.payments[0];
|
||||||
|
if (!paidPayment) {
|
||||||
|
throw new Error(
|
||||||
|
"Tidak ada Payment dengan status PAID di booking ini — tidak bisa di-refund"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasActive = await refundRepo.hasActiveRefund(input.bookingId, tx);
|
||||||
|
if (hasActive) {
|
||||||
|
throw new Error(
|
||||||
|
"Booking ini masih punya refund yang sedang diproses. Selesaikan dulu sebelum membuat yang baru."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const alreadyRefunded = await refundRepo.sumSucceededAmount(input.bookingId, tx);
|
||||||
|
const remaining = paidPayment.amount - alreadyRefunded;
|
||||||
|
if (remaining <= 0) {
|
||||||
|
throw new Error("Seluruh nominal sudah di-refund");
|
||||||
|
}
|
||||||
|
|
||||||
|
const amount = input.amount ?? remaining;
|
||||||
|
if (!Number.isInteger(amount) || amount <= 0) {
|
||||||
|
throw new Error("Nominal refund harus bilangan bulat positif");
|
||||||
|
}
|
||||||
|
if (amount > remaining) {
|
||||||
|
throw new Error(
|
||||||
|
`Nominal refund (Rp ${amount.toLocaleString("id-ID")}) melebihi sisa yang bisa di-refund (Rp ${remaining.toLocaleString("id-ID")})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return refundRepo.create(
|
||||||
|
{
|
||||||
|
bookingId: input.bookingId,
|
||||||
|
paymentId: paidPayment.id,
|
||||||
|
amount,
|
||||||
|
reason: input.reason,
|
||||||
|
reportedBy: input.reportedBy,
|
||||||
|
reportNote: input.reportNote,
|
||||||
|
initiatedBy: "ADMIN",
|
||||||
|
idempotencyKey: newIdempotencyKey(),
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/** PENDING → APPROVED. Boleh menambah catatan admin (opsional). */
|
||||||
|
async approveRefund(input: { refundId: string; adminId: string; adminNote?: string }) {
|
||||||
|
return runSerializable(async (tx) => {
|
||||||
|
const refund = await tx.refund.findUnique({ where: { id: input.refundId } });
|
||||||
|
if (!refund) {
|
||||||
|
throw new Error("Refund tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (refund.status !== "PENDING") {
|
||||||
|
throw new Error("Hanya refund berstatus PENDING yang bisa disetujui");
|
||||||
|
}
|
||||||
|
return refundRepo.update(
|
||||||
|
input.refundId,
|
||||||
|
{
|
||||||
|
status: "APPROVED",
|
||||||
|
reviewedById: input.adminId,
|
||||||
|
reviewedAt: new Date(),
|
||||||
|
adminNote: input.adminNote ?? refund.adminNote,
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/** PENDING → REJECTED. Alasan wajib supaya audit trail jelas. */
|
||||||
|
async rejectRefund(input: { refundId: string; adminId: string; adminNote: string }) {
|
||||||
|
if (!input.adminNote.trim()) {
|
||||||
|
throw new Error("Alasan tolak wajib diisi");
|
||||||
|
}
|
||||||
|
return runSerializable(async (tx) => {
|
||||||
|
const refund = await tx.refund.findUnique({ where: { id: input.refundId } });
|
||||||
|
if (!refund) {
|
||||||
|
throw new Error("Refund tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (refund.status !== "PENDING") {
|
||||||
|
throw new Error("Hanya refund berstatus PENDING yang bisa ditolak");
|
||||||
|
}
|
||||||
|
return refundRepo.update(
|
||||||
|
input.refundId,
|
||||||
|
{
|
||||||
|
status: "REJECTED",
|
||||||
|
reviewedById: input.adminId,
|
||||||
|
reviewedAt: new Date(),
|
||||||
|
adminNote: input.adminNote.trim(),
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APPROVED → SUCCEEDED untuk manual transfer (admin sudah transfer manual
|
||||||
|
* ke rekening peserta). adminNote diharapkan berisi referensi transfer.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* - Update Payment.status → REFUNDED hanya saat full refund.
|
||||||
|
* - Update Booking.status → REFUNDED (full) atau PARTIALLY_REFUNDED (partial).
|
||||||
|
* - Untuk USER_CANCELLATION: bebaskan slot — set TripParticipant → CANCELLED
|
||||||
|
* dan re-open Trip (FULL → OPEN) kalau peserta aktif < maxParticipants.
|
||||||
|
* Untuk ORGANIZER_CANCELLED slot tidak perlu dibebaskan (trip sudah CLOSED).
|
||||||
|
*/
|
||||||
|
async markSucceededManual(input: {
|
||||||
|
refundId: string;
|
||||||
|
adminId: string;
|
||||||
|
adminNote: string;
|
||||||
|
}) {
|
||||||
|
if (!input.adminNote.trim()) {
|
||||||
|
throw new Error("Catatan/referensi transfer wajib diisi");
|
||||||
|
}
|
||||||
|
return runSerializable(async (tx) => {
|
||||||
|
const refund = await tx.refund.findUnique({
|
||||||
|
where: { id: input.refundId },
|
||||||
|
});
|
||||||
|
if (!refund) {
|
||||||
|
throw new Error("Refund tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (refund.status !== "APPROVED") {
|
||||||
|
throw new Error(
|
||||||
|
"Hanya refund APPROVED yang bisa ditandai SUCCEEDED. Setujui dulu."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
await refundRepo.update(
|
||||||
|
input.refundId,
|
||||||
|
{
|
||||||
|
status: "SUCCEEDED",
|
||||||
|
succeededAt: now,
|
||||||
|
reviewedById: input.adminId,
|
||||||
|
reviewedAt: now,
|
||||||
|
adminNote: input.adminNote.trim(),
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
const totalRefunded = await refundRepo.sumSucceededAmount(
|
||||||
|
refund.bookingId,
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (refund.paymentId) {
|
||||||
|
const payment = await tx.payment.findUnique({
|
||||||
|
where: { id: refund.paymentId },
|
||||||
|
});
|
||||||
|
if (payment && totalRefunded >= payment.amount) {
|
||||||
|
await tx.payment.update({
|
||||||
|
where: { id: payment.id },
|
||||||
|
data: { status: "REFUNDED" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const booking = await tx.booking.findUnique({
|
||||||
|
where: { id: refund.bookingId },
|
||||||
|
include: {
|
||||||
|
trip: { select: { id: true, status: true, maxParticipants: true } },
|
||||||
|
payments: {
|
||||||
|
where: { status: { in: ["PAID", "REFUNDED"] } },
|
||||||
|
orderBy: { paidAt: "desc" },
|
||||||
|
take: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!booking) {
|
||||||
|
throw new Error("Booking tidak ditemukan saat menutup refund");
|
||||||
|
}
|
||||||
|
const paid = booking.payments[0];
|
||||||
|
if (paid) {
|
||||||
|
const nextStatus =
|
||||||
|
totalRefunded >= paid.amount ? "REFUNDED" : "PARTIALLY_REFUNDED";
|
||||||
|
if (booking.status !== nextStatus) {
|
||||||
|
await tx.booking.update({
|
||||||
|
where: { id: booking.id },
|
||||||
|
data: { status: nextStatus },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slot release untuk user cancellation. Organizer cancel di-handle
|
||||||
|
// closeTrip (participant + trip sudah di-CANCELLED/CLOSED di sana).
|
||||||
|
if (refund.reason === "USER_CANCELLATION") {
|
||||||
|
await tx.tripParticipant.updateMany({
|
||||||
|
where: {
|
||||||
|
id: booking.participantId,
|
||||||
|
status: { not: "CANCELLED" },
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
status: "CANCELLED",
|
||||||
|
markedPaidAt: null,
|
||||||
|
paymentConfirmedAt: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (booking.trip.status === "FULL") {
|
||||||
|
const remaining = await tx.tripParticipant.count({
|
||||||
|
where: { tripId: booking.tripId, status: { not: "CANCELLED" } },
|
||||||
|
});
|
||||||
|
if (remaining < booking.trip.maxParticipants) {
|
||||||
|
await tx.trip.update({
|
||||||
|
where: { id: booking.tripId },
|
||||||
|
data: { status: "OPEN" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ok: true as const };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peserta cancel booking sendiri. Hitung refund pakai policy default
|
||||||
|
* (lib/refund-policy.ts) — hardcoded MVP, akan jadi data-driven di R-5.
|
||||||
|
*
|
||||||
|
* Behaviour:
|
||||||
|
* - Kalau hasil hitung = 0 (di luar window): cancel participant + booking
|
||||||
|
* langsung, tanpa Refund row (uang tidak balik).
|
||||||
|
* - Kalau hasil hitung > 0: buat Refund PENDING (initiatedBy=USER,
|
||||||
|
* reportedBy=PARTICIPANT, reason=USER_CANCELLATION). Participant + booking
|
||||||
|
* TETAP CONFIRMED/PAID sampai admin mark SUCCEEDED — slot baru bebas saat
|
||||||
|
* refund tuntas. Cegah double-request via hasActiveRefund.
|
||||||
|
*/
|
||||||
|
async requestUserCancellation(input: {
|
||||||
|
bookingId: string;
|
||||||
|
userId: string;
|
||||||
|
}) {
|
||||||
|
return runSerializable(async (tx) => {
|
||||||
|
const booking = await tx.booking.findUnique({
|
||||||
|
where: { id: input.bookingId },
|
||||||
|
include: {
|
||||||
|
trip: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
date: true,
|
||||||
|
status: true,
|
||||||
|
maxParticipants: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payments: {
|
||||||
|
where: { status: "PAID" },
|
||||||
|
orderBy: { paidAt: "desc" },
|
||||||
|
take: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!booking) {
|
||||||
|
throw new Error("Booking tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (booking.userId !== input.userId) {
|
||||||
|
throw new Error("Booking ini bukan milikmu");
|
||||||
|
}
|
||||||
|
if (booking.status !== "PAID") {
|
||||||
|
throw new Error(
|
||||||
|
"Hanya booking PAID yang bisa cancel dengan refund. Booking yang belum lunas bisa cancel dari tombol 'Batal Ikut'."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isTripDepartureDayPast(booking.trip.date)) {
|
||||||
|
throw new Error(
|
||||||
|
"Trip sudah lewat tanggal berangkat — pembatalan ditutup"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const paid = booking.payments[0];
|
||||||
|
if (!paid) {
|
||||||
|
throw new Error(
|
||||||
|
"Tidak ada Payment dengan status PAID di booking ini"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const days = daysUntilDeparture(booking.trip.date);
|
||||||
|
const refundAmount = calculateRefundAmount(paid.amount, days);
|
||||||
|
|
||||||
|
if (refundAmount === 0) {
|
||||||
|
await tx.tripParticipant.update({
|
||||||
|
where: { id: booking.participantId },
|
||||||
|
data: {
|
||||||
|
status: "CANCELLED",
|
||||||
|
markedPaidAt: null,
|
||||||
|
paymentConfirmedAt: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await tx.booking.update({
|
||||||
|
where: { id: booking.id },
|
||||||
|
data: { status: "CANCELLED" },
|
||||||
|
});
|
||||||
|
if (booking.trip.status === "FULL") {
|
||||||
|
const remaining = await tx.tripParticipant.count({
|
||||||
|
where: { tripId: booking.tripId, status: { not: "CANCELLED" } },
|
||||||
|
});
|
||||||
|
if (remaining < booking.trip.maxParticipants) {
|
||||||
|
await tx.trip.update({
|
||||||
|
where: { id: booking.tripId },
|
||||||
|
data: { status: "OPEN" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kind: "CANCELLED_NO_REFUND" as const,
|
||||||
|
days,
|
||||||
|
refundAmount: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasActive = await refundRepo.hasActiveRefund(input.bookingId, tx);
|
||||||
|
if (hasActive) {
|
||||||
|
throw new Error(
|
||||||
|
"Booking ini sudah punya refund yang sedang diproses"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const percentage = Math.floor((refundAmount * 100) / paid.amount);
|
||||||
|
const refund = await refundRepo.create(
|
||||||
|
{
|
||||||
|
bookingId: booking.id,
|
||||||
|
paymentId: paid.id,
|
||||||
|
amount: refundAmount,
|
||||||
|
reason: "USER_CANCELLATION",
|
||||||
|
reportedBy: "PARTICIPANT",
|
||||||
|
reportNote: `Self-service cancel oleh peserta — H-${days} dari tanggal berangkat (refund ${percentage}%).`,
|
||||||
|
initiatedBy: "USER",
|
||||||
|
idempotencyKey: newIdempotencyKey(),
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
kind: "REFUND_PENDING" as const,
|
||||||
|
refundId: refund.id,
|
||||||
|
days,
|
||||||
|
refundAmount,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dipanggil dari tripService.closeTrip (organizer cancel trip) dengan tx
|
||||||
|
* yang sama. Buat Refund auto-approved untuk satu booking PAID. Tidak
|
||||||
|
* mengecek hasActiveRefund (caller harus filter dulu) supaya batch closeTrip
|
||||||
|
* idempotent dengan retry-safe.
|
||||||
|
*
|
||||||
|
* Refund langsung APPROVED — policy jelas (organizer cancel = 100% refund),
|
||||||
|
* tapi eksekusi (SUCCEEDED) tetap manual oleh admin.
|
||||||
|
*/
|
||||||
|
async createSystemRefundForClosedTrip(
|
||||||
|
tx: Prisma.TransactionClient,
|
||||||
|
input: {
|
||||||
|
bookingId: string;
|
||||||
|
paymentId: string;
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const now = new Date();
|
||||||
|
return tx.refund.create({
|
||||||
|
data: {
|
||||||
|
bookingId: input.bookingId,
|
||||||
|
paymentId: input.paymentId,
|
||||||
|
amount: input.amount,
|
||||||
|
reason: "ORGANIZER_CANCELLED",
|
||||||
|
reportedBy: "ORGANIZER",
|
||||||
|
reportNote: "Organizer membatalkan trip — auto-create oleh SYSTEM.",
|
||||||
|
initiatedBy: "SYSTEM",
|
||||||
|
idempotencyKey: newIdempotencyKey(),
|
||||||
|
status: "APPROVED",
|
||||||
|
reviewedAt: now,
|
||||||
|
adminNote: "Auto-approved (SYSTEM): organizer cancel = full refund.",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APPROVED/PROCESSING → FAILED. Catatan wajib (alasan gagal).
|
||||||
|
* Tidak mengubah Booking/Payment — uang belum keluar.
|
||||||
|
*/
|
||||||
|
async markFailed(input: { refundId: string; adminId: string; adminNote: string }) {
|
||||||
|
if (!input.adminNote.trim()) {
|
||||||
|
throw new Error("Alasan gagal wajib diisi");
|
||||||
|
}
|
||||||
|
return runSerializable(async (tx) => {
|
||||||
|
const refund = await tx.refund.findUnique({ where: { id: input.refundId } });
|
||||||
|
if (!refund) {
|
||||||
|
throw new Error("Refund tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (refund.status !== "APPROVED" && refund.status !== "PROCESSING") {
|
||||||
|
throw new Error(
|
||||||
|
"Hanya refund APPROVED atau PROCESSING yang bisa ditandai FAILED"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return refundRepo.update(
|
||||||
|
input.refundId,
|
||||||
|
{
|
||||||
|
status: "FAILED",
|
||||||
|
failedAt: new Date(),
|
||||||
|
reviewedById: input.adminId,
|
||||||
|
reviewedAt: new Date(),
|
||||||
|
adminNote: input.adminNote.trim(),
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ import { tripRepo, type TripFilters } from "@/server/repositories/trip.repo";
|
|||||||
import { participantRepo } from "@/server/repositories/participant.repo";
|
import { participantRepo } from "@/server/repositories/participant.repo";
|
||||||
import { bookingRepo } from "@/server/repositories/booking.repo";
|
import { bookingRepo } from "@/server/repositories/booking.repo";
|
||||||
import { bookingService } from "@/server/services/booking.service";
|
import { bookingService } from "@/server/services/booking.service";
|
||||||
|
import { refundService } from "@/server/services/refund.service";
|
||||||
import { LIMITS } from "@/lib/limits";
|
import { LIMITS } from "@/lib/limits";
|
||||||
import { utcStartOfDay, isTripDepartureDayPast } from "@/lib/trip-dates";
|
import { utcStartOfDay, isTripDepartureDayPast } from "@/lib/trip-dates";
|
||||||
import { isFreeTrip } from "@/lib/trip-pricing";
|
import { isFreeTrip } from "@/lib/trip-pricing";
|
||||||
@@ -253,6 +254,19 @@ export const tripService = {
|
|||||||
throw new Error("Kamu tidak terdaftar di trip ini");
|
throw new Error("Kamu tidak terdaftar di trip ini");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: kalau booking sudah PAID, paksa lewat refund flow supaya tidak
|
||||||
|
// ada uang menggantung tanpa Refund record.
|
||||||
|
const existingBooking = await bookingRepo.findByTripAndUser(tripId, userId);
|
||||||
|
if (
|
||||||
|
existingBooking &&
|
||||||
|
(existingBooking.status === "PAID" ||
|
||||||
|
existingBooking.status === "PARTIALLY_REFUNDED")
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Booking kamu sudah lunas — pakai tombol 'Cancel & Request Refund' supaya uang bisa dikembalikan."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await prisma.$transaction(async (tx) => {
|
const result = await prisma.$transaction(async (tx) => {
|
||||||
const cancelled = await tx.tripParticipant.update({
|
const cancelled = await tx.tripParticipant.update({
|
||||||
where: { tripId_userId: { tripId, userId } },
|
where: { tripId_userId: { tripId, userId } },
|
||||||
@@ -422,4 +436,164 @@ export const tripService = {
|
|||||||
|
|
||||||
return bookingService.confirmPaidManual(booking.id, organizerId);
|
return bookingService.confirmPaidManual(booking.id, organizerId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organizer batalkan trip (Trip.status = CLOSED). Atomic dalam satu
|
||||||
|
* serializable transaction:
|
||||||
|
* - Set Trip.status = CLOSED.
|
||||||
|
* - Untuk setiap peserta aktif:
|
||||||
|
* - Booking PAID → buat Refund ORGANIZER_CANCELLED (auto-approved, full
|
||||||
|
* amount). Booking tetap PAID sampai admin mark SUCCEEDED — jejak
|
||||||
|
* finansial harus terjaga.
|
||||||
|
* - Booking PENDING/AWAITING_PAY → set CANCELLED langsung (uang belum
|
||||||
|
* masuk, tidak ada refund).
|
||||||
|
* - Booking PARTIALLY_REFUNDED / dengan refund aktif → di-skip (admin
|
||||||
|
* handle manual supaya tidak double-refund).
|
||||||
|
* - Semua TripParticipant aktif → CANCELLED.
|
||||||
|
*
|
||||||
|
* Idempotent: trip yang sudah CLOSED/COMPLETED akan ditolak supaya tidak
|
||||||
|
* dobel-buat refund.
|
||||||
|
*/
|
||||||
|
async closeTrip(tripId: string, organizerId: string) {
|
||||||
|
let lastErr: unknown;
|
||||||
|
for (let attempt = 0; attempt < SERIAL_TX_ATTEMPTS; attempt++) {
|
||||||
|
try {
|
||||||
|
return await prisma.$transaction(
|
||||||
|
async (tx) => {
|
||||||
|
const trip = await tx.trip.findUnique({
|
||||||
|
where: { id: tripId },
|
||||||
|
select: { id: true, status: true, organizerId: true, date: true },
|
||||||
|
});
|
||||||
|
if (!trip) {
|
||||||
|
throw new Error("Trip tidak ditemukan");
|
||||||
|
}
|
||||||
|
if (trip.organizerId !== organizerId) {
|
||||||
|
throw new Error(
|
||||||
|
"Hanya organizer trip ini yang bisa membatalkan trip"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (trip.status === "CLOSED") {
|
||||||
|
throw new Error("Trip sudah dibatalkan");
|
||||||
|
}
|
||||||
|
if (trip.status === "COMPLETED") {
|
||||||
|
throw new Error(
|
||||||
|
"Trip sudah selesai (COMPLETED) — tidak bisa dibatalkan"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isTripDepartureDayPast(trip.date)) {
|
||||||
|
throw new Error(
|
||||||
|
"Tanggal berangkat sudah lewat — gunakan flow pelaporan biasa ke admin"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bookings = await tx.booking.findMany({
|
||||||
|
where: { tripId },
|
||||||
|
include: {
|
||||||
|
payments: {
|
||||||
|
where: { status: "PAID" },
|
||||||
|
orderBy: { paidAt: "desc" },
|
||||||
|
take: 1,
|
||||||
|
},
|
||||||
|
refunds: {
|
||||||
|
where: {
|
||||||
|
status: { in: ["PENDING", "APPROVED", "PROCESSING"] },
|
||||||
|
},
|
||||||
|
select: { id: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const refundsCreated: string[] = [];
|
||||||
|
const cancelledBookings: string[] = [];
|
||||||
|
const skippedBookings: string[] = [];
|
||||||
|
|
||||||
|
for (const b of bookings) {
|
||||||
|
if (b.status === "CANCELLED" || b.status === "EXPIRED") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (b.status === "REFUNDED") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (b.refunds.length > 0) {
|
||||||
|
// Sudah ada refund aktif (mis. user request cancel). Admin
|
||||||
|
// handle manual supaya tidak konflik dengan refund existing.
|
||||||
|
skippedBookings.push(b.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.status === "PAID" || b.status === "PARTIALLY_REFUNDED") {
|
||||||
|
const paid = b.payments[0];
|
||||||
|
if (!paid) {
|
||||||
|
// Payment tidak konsisten dgn booking status — skip + flag.
|
||||||
|
skippedBookings.push(b.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Untuk PARTIALLY_REFUNDED, hitung sisa refundable.
|
||||||
|
const alreadyRefunded = await tx.refund.aggregate({
|
||||||
|
where: { bookingId: b.id, status: "SUCCEEDED" },
|
||||||
|
_sum: { amount: true },
|
||||||
|
});
|
||||||
|
const remaining = paid.amount - (alreadyRefunded._sum.amount ?? 0);
|
||||||
|
if (remaining <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const refund = await refundService.createSystemRefundForClosedTrip(
|
||||||
|
tx,
|
||||||
|
{
|
||||||
|
bookingId: b.id,
|
||||||
|
paymentId: paid.id,
|
||||||
|
amount: remaining,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
refundsCreated.push(refund.id);
|
||||||
|
} else {
|
||||||
|
// PENDING / AWAITING_PAY → uang belum masuk → langsung CANCELLED.
|
||||||
|
await tx.booking.update({
|
||||||
|
where: { id: b.id },
|
||||||
|
data: { status: "CANCELLED" },
|
||||||
|
});
|
||||||
|
cancelledBookings.push(b.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Semua participant aktif → CANCELLED (apapun status booking-nya).
|
||||||
|
await tx.tripParticipant.updateMany({
|
||||||
|
where: { tripId, status: { not: "CANCELLED" } },
|
||||||
|
data: {
|
||||||
|
status: "CANCELLED",
|
||||||
|
markedPaidAt: null,
|
||||||
|
paymentConfirmedAt: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await tx.trip.update({
|
||||||
|
where: { id: tripId },
|
||||||
|
data: { status: "CLOSED" },
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: true as const,
|
||||||
|
refundsCreated,
|
||||||
|
cancelledBookings,
|
||||||
|
skippedBookings,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
|
||||||
|
maxWait: 5000,
|
||||||
|
timeout: 15000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
lastErr = e;
|
||||||
|
if (isSerializationConflict(e) && attempt < SERIAL_TX_ATTEMPTS - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw lastErr instanceof Error
|
||||||
|
? lastErr
|
||||||
|
: new Error("Gagal membatalkan trip. Coba lagi sebentar.");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user