89 lines
3.1 KiB
TypeScript
89 lines
3.1 KiB
TypeScript
|
|
/**
|
||
|
|
* The EOI signer slot, when linked to a CRM user, resolves that user's
|
||
|
|
* SIGNING identity — `user_profiles.signing_email` when set, otherwise the
|
||
|
|
* login `user.email`. This lets a person who logs in as `abbie@` sign on
|
||
|
|
* behalf of the shared `sales@` role mailbox without changing their login.
|
||
|
|
*/
|
||
|
|
import { afterAll, describe, expect, it, vi } from 'vitest';
|
||
|
|
import { eq } from 'drizzle-orm';
|
||
|
|
|
||
|
|
import { db } from '@/lib/db';
|
||
|
|
import { account, roles, user, userProfiles, systemSettings } from '@/lib/db/schema';
|
||
|
|
import { auth } from '@/lib/auth';
|
||
|
|
import { createUser } from '@/lib/services/users.service';
|
||
|
|
import { getPortEoiSigners } from '@/lib/services/documenso-payload';
|
||
|
|
import { makePort, makeAuditMeta } from '../helpers/factories';
|
||
|
|
|
||
|
|
describe('getPortEoiSigners - signing_email override', () => {
|
||
|
|
const createdUserIds: string[] = [];
|
||
|
|
|
||
|
|
afterAll(async () => {
|
||
|
|
for (const id of createdUserIds) {
|
||
|
|
await db.delete(account).where(eq(account.userId, id));
|
||
|
|
await db.delete(userProfiles).where(eq(userProfiles.userId, id));
|
||
|
|
await db.delete(user).where(eq(user.id, id));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
async function salesRoleId(): Promise<string> {
|
||
|
|
const r = await db.query.roles.findFirst({ where: eq(roles.name, 'sales_manager') });
|
||
|
|
if (!r) throw new Error('sales_manager role not seeded — run pnpm db:seed');
|
||
|
|
return r.id;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function makeSignerUser(loginEmail: string): Promise<string> {
|
||
|
|
const resetSpy = vi
|
||
|
|
.spyOn(auth.api, 'requestPasswordReset')
|
||
|
|
.mockResolvedValue({ status: true } as never);
|
||
|
|
try {
|
||
|
|
const port = await makePort();
|
||
|
|
const created = await createUser(
|
||
|
|
port.id,
|
||
|
|
{
|
||
|
|
email: loginEmail,
|
||
|
|
name: 'Abbie May',
|
||
|
|
displayName: 'Abbie May',
|
||
|
|
roleId: await salesRoleId(),
|
||
|
|
sendSetupEmail: true,
|
||
|
|
residentialAccess: false,
|
||
|
|
},
|
||
|
|
makeAuditMeta(),
|
||
|
|
);
|
||
|
|
createdUserIds.push(created.userId);
|
||
|
|
return created.userId;
|
||
|
|
} finally {
|
||
|
|
resetSpy.mockRestore();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
it('resolves the linked signer email from signing_email when set', async () => {
|
||
|
|
const port = await makePort();
|
||
|
|
const userId = await makeSignerUser(`login-${Date.now()}-a@example.test`);
|
||
|
|
await db
|
||
|
|
.update(userProfiles)
|
||
|
|
.set({ signingEmail: 'sales@portnimara.com' })
|
||
|
|
.where(eq(userProfiles.userId, userId));
|
||
|
|
await db
|
||
|
|
.insert(systemSettings)
|
||
|
|
.values({ portId: port.id, key: 'documenso_approver_user_id', value: userId });
|
||
|
|
|
||
|
|
const signers = await getPortEoiSigners(port.id);
|
||
|
|
|
||
|
|
expect(signers.approver.email).toBe('sales@portnimara.com');
|
||
|
|
expect(signers.approver.name).toBe('Abbie May');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('falls back to the login email when signing_email is null', async () => {
|
||
|
|
const port = await makePort();
|
||
|
|
const loginEmail = `login-${Date.now()}-b@example.test`;
|
||
|
|
const userId = await makeSignerUser(loginEmail);
|
||
|
|
await db
|
||
|
|
.insert(systemSettings)
|
||
|
|
.values({ portId: port.id, key: 'documenso_approver_user_id', value: userId });
|
||
|
|
|
||
|
|
const signers = await getPortEoiSigners(port.id);
|
||
|
|
|
||
|
|
expect(signers.approver.email).toBe(loginEmail);
|
||
|
|
});
|
||
|
|
});
|