191 lines
6.3 KiB
TypeScript
191 lines
6.3 KiB
TypeScript
import { db } from '../../db/db_index'
|
|
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '../../db/schema'
|
|
import { eq, and, like, or, inArray, lt, asc } from 'drizzle-orm'
|
|
import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface'
|
|
|
|
export class CouponDbService implements ICouponDbService {
|
|
async createCoupon(data: NewCoupon): Promise<Coupon> {
|
|
const [coupon] = await db.insert(coupons).values(data).returning()
|
|
return coupon
|
|
}
|
|
|
|
async getCouponById(id: number): Promise<CouponWithRelations | undefined> {
|
|
const result = await db.query.coupons.findFirst({
|
|
where: eq(coupons.id, id),
|
|
with: {
|
|
creator: true,
|
|
applicableUsers: { with: { user: true } },
|
|
applicableProducts: { with: { product: true } },
|
|
},
|
|
})
|
|
if (!result) return undefined
|
|
return {
|
|
...result,
|
|
productIds: (result.productIds as number[] | null) || null,
|
|
} as CouponWithRelations
|
|
}
|
|
|
|
async getCouponByCode(code: string): Promise<Coupon | undefined> {
|
|
return db.query.coupons.findFirst({
|
|
where: eq(coupons.couponCode, code),
|
|
})
|
|
}
|
|
|
|
async getAllCoupons(options: { cursor?: number; limit: number; search?: string }): Promise<CouponWithRelations[]> {
|
|
const { cursor, limit, search } = options
|
|
|
|
let whereCondition = undefined
|
|
const conditions = []
|
|
|
|
if (cursor) {
|
|
conditions.push(lt(coupons.id, cursor))
|
|
}
|
|
|
|
if (search && search.trim()) {
|
|
conditions.push(like(coupons.couponCode, `%${search}%`))
|
|
}
|
|
|
|
if (conditions.length > 0) {
|
|
whereCondition = and(...conditions)
|
|
}
|
|
|
|
const result = await db.query.coupons.findMany({
|
|
where: whereCondition,
|
|
with: {
|
|
creator: true,
|
|
applicableUsers: { with: { user: true } },
|
|
applicableProducts: { with: { product: true } },
|
|
},
|
|
orderBy: (coupons, { desc }) => [desc(coupons.createdAt)],
|
|
limit: limit + 1,
|
|
})
|
|
|
|
return result.map((coupon) => ({
|
|
...coupon,
|
|
productIds: (coupon.productIds as number[] | null) || null,
|
|
})) as CouponWithRelations[]
|
|
}
|
|
|
|
async updateCoupon(id: number, data: Partial<NewCoupon>): Promise<Coupon> {
|
|
const [coupon] = await db.update(coupons).set(data).where(eq(coupons.id, id)).returning()
|
|
return coupon
|
|
}
|
|
|
|
async invalidateCoupon(id: number): Promise<Coupon> {
|
|
const [coupon] = await db.update(coupons).set({ isInvalidated: true }).where(eq(coupons.id, id)).returning()
|
|
return coupon
|
|
}
|
|
|
|
async addApplicableUsers(couponId: number, userIds: number[]): Promise<void> {
|
|
await db.insert(couponApplicableUsers).values(
|
|
userIds.map(userId => ({ couponId, userId }))
|
|
)
|
|
}
|
|
|
|
async addApplicableProducts(couponId: number, productIds: number[]): Promise<void> {
|
|
await db.insert(couponApplicableProducts).values(
|
|
productIds.map(productId => ({ couponId, productId }))
|
|
)
|
|
}
|
|
|
|
async removeAllApplicableUsers(couponId: number): Promise<void> {
|
|
await db.delete(couponApplicableUsers).where(eq(couponApplicableUsers.couponId, couponId))
|
|
}
|
|
|
|
async removeAllApplicableProducts(couponId: number): Promise<void> {
|
|
await db.delete(couponApplicableProducts).where(eq(couponApplicableProducts.couponId, couponId))
|
|
}
|
|
|
|
async countApplicableUsers(couponId: number): Promise<number> {
|
|
return db.$count(couponApplicableUsers, eq(couponApplicableUsers.couponId, couponId))
|
|
}
|
|
|
|
async createReservedCoupon(data: NewReservedCoupon): Promise<ReservedCoupon> {
|
|
const [coupon] = await db.insert(reservedCoupons).values(data).returning()
|
|
return coupon
|
|
}
|
|
|
|
async getReservedCoupons(options: { cursor?: number; limit: number; search?: string }): Promise<ReservedCoupon[]> {
|
|
const { cursor, limit, search } = options
|
|
|
|
let whereCondition = undefined
|
|
const conditions = []
|
|
|
|
if (cursor) {
|
|
conditions.push(lt(reservedCoupons.id, cursor))
|
|
}
|
|
|
|
if (search && search.trim()) {
|
|
conditions.push(or(
|
|
like(reservedCoupons.secretCode, `%${search}%`),
|
|
like(reservedCoupons.couponCode, `%${search}%`)
|
|
))
|
|
}
|
|
|
|
if (conditions.length > 0) {
|
|
whereCondition = and(...conditions)
|
|
}
|
|
|
|
return db.query.reservedCoupons.findMany({
|
|
where: whereCondition,
|
|
with: { redeemedUser: true, creator: true },
|
|
orderBy: (reservedCoupons, { desc }) => [desc(reservedCoupons.createdAt)],
|
|
limit: limit + 1,
|
|
})
|
|
}
|
|
|
|
async getUsersByIds(ids: number[]): Promise<Array<{ id: number; name: string | null; mobile: string | null }>> {
|
|
return db.query.users.findMany({
|
|
where: inArray(users.id, ids),
|
|
columns: { id: true, name: true, mobile: true },
|
|
})
|
|
}
|
|
|
|
async getUsersBySearch(search: string, limit: number, offset: number): Promise<Array<{ id: number; name: string | null; mobile: string | null }>> {
|
|
const whereCondition = or(
|
|
like(users.name, `%${search}%`),
|
|
like(users.mobile, `%${search}%`)
|
|
)
|
|
|
|
return db.query.users.findMany({
|
|
where: whereCondition,
|
|
columns: { id: true, name: true, mobile: true },
|
|
limit,
|
|
offset,
|
|
orderBy: (users, { asc }) => [asc(users.name)],
|
|
})
|
|
}
|
|
|
|
async createUser(data: Partial<typeof users.$inferInsert>): Promise<typeof users.$inferSelect> {
|
|
const [user] = await db.insert(users).values(data).returning()
|
|
return user
|
|
}
|
|
|
|
async getUserByMobile(mobile: string): Promise<typeof users.$inferSelect | undefined> {
|
|
return db.query.users.findFirst({
|
|
where: eq(users.mobile, mobile),
|
|
})
|
|
}
|
|
|
|
async getOrderByIdWithUserAndStatus(id: number): Promise<typeof orders.$inferSelect & { user?: typeof users.$inferSelect; orderStatus?: any[] } | undefined> {
|
|
return db.query.orders.findFirst({
|
|
where: eq(orders.id, id),
|
|
with: {
|
|
user: true,
|
|
orderStatus: true,
|
|
},
|
|
})
|
|
}
|
|
|
|
async updateOrderStatusRefundCoupon(orderId: number, couponId: number): Promise<void> {
|
|
await db.update(orderStatus)
|
|
.set({ refundCouponId: couponId })
|
|
.where(eq(orderStatus.orderId, orderId))
|
|
}
|
|
|
|
async withTransaction<T>(fn: (tx: any) => Promise<T>): Promise<T> {
|
|
return db.transaction(fn)
|
|
}
|
|
}
|
|
|
|
export const couponDbService: ICouponDbService = new CouponDbService()
|