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 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))

View file

@ -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<number>`COALESCE(SUM(${projectsTable.scrapsAwarded}), 0)`,
total: sql<number>`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<number>`COALESCE(SUM(${projectsTable.scrapsAwarded}), 0)`,
total: sql<number>`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

View file

@ -51,7 +51,7 @@ async function requireReviewer(headers: Record<string, string>) {
async function requireAdmin(headers: Record<string, string>) {
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(),
})

View file

@ -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'

View file

@ -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),

View file

@ -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),
],
);