407 lines
8.8 KiB
TypeScript
407 lines
8.8 KiB
TypeScript
import apiClient from './apiClient';
|
|
|
|
// Types
|
|
export interface PaymentData {
|
|
booking_id: number;
|
|
amount: number;
|
|
payment_method: 'cash' | 'bank_transfer' | 'stripe' | 'paypal';
|
|
transaction_id?: string;
|
|
notes?: string;
|
|
}
|
|
|
|
export interface Payment {
|
|
id: number;
|
|
booking_id: number;
|
|
amount: number;
|
|
payment_method: 'cash' | 'bank_transfer' | 'credit_card' | 'debit_card' | 'e_wallet' | 'stripe' | 'paypal';
|
|
payment_type: 'full' | 'deposit' | 'remaining';
|
|
deposit_percentage?: number;
|
|
payment_status: 'pending' | 'completed' | 'failed' | 'refunded';
|
|
transaction_id?: string;
|
|
payment_date?: string;
|
|
notes?: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
booking?: {
|
|
id: number;
|
|
booking_number: string;
|
|
user?: {
|
|
name: string;
|
|
email?: string;
|
|
};
|
|
};
|
|
}
|
|
|
|
export interface BankInfo {
|
|
bank_name: string;
|
|
bank_code: string;
|
|
account_number: string;
|
|
account_name: string;
|
|
amount: number;
|
|
content: string;
|
|
qr_url: string;
|
|
}
|
|
|
|
export interface PaymentResponse {
|
|
success: boolean;
|
|
data: {
|
|
payment: Payment;
|
|
};
|
|
message?: string;
|
|
}
|
|
|
|
/**
|
|
* Create a new payment record
|
|
* POST /api/payments
|
|
*/
|
|
export const createPayment = async (
|
|
paymentData: PaymentData
|
|
): Promise<PaymentResponse> => {
|
|
const response = await apiClient.post<PaymentResponse>(
|
|
'/payments',
|
|
paymentData
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get payment details by booking ID
|
|
* GET /api/payments/:bookingId
|
|
*/
|
|
export const getPaymentByBookingId = async (
|
|
bookingId: number
|
|
): Promise<PaymentResponse> => {
|
|
const response = await apiClient.get<PaymentResponse>(
|
|
`/payments/${bookingId}`
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Confirm bank transfer payment (with receipt)
|
|
* POST /api/payments/confirm
|
|
*/
|
|
export const confirmBankTransfer = async (
|
|
bookingId: number,
|
|
transactionId?: string,
|
|
receipt?: File
|
|
): Promise<{ success: boolean; message?: string }> => {
|
|
const formData = new FormData();
|
|
formData.append('booking_id', bookingId.toString());
|
|
|
|
if (transactionId) {
|
|
formData.append('transaction_id', transactionId);
|
|
}
|
|
|
|
if (receipt) {
|
|
formData.append('receipt', receipt);
|
|
}
|
|
|
|
const response = await apiClient.post(
|
|
'/payments/confirm',
|
|
formData,
|
|
{
|
|
headers: {
|
|
'Content-Type': 'multipart/form-data',
|
|
},
|
|
}
|
|
);
|
|
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get bank transfer info with QR code for deposit
|
|
* GET /api/payments/:paymentId/bank-info
|
|
*/
|
|
export const getBankTransferInfo = async (
|
|
paymentId: number
|
|
): Promise<{
|
|
success: boolean;
|
|
data: { payment: Payment; bank_info: BankInfo };
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.get(
|
|
`/payments/${paymentId}/bank-info`
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Confirm deposit payment
|
|
* POST /api/payments/confirm-deposit
|
|
*/
|
|
export const confirmDepositPayment = async (
|
|
paymentId: number,
|
|
transactionId?: string
|
|
): Promise<{
|
|
success: boolean;
|
|
data: { payment: Payment; booking: any };
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.post(
|
|
'/payments/confirm-deposit',
|
|
{
|
|
payment_id: paymentId,
|
|
transaction_id: transactionId,
|
|
}
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Notify payment completion (for admin verification)
|
|
* POST /api/payments/notify
|
|
*/
|
|
export const notifyPaymentCompletion = async (
|
|
paymentId: number,
|
|
notes?: string
|
|
): Promise<{ success: boolean; message?: string }> => {
|
|
const response = await apiClient.post(
|
|
'/payments/notify',
|
|
{
|
|
payment_id: paymentId,
|
|
notes,
|
|
}
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get all payments (with optional filters)
|
|
* GET /api/payments
|
|
*/
|
|
export const getPayments = async (params?: {
|
|
booking_id?: number;
|
|
status?: string;
|
|
page?: number;
|
|
limit?: number;
|
|
}): Promise<{
|
|
success: boolean;
|
|
data: {
|
|
payments: Payment[];
|
|
pagination?: {
|
|
total: number;
|
|
page: number;
|
|
limit: number;
|
|
totalPages: number;
|
|
};
|
|
};
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.get('/payments', { params });
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
data: data.data || { payments: [] },
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get payments for a booking
|
|
* GET /api/payments/booking/:bookingId
|
|
*/
|
|
export const getPaymentsByBookingId = async (
|
|
bookingId: number
|
|
): Promise<{
|
|
success: boolean;
|
|
data: { payments: Payment[] };
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.get(
|
|
`/payments/booking/${bookingId}`
|
|
);
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
data: data.data || { payments: [] },
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
|
|
/**
|
|
* Create Stripe payment intent
|
|
* POST /api/payments/stripe/create-intent
|
|
*/
|
|
export const createStripePaymentIntent = async (
|
|
bookingId: number,
|
|
amount: number,
|
|
currency: string = 'usd'
|
|
): Promise<{
|
|
success: boolean;
|
|
data: {
|
|
client_secret: string;
|
|
payment_intent_id: string;
|
|
publishable_key: string;
|
|
};
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.post(
|
|
'/payments/stripe/create-intent',
|
|
{
|
|
booking_id: bookingId,
|
|
amount,
|
|
currency,
|
|
}
|
|
);
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
data: data.data || {},
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Confirm Stripe payment
|
|
* POST /api/payments/stripe/confirm
|
|
*/
|
|
export const confirmStripePayment = async (
|
|
paymentIntentId: string,
|
|
bookingId: number
|
|
): Promise<{
|
|
success: boolean;
|
|
data: {
|
|
payment: Payment;
|
|
booking: {
|
|
id: number;
|
|
booking_number: string;
|
|
status: string;
|
|
};
|
|
};
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.post(
|
|
'/payments/stripe/confirm',
|
|
{
|
|
payment_intent_id: paymentIntentId,
|
|
booking_id: bookingId,
|
|
}
|
|
);
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
data: data.data || {},
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Create PayPal order
|
|
* POST /api/payments/paypal/create-order
|
|
*/
|
|
export const createPayPalOrder = async (
|
|
bookingId: number,
|
|
amount: number,
|
|
currency: string = 'USD',
|
|
returnUrl?: string,
|
|
cancelUrl?: string
|
|
): Promise<{
|
|
success: boolean;
|
|
data: {
|
|
order_id: string;
|
|
approval_url: string;
|
|
status: string;
|
|
};
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.post(
|
|
'/payments/paypal/create-order',
|
|
{
|
|
booking_id: bookingId,
|
|
amount,
|
|
currency,
|
|
return_url: returnUrl,
|
|
cancel_url: cancelUrl,
|
|
}
|
|
);
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
data: data.data || {},
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Capture PayPal payment
|
|
* POST /api/payments/paypal/capture
|
|
*/
|
|
export const capturePayPalPayment = async (
|
|
orderId: string,
|
|
bookingId: number
|
|
): Promise<{
|
|
success: boolean;
|
|
data: {
|
|
payment: Payment;
|
|
booking: {
|
|
id: number;
|
|
booking_number: string;
|
|
status: string;
|
|
};
|
|
};
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.post(
|
|
'/payments/paypal/capture',
|
|
{
|
|
order_id: orderId,
|
|
booking_id: bookingId,
|
|
}
|
|
);
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
data: data.data || {},
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Cancel PayPal payment (when user cancels on PayPal page)
|
|
* POST /api/payments/paypal/cancel
|
|
*/
|
|
export const cancelPayPalPayment = async (
|
|
bookingId: number
|
|
): Promise<{
|
|
success: boolean;
|
|
message?: string;
|
|
}> => {
|
|
const response = await apiClient.post(
|
|
'/payments/paypal/cancel',
|
|
{
|
|
booking_id: bookingId,
|
|
}
|
|
);
|
|
// Map backend response format (status: "success") to frontend format (success: true)
|
|
const data = response.data;
|
|
return {
|
|
success: data.status === "success" || data.success === true,
|
|
message: data.message,
|
|
};
|
|
};
|
|
|
|
export default {
|
|
createPayment,
|
|
getPayments,
|
|
getPaymentByBookingId,
|
|
confirmBankTransfer,
|
|
getBankTransferInfo,
|
|
confirmDepositPayment,
|
|
notifyPaymentCompletion,
|
|
getPaymentsByBookingId,
|
|
createStripePaymentIntent,
|
|
confirmStripePayment,
|
|
createPayPalOrder,
|
|
capturePayPalPayment,
|
|
cancelPayPalPayment,
|
|
};
|