* 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>
115 lines
2.7 KiB
TypeScript
Executable File
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",
|
|
}
|
|
}
|
|
}
|