260322:1648 Correct Coresspondence / Doing RFA / Correct CI
This commit is contained in:
@@ -135,10 +135,7 @@ describe('correspondenceService', () => {
|
||||
|
||||
const result = await correspondenceService.addReference(1, referenceDto);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith(
|
||||
'/correspondences/1/references',
|
||||
referenceDto
|
||||
);
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/correspondences/1/references', referenceDto);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -90,6 +90,4 @@ describe('projectService', () => {
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { AuditQueryParams } from '@/types/dto/numbering.dto';
|
||||
|
||||
export interface AuditLog {
|
||||
auditId: string;
|
||||
userId?: number | null;
|
||||
user?: {
|
||||
id: number;
|
||||
fullName?: string;
|
||||
username: string;
|
||||
};
|
||||
action: string;
|
||||
severity: string;
|
||||
entityType?: string;
|
||||
entityId?: string;
|
||||
detailsJson?: Record<string, unknown>;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: string;
|
||||
auditId: string;
|
||||
userId?: number | null;
|
||||
user?: {
|
||||
id: number;
|
||||
fullName?: string;
|
||||
username: string;
|
||||
};
|
||||
action: string;
|
||||
severity: string;
|
||||
entityType?: string;
|
||||
entityId?: string;
|
||||
detailsJson?: Record<string, unknown>;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export type AuditLogQueryParams = AuditQueryParams;
|
||||
|
||||
export const auditLogService = {
|
||||
getLogs: async (params?: AuditLogQueryParams) => {
|
||||
const response = await apiClient.get<{ data: AuditLog[] } | AuditLog[]>("/audit-logs", { params });
|
||||
const response = await apiClient.get<{ data: AuditLog[] } | AuditLog[]>('/audit-logs', { params });
|
||||
// Support both wrapped and unwrapped scenarios
|
||||
return (response.data as { data: AuditLog[] }).data ?? response.data;
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// File: lib/services/circulation.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
|
||||
// Import DTO ที่สร้างไว้
|
||||
import { CreateCirculationDto } from "@/types/dto/circulation/create-circulation.dto";
|
||||
import { SearchCirculationDto } from "@/types/dto/circulation/search-circulation.dto";
|
||||
import { UpdateCirculationRoutingDto } from "@/types/dto/circulation/update-circulation-routing.dto";
|
||||
import { CreateCirculationDto } from '@/types/dto/circulation/create-circulation.dto';
|
||||
import { SearchCirculationDto } from '@/types/dto/circulation/search-circulation.dto';
|
||||
import { UpdateCirculationRoutingDto } from '@/types/dto/circulation/update-circulation-routing.dto';
|
||||
|
||||
export const circulationService = {
|
||||
/**
|
||||
@@ -12,7 +12,7 @@ export const circulationService = {
|
||||
*/
|
||||
getAll: async (params?: SearchCirculationDto) => {
|
||||
// GET /circulations
|
||||
const response = await apiClient.get("/circulations", { params });
|
||||
const response = await apiClient.get('/circulations', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@ export const circulationService = {
|
||||
*/
|
||||
create: async (data: CreateCirculationDto) => {
|
||||
// POST /circulations
|
||||
const response = await apiClient.post("/circulations", data);
|
||||
const response = await apiClient.post('/circulations', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -50,5 +50,5 @@ export const circulationService = {
|
||||
delete: async (uuid: string) => {
|
||||
const response = await apiClient.delete(`/circulations/${uuid}`);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateContractDto,
|
||||
UpdateContractDto,
|
||||
SearchContractDto,
|
||||
} from "@/types/dto/contract/contract.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { CreateContractDto, UpdateContractDto, SearchContractDto } from '@/types/dto/contract/contract.dto';
|
||||
|
||||
export const contractService = {
|
||||
/**
|
||||
@@ -11,7 +7,7 @@ export const contractService = {
|
||||
* GET /contracts?projectId=1
|
||||
*/
|
||||
getAll: async (params?: SearchContractDto) => {
|
||||
const response = await apiClient.get("/contracts", { params });
|
||||
const response = await apiClient.get('/contracts', { params });
|
||||
if (response.data && Array.isArray(response.data.data)) {
|
||||
return response.data.data;
|
||||
}
|
||||
@@ -32,7 +28,7 @@ export const contractService = {
|
||||
* POST /contracts
|
||||
*/
|
||||
create: async (data: CreateContractDto) => {
|
||||
const response = await apiClient.post("/contracts", data);
|
||||
const response = await apiClient.post('/contracts', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// File: lib/services/correspondence.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { SearchCorrespondenceDto } from "@/types/dto/correspondence/search-correspondence.dto";
|
||||
import { CreateCorrespondenceDto } from "@/types/dto/correspondence/create-correspondence.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { SearchCorrespondenceDto } from '@/types/dto/correspondence/search-correspondence.dto';
|
||||
import { CreateCorrespondenceDto } from '@/types/dto/correspondence/create-correspondence.dto';
|
||||
// Import DTO ใหม่
|
||||
import { SubmitCorrespondenceDto } from "@/types/dto/correspondence/submit-correspondence.dto";
|
||||
import { WorkflowActionDto } from "@/types/dto/correspondence/workflow-action.dto";
|
||||
import { AddReferenceDto, RemoveReferenceDto } from "@/types/dto/correspondence/add-reference.dto";
|
||||
import { SubmitCorrespondenceDto } from '@/types/dto/correspondence/submit-correspondence.dto';
|
||||
import { WorkflowActionDto } from '@/types/dto/correspondence/workflow-action.dto';
|
||||
import { AddReferenceDto, RemoveReferenceDto } from '@/types/dto/correspondence/add-reference.dto';
|
||||
|
||||
export const correspondenceService = {
|
||||
// ... (getAll, getById, create, update, delete เดิมคงไว้) ...
|
||||
|
||||
getAll: async (params?: SearchCorrespondenceDto) => {
|
||||
const response = await apiClient.get("/correspondences", { params });
|
||||
const response = await apiClient.get('/correspondences', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ export const correspondenceService = {
|
||||
},
|
||||
|
||||
create: async (data: CreateCorrespondenceDto) => {
|
||||
const response = await apiClient.post("/correspondences", data);
|
||||
const response = await apiClient.post('/correspondences', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -67,7 +67,7 @@ export const correspondenceService = {
|
||||
removeReference: async (uuid: string, data: RemoveReferenceDto) => {
|
||||
// ใช้ DELETE method โดยส่ง body ไปด้วย (axios รองรับผ่าน config.data)
|
||||
const response = await apiClient.delete(`/correspondences/${uuid}/references`, {
|
||||
data: data
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
@@ -75,7 +75,7 @@ export const correspondenceService = {
|
||||
* Preview Document Number
|
||||
*/
|
||||
previewNumber: async (data: Partial<CreateCorrespondenceDto>) => {
|
||||
const response = await apiClient.post("/correspondences/preview-number", data);
|
||||
const response = await apiClient.post('/correspondences/preview-number', data);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { DashboardStats, ActivityLog, PendingTask } from "@/types/dashboard";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { DashboardStats, ActivityLog, PendingTask } from '@/types/dashboard';
|
||||
|
||||
export const dashboardService = {
|
||||
getStats: async (): Promise<DashboardStats> => {
|
||||
const response = await apiClient.get("/dashboard/stats");
|
||||
const response = await apiClient.get('/dashboard/stats');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getRecentActivity: async (): Promise<ActivityLog[]> => {
|
||||
try {
|
||||
const response = await apiClient.get("/dashboard/activity");
|
||||
const response = await apiClient.get('/dashboard/activity');
|
||||
// ตรวจสอบว่า response.data เป็น array จริงๆ
|
||||
if (Array.isArray(response.data)) {
|
||||
return response.data;
|
||||
}
|
||||
return [];
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
getPendingTasks: async (): Promise<PendingTask[]> => {
|
||||
try {
|
||||
const response = await apiClient.get("/dashboard/pending");
|
||||
const response = await apiClient.get('/dashboard/pending');
|
||||
// Backend คืน { data: [], meta: {} } ต้องดึง data ออกมา
|
||||
if (response.data?.data && Array.isArray(response.data.data)) {
|
||||
return response.data.data;
|
||||
@@ -31,7 +31,7 @@ export const dashboardService = {
|
||||
return response.data;
|
||||
}
|
||||
return [];
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
NumberingMetrics,
|
||||
ManualOverrideDto,
|
||||
VoidReplaceDto,
|
||||
CancelNumberDto,
|
||||
} from "@/types/dto/numbering.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { NumberingMetrics, ManualOverrideDto, VoidReplaceDto, CancelNumberDto } from '@/types/dto/numbering.dto';
|
||||
|
||||
/** A bulk-import record row */
|
||||
export interface BulkImportRecord {
|
||||
@@ -17,37 +12,37 @@ export interface BulkImportRecord {
|
||||
export const documentNumberingService = {
|
||||
// --- Admin Dashboard Metrics ---
|
||||
getMetrics: async (): Promise<NumberingMetrics> => {
|
||||
const response = await apiClient.get("/admin/document-numbering/metrics");
|
||||
const response = await apiClient.get('/admin/document-numbering/metrics');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// --- Admin Tools ---
|
||||
manualOverride: async (dto: ManualOverrideDto): Promise<void> => {
|
||||
await apiClient.post("/admin/document-numbering/manual-override", dto);
|
||||
await apiClient.post('/admin/document-numbering/manual-override', dto);
|
||||
},
|
||||
|
||||
voidAndReplace: async (dto: VoidReplaceDto): Promise<{ documentNumber: string }> => {
|
||||
const response = await apiClient.post("/admin/document-numbering/void-and-replace", dto);
|
||||
const response = await apiClient.post('/admin/document-numbering/void-and-replace', dto);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
cancelNumber: async (dto: CancelNumberDto): Promise<void> => {
|
||||
await apiClient.post("/admin/document-numbering/cancel", dto);
|
||||
await apiClient.post('/admin/document-numbering/cancel', dto);
|
||||
},
|
||||
|
||||
bulkImport: async (data: FormData | BulkImportRecord[]): Promise<{ imported: number; errors: string[] }> => {
|
||||
const isFormData = data instanceof FormData;
|
||||
const config = isFormData ? { headers: { "Content-Type": "multipart/form-data" } } : {};
|
||||
const response = await apiClient.post("/admin/document-numbering/bulk-import", data, config);
|
||||
const config = isFormData ? { headers: { 'Content-Type': 'multipart/form-data' } } : {};
|
||||
const response = await apiClient.post('/admin/document-numbering/bulk-import', data, config);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// --- Audit Logs ---
|
||||
getAuditLogs: async () => {
|
||||
// NOTE: endpoint might be merged with metrics or separate
|
||||
// Currently controller has getMetrics returning audit logs too.
|
||||
// But if we want separate pagination later:
|
||||
// return apiClient.get("/admin/document-numbering/audit", { params });
|
||||
return [];
|
||||
}
|
||||
// NOTE: endpoint might be merged with metrics or separate
|
||||
// Currently controller has getMetrics returning audit logs too.
|
||||
// But if we want separate pagination later:
|
||||
// return apiClient.get("/admin/document-numbering/audit", { params });
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
@@ -18,4 +18,4 @@ export * from './search.service';
|
||||
export * from './notification.service';
|
||||
export * from './workflow-engine.service';
|
||||
export * from './monitoring.service';
|
||||
export * from './json-schema.service';
|
||||
export * from './json-schema.service';
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
// File: lib/services/json-schema.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateJsonSchemaDto,
|
||||
UpdateJsonSchemaDto,
|
||||
SearchJsonSchemaDto
|
||||
} from "@/types/dto/json-schema/json-schema.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { CreateJsonSchemaDto, UpdateJsonSchemaDto, SearchJsonSchemaDto } from '@/types/dto/json-schema/json-schema.dto';
|
||||
|
||||
export const jsonSchemaService = {
|
||||
/**
|
||||
@@ -12,7 +8,7 @@ export const jsonSchemaService = {
|
||||
*/
|
||||
getAll: async (params?: SearchJsonSchemaDto) => {
|
||||
// GET /json-schemas
|
||||
const response = await apiClient.get("/json-schemas", { params });
|
||||
const response = await apiClient.get('/json-schemas', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -39,7 +35,7 @@ export const jsonSchemaService = {
|
||||
*/
|
||||
create: async (data: CreateJsonSchemaDto) => {
|
||||
// POST /json-schemas
|
||||
const response = await apiClient.post("/json-schemas", data);
|
||||
const response = await apiClient.post('/json-schemas', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -68,8 +64,8 @@ export const jsonSchemaService = {
|
||||
// POST /json-schemas/validate
|
||||
const response = await apiClient.post(`/json-schemas/validate`, {
|
||||
schemaCode: code,
|
||||
data: data
|
||||
data: data,
|
||||
});
|
||||
return response.data; // { valid: true, errors: [] }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
// File: lib/services/master-data.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
|
||||
// Import DTOs
|
||||
import { CreateTagDto, UpdateTagDto, SearchTagDto } from "@/types/dto/master/tag.dto";
|
||||
import { CreateDisciplineDto } from "@/types/dto/master/discipline.dto";
|
||||
import { CreateSubTypeDto } from "@/types/dto/master/sub-type.dto";
|
||||
import { SaveNumberFormatDto } from "@/types/dto/master/number-format.dto";
|
||||
import { CreateRfaTypeDto, UpdateRfaTypeDto } from "@/types/dto/master/rfa-type.dto";
|
||||
import { CreateCorrespondenceTypeDto, UpdateCorrespondenceTypeDto } from "@/types/dto/master/correspondence-type.dto";
|
||||
import { Organization } from "@/types/organization";
|
||||
import { CreateTagDto, UpdateTagDto, SearchTagDto } from '@/types/dto/master/tag.dto';
|
||||
import { CreateDisciplineDto } from '@/types/dto/master/discipline.dto';
|
||||
import { CreateSubTypeDto } from '@/types/dto/master/sub-type.dto';
|
||||
import { SaveNumberFormatDto } from '@/types/dto/master/number-format.dto';
|
||||
import { CreateRfaTypeDto, UpdateRfaTypeDto } from '@/types/dto/master/rfa-type.dto';
|
||||
import { CreateCorrespondenceTypeDto, UpdateCorrespondenceTypeDto } from '@/types/dto/master/correspondence-type.dto';
|
||||
import { Organization } from '@/types/organization';
|
||||
import {
|
||||
CreateOrganizationDto,
|
||||
UpdateOrganizationDto,
|
||||
SearchOrganizationDto,
|
||||
} from "@/types/dto/organization/organization.dto";
|
||||
} from '@/types/dto/organization/organization.dto';
|
||||
|
||||
const extractArrayData = <T>(value: unknown): T[] => {
|
||||
let current: unknown = value;
|
||||
@@ -23,7 +23,7 @@ const extractArrayData = <T>(value: unknown): T[] => {
|
||||
return current as T[];
|
||||
}
|
||||
|
||||
if (!current || typeof current !== "object" || !("data" in current)) {
|
||||
if (!current || typeof current !== 'object' || !('data' in current)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -38,14 +38,14 @@ export const masterDataService = {
|
||||
|
||||
/** ดึงรายการ Tags ทั้งหมด (Search & Pagination) */
|
||||
getTags: async (params?: SearchTagDto) => {
|
||||
const response = await apiClient.get("/master/tags", { params });
|
||||
const response = await apiClient.get('/master/tags', { params });
|
||||
// Support both wrapped and unwrapped scenarios
|
||||
return response.data.data || response.data;
|
||||
},
|
||||
|
||||
/** สร้าง Tag ใหม่ */
|
||||
createTag: async (data: CreateTagDto) => {
|
||||
const response = await apiClient.post("/master/tags", data);
|
||||
const response = await apiClient.post('/master/tags', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -65,14 +65,14 @@ export const masterDataService = {
|
||||
|
||||
/** ดึงรายชื่อองค์กรทั้งหมด */
|
||||
getOrganizations: async (params?: SearchOrganizationDto) => {
|
||||
const response = await apiClient.get<Organization[] | { data: Organization[] }>("/organizations", { params });
|
||||
const response = await apiClient.get<Organization[] | { data: Organization[] }>('/organizations', { params });
|
||||
// Support paginated response
|
||||
if (response.data && Array.isArray((response.data as { data: Organization[] }).data)) {
|
||||
return (response.data as { data: Organization[] }).data;
|
||||
return (response.data as { data: Organization[] }).data;
|
||||
}
|
||||
// If response.data itself is an array
|
||||
if (Array.isArray(response.data)) {
|
||||
return response.data;
|
||||
return response.data;
|
||||
}
|
||||
// If we're here, it might be { data: [], total: ... } but data is missing? or empty?
|
||||
// Or it returned the object but data.data check failed (shouldn't happen if it follows schema).
|
||||
@@ -82,8 +82,10 @@ export const masterDataService = {
|
||||
// Fallback: Check if response.data is object?
|
||||
// If it's the paginated object, return the data array if it exists
|
||||
if (response.data && (response.data as { data: Organization[] }).data) {
|
||||
// Maybe it's not an array?
|
||||
return Array.isArray((response.data as { data: Organization[] }).data) ? (response.data as { data: Organization[] }).data : [];
|
||||
// Maybe it's not an array?
|
||||
return Array.isArray((response.data as { data: Organization[] }).data)
|
||||
? (response.data as { data: Organization[] }).data
|
||||
: [];
|
||||
}
|
||||
|
||||
return []; // Return empty array to prevent map errors
|
||||
@@ -91,7 +93,7 @@ export const masterDataService = {
|
||||
|
||||
/** สร้างองค์กรใหม่ */
|
||||
createOrganization: async (data: CreateOrganizationDto) => {
|
||||
const response = await apiClient.post("/organizations", data);
|
||||
const response = await apiClient.post('/organizations', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -107,20 +109,19 @@ export const masterDataService = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
// --- Disciplines Management (Admin / Req 6B) ---
|
||||
|
||||
/** ดึงรายชื่อสาขางาน (มักจะกรองตาม Contract ID) */
|
||||
getDisciplines: async (contractId?: number | string) => {
|
||||
const response = await apiClient.get("/master/disciplines", {
|
||||
params: { contractId }
|
||||
const response = await apiClient.get('/master/disciplines', {
|
||||
params: { contractId },
|
||||
});
|
||||
return extractArrayData(response.data);
|
||||
},
|
||||
|
||||
/** สร้างสาขางานใหม่ */
|
||||
createDiscipline: async (data: CreateDisciplineDto) => {
|
||||
const response = await apiClient.post("/master/disciplines", data);
|
||||
const response = await apiClient.post('/master/disciplines', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -134,15 +135,15 @@ export const masterDataService = {
|
||||
|
||||
/** ดึงรายชื่อประเภทย่อย (กรองตาม Contract และ Type) */
|
||||
getSubTypes: async (contractId?: number | string, typeId?: number) => {
|
||||
const response = await apiClient.get("/master/sub-types", {
|
||||
params: { contractId, correspondenceTypeId: typeId }
|
||||
const response = await apiClient.get('/master/sub-types', {
|
||||
params: { contractId, correspondenceTypeId: typeId },
|
||||
});
|
||||
return extractArrayData(response.data);
|
||||
},
|
||||
|
||||
/** สร้างประเภทย่อยใหม่ */
|
||||
createSubType: async (data: CreateSubTypeDto) => {
|
||||
const response = await apiClient.post("/master/sub-types", data);
|
||||
const response = await apiClient.post('/master/sub-types', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -150,55 +151,55 @@ export const masterDataService = {
|
||||
|
||||
/** ดึงประเภท RFA ทั้งหมด */
|
||||
getRfaTypes: async (contractId?: number | string) => {
|
||||
const response = await apiClient.get("/master/rfa-types", {
|
||||
params: { contractId }
|
||||
const response = await apiClient.get('/master/rfa-types', {
|
||||
params: { contractId },
|
||||
});
|
||||
return extractArrayData(response.data);
|
||||
},
|
||||
|
||||
/** สร้างประเภท RFA ใหม่ */
|
||||
createRfaType: async (data: CreateRfaTypeDto) => {
|
||||
return apiClient.post("/master/rfa-types", data).then(res => res.data);
|
||||
return apiClient.post('/master/rfa-types', data).then((res) => res.data);
|
||||
},
|
||||
|
||||
updateRfaType: async (id: number, data: UpdateRfaTypeDto) => {
|
||||
return apiClient.patch(`/master/rfa-types/${id}`, data).then(res => res.data);
|
||||
return apiClient.patch(`/master/rfa-types/${id}`, data).then((res) => res.data);
|
||||
},
|
||||
|
||||
deleteRfaType: async (id: number) => {
|
||||
return apiClient.delete(`/master/rfa-types/${id}`).then(res => res.data);
|
||||
return apiClient.delete(`/master/rfa-types/${id}`).then((res) => res.data);
|
||||
},
|
||||
|
||||
// --- Document Numbering Format (Admin Config) ---
|
||||
|
||||
// --- Correspondence Types Management ---
|
||||
getCorrespondenceTypes: async () => {
|
||||
const response = await apiClient.get("/master/correspondence-types");
|
||||
const response = await apiClient.get('/master/correspondence-types');
|
||||
return extractArrayData(response.data);
|
||||
},
|
||||
|
||||
createCorrespondenceType: async (data: CreateCorrespondenceTypeDto) => {
|
||||
return apiClient.post("/master/correspondence-types", data).then(res => res.data);
|
||||
return apiClient.post('/master/correspondence-types', data).then((res) => res.data);
|
||||
},
|
||||
|
||||
updateCorrespondenceType: async (id: number, data: UpdateCorrespondenceTypeDto) => {
|
||||
return apiClient.patch(`/master/correspondence-types/${id}`, data).then(res => res.data);
|
||||
return apiClient.patch(`/master/correspondence-types/${id}`, data).then((res) => res.data);
|
||||
},
|
||||
|
||||
deleteCorrespondenceType: async (id: number) => {
|
||||
return apiClient.delete(`/master/correspondence-types/${id}`).then(res => res.data);
|
||||
return apiClient.delete(`/master/correspondence-types/${id}`).then((res) => res.data);
|
||||
},
|
||||
|
||||
/** บันทึกรูปแบบเลขที่เอกสาร */
|
||||
saveNumberFormat: async (data: SaveNumberFormatDto) => {
|
||||
const response = await apiClient.post("/document-numbering/formats", data);
|
||||
const response = await apiClient.post('/document-numbering/formats', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** ดึงรูปแบบเลขที่เอกสารปัจจุบัน (เพื่อมาแก้ไข) */
|
||||
getNumberFormat: async (projectId: number, typeId: number) => {
|
||||
const response = await apiClient.get("/document-numbering/formats", {
|
||||
params: { projectId, correspondenceTypeId: typeId }
|
||||
const response = await apiClient.get('/document-numbering/formats', {
|
||||
params: { projectId, correspondenceTypeId: typeId },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
@@ -206,21 +207,21 @@ export const masterDataService = {
|
||||
// --- Drawing Categories ---
|
||||
|
||||
getContractDrawingCategories: async (projectId?: number | string) => {
|
||||
const response = await apiClient.get("/drawings/contract/categories", {
|
||||
params: { projectId }
|
||||
const response = await apiClient.get('/drawings/contract/categories', {
|
||||
params: { projectId },
|
||||
});
|
||||
return extractArrayData(response.data);
|
||||
},
|
||||
|
||||
getShopMainCategories: async (projectId: number) => {
|
||||
const response = await apiClient.get("/drawings/shop/main-categories", { params: { projectId } });
|
||||
const response = await apiClient.get('/drawings/shop/main-categories', { params: { projectId } });
|
||||
return extractArrayData(response.data);
|
||||
},
|
||||
|
||||
getShopSubCategories: async (projectId: number, mainCategoryId?: number) => {
|
||||
const response = await apiClient.get("/drawings/shop/sub-categories", {
|
||||
params: { projectId, mainCategoryId }
|
||||
const response = await apiClient.get('/drawings/shop/sub-categories', {
|
||||
params: { projectId, mainCategoryId },
|
||||
});
|
||||
return extractArrayData(response.data);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ interface WrappedData {
|
||||
data?: unknown;
|
||||
}
|
||||
|
||||
const extractNestedData = <T,>(value: unknown): T => {
|
||||
const extractNestedData = <T>(value: unknown): T => {
|
||||
let current: unknown = value;
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
@@ -25,7 +25,7 @@ const extractNestedData = <T,>(value: unknown): T => {
|
||||
return current as T;
|
||||
};
|
||||
|
||||
const normalizePaginatedResponse = <T,>(value: unknown): PaginatedResponse<T> => {
|
||||
const normalizePaginatedResponse = <T>(value: unknown): PaginatedResponse<T> => {
|
||||
const extracted = extractNestedData<unknown>(value);
|
||||
|
||||
if (!extracted || typeof extracted !== 'object') {
|
||||
@@ -84,15 +84,12 @@ export const migrationService = {
|
||||
return extractNestedData<MigrationReviewQueueItem>(data);
|
||||
},
|
||||
|
||||
getErrors: async (params: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}): Promise<PaginatedResponse<MigrationErrorItem>> => {
|
||||
getErrors: async (params: { page?: number; limit?: number }): Promise<PaginatedResponse<MigrationErrorItem>> => {
|
||||
const { data } = await api.get('/migration/errors', { params });
|
||||
return normalizePaginatedResponse<MigrationErrorItem>(data);
|
||||
},
|
||||
|
||||
approveQueueItem: async (id: number, payload: any, idempotencyKey: string) => {
|
||||
approveQueueItem: async (id: number, payload: Record<string, unknown>, idempotencyKey: string) => {
|
||||
const { data } = await api.post(`/migration/queue/${id}/approve`, payload, {
|
||||
headers: {
|
||||
'idempotency-key': idempotencyKey,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// File: lib/services/monitoring.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
|
||||
export interface SetMaintenanceDto {
|
||||
enabled: boolean;
|
||||
@@ -9,19 +9,19 @@ export interface SetMaintenanceDto {
|
||||
export const monitoringService = {
|
||||
/** ตรวจสอบสถานะสุขภาพระบบ (Health Check) */
|
||||
getHealth: async () => {
|
||||
const response = await apiClient.get("/health");
|
||||
const response = await apiClient.get('/health');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** ดึง Metrics การทำงาน (CPU, Memory, Request Count) */
|
||||
getMetrics: async () => {
|
||||
const response = await apiClient.get("/monitoring/metrics");
|
||||
const response = await apiClient.get('/monitoring/metrics');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** เปิด/ปิด Maintenance Mode */
|
||||
setMaintenanceMode: async (data: SetMaintenanceDto) => {
|
||||
const response = await apiClient.post("/monitoring/maintenance", data);
|
||||
const response = await apiClient.post('/monitoring/maintenance', data);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { NotificationResponse } from "@/types/notification";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { NotificationResponse } from '@/types/notification';
|
||||
|
||||
export const notificationService = {
|
||||
getUnread: async (): Promise<NotificationResponse> => {
|
||||
const response = await apiClient.get("/notifications/unread");
|
||||
const response = await apiClient.get('/notifications/unread');
|
||||
// Backend should return { items: [], unreadCount: number }
|
||||
// Or just items and we count on frontend, but typically backend gives count.
|
||||
return response.data;
|
||||
@@ -17,5 +17,5 @@ export const notificationService = {
|
||||
markAllAsRead: async () => {
|
||||
const response = await apiClient.patch(`/notifications/read-all`);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import {
|
||||
CreateOrganizationDto,
|
||||
UpdateOrganizationDto,
|
||||
SearchOrganizationDto,
|
||||
} from "@/types/dto/organization/organization.dto";
|
||||
} from '@/types/dto/organization/organization.dto';
|
||||
|
||||
export const organizationService = {
|
||||
/**
|
||||
@@ -11,7 +11,7 @@ export const organizationService = {
|
||||
* GET /organizations?projectId=1
|
||||
*/
|
||||
getAll: async (params?: SearchOrganizationDto) => {
|
||||
const response = await apiClient.get("/organizations", { params });
|
||||
const response = await apiClient.get('/organizations', { params });
|
||||
// Normalize response if wrapped in data.data or direct data
|
||||
if (response.data && Array.isArray(response.data.data)) {
|
||||
return response.data.data;
|
||||
@@ -33,7 +33,7 @@ export const organizationService = {
|
||||
* POST /organizations
|
||||
*/
|
||||
create: async (data: CreateOrganizationDto) => {
|
||||
const response = await apiClient.post("/organizations", data);
|
||||
const response = await apiClient.post('/organizations', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
// File: lib/services/project.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateProjectDto,
|
||||
UpdateProjectDto,
|
||||
SearchProjectDto
|
||||
} from "@/types/dto/project/project.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { CreateProjectDto, UpdateProjectDto, SearchProjectDto } from '@/types/dto/project/project.dto';
|
||||
|
||||
export const projectService = {
|
||||
// --- Basic CRUD ---
|
||||
@@ -15,10 +11,10 @@ export const projectService = {
|
||||
*/
|
||||
getAll: async (params?: SearchProjectDto) => {
|
||||
// GET /projects
|
||||
const response = await apiClient.get("/projects", { params });
|
||||
const response = await apiClient.get('/projects', { params });
|
||||
// Handle paginated response
|
||||
if (response.data && Array.isArray(response.data.data)) {
|
||||
return response.data.data;
|
||||
return response.data.data;
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
@@ -31,7 +27,7 @@ export const projectService = {
|
||||
|
||||
/** สร้างโครงการใหม่ (Admin) */
|
||||
create: async (data: CreateProjectDto) => {
|
||||
const response = await apiClient.post("/projects", data);
|
||||
const response = await apiClient.post('/projects', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
// File: lib/services/rfa.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import {
|
||||
CreateRfaDto,
|
||||
UpdateRfaDto,
|
||||
SearchRfaDto
|
||||
} from "@/types/dto/rfa/rfa.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { CreateRfaDto, UpdateRfaDto, SearchRfaDto } from '@/types/dto/rfa/rfa.dto';
|
||||
|
||||
// DTO สำหรับการอนุมัติ (อาจจะย้ายไปไว้ใน folder dto/rfa/ ก็ได้ในอนาคต)
|
||||
export interface WorkflowActionDto {
|
||||
@@ -19,7 +15,7 @@ export const rfaService = {
|
||||
*/
|
||||
getAll: async (params: SearchRfaDto) => {
|
||||
// GET /rfas
|
||||
const response = await apiClient.get("/rfas", { params });
|
||||
const response = await apiClient.get('/rfas', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -37,7 +33,7 @@ export const rfaService = {
|
||||
*/
|
||||
create: async (data: CreateRfaDto) => {
|
||||
// POST /rfas
|
||||
const response = await apiClient.post("/rfas", data);
|
||||
const response = await apiClient.post('/rfas', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -66,5 +62,5 @@ export const rfaService = {
|
||||
// DELETE /rfas/:uuid (ADR-019)
|
||||
const response = await apiClient.delete(`/rfas/${uuid}`);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// File: lib/services/search.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { SearchQueryDto } from "@/types/dto/search/search-query.dto";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { SearchQueryDto } from '@/types/dto/search/search-query.dto';
|
||||
|
||||
export const searchService = {
|
||||
/**
|
||||
@@ -10,8 +10,8 @@ export const searchService = {
|
||||
search: async (query: SearchQueryDto) => {
|
||||
// ส่ง params แบบ flat ตาม DTO
|
||||
// GET /search?q=...&type=...&projectId=...
|
||||
const response = await apiClient.get("/search", {
|
||||
params: query
|
||||
const response = await apiClient.get('/search', {
|
||||
params: query,
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
@@ -21,8 +21,8 @@ export const searchService = {
|
||||
* ใช้ search endpoint แต่จำกัดจำนวน
|
||||
*/
|
||||
suggest: async (query: string) => {
|
||||
const response = await apiClient.get("/search", {
|
||||
params: { q: query, limit: 5 }
|
||||
const response = await apiClient.get('/search', {
|
||||
params: { q: query, limit: 5 },
|
||||
});
|
||||
// Assuming backend returns { items: [], ... } or just []
|
||||
return response.data.items || response.data;
|
||||
@@ -32,7 +32,7 @@ export const searchService = {
|
||||
* (Optional) Re-index ข้อมูลใหม่ กรณีข้อมูลไม่ตรง (Admin Only)
|
||||
*/
|
||||
reindex: async (type?: string) => {
|
||||
const response = await apiClient.post("/search/reindex", { type });
|
||||
const response = await apiClient.post('/search/reindex', { type });
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface Session {
|
||||
isCurrent: boolean;
|
||||
}
|
||||
|
||||
const extractArrayData = <T,>(value: unknown): T[] => {
|
||||
const extractArrayData = <T>(value: unknown): T[] => {
|
||||
let current: unknown = value;
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
@@ -39,8 +39,12 @@ const transformSession = (session: Session | (Omit<Session, 'id'> & { id: string
|
||||
|
||||
export const sessionService = {
|
||||
getActiveSessions: async (): Promise<Session[]> => {
|
||||
const response = await apiClient.get<Session[] | { data: Session[] } | { data: { data: Session[] } }>('/auth/sessions');
|
||||
return extractArrayData<Session | (Omit<Session, 'id'> & { id: string | number })>(response.data).map(transformSession);
|
||||
const response = await apiClient.get<Session[] | { data: Session[] } | { data: { data: Session[] } }>(
|
||||
'/auth/sessions'
|
||||
);
|
||||
return extractArrayData<Session | (Omit<Session, 'id'> & { id: string | number })>(response.data).map(
|
||||
transformSession
|
||||
);
|
||||
},
|
||||
|
||||
revokeSession: async (sessionId: number) => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// File: lib/services/transmittal.service.ts
|
||||
import apiClient from "@/lib/api/client";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import {
|
||||
CreateTransmittalDto,
|
||||
UpdateTransmittalDto,
|
||||
SearchTransmittalDto
|
||||
} from "@/types/dto/transmittal/transmittal.dto";
|
||||
SearchTransmittalDto,
|
||||
} from '@/types/dto/transmittal/transmittal.dto';
|
||||
|
||||
export const transmittalService = {
|
||||
/**
|
||||
@@ -12,7 +12,7 @@ export const transmittalService = {
|
||||
*/
|
||||
getAll: async (params: SearchTransmittalDto) => {
|
||||
// GET /transmittals
|
||||
const response = await apiClient.get("/transmittals", { params });
|
||||
const response = await apiClient.get('/transmittals', { params });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@ export const transmittalService = {
|
||||
*/
|
||||
create: async (data: CreateTransmittalDto) => {
|
||||
// POST /transmittals
|
||||
const response = await apiClient.post("/transmittals", data);
|
||||
const response = await apiClient.post('/transmittals', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -50,5 +50,5 @@ export const transmittalService = {
|
||||
// DELETE /transmittals/:uuid (ADR-019)
|
||||
const response = await apiClient.delete(`/transmittals/${uuid}`);
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import apiClient from "@/lib/api/client";
|
||||
import { CreateUserDto, UpdateUserDto, SearchUserDto, User, Role } from "@/types/user";
|
||||
import apiClient from '@/lib/api/client';
|
||||
import { CreateUserDto, UpdateUserDto, SearchUserDto, User, Role } from '@/types/user';
|
||||
|
||||
/** Raw API user shape (before transform) */
|
||||
interface RawUser {
|
||||
@@ -9,7 +9,7 @@ interface RawUser {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const extractArrayData = <T,>(value: unknown): T[] => {
|
||||
const extractArrayData = <T>(value: unknown): T[] => {
|
||||
let current: unknown = value;
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
@@ -17,7 +17,7 @@ const extractArrayData = <T,>(value: unknown): T[] => {
|
||||
return current as T[];
|
||||
}
|
||||
|
||||
if (!current || typeof current !== "object" || !("data" in current)) {
|
||||
if (!current || typeof current !== 'object' || !('data' in current)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -41,12 +41,12 @@ type UserListResponse = User[] | { data: User[] | { data: User[] } };
|
||||
|
||||
export const userService = {
|
||||
getAll: async (params?: SearchUserDto) => {
|
||||
const response = await apiClient.get<UserListResponse>("/users", { params });
|
||||
const response = await apiClient.get<UserListResponse>('/users', { params });
|
||||
return extractArrayData<RawUser>(response.data).map(transformUser);
|
||||
},
|
||||
|
||||
getRoles: async (): Promise<Role[]> => {
|
||||
const response = await apiClient.get<{ data: unknown } | unknown>("/users/roles");
|
||||
const response = await apiClient.get<{ data: unknown } | unknown>('/users/roles');
|
||||
return extractArrayData<Role>(response.data);
|
||||
},
|
||||
|
||||
@@ -56,7 +56,7 @@ export const userService = {
|
||||
},
|
||||
|
||||
create: async (data: CreateUserDto) => {
|
||||
const response = await apiClient.post<RawUser>("/users", data);
|
||||
const response = await apiClient.post<RawUser>('/users', data);
|
||||
return transformUser(response.data);
|
||||
},
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ interface BackendWorkflowShape {
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
const extractArrayData = <T,>(value: unknown): T[] => {
|
||||
const extractArrayData = <T>(value: unknown): T[] => {
|
||||
let current: unknown = value;
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
@@ -52,7 +52,7 @@ const extractArrayData = <T,>(value: unknown): T[] => {
|
||||
return Array.isArray(current) ? (current as T[]) : [];
|
||||
};
|
||||
|
||||
const extractNestedData = <T,>(value: unknown): T => {
|
||||
const extractNestedData = <T>(value: unknown): T => {
|
||||
let current: unknown = value;
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
@@ -106,9 +106,7 @@ const mapWorkflow = (backendObj: BackendWorkflowShape): Workflow => {
|
||||
backendObj.workflow_code ||
|
||||
'',
|
||||
description:
|
||||
backendObj.description ||
|
||||
(typeof backendObj.dsl === 'object' ? backendObj.dsl?.description : undefined) ||
|
||||
'',
|
||||
backendObj.description || (typeof backendObj.dsl === 'object' ? backendObj.dsl?.description : undefined) || '',
|
||||
workflowType: normalizeWorkflowType(backendObj.workflow_code),
|
||||
version: backendObj.version || 1,
|
||||
isActive: backendObj.is_active ?? false,
|
||||
|
||||
Reference in New Issue
Block a user