Files
order_site/apps/backend/src/repositories/order-repo.ts
T
2026-05-25 22:03:07 +08:00

233 lines
5.5 KiB
TypeScript

import { query } from '../db/client.js'
import type {
OrderCreateInput,
OrderListQueryInput,
OrderUpdateInput,
} from '../types/repository-inputs.js'
import type {
OrderListQueryResult,
OrderListRow,
OrderRow,
} from '../types/repository-rows.js'
type OrderPlatformLookupInput = {
provider?: string
platform: string
shopId?: string
platformOrderId: string
}
type OrderPlatformCandidateLookupInput = {
provider?: string
platform?: string
shopIds?: unknown[]
platformOrderId?: string
}
export async function findOrderByPlatformOrderId({
provider = '91kaquan',
platform,
shopId = '',
platformOrderId,
}: OrderPlatformLookupInput): Promise<OrderRow | null> {
const result = await query<OrderRow>(
`
SELECT *
FROM orders
WHERE provider = $1 AND platform = $2 AND shop_id = $3 AND platform_order_id = $4
LIMIT 1
`,
[provider, platform, shopId, platformOrderId],
)
return result.rows[0] || null
}
export async function findOrderByPlatformOrderIdCandidates({
provider = '91kaquan',
platform,
shopIds = [],
platformOrderId,
}: OrderPlatformCandidateLookupInput): Promise<OrderRow | null> {
const normalizedShopIds = [...new Set((Array.isArray(shopIds) ? shopIds : [])
.map((item) => String(item || '').trim())
.filter(Boolean))]
if (!platform || !platformOrderId || normalizedShopIds.length === 0) {
return null
}
const result = await query<OrderRow>(
`
SELECT *
FROM orders
WHERE provider = $1 AND platform = $2 AND shop_id = ANY($3::text[]) AND platform_order_id = $4
ORDER BY id DESC
LIMIT 1
`,
[provider, platform, normalizedShopIds, platformOrderId],
)
return result.rows[0] || null
}
export async function createOrder(input: OrderCreateInput): Promise<OrderRow | null> {
const result = await query<OrderRow>(
`
INSERT INTO orders (
provider,
platform,
shop_id,
shop_name,
platform_order_id,
order_status,
pay_status,
buyer_id,
buyer_name,
receiver_contact,
total_amount,
currency,
raw_payload_json,
paid_at,
created_at,
updated_at
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13::jsonb, $14, $15, $16)
RETURNING *
`,
[
input.provider,
input.platform,
input.shopId,
input.shopName,
input.platformOrderId,
input.orderStatus,
input.payStatus,
input.buyerId,
input.buyerName,
input.receiverContact,
input.totalAmount,
input.currency,
input.rawPayloadJson || '{}',
input.paidAt || null,
input.createdAt,
input.updatedAt,
],
)
return result.rows[0] || null
}
export async function updateOrder(orderId: number | string, input: OrderUpdateInput): Promise<OrderRow | null> {
const result = await query<OrderRow>(
`
UPDATE orders
SET
provider = $1,
platform = $2,
shop_id = $3,
shop_name = $4,
order_status = $5,
pay_status = $6,
buyer_id = $7,
buyer_name = $8,
receiver_contact = $9,
total_amount = $10,
currency = $11,
raw_payload_json = $12::jsonb,
paid_at = $13,
updated_at = $14
WHERE id = $15
RETURNING *
`,
[
input.provider,
input.platform,
input.shopId,
input.shopName,
input.orderStatus,
input.payStatus,
input.buyerId,
input.buyerName,
input.receiverContact,
input.totalAmount,
input.currency,
input.rawPayloadJson || '{}',
input.paidAt || null,
input.updatedAt,
Number(orderId),
],
)
return result.rows[0] || null
}
export async function getOrderById(orderId: number | string): Promise<OrderRow | null> {
const result = await query<OrderRow>('SELECT * FROM orders WHERE id = $1 LIMIT 1', [Number(orderId)])
return result.rows[0] || null
}
export async function listOrders({
page = 1,
pageSize = 20,
platformOrderId = '',
payStatus = '',
skuCode = '',
dateFrom = '',
dateTo = '',
}: OrderListQueryInput = {}): Promise<OrderListQueryResult> {
const offset = (page - 1) * pageSize
const filters: string[] = []
const params: unknown[] = []
if (platformOrderId) {
params.push(`%${platformOrderId}%`)
filters.push(`o.platform_order_id ILIKE $${params.length}`)
}
if (payStatus) {
params.push(payStatus)
filters.push(`o.pay_status = $${params.length}`)
}
if (skuCode) {
params.push(skuCode)
filters.push(`EXISTS (SELECT 1 FROM order_items oi WHERE oi.order_id = o.id AND oi.sku_code = $${params.length})`)
}
if (dateFrom) {
params.push(dateFrom)
filters.push(`o.created_at >= $${params.length}`)
}
if (dateTo) {
params.push(dateTo)
filters.push(`o.created_at <= $${params.length}`)
}
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
const totalResult = await query<{ [column: string]: unknown, total: number }>(
`SELECT COUNT(*)::int AS total FROM orders o ${whereClause}`,
params,
)
params.push(pageSize)
params.push(offset)
const itemsResult = await query<OrderListRow>(
`
SELECT
o.*,
(SELECT COUNT(*)::int FROM fulfillment_tasks ft WHERE ft.order_id = o.id) AS task_count
FROM orders o
${whereClause}
ORDER BY o.id DESC
LIMIT $${params.length - 1} OFFSET $${params.length}
`,
params,
)
return {
items: itemsResult.rows,
total: Number(totalResult.rows[0]?.total || 0),
}
}