enh
This commit is contained in:
parent
3c836e274d
commit
4414f9f64b
6 changed files with 81 additions and 199 deletions
|
|
@ -63,7 +63,8 @@ export default function OrderDetails() {
|
||||||
onSuccess: (result) => {
|
onSuccess: (result) => {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
"Success",
|
"Success",
|
||||||
`Refund initiated successfully!\n\nAmount: ₹${result.amount}\nStatus: ${result.status}`
|
`Refund initiated successfully!\n\nAmount: `
|
||||||
|
// `Refund initiated successfully!\n\nAmount: ₹${result.amount}\nStatus: ${result.status}`
|
||||||
);
|
);
|
||||||
setInitiateRefundDialogOpen(false);
|
setInitiateRefundDialogOpen(false);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import * as cron from 'node-cron';
|
||||||
import { db } from '@/src/db/db_index'
|
import { db } from '@/src/db/db_index'
|
||||||
import { payments, orders, deliverySlotInfo, refunds } from '@/src/db/schema'
|
import { payments, orders, deliverySlotInfo, refunds } from '@/src/db/schema'
|
||||||
import { eq, and, gt, isNotNull } from 'drizzle-orm';
|
import { eq, and, gt, isNotNull } from 'drizzle-orm';
|
||||||
import { RazorpayPaymentService } from '@/src/lib/payments-utils'
|
|
||||||
|
|
||||||
interface PendingPaymentRecord {
|
interface PendingPaymentRecord {
|
||||||
payment: typeof payments.$inferSelect;
|
payment: typeof payments.$inferSelect;
|
||||||
|
|
@ -20,34 +19,34 @@ export const createPaymentNotification = (record: PendingPaymentRecord) => {
|
||||||
|
|
||||||
export const checkRefundStatuses = async () => {
|
export const checkRefundStatuses = async () => {
|
||||||
try {
|
try {
|
||||||
const initiatedRefunds = await db
|
// const initiatedRefunds = await db
|
||||||
.select()
|
// .select()
|
||||||
.from(refunds)
|
// .from(refunds)
|
||||||
.where(and(
|
// .where(and(
|
||||||
eq(refunds.refundStatus, 'initiated'),
|
// eq(refunds.refundStatus, 'initiated'),
|
||||||
isNotNull(refunds.merchantRefundId)
|
// isNotNull(refunds.merchantRefundId)
|
||||||
));
|
// ));
|
||||||
|
//
|
||||||
// Process refunds concurrently using Promise.allSettled
|
// // Process refunds concurrently using Promise.allSettled
|
||||||
const promises = initiatedRefunds.map(async (refund) => {
|
// const promises = initiatedRefunds.map(async (refund) => {
|
||||||
if (!refund.merchantRefundId) return;
|
// if (!refund.merchantRefundId) return;
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
const razorpayRefund = await RazorpayPaymentService.fetchRefund(refund.merchantRefundId);
|
// const razorpayRefund = await RazorpayPaymentService.fetchRefund(refund.merchantRefundId);
|
||||||
|
//
|
||||||
if (razorpayRefund.status === 'processed') {
|
// if (razorpayRefund.status === 'processed') {
|
||||||
await db
|
// await db
|
||||||
.update(refunds)
|
// .update(refunds)
|
||||||
.set({ refundStatus: 'success', refundProcessedAt: new Date() })
|
// .set({ refundStatus: 'success', refundProcessedAt: new Date() })
|
||||||
.where(eq(refunds.id, refund.id));
|
// .where(eq(refunds.id, refund.id));
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error(`Error checking refund ${refund.id}:`, error);
|
// console.error(`Error checking refund ${refund.id}:`, error);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
// Wait for all promises to complete
|
// // Wait for all promises to complete
|
||||||
await Promise.allSettled(promises);
|
// await Promise.allSettled(promises);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in checkRefundStatuses:', error);
|
console.error('Error in checkRefundStatuses:', error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import Razorpay from "razorpay";
|
// import Razorpay from "razorpay";
|
||||||
import { razorpayId, razorpaySecret } from "@/src/lib/env-exporter"
|
import { razorpayId, razorpaySecret } from "@/src/lib/env-exporter"
|
||||||
import { db } from "@/src/db/db_index"
|
import { db } from "@/src/db/db_index"
|
||||||
import { payments } from "@/src/db/schema"
|
import { payments } from "@/src/db/schema"
|
||||||
|
|
@ -6,54 +6,54 @@ import { payments } from "@/src/db/schema"
|
||||||
type Tx = Parameters<Parameters<typeof db.transaction>[0]>[0];
|
type Tx = Parameters<Parameters<typeof db.transaction>[0]>[0];
|
||||||
|
|
||||||
export class RazorpayPaymentService {
|
export class RazorpayPaymentService {
|
||||||
private static instance = new Razorpay({
|
// private static instance = new Razorpay({
|
||||||
key_id: razorpayId,
|
// key_id: razorpayId,
|
||||||
key_secret: razorpaySecret,
|
// key_secret: razorpaySecret,
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
static async createOrder(orderId: number, amount: string) {
|
static async createOrder(orderId: number, amount: string) {
|
||||||
// Create Razorpay order
|
// Create Razorpay order
|
||||||
const razorpayOrder = await this.instance.orders.create({
|
// const razorpayOrder = await this.instance.orders.create({
|
||||||
amount: parseFloat(amount) * 100, // Convert to paisa
|
// amount: parseFloat(amount) * 100, // Convert to paisa
|
||||||
currency: 'INR',
|
// currency: 'INR',
|
||||||
receipt: `order_${orderId}`,
|
// receipt: `order_${orderId}`,
|
||||||
notes: {
|
// notes: {
|
||||||
customerOrderId: orderId.toString(),
|
// customerOrderId: orderId.toString(),
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
return razorpayOrder;
|
// return razorpayOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async insertPaymentRecord(orderId: number, razorpayOrder: any, tx?: Tx) {
|
static async insertPaymentRecord(orderId: number, razorpayOrder: any, tx?: Tx) {
|
||||||
// Use transaction if provided, otherwise use db
|
// Use transaction if provided, otherwise use db
|
||||||
const dbInstance = tx || db;
|
// const dbInstance = tx || db;
|
||||||
|
//
|
||||||
// Insert payment record
|
// // Insert payment record
|
||||||
const [payment] = await dbInstance
|
// const [payment] = await dbInstance
|
||||||
.insert(payments)
|
// .insert(payments)
|
||||||
.values({
|
// .values({
|
||||||
status: 'pending',
|
// status: 'pending',
|
||||||
gateway: 'razorpay',
|
// gateway: 'razorpay',
|
||||||
orderId,
|
// orderId,
|
||||||
token: orderId.toString(),
|
// token: orderId.toString(),
|
||||||
merchantOrderId: razorpayOrder.id,
|
// merchantOrderId: razorpayOrder.id,
|
||||||
payload: razorpayOrder,
|
// payload: razorpayOrder,
|
||||||
})
|
// })
|
||||||
.returning();
|
// .returning();
|
||||||
|
//
|
||||||
return payment;
|
// return payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async initiateRefund(paymentId: string, amount: number) {
|
static async initiateRefund(paymentId: string, amount: number) {
|
||||||
const refund = await this.instance.payments.refund(paymentId, {
|
// const refund = await this.instance.payments.refund(paymentId, {
|
||||||
amount,
|
// amount,
|
||||||
});
|
// });
|
||||||
return refund;
|
// return refund;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async fetchRefund(refundId: string) {
|
static async fetchRefund(refundId: string) {
|
||||||
const refund = await this.instance.refunds.fetch(refundId);
|
// const refund = await this.instance.refunds.fetch(refundId);
|
||||||
return refund;
|
// return refund;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,5 @@
|
||||||
import { router, protectedProcedure } from "@/src/trpc/trpc-index"
|
import { router, protectedProcedure } from "@/src/trpc/trpc-index"
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@/src/db/db_index"
|
|
||||||
import {
|
|
||||||
orders,
|
|
||||||
orderStatus,
|
|
||||||
payments,
|
|
||||||
refunds,
|
|
||||||
} from "@/src/db/schema";
|
|
||||||
import { and, eq } from "drizzle-orm";
|
|
||||||
import { ApiError } from "@/src/lib/api-error"
|
|
||||||
import { RazorpayPaymentService } from "@/src/lib/payments-utils"
|
|
||||||
|
|
||||||
const initiateRefundSchema = z
|
const initiateRefundSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|
@ -33,114 +23,6 @@ export const adminPaymentsRouter = router({
|
||||||
initiateRefund: protectedProcedure
|
initiateRefund: protectedProcedure
|
||||||
.input(initiateRefundSchema)
|
.input(initiateRefundSchema)
|
||||||
.mutation(async ({ input }) => {
|
.mutation(async ({ input }) => {
|
||||||
try {
|
return {}
|
||||||
const { orderId, refundPercent, refundAmount } = input;
|
|
||||||
|
|
||||||
// Validate order exists
|
|
||||||
const order = await db.query.orders.findFirst({
|
|
||||||
where: eq(orders.id, orderId),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!order) {
|
|
||||||
throw new ApiError("Order not found", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if order is paid
|
|
||||||
const orderStatusRecord = await db.query.orderStatus.findFirst({
|
|
||||||
where: eq(orderStatus.orderId, orderId),
|
|
||||||
});
|
|
||||||
|
|
||||||
if(order.isCod) {
|
|
||||||
throw new ApiError("Order is a Cash On Delivery. Not eligible for refund")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!orderStatusRecord ||
|
|
||||||
(orderStatusRecord.paymentStatus !== "success" &&
|
|
||||||
!(order.isCod && orderStatusRecord.isDelivered))
|
|
||||||
) {
|
|
||||||
throw new ApiError("Order payment not verified or not eligible for refund", 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate refund amount
|
|
||||||
let calculatedRefundAmount: number;
|
|
||||||
if (refundPercent !== undefined) {
|
|
||||||
calculatedRefundAmount =
|
|
||||||
(parseFloat(order.totalAmount) * refundPercent) / 100;
|
|
||||||
} else if (refundAmount !== undefined) {
|
|
||||||
calculatedRefundAmount = refundAmount;
|
|
||||||
if (calculatedRefundAmount > parseFloat(order.totalAmount)) {
|
|
||||||
throw new ApiError("Refund amount cannot exceed order total", 400);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new ApiError("Invalid refund parameters", 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
let razorpayRefund = null;
|
|
||||||
let merchantRefundId = null;
|
|
||||||
|
|
||||||
// Get payment record for online payments
|
|
||||||
const payment = await db.query.payments.findFirst({
|
|
||||||
where: and(
|
|
||||||
eq(payments.orderId, orderId),
|
|
||||||
eq(payments.status, "success")
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!payment || payment.status !== "success") {
|
|
||||||
throw new ApiError("Payment not found or not successful", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = payment.payload as any;
|
|
||||||
// Initiate Razorpay refund
|
|
||||||
razorpayRefund = await RazorpayPaymentService.initiateRefund(
|
|
||||||
payload.payment_id,
|
|
||||||
Math.round(calculatedRefundAmount * 100) // Convert to paisa
|
|
||||||
);
|
|
||||||
merchantRefundId = razorpayRefund.id;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check if refund already exists for this order
|
|
||||||
const existingRefund = await db.query.refunds.findFirst({
|
|
||||||
where: eq(refunds.orderId, orderId),
|
|
||||||
});
|
|
||||||
|
|
||||||
const refundStatus = "initiated";
|
|
||||||
|
|
||||||
if (existingRefund) {
|
|
||||||
// Update existing refund
|
|
||||||
await db
|
|
||||||
.update(refunds)
|
|
||||||
.set({
|
|
||||||
refundAmount: calculatedRefundAmount.toString(),
|
|
||||||
refundStatus,
|
|
||||||
merchantRefundId,
|
|
||||||
refundProcessedAt: order.isCod ? new Date() : null,
|
|
||||||
})
|
|
||||||
.where(eq(refunds.id, existingRefund.id));
|
|
||||||
} else {
|
|
||||||
// Insert new refund
|
|
||||||
await db
|
|
||||||
.insert(refunds)
|
|
||||||
.values({
|
|
||||||
orderId,
|
|
||||||
refundAmount: calculatedRefundAmount.toString(),
|
|
||||||
refundStatus,
|
|
||||||
merchantRefundId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
refundId: merchantRefundId || `cod_${orderId}`,
|
|
||||||
amount: calculatedRefundAmount,
|
|
||||||
status: refundStatus,
|
|
||||||
message: order.isCod ? "COD refund processed successfully" : "Refund initiated successfully",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
console.log(e);
|
|
||||||
throw new ApiError("Failed to initiate refund")
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import {
|
||||||
sendOrderPlacedNotification,
|
sendOrderPlacedNotification,
|
||||||
sendOrderCancelledNotification,
|
sendOrderCancelledNotification,
|
||||||
} from "@/src/lib/notif-job";
|
} from "@/src/lib/notif-job";
|
||||||
import { RazorpayPaymentService } from "@/src/lib/payments-utils";
|
|
||||||
import { getNextDeliveryDate } from "@/src/trpc/apis/common-apis/common";
|
import { getNextDeliveryDate } from "@/src/trpc/apis/common-apis/common";
|
||||||
import { CONST_KEYS, getConstant, getConstants } from "@/src/lib/const-store";
|
import { CONST_KEYS, getConstant, getConstants } from "@/src/lib/const-store";
|
||||||
import { publishFormattedOrder, publishCancellation } from "@/src/lib/post-order-handler";
|
import { publishFormattedOrder, publishCancellation } from "@/src/lib/post-order-handler";
|
||||||
|
|
@ -316,15 +315,15 @@ const placeOrderUtil = async (params: {
|
||||||
await tx.insert(orderStatus).values(allOrderStatuses);
|
await tx.insert(orderStatus).values(allOrderStatuses);
|
||||||
|
|
||||||
if (paymentMethod === "online" && sharedPaymentInfoId) {
|
if (paymentMethod === "online" && sharedPaymentInfoId) {
|
||||||
const razorpayOrder = await RazorpayPaymentService.createOrder(
|
// const razorpayOrder = await RazorpayPaymentService.createOrder(
|
||||||
sharedPaymentInfoId,
|
// sharedPaymentInfoId,
|
||||||
totalWithDelivery.toString()
|
// totalWithDelivery.toString()
|
||||||
);
|
// );
|
||||||
await RazorpayPaymentService.insertPaymentRecord(
|
// await RazorpayPaymentService.insertPaymentRecord(
|
||||||
sharedPaymentInfoId,
|
// sharedPaymentInfoId,
|
||||||
razorpayOrder,
|
// razorpayOrder,
|
||||||
tx
|
// tx
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
return insertedOrders;
|
return insertedOrders;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ export const paymentRouter = router({
|
||||||
await RazorpayPaymentService.insertPaymentRecord(parseInt(orderId), razorpayOrder);
|
await RazorpayPaymentService.insertPaymentRecord(parseInt(orderId), razorpayOrder);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
razorpayOrderId: razorpayOrder.id,
|
razorpayOrderId: 0,
|
||||||
|
// razorpayOrderId: razorpayOrder.id,
|
||||||
key: razorpayId,
|
key: razorpayId,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue