From 86425dfca32151cd1499b9766d65c69d7e6ba1e1 Mon Sep 17 00:00:00 2001 From: NotARoomba Date: Wed, 4 Mar 2026 12:31:57 -0500 Subject: [PATCH] add in stuff --- backend/src/lib/scraps-payout.ts | 5 +++-- backend/src/lib/scraps.ts | 12 ++++++------ backend/src/routes/admin.ts | 3 ++- backend/src/schemas/index.ts | 2 +- backend/src/schemas/projects.ts | 1 + backend/src/schemas/shop.ts | 33 ++++++++++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/backend/src/lib/scraps-payout.ts b/backend/src/lib/scraps-payout.ts index 5f370a9..7009c65 100644 --- a/backend/src/lib/scraps-payout.ts +++ b/backend/src/lib/scraps-payout.ts @@ -110,11 +110,12 @@ export async function payoutPendingScraps(): Promise<{ paidCount: number; totalS const totalScraps = pendingProjects.reduce((sum, p) => sum + p.scrapsAwarded, 0) const uniqueUserIds = [...new Set(pendingProjects.map(p => p.userId))] - // Mark all pending projects as paid + // Mark all pending projects as paid and record the paid amount await db .update(projectsTable) .set({ - scrapsPaidAt: now + scrapsPaidAt: now, + scrapsPaidAmount: sql`${projectsTable.scrapsAwarded}` }) .where(inArray(projectsTable.id, projectIds)) diff --git a/backend/src/lib/scraps.ts b/backend/src/lib/scraps.ts index ff7c010..6a07a55 100644 --- a/backend/src/lib/scraps.ts +++ b/backend/src/lib/scraps.ts @@ -154,24 +154,24 @@ export async function getUserScrapsBalance( spent: number; balance: number; }> { - // Earned scraps: sum of scrapsAwarded for projects that have been paid out + // Earned scraps: sum of scrapsPaidAmount (what has actually been paid out per project) const earnedResult = await txOrDb .select({ - total: sql`COALESCE(SUM(${projectsTable.scrapsAwarded}), 0)`, + total: sql`COALESCE(SUM(${projectsTable.scrapsPaidAmount}), 0)`, }) .from(projectsTable) .where( - sql`${projectsTable.userId} = ${userId} AND ${projectsTable.scrapsPaidAt} IS NOT NULL`, + sql`${projectsTable.userId} = ${userId} AND ${projectsTable.scrapsPaidAmount} > 0`, ); - // Pending scraps: scrapsAwarded for shipped projects not yet paid out + // Pending scraps: the delta between scrapsAwarded and scrapsPaidAmount for shipped unpaid projects const pendingResult = await txOrDb .select({ - total: sql`COALESCE(SUM(${projectsTable.scrapsAwarded}), 0)`, + total: sql`COALESCE(SUM(${projectsTable.scrapsAwarded} - ${projectsTable.scrapsPaidAmount}), 0)`, }) .from(projectsTable) .where( - sql`${projectsTable.userId} = ${userId} AND ${projectsTable.status} = 'shipped' AND (${projectsTable.deleted} = 0 OR ${projectsTable.deleted} IS NULL) AND ${projectsTable.scrapsPaidAt} IS NULL AND ${projectsTable.scrapsAwarded} > 0`, + sql`${projectsTable.userId} = ${userId} AND ${projectsTable.status} = 'shipped' AND (${projectsTable.deleted} = 0 OR ${projectsTable.deleted} IS NULL) AND ${projectsTable.scrapsPaidAt} IS NULL AND ${projectsTable.scrapsAwarded} > ${projectsTable.scrapsPaidAmount}`, ); const bonusResult = await txOrDb diff --git a/backend/src/routes/admin.ts b/backend/src/routes/admin.ts index cb51c61..4eb9886 100644 --- a/backend/src/routes/admin.ts +++ b/backend/src/routes/admin.ts @@ -51,7 +51,7 @@ async function requireReviewer(headers: Record) { async function requireAdmin(headers: Record) { const user = await getUserFromSession(headers); if (!user) return null; - if (user.role !== "admin") return null; + if (user.role !== "admin" && user.role !== "creator") return null; return user; } @@ -3269,6 +3269,7 @@ admin.post( .set({ status: "in_progress", scrapsAwarded: 0, + scrapsPaidAmount: 0, scrapsPaidAt: null, updatedAt: new Date(), }) diff --git a/backend/src/schemas/index.ts b/backend/src/schemas/index.ts index 909b567..a9a9952 100644 --- a/backend/src/schemas/index.ts +++ b/backend/src/schemas/index.ts @@ -2,7 +2,7 @@ export { usersTable } from './users' export { projectsTable } from './projects' export { reviewsTable } from './reviews' export { sessionsTable } from './sessions' -export { shopItemsTable, shopHeartsTable, shopOrdersTable, shopRollsTable, refineryOrdersTable, shopPenaltiesTable, refinerySpendingHistoryTable } from './shop' +export { shopItemsTable, shopHeartsTable, shopOrdersTable, shopRollsTable, refineryOrdersTable, shopPenaltiesTable, refinerySpendingHistoryTable, adminDeletedOrdersTable } from './shop' export { newsTable } from './news' export { projectActivityTable } from './activity' export { userActivityTable } from './user-emails' diff --git a/backend/src/schemas/projects.ts b/backend/src/schemas/projects.ts index c89e049..ea3d212 100644 --- a/backend/src/schemas/projects.ts +++ b/backend/src/schemas/projects.ts @@ -20,6 +20,7 @@ export const projectsTable = pgTable('projects', { status: varchar().notNull().default('in_progress'), deleted: integer('deleted').default(0), scrapsAwarded: integer('scraps_awarded').notNull().default(0), + scrapsPaidAmount: integer('scraps_paid_amount').notNull().default(0), scrapsPaidAt: timestamp('scraps_paid_at'), views: integer().notNull().default(0), diff --git a/backend/src/schemas/shop.ts b/backend/src/schemas/shop.ts index beacbeb..ae4b788 100644 --- a/backend/src/schemas/shop.ts +++ b/backend/src/schemas/shop.ts @@ -7,6 +7,8 @@ import { unique, text, boolean, + jsonb, + index, } from "drizzle-orm/pg-core"; import { usersTable } from "./users"; @@ -128,3 +130,34 @@ export const refinerySpendingHistoryTable = pgTable( createdAt: timestamp("created_at").defaultNow().notNull(), }, ); + +export const adminDeletedOrdersTable = pgTable( + "admin_deleted_orders", + { + id: integer().primaryKey().generatedAlwaysAsIdentity(), + originalOrderId: integer("original_order_id").notNull(), + userId: integer("user_id").notNull(), + shopItemId: integer("shop_item_id"), + quantity: integer().notNull().default(1), + pricePerItem: integer("price_per_item").notNull(), + totalPrice: integer("total_price").notNull(), + status: varchar(), + orderType: varchar("order_type"), + shippingAddress: text("shipping_address"), + phone: varchar(), + itemName: varchar("item_name"), + createdAt: timestamp("created_at", { withTimezone: true }), + deletedBy: integer("deleted_by"), + deletedAt: timestamp("deleted_at", { withTimezone: true }).defaultNow().notNull(), + reason: text(), + deletedPayload: jsonb("deleted_payload"), + restored: boolean().notNull().default(false), + restoredBy: integer("restored_by"), + restoredAt: timestamp("restored_at", { withTimezone: true }), + }, + (table) => [ + index("idx_admin_deleted_orders_deleted_at").on(table.deletedAt), + index("idx_admin_deleted_orders_user_id").on(table.userId), + index("idx_admin_deleted_orders_original_order_id").on(table.originalOrderId), + ], +);