refactor: rename Recipient to Person, remove username, add userId FK
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type {
|
||||
PrismaClient,
|
||||
RecipientDepartment,
|
||||
PersonDepartment,
|
||||
UserRole,
|
||||
} from "@/generated/prisma/client"
|
||||
|
||||
@@ -48,24 +48,22 @@ export async function createTestCategory(
|
||||
})
|
||||
}
|
||||
|
||||
export async function createTestRecipient(
|
||||
export async function createTestPerson(
|
||||
prisma: PrismaClient,
|
||||
overrides: Partial<{
|
||||
username: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
department: RecipientDepartment
|
||||
department: PersonDepartment
|
||||
email: string | null
|
||||
phone: string | null
|
||||
}> = {},
|
||||
) {
|
||||
const suffix = nextSuffix()
|
||||
|
||||
return prisma.recipient.create({
|
||||
return prisma.person.create({
|
||||
data: {
|
||||
username: overrides.username ?? `test-recipient-${suffix}`,
|
||||
firstName: overrides.firstName ?? "Test",
|
||||
lastName: overrides.lastName ?? "Recipient",
|
||||
lastName: overrides.lastName ?? `Person-${suffix}`,
|
||||
department: overrides.department ?? "OTHER",
|
||||
email: overrides.email ?? null,
|
||||
phone: overrides.phone ?? null,
|
||||
@@ -92,4 +90,4 @@ export async function createTestItem(
|
||||
category: { connect: { id: categoryId } },
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ const TABLES_TO_TRUNCATE = [
|
||||
"Asset",
|
||||
"Item",
|
||||
"Category",
|
||||
"Recipient",
|
||||
"Person",
|
||||
"User",
|
||||
]
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
|
||||
import type { PrismaClient } from "@/generated/prisma/client"
|
||||
import {
|
||||
createTestItem,
|
||||
createTestRecipient,
|
||||
createTestPerson,
|
||||
createTestUser,
|
||||
} from "../helpers/factories"
|
||||
import {
|
||||
@@ -80,7 +80,7 @@ describe("asset use-cases", () => {
|
||||
|
||||
it("creates an assigned asset with assignment and ASSIGNMENT movement", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 0 })
|
||||
|
||||
const result = await createAssetUseCase({
|
||||
@@ -133,7 +133,7 @@ describe("asset use-cases", () => {
|
||||
|
||||
it("moves an available asset to assigned and back to available", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 0 })
|
||||
|
||||
const created = await createAssetUseCase({
|
||||
@@ -230,7 +230,7 @@ describe("asset use-cases", () => {
|
||||
|
||||
it("returns an active assignment without restoring stock when an assigned asset moves to a terminal status", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 0 })
|
||||
|
||||
const created = await createAssetUseCase({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
|
||||
import type { PrismaClient } from "@/generated/prisma/client"
|
||||
import {
|
||||
createTestItem,
|
||||
createTestRecipient,
|
||||
createTestPerson,
|
||||
createTestUser,
|
||||
} from "../helpers/factories"
|
||||
import {
|
||||
@@ -38,7 +38,7 @@ afterAll(async () => {
|
||||
describe("assignment use-cases", () => {
|
||||
it("creates an assignment, decrements stock, and records an ASSIGNMENT movement", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 5 })
|
||||
|
||||
const assignmentDate = new Date("2026-01-01T00:00:00.000Z")
|
||||
@@ -88,7 +88,7 @@ describe("assignment use-cases", () => {
|
||||
|
||||
it("rejects assignment creation when item stock is insufficient", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 1 })
|
||||
|
||||
const result = await createAssignmentUseCase({
|
||||
@@ -114,7 +114,7 @@ describe("assignment use-cases", () => {
|
||||
|
||||
it("returns an assignment, restores stock, closes it, and records a RETURN movement", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 4 })
|
||||
|
||||
const created = await createAssignmentUseCase({
|
||||
@@ -172,7 +172,7 @@ describe("assignment use-cases", () => {
|
||||
|
||||
it("rejects returning the same assignment twice", async () => {
|
||||
const actor = await createTestUser(prisma)
|
||||
const recipient = await createTestRecipient(prisma)
|
||||
const recipient = await createTestPerson(prisma)
|
||||
const item = await createTestItem(prisma, { stock: 2 })
|
||||
|
||||
const created = await createAssignmentUseCase({
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
|
||||
import type { PrismaClient } from "@/generated/prisma/client"
|
||||
import { createTestPerson, createTestUser } from "../helpers/factories"
|
||||
import {
|
||||
resetIntegrationTestDatabase,
|
||||
startIntegrationTestDatabase,
|
||||
stopIntegrationTestDatabase,
|
||||
} from "../helpers/test-db"
|
||||
|
||||
let prisma: PrismaClient
|
||||
let createPersonUseCase: typeof import("@/use-cases/person.use-cases").createPersonUseCase
|
||||
let updatePersonUseCase: typeof import("@/use-cases/person.use-cases").updatePersonUseCase
|
||||
|
||||
beforeAll(async () => {
|
||||
await startIntegrationTestDatabase()
|
||||
|
||||
const prismaModule = await import("@/lib/prisma")
|
||||
const personUseCases = await import("@/use-cases/person.use-cases")
|
||||
|
||||
prisma = prismaModule.prisma
|
||||
createPersonUseCase = personUseCases.createPersonUseCase
|
||||
updatePersonUseCase = personUseCases.updatePersonUseCase
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
await resetIntegrationTestDatabase(prisma)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma?.$disconnect()
|
||||
await stopIntegrationTestDatabase()
|
||||
})
|
||||
|
||||
describe("person use-cases", () => {
|
||||
it("creates a person and normalizes empty optional contact fields to null", async () => {
|
||||
await expect(
|
||||
createPersonUseCase({
|
||||
firstName: "Person",
|
||||
lastName: "One",
|
||||
department: "IT",
|
||||
email: "",
|
||||
phone: "",
|
||||
}),
|
||||
).resolves.toEqual({ success: true })
|
||||
|
||||
await expect(
|
||||
prisma.person.findFirstOrThrow({
|
||||
where: { firstName: "Person", lastName: "One" },
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
firstName: "Person",
|
||||
lastName: "One",
|
||||
department: "IT",
|
||||
email: null,
|
||||
phone: null,
|
||||
userId: null,
|
||||
})
|
||||
})
|
||||
|
||||
it("creates a person with linked userId", async () => {
|
||||
const user = await createTestUser(prisma)
|
||||
|
||||
await expect(
|
||||
createPersonUseCase({
|
||||
firstName: "Linked",
|
||||
lastName: "Person",
|
||||
department: "ENGINEERING",
|
||||
email: "linked@example.test",
|
||||
phone: null,
|
||||
userId: user.id,
|
||||
}),
|
||||
).resolves.toEqual({ success: true })
|
||||
|
||||
await expect(
|
||||
prisma.person.findFirstOrThrow({
|
||||
where: { firstName: "Linked" },
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
firstName: "Linked",
|
||||
lastName: "Person",
|
||||
department: "ENGINEERING",
|
||||
email: "linked@example.test",
|
||||
userId: user.id,
|
||||
})
|
||||
})
|
||||
|
||||
it("rejects duplicate emails on create", async () => {
|
||||
await createTestPerson(prisma, {
|
||||
email: "existing@example.test",
|
||||
})
|
||||
|
||||
await expect(
|
||||
createPersonUseCase({
|
||||
firstName: "Duplicate",
|
||||
lastName: "Email",
|
||||
department: "OTHER",
|
||||
email: "existing@example.test",
|
||||
phone: null,
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
success: false,
|
||||
errors: { email: ["Email already exists"] },
|
||||
})
|
||||
|
||||
await expect(prisma.person.count()).resolves.toBe(1)
|
||||
})
|
||||
|
||||
it("updates a person and rejects duplicate emails", async () => {
|
||||
const person = await createTestPerson(prisma, {
|
||||
email: "person@example.test",
|
||||
phone: "111111111",
|
||||
})
|
||||
const other = await createTestPerson(prisma, {
|
||||
email: "other@example.test",
|
||||
})
|
||||
|
||||
await expect(
|
||||
updatePersonUseCase({
|
||||
id: person.id,
|
||||
firstName: "Edited",
|
||||
lastName: "Person",
|
||||
department: "ENGINEERING",
|
||||
email: "edited@example.test",
|
||||
phone: "222222222",
|
||||
}),
|
||||
).resolves.toEqual({ success: true })
|
||||
|
||||
await expect(
|
||||
prisma.person.findUniqueOrThrow({ where: { id: person.id } }),
|
||||
).resolves.toMatchObject({
|
||||
firstName: "Edited",
|
||||
lastName: "Person",
|
||||
department: "ENGINEERING",
|
||||
email: "edited@example.test",
|
||||
phone: "222222222",
|
||||
})
|
||||
|
||||
await expect(
|
||||
updatePersonUseCase({
|
||||
id: person.id,
|
||||
firstName: "Edited",
|
||||
lastName: "Person",
|
||||
department: "ENGINEERING",
|
||||
email: other.email,
|
||||
phone: "222222222",
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
success: false,
|
||||
errors: { email: ["Email already exists"] },
|
||||
})
|
||||
|
||||
await expect(
|
||||
prisma.person.findUniqueOrThrow({ where: { id: person.id } }),
|
||||
).resolves.toMatchObject({
|
||||
email: "edited@example.test",
|
||||
})
|
||||
await expect(prisma.person.count()).resolves.toBe(2)
|
||||
})
|
||||
|
||||
it("searches by email and name in paginated results", async () => {
|
||||
await createTestPerson(prisma, {
|
||||
firstName: "Alice",
|
||||
lastName: "Smith",
|
||||
email: "alice@company.com",
|
||||
})
|
||||
await createTestPerson(prisma, {
|
||||
firstName: "Bob",
|
||||
lastName: "Jones",
|
||||
email: "bob@other.com",
|
||||
})
|
||||
|
||||
const { PersonService } = await import("@/services/person.service")
|
||||
|
||||
const emailResults = await PersonService.findAllPaginated({
|
||||
search: "company",
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
expect(emailResults.data).toHaveLength(1)
|
||||
expect(emailResults.data[0].firstName).toBe("Alice")
|
||||
|
||||
const nameResults = await PersonService.findAllPaginated({
|
||||
search: "Bob",
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
expect(nameResults.data).toHaveLength(1)
|
||||
expect(nameResults.data[0].firstName).toBe("Bob")
|
||||
})
|
||||
})
|
||||
@@ -1,170 +0,0 @@
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"
|
||||
import type { PrismaClient } from "@/generated/prisma/client"
|
||||
import { createTestRecipient } from "../helpers/factories"
|
||||
import {
|
||||
resetIntegrationTestDatabase,
|
||||
startIntegrationTestDatabase,
|
||||
stopIntegrationTestDatabase,
|
||||
} from "../helpers/test-db"
|
||||
|
||||
let prisma: PrismaClient
|
||||
let createRecipientUseCase: typeof import("@/use-cases/recipient.use-cases").createRecipientUseCase
|
||||
let updateRecipientUseCase: typeof import("@/use-cases/recipient.use-cases").updateRecipientUseCase
|
||||
|
||||
beforeAll(async () => {
|
||||
await startIntegrationTestDatabase()
|
||||
|
||||
const prismaModule = await import("@/lib/prisma")
|
||||
const recipientUseCases = await import("@/use-cases/recipient.use-cases")
|
||||
|
||||
prisma = prismaModule.prisma
|
||||
createRecipientUseCase = recipientUseCases.createRecipientUseCase
|
||||
updateRecipientUseCase = recipientUseCases.updateRecipientUseCase
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
await resetIntegrationTestDatabase(prisma)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma?.$disconnect()
|
||||
await stopIntegrationTestDatabase()
|
||||
})
|
||||
|
||||
describe("recipient use-cases", () => {
|
||||
it("creates a recipient and normalizes empty optional contact fields to null", async () => {
|
||||
await expect(
|
||||
createRecipientUseCase({
|
||||
username: "recipient-one",
|
||||
firstName: "Recipient",
|
||||
lastName: "One",
|
||||
department: "IT",
|
||||
email: "",
|
||||
phone: "",
|
||||
}),
|
||||
).resolves.toEqual({ success: true })
|
||||
|
||||
await expect(
|
||||
prisma.recipient.findUniqueOrThrow({
|
||||
where: { username: "recipient-one" },
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
username: "recipient-one",
|
||||
firstName: "Recipient",
|
||||
lastName: "One",
|
||||
department: "IT",
|
||||
email: null,
|
||||
phone: null,
|
||||
})
|
||||
})
|
||||
|
||||
it("rejects duplicate usernames and duplicate emails on create", async () => {
|
||||
await createTestRecipient(prisma, {
|
||||
username: "existing-recipient",
|
||||
email: "existing-recipient@example.test",
|
||||
})
|
||||
|
||||
await expect(
|
||||
createRecipientUseCase({
|
||||
username: "existing-recipient",
|
||||
firstName: "Duplicate",
|
||||
lastName: "Username",
|
||||
department: "OTHER",
|
||||
email: "unique-recipient@example.test",
|
||||
phone: null,
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
success: false,
|
||||
errors: { username: ["Username already exists"] },
|
||||
})
|
||||
|
||||
await expect(
|
||||
createRecipientUseCase({
|
||||
username: "unique-recipient",
|
||||
firstName: "Duplicate",
|
||||
lastName: "Email",
|
||||
department: "OTHER",
|
||||
email: "existing-recipient@example.test",
|
||||
phone: null,
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
success: false,
|
||||
errors: { email: ["Email already exists"] },
|
||||
})
|
||||
|
||||
await expect(prisma.recipient.count()).resolves.toBe(1)
|
||||
})
|
||||
|
||||
it("updates a recipient and rejects duplicate usernames or emails", async () => {
|
||||
const recipient = await createTestRecipient(prisma, {
|
||||
username: "editable-recipient",
|
||||
email: "editable-recipient@example.test",
|
||||
phone: "111111111",
|
||||
})
|
||||
const other = await createTestRecipient(prisma, {
|
||||
username: "other-recipient",
|
||||
email: "other-recipient@example.test",
|
||||
})
|
||||
|
||||
await expect(
|
||||
updateRecipientUseCase({
|
||||
id: recipient.id,
|
||||
username: "edited-recipient",
|
||||
firstName: "Edited",
|
||||
lastName: "Recipient",
|
||||
department: "ENGINEERING",
|
||||
email: "edited-recipient@example.test",
|
||||
phone: "222222222",
|
||||
}),
|
||||
).resolves.toEqual({ success: true })
|
||||
|
||||
await expect(
|
||||
prisma.recipient.findUniqueOrThrow({ where: { id: recipient.id } }),
|
||||
).resolves.toMatchObject({
|
||||
username: "edited-recipient",
|
||||
firstName: "Edited",
|
||||
lastName: "Recipient",
|
||||
department: "ENGINEERING",
|
||||
email: "edited-recipient@example.test",
|
||||
phone: "222222222",
|
||||
})
|
||||
|
||||
await expect(
|
||||
updateRecipientUseCase({
|
||||
id: recipient.id,
|
||||
username: other.username,
|
||||
firstName: "Edited",
|
||||
lastName: "Recipient",
|
||||
department: "ENGINEERING",
|
||||
email: "new-recipient@example.test",
|
||||
phone: "222222222",
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
success: false,
|
||||
errors: { username: ["Username already exists"] },
|
||||
})
|
||||
|
||||
await expect(
|
||||
updateRecipientUseCase({
|
||||
id: recipient.id,
|
||||
username: "edited-recipient",
|
||||
firstName: "Edited",
|
||||
lastName: "Recipient",
|
||||
department: "ENGINEERING",
|
||||
email: other.email,
|
||||
phone: "222222222",
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
success: false,
|
||||
errors: { email: ["Email already exists"] },
|
||||
})
|
||||
|
||||
await expect(
|
||||
prisma.recipient.findUniqueOrThrow({ where: { id: recipient.id } }),
|
||||
).resolves.toMatchObject({
|
||||
username: "edited-recipient",
|
||||
email: "edited-recipient@example.test",
|
||||
})
|
||||
await expect(prisma.recipient.count()).resolves.toBe(2)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user