refactor(wholesale): split monolithic wholesale.ts into focused modules
The wholesale action set was a single 887-line file mixing 8 distinct concerns: shared types, brand-scoping helpers, order CRUD, customer CRUD, product CRUD, settings, deposits, notifications, and webhooks. Split into a wholesale/ directory with one file per concern plus a barrel re-export for backwards compatibility. New structure: - wholesale/types.ts — type definitions (no "use server") - wholesale/scope.ts — resolveBrandId, enforceBrandScope helpers - wholesale/orders.ts — order CRUD + dashboard stats (127 lines) - wholesale/customers.ts — customer CRUD (94) - wholesale/products.ts — product CRUD (100) - wholesale/settings.ts — wholesale_settings + public read (86) - wholesale/deposits.ts — deposits + bulk actions (84) - wholesale/notifications.ts — email/SMS notification queue (88) - wholesale/webhooks.ts — outbound webhook settings + dispatch (90) - wholesale/index.ts — barrel re-export (77 lines) Each module is now under 155 lines and topically cohesive. Existing imports of `@/actions/wholesale` keep working unchanged because of the barrel. New code can import directly from the focused module to keep its dep graph smaller. Notable small cleanups inside the split: - Removed two private helpers that enqueued webhooks by calling the RPC directly; consolidated on the public enqueueWholesaleWebhook export from webhooks.ts so orders.ts and deposits.ts no longer need fire-and-forget duplication. - recordWholesaleDeposit now correctly accepts the brandId parameter (the original signature lacked it despite the docstring implying it). Verified: tsc clean, 175/175 tests pass, dev server still compiles all routes. /wholesale/portal returns 500 due to a pre-existing brand-scope.ts "server-only" issue in the Pages Router chain — not introduced by this commit.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"use server";
|
||||
|
||||
import { pool } from "@/lib/db";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getActiveBrandId } from "@/lib/brand-scope";
|
||||
import { enqueueWholesaleWebhook } from "./webhooks";
|
||||
|
||||
export async function recordWholesaleDeposit(
|
||||
orderId: string,
|
||||
amount: number,
|
||||
method: string = "cash",
|
||||
reference?: string,
|
||||
brandId?: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const adminUser = await getAdminUser();
|
||||
if (!adminUser) return { success: false, error: "Not authenticated" };
|
||||
if (!adminUser.can_manage_orders) return { success: false, error: "Not authorized" };
|
||||
|
||||
const activeBrandId = await getActiveBrandId(adminUser, brandId);
|
||||
let data: { success?: boolean; error?: string } | null = null;
|
||||
try {
|
||||
const { rows } = await pool.query<{ success: boolean; error?: string }>(
|
||||
"SELECT * FROM record_wholesale_deposit($1, $2, $3, $4, $5, $6)",
|
||||
[orderId, amount, method, reference ?? null, adminUser.user_id, activeBrandId]
|
||||
);
|
||||
data = Array.isArray(rows) ? rows[0] : rows;
|
||||
if (!data?.success) {
|
||||
return { success: false, error: data?.error ?? "Failed to record deposit" };
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
return { success: false, error: e instanceof Error ? e.message : "Failed to record deposit" };
|
||||
}
|
||||
|
||||
// Fire webhook — fire-and-forget
|
||||
enqueueWholesaleWebhook("deposit_recorded", orderId, { order_id: orderId, amount }, activeBrandId ?? undefined).catch(() => {});
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
export async function bulkFulfillWholesaleOrders(
|
||||
orderIds: string[]
|
||||
): Promise<{ success: boolean; count?: number; error?: string }> {
|
||||
const adminUser = await getAdminUser();
|
||||
if (!adminUser) return { success: false, error: "Not authenticated" };
|
||||
if (!adminUser.can_manage_orders) return { success: false, error: "Not authorized" };
|
||||
|
||||
try {
|
||||
const { rows } = await pool.query<{ success: boolean; count?: number; error?: string }>(
|
||||
"SELECT * FROM bulk_fulfill_wholesale_orders($1, $2, $3)",
|
||||
[orderIds, adminUser.user_id, await getActiveBrandId(adminUser)]
|
||||
);
|
||||
const data = Array.isArray(rows) ? rows[0] : rows;
|
||||
if (!data?.success) {
|
||||
return { success: false, error: data?.error ?? "Failed to bulk fulfill orders" };
|
||||
}
|
||||
return { success: true, count: data.count };
|
||||
} catch (e: unknown) {
|
||||
return { success: false, error: e instanceof Error ? e.message : "Failed to bulk fulfill orders" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function bulkRecordWholesaleDeposit(
|
||||
orderIds: string[],
|
||||
amount: number,
|
||||
method: string = "cash",
|
||||
reference?: string
|
||||
): Promise<{ success: boolean; count?: number; error?: string }> {
|
||||
const adminUser = await getAdminUser();
|
||||
if (!adminUser) return { success: false, error: "Not authenticated" };
|
||||
if (!adminUser.can_manage_orders) return { success: false, error: "Not authorized" };
|
||||
|
||||
try {
|
||||
const { rows } = await pool.query<{ success: boolean; count?: number; error?: string }>(
|
||||
"SELECT * FROM bulk_record_wholesale_deposit($1, $2, $3, $4, $5, $6)",
|
||||
[orderIds, amount, method, reference ?? null, adminUser.user_id, await getActiveBrandId(adminUser)]
|
||||
);
|
||||
const data = Array.isArray(rows) ? rows[0] : rows;
|
||||
if (!data?.success) {
|
||||
return { success: false, error: data?.error ?? "Failed to bulk record deposits" };
|
||||
}
|
||||
return { success: true, count: data.count };
|
||||
} catch (e: unknown) {
|
||||
return { success: false, error: e instanceof Error ? e.message : "Failed to bulk record deposits" };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user