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>
This commit is contained in:
@@ -135,13 +135,29 @@ export class OrdersService {
|
||||
.gt(customer.goldCreditLimitGrams);
|
||||
const initialStatus = isSuspendedOverCreditLimit ? OrderStatus.SUSPENDED : OrderStatus.PLACED;
|
||||
|
||||
// App (B2B) orders are always WHOLESALE. Legacy wrote them to `orders`,
|
||||
// not `orders_orders` (RETAIL). The DTO default was RETAIL and the apps
|
||||
// never sent `channel`, so every app order landed on the retail list.
|
||||
// Operators still pick the channel (admin MakeOrder forces WHOLESALE;
|
||||
// the retail list builder can pass RETAIL). A client-supplied channel on
|
||||
// the customer path is ignored — same posture as MON-08 pricing.
|
||||
const channel =
|
||||
opts.placedBy === 'customer'
|
||||
? OrderChannel.WHOLESALE
|
||||
: (dto.channel ?? OrderChannel.RETAIL);
|
||||
if (opts.placedBy === 'customer' && dto.channel && dto.channel !== OrderChannel.WHOLESALE) {
|
||||
this.logger.warn(
|
||||
`Order body carried channel=${dto.channel} from the app; forcing WHOLESALE.`,
|
||||
);
|
||||
}
|
||||
|
||||
const placed = await this.prisma.$transaction(async (tx) => {
|
||||
const order = await tx.order.create({
|
||||
data: {
|
||||
orderNumber: this.generateOrderNumber(),
|
||||
orderNumber: await this.nextOrderNumber(tx),
|
||||
customerId,
|
||||
branchId: dto.branchId,
|
||||
channel: dto.channel ?? OrderChannel.RETAIL,
|
||||
channel,
|
||||
status: initialStatus,
|
||||
totalGoldWeightGrams,
|
||||
wageWeightGrams,
|
||||
@@ -360,8 +376,21 @@ export class OrdersService {
|
||||
return order;
|
||||
}
|
||||
|
||||
private generateOrderNumber(): string {
|
||||
const random = Math.random().toString(36).slice(2, 8).toUpperCase();
|
||||
return `ORD-${Date.now()}-${random}`;
|
||||
/**
|
||||
* Short global sequential number for the customer, SMS and search
|
||||
* (`100`, `101`, …). Allocated from Postgres `order_number_seq` inside the
|
||||
* placement transaction so concurrent creates cannot collide. Legacy used
|
||||
* the auto-increment order id the same way; the old `ORD-{ts}-{rand}` form
|
||||
* was too long for SMS and the list UI.
|
||||
*/
|
||||
private async nextOrderNumber(tx: Prisma.TransactionClient): Promise<string> {
|
||||
const rows = await tx.$queryRaw<Array<{ n: bigint | number | string }>>`
|
||||
SELECT nextval('order_number_seq') AS n
|
||||
`;
|
||||
const n = rows[0]?.n;
|
||||
if (n === undefined || n === null) {
|
||||
throw new Error('order_number_seq returned no value');
|
||||
}
|
||||
return String(n);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user