add in stuff

This commit is contained in:
NotARoomba 2026-03-04 12:31:57 -05:00
parent fea18cf0ed
commit 86425dfca3
6 changed files with 46 additions and 10 deletions

View file

@ -110,11 +110,12 @@ export async function payoutPendingScraps(): Promise<{ paidCount: number; totalS
const totalScraps = pendingProjects.reduce((sum, p) => sum + p.scrapsAwarded, 0) const totalScraps = pendingProjects.reduce((sum, p) => sum + p.scrapsAwarded, 0)
const uniqueUserIds = [...new Set(pendingProjects.map(p => p.userId))] 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 await db
.update(projectsTable) .update(projectsTable)
.set({ .set({
scrapsPaidAt: now scrapsPaidAt: now,
scrapsPaidAmount: sql`${projectsTable.scrapsAwarded}`
}) })
.where(inArray(projectsTable.id, projectIds)) .where(inArray(projectsTable.id, projectIds))

View file

@ -154,24 +154,24 @@ export async function getUserScrapsBalance(
spent: number; spent: number;
balance: 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 const earnedResult = await txOrDb
.select({ .select({
total: sql<number>`COALESCE(SUM(${projectsTable.scrapsAwarded}), 0)`, total: sql<number>`COALESCE(SUM(${projectsTable.scrapsPaidAmount}), 0)`,
}) })
.from(projectsTable) .from(projectsTable)
.where( .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 const pendingResult = await txOrDb
.select({ .select({
total: sql<number>`COALESCE(SUM(${projectsTable.scrapsAwarded}), 0)`, total: sql<number>`COALESCE(SUM(${projectsTable.scrapsAwarded} - ${projectsTable.scrapsPaidAmount}), 0)`,
}) })
.from(projectsTable) .from(projectsTable)
.where( .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 const bonusResult = await txOrDb

View file

@ -51,7 +51,7 @@ async function requireReviewer(headers: Record<string, string>) {
async function requireAdmin(headers: Record<string, string>) { async function requireAdmin(headers: Record<string, string>) {
const user = await getUserFromSession(headers); const user = await getUserFromSession(headers);
if (!user) return null; if (!user) return null;
if (user.role !== "admin") return null; if (user.role !== "admin" && user.role !== "creator") return null;
return user; return user;
} }
@ -3269,6 +3269,7 @@ admin.post(
.set({ .set({
status: "in_progress", status: "in_progress",
scrapsAwarded: 0, scrapsAwarded: 0,
scrapsPaidAmount: 0,
scrapsPaidAt: null, scrapsPaidAt: null,
updatedAt: new Date(), updatedAt: new Date(),
}) })

View file

@ -2,7 +2,7 @@ export { usersTable } from './users'
export { projectsTable } from './projects' export { projectsTable } from './projects'
export { reviewsTable } from './reviews' export { reviewsTable } from './reviews'
export { sessionsTable } from './sessions' 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 { newsTable } from './news'
export { projectActivityTable } from './activity' export { projectActivityTable } from './activity'
export { userActivityTable } from './user-emails' export { userActivityTable } from './user-emails'

View file

@ -20,6 +20,7 @@ export const projectsTable = pgTable('projects', {
status: varchar().notNull().default('in_progress'), status: varchar().notNull().default('in_progress'),
deleted: integer('deleted').default(0), deleted: integer('deleted').default(0),
scrapsAwarded: integer('scraps_awarded').notNull().default(0), scrapsAwarded: integer('scraps_awarded').notNull().default(0),
scrapsPaidAmount: integer('scraps_paid_amount').notNull().default(0),
scrapsPaidAt: timestamp('scraps_paid_at'), scrapsPaidAt: timestamp('scraps_paid_at'),
views: integer().notNull().default(0), views: integer().notNull().default(0),

View file

@ -7,6 +7,8 @@ import {
unique, unique,
text, text,
boolean, boolean,
jsonb,
index,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import { usersTable } from "./users"; import { usersTable } from "./users";
@ -128,3 +130,34 @@ export const refinerySpendingHistoryTable = pgTable(
createdAt: timestamp("created_at").defaultNow().notNull(), 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),
],
);