compassmock/src/app/actions/customers.ts
Nicholai fbd31b58ae
feat(netsuite): add NetSuite integration and financials (#29)
* feat(schema): add auth, people, and financial tables

Add users, organizations, teams, groups, and project
members tables. Extend customers/vendors with netsuite
fields. Add netsuite schema for invoices, bills,
payments, and credit memos. Include all migrations,
seeds, new UI primitives, and config updates.

* feat(auth): add WorkOS authentication system

Add login, signup, password reset, email verification,
and invitation flows via WorkOS AuthKit. Includes auth
middleware, permission helpers, dev mode fallbacks,
and auth page components.

* feat(people): add people management system

Add user, team, group, and organization management
with CRUD actions, dashboard pages, invite dialog,
user drawer, and role-based filtering. Includes
WorkOS invitation integration.

* feat(netsuite): add NetSuite integration and financials

Add bidirectional NetSuite REST API integration with
OAuth 2.0, rate limiting, sync engine, and conflict
resolution. Includes invoices, vendor bills, payments,
credit memos CRUD, customer/vendor management pages,
and financial dashboard with tabbed views.

* ci: retrigger build

* fix: add mobile-list-card dependency for people-table

---------

Co-authored-by: Nicholai <nicholaivogelfilms@gmail.com>
2026-02-04 16:36:19 -07:00

115 lines
2.7 KiB
TypeScript
Executable File

"use server"
import { getCloudflareContext } from "@opennextjs/cloudflare"
import { eq } from "drizzle-orm"
import { getDb } from "@/db"
import { customers, type NewCustomer } from "@/db/schema"
import { getCurrentUser } from "@/lib/auth"
import { requirePermission } from "@/lib/permissions"
import { revalidatePath } from "next/cache"
export async function getCustomers() {
const user = await getCurrentUser()
requirePermission(user, "customer", "read")
const { env } = await getCloudflareContext()
const db = getDb(env.DB)
return db.select().from(customers)
}
export async function getCustomer(id: string) {
const user = await getCurrentUser()
requirePermission(user, "customer", "read")
const { env } = await getCloudflareContext()
const db = getDb(env.DB)
const rows = await db
.select()
.from(customers)
.where(eq(customers.id, id))
.limit(1)
return rows[0] ?? null
}
export async function createCustomer(
data: Omit<NewCustomer, "id" | "createdAt" | "updatedAt">
) {
try {
const user = await getCurrentUser()
requirePermission(user, "customer", "create")
const { env } = await getCloudflareContext()
const db = getDb(env.DB)
const now = new Date().toISOString()
const id = crypto.randomUUID()
await db.insert(customers).values({
id,
...data,
createdAt: now,
updatedAt: now,
})
revalidatePath("/dashboard/customers")
return { success: true, id }
} catch (err) {
return {
success: false,
error:
err instanceof Error ? err.message : "Failed to create customer",
}
}
}
export async function updateCustomer(
id: string,
data: Partial<NewCustomer>
) {
try {
const user = await getCurrentUser()
requirePermission(user, "customer", "update")
const { env } = await getCloudflareContext()
const db = getDb(env.DB)
await db
.update(customers)
.set({ ...data, updatedAt: new Date().toISOString() })
.where(eq(customers.id, id))
revalidatePath("/dashboard/customers")
return { success: true }
} catch (err) {
return {
success: false,
error:
err instanceof Error ? err.message : "Failed to update customer",
}
}
}
export async function deleteCustomer(id: string) {
try {
const user = await getCurrentUser()
requirePermission(user, "customer", "delete")
const { env } = await getCloudflareContext()
const db = getDb(env.DB)
await db.delete(customers).where(eq(customers.id, id))
revalidatePath("/dashboard/customers")
return { success: true }
} catch (err) {
return {
success: false,
error:
err instanceof Error ? err.message : "Failed to delete customer",
}
}
}