task-j1
This commit is contained in:
118
src/app/api/crm/settings/approval-workflows/[id]/route.ts
Normal file
118
src/app/api/crm/settings/approval-workflows/[id]/route.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditDelete, auditUpdate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
getApprovalWorkflow,
|
||||
softDeleteApprovalWorkflow,
|
||||
updateApprovalWorkflow
|
||||
} from '@/features/foundation/approval/server/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const workflowSchema = z.object({
|
||||
code: z.string().min(1).optional(),
|
||||
name: z.string().min(1).optional(),
|
||||
entityType: z.string().min(1).optional(),
|
||||
isActive: z.boolean().optional()
|
||||
});
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmApprovalWorkflowRead
|
||||
});
|
||||
const workflow = await getApprovalWorkflow(id, organization.id);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
time: new Date().toISOString(),
|
||||
message: 'Approval workflow loaded successfully',
|
||||
workflow
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to load approval workflow' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmApprovalWorkflowUpdate
|
||||
});
|
||||
const payload = workflowSchema.parse(await request.json());
|
||||
const before = await getApprovalWorkflow(id, organization.id);
|
||||
const updated = await updateApprovalWorkflow(id, organization.id, payload);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_approval_workflow',
|
||||
entityId: id,
|
||||
beforeData: before,
|
||||
afterData: updated
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Approval workflow updated successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to update approval workflow' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(_request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmApprovalWorkflowDelete
|
||||
});
|
||||
const result = await softDeleteApprovalWorkflow(id, organization.id);
|
||||
|
||||
await auditDelete({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_approval_workflow',
|
||||
entityId: id,
|
||||
beforeData: result.before,
|
||||
afterData: result.after
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Approval workflow deleted successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to delete approval workflow' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditUpdate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
getApprovalWorkflow,
|
||||
replaceApprovalWorkflowSteps
|
||||
} from '@/features/foundation/approval/server/service';
|
||||
import { BUSINESS_ROLES, PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const stepSchema = z.object({
|
||||
stepNumber: z.number().int().min(1),
|
||||
roleCode: z.enum(BUSINESS_ROLES),
|
||||
roleName: z.string().min(1),
|
||||
isRequired: z.boolean().optional()
|
||||
});
|
||||
|
||||
const payloadSchema = z.object({
|
||||
steps: z.array(stepSchema)
|
||||
});
|
||||
|
||||
export async function PUT(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmApprovalWorkflowUpdate
|
||||
});
|
||||
const payload = payloadSchema.parse(await request.json());
|
||||
const before = await getApprovalWorkflow(id, organization.id);
|
||||
const steps = await replaceApprovalWorkflowSteps(id, organization.id, payload.steps);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_approval_step',
|
||||
entityId: id,
|
||||
beforeData: before.steps,
|
||||
afterData: steps
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Approval workflow steps updated successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Unable to update approval workflow steps' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
78
src/app/api/crm/settings/approval-workflows/route.ts
Normal file
78
src/app/api/crm/settings/approval-workflows/route.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditCreate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
createApprovalWorkflow,
|
||||
listApprovalWorkflows
|
||||
} from '@/features/foundation/approval/server/service';
|
||||
import { BUSINESS_ROLES, PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
const workflowSchema = z.object({
|
||||
code: z.string().min(1),
|
||||
name: z.string().min(1),
|
||||
entityType: z.string().min(1),
|
||||
isActive: z.boolean().optional()
|
||||
});
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
try {
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmApprovalWorkflowRead
|
||||
});
|
||||
const items = await listApprovalWorkflows(organization.id);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
time: new Date().toISOString(),
|
||||
message: 'Approval workflows loaded successfully',
|
||||
items
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to load approval workflows' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmApprovalWorkflowCreate
|
||||
});
|
||||
const payload = workflowSchema.parse(await request.json());
|
||||
const created = await createApprovalWorkflow(organization.id, payload);
|
||||
|
||||
await auditCreate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_approval_workflow',
|
||||
entityId: created.id,
|
||||
afterData: created
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Approval workflow created successfully',
|
||||
allowedRoles: BUSINESS_ROLES
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to create approval workflow' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { previewDocumentSequenceById } from '@/features/foundation/document-sequence/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceRead
|
||||
});
|
||||
const preview = await previewDocumentSequenceById(id, organization.id);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
time: new Date().toISOString(),
|
||||
message: 'Document sequence preview loaded successfully',
|
||||
preview
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Unable to preview document sequence' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditUpdate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
getDocumentSequence,
|
||||
resetDocumentSequence
|
||||
} from '@/features/foundation/document-sequence/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const resetSchema = z.object({
|
||||
currentNumber: z.number().int().min(0)
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceReset
|
||||
});
|
||||
const payload = resetSchema.parse(await request.json());
|
||||
const before = await getDocumentSequence(id, organization.id);
|
||||
const updated = await resetDocumentSequence(id, organization.id, payload);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_sequence',
|
||||
entityId: id,
|
||||
beforeData: before,
|
||||
afterData: updated
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document sequence reset successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to reset document sequence' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
122
src/app/api/crm/settings/document-sequences/[id]/route.ts
Normal file
122
src/app/api/crm/settings/document-sequences/[id]/route.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditDelete, auditUpdate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
deleteDocumentSequence,
|
||||
getDocumentSequence,
|
||||
updateDocumentSequence
|
||||
} from '@/features/foundation/document-sequence/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const sequenceSchema = z.object({
|
||||
documentType: z.string().min(1).optional(),
|
||||
prefix: z.string().min(1).optional(),
|
||||
period: z.string().min(1).optional(),
|
||||
branchId: z.string().optional().nullable(),
|
||||
currentNumber: z.number().int().min(0).optional(),
|
||||
paddingLength: z.number().int().min(1).optional(),
|
||||
isActive: z.boolean().optional()
|
||||
});
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceRead
|
||||
});
|
||||
const sequence = await getDocumentSequence(id, organization.id);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
time: new Date().toISOString(),
|
||||
message: 'Document sequence loaded successfully',
|
||||
sequence
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to load document sequence' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceUpdate
|
||||
});
|
||||
const payload = sequenceSchema.parse(await request.json());
|
||||
const before = await getDocumentSequence(id, organization.id);
|
||||
const updated = await updateDocumentSequence(id, organization.id, payload);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_sequence',
|
||||
entityId: id,
|
||||
beforeData: before,
|
||||
afterData: updated
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document sequence updated successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to update document sequence' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(_request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceUpdate
|
||||
});
|
||||
const before = await getDocumentSequence(id, organization.id);
|
||||
const deleted = await deleteDocumentSequence(id, organization.id);
|
||||
|
||||
await auditDelete({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_sequence',
|
||||
entityId: id,
|
||||
beforeData: before,
|
||||
afterData: deleted
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document sequence deleted successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to delete document sequence' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
80
src/app/api/crm/settings/document-sequences/route.ts
Normal file
80
src/app/api/crm/settings/document-sequences/route.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditCreate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
createDocumentSequence,
|
||||
listDocumentSequences
|
||||
} from '@/features/foundation/document-sequence/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
const sequenceSchema = z.object({
|
||||
documentType: z.string().min(1),
|
||||
prefix: z.string().min(1),
|
||||
period: z.string().min(1),
|
||||
branchId: z.string().optional().nullable(),
|
||||
currentNumber: z.number().int().min(0).optional(),
|
||||
paddingLength: z.number().int().min(1),
|
||||
isActive: z.boolean().optional()
|
||||
});
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
try {
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceRead
|
||||
});
|
||||
const items = await listDocumentSequences(organization.id);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
time: new Date().toISOString(),
|
||||
message: 'Document sequences loaded successfully',
|
||||
items
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to load document sequences' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentSequenceCreate
|
||||
});
|
||||
const payload = sequenceSchema.parse(await request.json());
|
||||
const created = await createDocumentSequence(organization.id, payload);
|
||||
|
||||
await auditCreate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_sequence',
|
||||
entityId: created.id,
|
||||
afterData: created
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document sequence created successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: 'Unable to create document sequence' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { GET, PATCH, DELETE } from '@/app/api/crm/document-templates/[id]/route';
|
||||
@@ -0,0 +1 @@
|
||||
export { GET, POST } from '@/app/api/crm/document-templates/[id]/versions/route';
|
||||
@@ -0,0 +1,108 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditDelete, auditUpdate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
deleteDocumentTemplateMapping,
|
||||
updateDocumentTemplateMapping
|
||||
} from '@/features/foundation/document-template/server/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const columnSchema = z.object({
|
||||
columnName: z.string().min(1),
|
||||
sourceField: z.string().min(1),
|
||||
columnLetter: z.string().optional().nullable(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
formatMask: z.string().optional().nullable()
|
||||
});
|
||||
|
||||
const mappingSchema = z.object({
|
||||
placeholderKey: z.string().min(1).optional(),
|
||||
sourcePath: z.string().min(1).optional(),
|
||||
dataType: z.enum(['scalar', 'multiline', 'table', 'image']).optional(),
|
||||
sheetName: z.string().optional().nullable(),
|
||||
defaultValue: z.string().optional().nullable(),
|
||||
formatMask: z.string().optional().nullable(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
columns: z.array(columnSchema).optional()
|
||||
});
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentTemplateUpdate
|
||||
});
|
||||
const payload = mappingSchema.parse(await request.json());
|
||||
const updated = await updateDocumentTemplateMapping(id, organization.id, payload);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_template_mapping',
|
||||
entityId: id,
|
||||
afterData: updated
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document template mapping updated successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Unable to update document template mapping' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(_request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentTemplateDelete
|
||||
});
|
||||
const result = await deleteDocumentTemplateMapping(id, organization.id);
|
||||
|
||||
await auditDelete({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_template_mapping',
|
||||
entityId: id,
|
||||
beforeData: result.before,
|
||||
afterData: result.after
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document template mapping deleted successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Unable to delete document template mapping' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
1
src/app/api/crm/settings/document-templates/route.ts
Normal file
1
src/app/api/crm/settings/document-templates/route.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { GET, POST } from '@/app/api/crm/document-templates/route';
|
||||
@@ -0,0 +1,70 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditCreate } from '@/features/foundation/audit-log/service';
|
||||
import { createDocumentTemplateMapping } from '@/features/foundation/document-template/server/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const columnSchema = z.object({
|
||||
columnName: z.string().min(1),
|
||||
sourceField: z.string().min(1),
|
||||
columnLetter: z.string().optional().nullable(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
formatMask: z.string().optional().nullable()
|
||||
});
|
||||
|
||||
const mappingSchema = z.object({
|
||||
placeholderKey: z.string().min(1),
|
||||
sourcePath: z.string().min(1),
|
||||
dataType: z.enum(['scalar', 'multiline', 'table', 'image']),
|
||||
sheetName: z.string().optional().nullable(),
|
||||
defaultValue: z.string().optional().nullable(),
|
||||
formatMask: z.string().optional().nullable(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
columns: z.array(columnSchema).optional()
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentTemplateUpdate
|
||||
});
|
||||
const payload = mappingSchema.parse(await request.json());
|
||||
const created = await createDocumentTemplateMapping(id, organization.id, payload);
|
||||
|
||||
await auditCreate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_template_mapping',
|
||||
entityId: created.id,
|
||||
afterData: created
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document template mapping created successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Unable to create document template mapping' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { auditUpdate } from '@/features/foundation/audit-log/service';
|
||||
import {
|
||||
setDocumentTemplateVersionActive,
|
||||
updateDocumentTemplateVersion
|
||||
} from '@/features/foundation/document-template/server/service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
type Params = {
|
||||
params: Promise<{ id: string }>;
|
||||
};
|
||||
|
||||
const versionSchema = z.object({
|
||||
version: z.string().min(1).optional(),
|
||||
filePath: z.string().optional().nullable(),
|
||||
schemaJson: z.unknown().optional(),
|
||||
previewImageUrl: z.string().optional().nullable(),
|
||||
isActive: z.boolean().optional()
|
||||
});
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: Params) {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.crmDocumentTemplateUpdate
|
||||
});
|
||||
const payload = versionSchema.parse(await request.json());
|
||||
|
||||
if (Object.keys(payload).length === 1 && typeof payload.isActive === 'boolean') {
|
||||
const result = await setDocumentTemplateVersionActive(id, organization.id, payload.isActive);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_template_version',
|
||||
entityId: id,
|
||||
beforeData: result.before,
|
||||
afterData: result.after
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document template version status updated successfully'
|
||||
});
|
||||
}
|
||||
|
||||
const updated = await updateDocumentTemplateVersion(id, organization.id, payload);
|
||||
|
||||
await auditUpdate({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
entityType: 'crm_document_template_version',
|
||||
entityId: id,
|
||||
afterData: updated
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Document template version updated successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: error.issues[0]?.message ?? 'Invalid payload' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ message: 'Unable to update document template version' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user