mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
223 lines
7.4 KiB
TypeScript
223 lines
7.4 KiB
TypeScript
import {
|
|
IsString,
|
|
IsEnum,
|
|
IsOptional,
|
|
IsIn,
|
|
IsBoolean,
|
|
IsInt,
|
|
} from "class-validator";
|
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
|
import { PaymentIntentStatus } from "@prisma/client";
|
|
|
|
export enum PaymentRegionEnum {
|
|
ETHIOPIA = "ETHIOPIA",
|
|
DJIBOUTI = "DJIBOUTI",
|
|
INTERNATIONAL = "INTERNATIONAL",
|
|
GLOBAL = "GLOBAL",
|
|
}
|
|
|
|
export enum PaymentMethodTypeEnum {
|
|
TELEBIRR = "TELEBIRR", // Ethiopia
|
|
CBE_BIRR = "CBE_BIRR", // Ethiopia
|
|
EBIRR = "EBIRR", // Ethiopia
|
|
WAAFI = "WAAFI",
|
|
DMONEY= "DMONEY",// Djibouti
|
|
CAC_BANK = "CAC_BANK", // Djibouti (OTP debit)
|
|
CARD = "CARD", // International
|
|
WALLET = "WALLET", // Internal
|
|
CBE_BILL = "CBE_BILL", // Ethiopia (pay at any CBE channel by bill number)
|
|
}
|
|
|
|
/** Mirrors `PaymentPlatform` in @edr/types — see there for what each surface means. */
|
|
export type PaymentPlatformDto = "web" | "mobile" | "inapp";
|
|
|
|
export class InitiatePaymentDto {
|
|
@ApiProperty({ example: "booking-uuid" }) @IsString() bookingId: string;
|
|
@ApiProperty({
|
|
enum: PaymentMethodTypeEnum,
|
|
description:
|
|
"Payment method: TELEBIRR/CBE_BIRR/EBIRR (Ethiopia), WAAFI (Djibouti), CARD (International), WALLET (Internal)",
|
|
example: "TELEBIRR",
|
|
})
|
|
@IsEnum(PaymentMethodTypeEnum)
|
|
method: PaymentMethodTypeEnum;
|
|
@ApiPropertyOptional({ description: "Saved payment method ID (optional)" })
|
|
@IsOptional()
|
|
@IsString()
|
|
paymentMethodId?: string;
|
|
@ApiPropertyOptional({
|
|
enum: ["web", "mobile", "inapp"],
|
|
default: "web",
|
|
description:
|
|
"Payer surface. `inapp` = the portal is running inside a SuperApp mini-app WebView " +
|
|
"(Telebirr), which cannot follow redirect flows and gets a bridge payload instead.",
|
|
})
|
|
@IsOptional()
|
|
@IsIn(["web", "mobile", "inapp"])
|
|
platform?: PaymentPlatformDto;
|
|
@ApiPropertyOptional({
|
|
description:
|
|
"Payer account / mobile number. Required for OTP-debit methods (CAC_BANK) — " +
|
|
"the bank sends the OTP to this number.",
|
|
example: "77112233",
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
payerAccount?: string;
|
|
}
|
|
|
|
export class ConfirmOtpDto {
|
|
@ApiProperty({
|
|
description: "One-time password the payer received by SMS (e.g. CAC Bank).",
|
|
example: "4530",
|
|
})
|
|
@IsString()
|
|
otp: string;
|
|
}
|
|
|
|
export class RefundDto {
|
|
@ApiProperty() @IsString() bookingId: string;
|
|
@ApiPropertyOptional() @IsOptional() @IsString() reason?: string;
|
|
}
|
|
|
|
export class AddPaymentMethodDto {
|
|
@ApiProperty({ enum: PaymentMethodTypeEnum })
|
|
@IsEnum(PaymentMethodTypeEnum)
|
|
type: PaymentMethodTypeEnum;
|
|
@ApiProperty() @IsString() displayName: string;
|
|
@ApiProperty({ enum: PaymentRegionEnum })
|
|
@IsEnum(PaymentRegionEnum)
|
|
region: PaymentRegionEnum;
|
|
@ApiPropertyOptional({ example: "ETB" })
|
|
@IsOptional()
|
|
@IsString()
|
|
currency?: string;
|
|
@ApiPropertyOptional() @IsOptional() @IsString() providerId?: string;
|
|
@ApiPropertyOptional({ default: true })
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
enabled?: boolean;
|
|
@ApiPropertyOptional({ default: 0 })
|
|
@IsOptional()
|
|
@IsInt()
|
|
sortOrder?: number;
|
|
}
|
|
|
|
export class SupportedPaymentMethodDto {
|
|
@ApiProperty({ enum: PaymentMethodTypeEnum }) type: PaymentMethodTypeEnum;
|
|
@ApiProperty({ example: "Telebirr" }) displayName: string;
|
|
@ApiProperty({ enum: PaymentRegionEnum }) region: PaymentRegionEnum;
|
|
@ApiProperty({
|
|
example: "ETB",
|
|
description: "Settlement currency for this method",
|
|
})
|
|
currency: string;
|
|
@ApiProperty({
|
|
description: "Whether the platform currently accepts this method",
|
|
})
|
|
enabled: boolean;
|
|
}
|
|
|
|
export class ClientActionDto {
|
|
@ApiProperty({
|
|
enum: [
|
|
"REDIRECT",
|
|
"LAUNCH_APP",
|
|
"INVOKE_BRIDGE",
|
|
"COLLECT_OTP",
|
|
"SHOW_BILL_REFERENCE",
|
|
],
|
|
})
|
|
type:
|
|
| "REDIRECT"
|
|
| "LAUNCH_APP"
|
|
| "INVOKE_BRIDGE"
|
|
| "COLLECT_OTP"
|
|
| "SHOW_BILL_REFERENCE";
|
|
@ApiPropertyOptional({ description: "Set when type=REDIRECT (web flow)" })
|
|
url?: string;
|
|
@ApiPropertyOptional({
|
|
description: "Set when type=LAUNCH_APP (mobile flow)",
|
|
})
|
|
prepayId?: string;
|
|
@ApiPropertyOptional({
|
|
description: "Set when type=LAUNCH_APP (mobile flow)",
|
|
})
|
|
receiveCode?: string;
|
|
@ApiPropertyOptional({
|
|
description: "Set when type=LAUNCH_APP (mobile flow)",
|
|
})
|
|
shortCode?: string;
|
|
@ApiPropertyOptional({
|
|
description:
|
|
"Set when type=INVOKE_BRIDGE (telebirr mini app) — which SuperApp host bridge to call",
|
|
enum: ["TELEBIRR"],
|
|
})
|
|
bridge?: "TELEBIRR";
|
|
@ApiPropertyOptional({
|
|
description:
|
|
"Set when type=INVOKE_BRIDGE (telebirr mini app). Signed query string handed verbatim " +
|
|
"to the host bridge (js_fun_start_pay). NOT a URL — never navigate to it.",
|
|
})
|
|
rawRequest?: string;
|
|
@ApiPropertyOptional({ description: "Set when type=COLLECT_OTP (e.g. CAC Bank)" })
|
|
providerOrderId?: string;
|
|
@ApiPropertyOptional({ description: "Set when type=COLLECT_OTP" })
|
|
message?: string;
|
|
@ApiPropertyOptional({
|
|
description: "Set when type=SHOW_BILL_REFERENCE (CBE bill payment)",
|
|
})
|
|
billReference?: string;
|
|
@ApiPropertyOptional({ description: "Set when type=SHOW_BILL_REFERENCE" })
|
|
instructions?: string;
|
|
@ApiPropertyOptional({ description: "Set when type=SHOW_BILL_REFERENCE" })
|
|
expiresAt?: string;
|
|
}
|
|
|
|
export class InitiateResponseDto {
|
|
@ApiProperty() intentId: string;
|
|
@ApiProperty({ enum: PaymentIntentStatus }) status: PaymentIntentStatus;
|
|
@ApiPropertyOptional({ type: ClientActionDto })
|
|
clientAction?: ClientActionDto;
|
|
@ApiPropertyOptional() merchantOrderId?: string;
|
|
/** When this payment session stops being offered — PAYMENT_SESSION_MINUTES from initiation, capped at paymentDeadline. Drives the client-side countdown. */
|
|
@ApiPropertyOptional() sessionExpiresAt?: string;
|
|
/** The booking's payment deadline: after it, the booking is auto-cancelled. */
|
|
@ApiPropertyOptional() paymentDeadline?: string;
|
|
}
|
|
|
|
export class IntentStatusDto {
|
|
@ApiProperty() intentId: string;
|
|
@ApiProperty({ enum: PaymentIntentStatus }) status: PaymentIntentStatus;
|
|
@ApiPropertyOptional({ type: ClientActionDto })
|
|
clientAction?: ClientActionDto;
|
|
@ApiPropertyOptional() merchantOrderId?: string;
|
|
@ApiPropertyOptional() paidAt?: string;
|
|
@ApiPropertyOptional() failureCode?: string;
|
|
@ApiPropertyOptional() failureMessage?: string;
|
|
@ApiPropertyOptional({
|
|
type: "object",
|
|
additionalProperties: true,
|
|
description:
|
|
"Raw provider payload (initiation response merged with the latest status query) for inspection/debugging. Provider-specific shape; never trusted for state.",
|
|
})
|
|
providerResponse?: Record<string, unknown>;
|
|
}
|
|
|
|
export class BookingAmountResponseDto {
|
|
@ApiProperty({ example: 'booking-uuid' }) booking_id: string;
|
|
@ApiProperty({ example: 'DJF', description: 'Currency of the returned amount' }) currency: string;
|
|
@ApiProperty({ example: 162.5, description: 'Booking total converted to the requested currency (major units)' }) amount: number;
|
|
}
|
|
|
|
export class ForceConfirmDto {
|
|
@ApiPropertyOptional({ description: 'External payment reference / transaction ID from the vendor', example: 'TXN-123456' })
|
|
@IsOptional() @IsString() paymentReference?: string;
|
|
|
|
@ApiPropertyOptional({ enum: PaymentMethodTypeEnum, description: 'Payment method used externally', example: 'TELEBIRR' })
|
|
@IsOptional() @IsEnum(PaymentMethodTypeEnum) paymentMethod?: PaymentMethodTypeEnum;
|
|
|
|
@ApiPropertyOptional({ description: 'Internal notes about why this was force-confirmed', example: 'Vendor confirmed via phone' })
|
|
@IsOptional() @IsString() notes?: string;
|
|
}
|