- category table with hierarchical parent_id, sort ordering, soft-delete - supplier table with contact info, account number, payment terms - CRUD routes for both with search on suppliers - Zod validation schemas in @forte/shared - Products will link to suppliers via join table (many-to-many) - 26 tests passing
110 lines
3.4 KiB
TypeScript
110 lines
3.4 KiB
TypeScript
import { eq, and, ilike } from 'drizzle-orm'
|
|
import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'
|
|
import { categories, suppliers } from '../db/schema/inventory.js'
|
|
import type {
|
|
CategoryCreateInput,
|
|
CategoryUpdateInput,
|
|
SupplierCreateInput,
|
|
SupplierUpdateInput,
|
|
} from '@forte/shared/schemas'
|
|
|
|
export const CategoryService = {
|
|
async create(db: PostgresJsDatabase, companyId: string, input: CategoryCreateInput) {
|
|
const [category] = await db
|
|
.insert(categories)
|
|
.values({ companyId, ...input })
|
|
.returning()
|
|
return category
|
|
},
|
|
|
|
async getById(db: PostgresJsDatabase, companyId: string, id: string) {
|
|
const [category] = await db
|
|
.select()
|
|
.from(categories)
|
|
.where(and(eq(categories.id, id), eq(categories.companyId, companyId)))
|
|
.limit(1)
|
|
return category ?? null
|
|
},
|
|
|
|
async list(db: PostgresJsDatabase, companyId: string) {
|
|
return db
|
|
.select()
|
|
.from(categories)
|
|
.where(and(eq(categories.companyId, companyId), eq(categories.isActive, true)))
|
|
.orderBy(categories.sortOrder)
|
|
},
|
|
|
|
async update(db: PostgresJsDatabase, companyId: string, id: string, input: CategoryUpdateInput) {
|
|
const [category] = await db
|
|
.update(categories)
|
|
.set({ ...input, updatedAt: new Date() })
|
|
.where(and(eq(categories.id, id), eq(categories.companyId, companyId)))
|
|
.returning()
|
|
return category ?? null
|
|
},
|
|
|
|
async softDelete(db: PostgresJsDatabase, companyId: string, id: string) {
|
|
const [category] = await db
|
|
.update(categories)
|
|
.set({ isActive: false, updatedAt: new Date() })
|
|
.where(and(eq(categories.id, id), eq(categories.companyId, companyId)))
|
|
.returning()
|
|
return category ?? null
|
|
},
|
|
}
|
|
|
|
export const SupplierService = {
|
|
async create(db: PostgresJsDatabase, companyId: string, input: SupplierCreateInput) {
|
|
const [supplier] = await db
|
|
.insert(suppliers)
|
|
.values({ companyId, ...input })
|
|
.returning()
|
|
return supplier
|
|
},
|
|
|
|
async getById(db: PostgresJsDatabase, companyId: string, id: string) {
|
|
const [supplier] = await db
|
|
.select()
|
|
.from(suppliers)
|
|
.where(and(eq(suppliers.id, id), eq(suppliers.companyId, companyId)))
|
|
.limit(1)
|
|
return supplier ?? null
|
|
},
|
|
|
|
async list(db: PostgresJsDatabase, companyId: string) {
|
|
return db
|
|
.select()
|
|
.from(suppliers)
|
|
.where(and(eq(suppliers.companyId, companyId), eq(suppliers.isActive, true)))
|
|
},
|
|
|
|
async search(db: PostgresJsDatabase, companyId: string, query: string) {
|
|
const pattern = `%${query}%`
|
|
return db
|
|
.select()
|
|
.from(suppliers)
|
|
.where(
|
|
and(eq(suppliers.companyId, companyId), eq(suppliers.isActive, true), ilike(suppliers.name, pattern)),
|
|
)
|
|
.limit(50)
|
|
},
|
|
|
|
async update(db: PostgresJsDatabase, companyId: string, id: string, input: SupplierUpdateInput) {
|
|
const [supplier] = await db
|
|
.update(suppliers)
|
|
.set({ ...input, updatedAt: new Date() })
|
|
.where(and(eq(suppliers.id, id), eq(suppliers.companyId, companyId)))
|
|
.returning()
|
|
return supplier ?? null
|
|
},
|
|
|
|
async softDelete(db: PostgresJsDatabase, companyId: string, id: string) {
|
|
const [supplier] = await db
|
|
.update(suppliers)
|
|
.set({ isActive: false, updatedAt: new Date() })
|
|
.where(and(eq(suppliers.id, id), eq(suppliers.companyId, companyId)))
|
|
.returning()
|
|
return supplier ?? null
|
|
},
|
|
}
|