Files
tehran_taj/apps/api/scripts/seed-mock-orders.ts
s.esmaeiliandCursor afb068c643 feat: paginate customer orders and polish the dashboard hero
Add paged orders API and infinite scroll, short order numbers, and align the guest invite card with the logged-in hero shell.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-17 13:11:42 +03:30

200 lines
6.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Dev helper: seed >15 mock orders per OrderStatus so the Orders UI can be inspected.
* Run: npx tsx scripts/seed-mock-orders.ts
*/
import {
OrderChannel,
OrderStatus,
Prisma,
PrismaClient,
} from '@prisma/client'
const prisma = new PrismaClient()
const STATUSES: OrderStatus[] = [
OrderStatus.SUSPENDED,
OrderStatus.PLACED,
OrderStatus.ADMIN_APPROVED,
OrderStatus.SOURCING,
OrderStatus.PREPARING,
OrderStatus.DELIVERED_TO_AGENT,
OrderStatus.DELIVERED_TO_CUSTOMER,
OrderStatus.CANCELLED,
]
const PER_STATUS = 18
const TAG = 'MOCK-ORD'
function d(n: number | string) {
return new Prisma.Decimal(n)
}
function orderNumber(status: OrderStatus, i: number) {
// Unique, easy to spot/delete later
return `${TAG}-${status.slice(0, 4)}-${String(i).padStart(3, '0')}-${Date.now().toString(36)}`
}
async function main() {
const mobileOverride = process.env.MOCK_ORDERS_MOBILE?.trim()
const customer = mobileOverride
? await prisma.customer.findUnique({
where: { mobile: mobileOverride },
select: { id: true, mobile: true, fullName: true, referredByAgentId: true },
})
: await prisma.customer.findFirst({
orderBy: { updatedAt: 'desc' },
select: { id: true, mobile: true, fullName: true, referredByAgentId: true },
})
if (!customer) {
throw new Error(
mobileOverride
? `No customer with mobile=${mobileOverride}`
: 'No customers in DB — create/login a customer first',
)
}
const variants = await prisma.productVariant.findMany({
take: 30,
where: { isActive: true },
include: { product: { select: { title: true } } },
})
if (variants.length === 0) {
throw new Error('No product variants in DB — seed catalog first')
}
const branch = await prisma.branch.findFirst({ select: { id: true, name: true } })
console.log(
`Seeding ${PER_STATUS} orders × ${STATUSES.length} statuses for customer ${customer.mobile} (${customer.fullName}), ${variants.length} variants` +
(branch ? `, branch=${branch.name}` : ''),
)
let created = 0
for (const status of STATUSES) {
for (let i = 1; i <= PER_STATUS; i++) {
const variant = variants[i % variants.length]!
const qty = 1 + (i % 3)
const rash = Number(variant.rashWeightGrams ?? 1.25)
const wagePct = Number(variant.defaultWagePercent ?? 7)
const discountPct = 0
const computed = rash * (1 + (wagePct - discountPct) / 100)
const totalGold = computed * qty
const wageWeight = totalGold - rash * qty
const flatRial = i % 4 === 0 ? 150_000 * i : 0
const daysAgo = (STATUSES.indexOf(status) * PER_STATUS + i) % 40
const createdAt = new Date(Date.now() - daysAgo * 24 * 60 * 60 * 1000 - i * 60_000)
const deliveredAt =
status === OrderStatus.DELIVERED_TO_CUSTOMER
? new Date(createdAt.getTime() + 2 * 24 * 60 * 60 * 1000)
: null
// 1–2 line items so list/detail both look realistic
const second = variants[(i + 3) % variants.length]!
const useSecond = i % 3 === 0
const order = await prisma.order.create({
data: {
orderNumber: orderNumber(status, i),
customerId: customer.id,
branchId: branch?.id ?? null,
channel: i % 5 === 0 ? OrderChannel.WHOLESALE : OrderChannel.RETAIL,
status,
totalGoldWeightGrams: d(
(useSecond
? totalGold + Number(second.rashWeightGrams) * (1 + Number(second.defaultWagePercent) / 100)
: totalGold
).toFixed(4),
),
wageWeightGrams: d(Math.max(0, wageWeight).toFixed(4)),
flatRialCharge: d(flatRial),
isSuspendedOverCreditLimit: status === OrderStatus.SUSPENDED,
deliveredAt,
salesAgentId: customer.referredByAgentId ?? null,
createdAt,
updatedAt: createdAt,
items: {
create: [
{
productVariantId: variant.id,
quantity: qty,
rashWeightGramsSnapshot: d(rash.toFixed(4)),
wagePercentSnapshot: d(wagePct.toFixed(3)),
discountPercentSnapshot: d(discountPct.toFixed(3)),
computedWeightGrams: d(computed.toFixed(4)),
flatRialCharge: d(flatRial),
},
...(useSecond
? [
{
productVariantId: second.id,
quantity: 1,
rashWeightGramsSnapshot: d(Number(second.rashWeightGrams).toFixed(4)),
wagePercentSnapshot: d(Number(second.defaultWagePercent).toFixed(3)),
discountPercentSnapshot: d(0),
computedWeightGrams: d(
(
Number(second.rashWeightGrams) *
(1 + Number(second.defaultWagePercent) / 100)
).toFixed(4),
),
flatRialCharge: d(0),
},
]
: []),
],
},
statusEvents: {
create: [
{
fromStatus: null,
toStatus: OrderStatus.PLACED,
note: 'mock seed: placed',
createdAt,
},
...(status !== OrderStatus.PLACED
? [
{
fromStatus: OrderStatus.PLACED,
toStatus: status,
note: `mock seed: set to ${status}`,
createdAt: new Date(createdAt.getTime() + 60_000),
},
]
: []),
],
},
},
})
created++
if (i === 1) {
console.log(` ${status}: first=${order.orderNumber}`)
}
}
console.log(` ${status}: +${PER_STATUS}`)
}
const counts = await prisma.order.groupBy({
by: ['status'],
_count: { _all: true },
where: { orderNumber: { startsWith: TAG } },
})
console.log(`Done. Created ${created} mock orders (tag ${TAG}).`)
console.log(
'Mock counts:',
Object.fromEntries(counts.map((c) => [c.status, c._count._all])),
)
console.log(`Login as mobile ${customer.mobile} to see them in the app.`)
}
main()
.catch((e) => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})