Browse Source

update epic 8 & 10

pearlgw 18 hours ago
parent
commit
a0148298df
58 changed files with 1687 additions and 2121 deletions
  1. 48 0
      prisma/migrations/20250908013400_update_erd_vendor_experience/migration.sql
  2. 11 0
      prisma/migrations/20250908020610_update/migration.sql
  3. 11 0
      prisma/migrations/20250908023150_update/migration.sql
  4. 2 0
      prisma/migrations/20250908065231_add_field_status_archieve_in_table_category/migration.sql
  5. 9 0
      prisma/migrations/20250908065458_add_field_status_archieve_in_table_category_update_type/migration.sql
  6. 2 0
      prisma/migrations/20250908070214_add_field_status_archieve_in_table_category_update_type_add_default/migration.sql
  7. 9 0
      prisma/migrations/20250908071236_add_field_status_archieve_in_table_category_update_type_add_default_edit/migration.sql
  8. 43 35
      prisma/schema.prisma
  9. 43 43
      prisma/seeders/DatabaseSeeder.ts
  10. 2 2
      prisma/seeders/HospitalSeeder.ts
  11. 2 2
      prisma/seeders/UserAreaSeeder.ts
  12. 1 1
      prisma/seeders/VendorSeeder.ts
  13. 9 25
      src/controllers/admin/CategoryController.ts
  14. 3 64
      src/controllers/admin/VendorExperienceController.ts
  15. 1 52
      src/controllers/sales/HospitalController.ts
  16. 2 2
      src/controllers/sales/VendorExperienceController.ts
  17. 65 64
      src/repository/admin/CategoryRepository.ts
  18. 2 2
      src/repository/admin/HospitalRepository.ts
  19. 24 5
      src/repository/admin/ScheduleVisitationRepository.ts
  20. 51 161
      src/repository/admin/VendorExperienceRepository.ts
  21. 2 1
      src/repository/admin/VendorRepository.ts
  22. 3 138
      src/repository/sales/HospitalRepository.ts
  23. 14 4
      src/repository/sales/ScheduleVisitationRepository.ts
  24. 49 105
      src/repository/sales/VendorExperienceRepository.ts
  25. 25 25
      src/resources/admin/hospital/HospitalCollection.ts
  26. 14 14
      src/resources/admin/hospital/HospitalResource.ts
  27. 2 2
      src/resources/admin/schedule_visitation/ScheduleVisitationResource.ts
  28. 26 26
      src/resources/admin/status_history/StatusHistoryCollection.ts
  29. 21 21
      src/resources/admin/vendor/VendorCollection.ts
  30. 18 18
      src/resources/admin/vendor/VendorResource.ts
  31. 32 32
      src/resources/admin/vendor_experience/VendorExperienceCollection.ts
  32. 38 25
      src/resources/admin/vendor_experience/VendorExperienceResource.ts
  33. 25 25
      src/resources/sales/hospital/HospitalCollection.ts
  34. 14 14
      src/resources/sales/hospital/HospitalResource.ts
  35. 2 2
      src/resources/sales/schedule_visitation/ScheduleVisitationResource.ts
  36. 25 25
      src/resources/sales/status_history/StatusHistoryCollection.ts
  37. 33 34
      src/resources/sales/vendor_experience/VendorExperienceCollection.ts
  38. 38 25
      src/resources/sales/vendor_experience/VendorExperienceResource.ts
  39. 4 3
      src/routes/admin/CategoryRoute.ts
  40. 55 55
      src/services/admin/CategoryLinkService.ts
  41. 154 114
      src/services/admin/CategoryService.ts
  42. 1 75
      src/services/admin/CityService.ts
  43. 25 25
      src/services/admin/HospitalService.ts
  44. 9 9
      src/services/admin/StatusHistoryService.ts
  45. 213 445
      src/services/admin/VendorExperienceService.ts
  46. 41 42
      src/services/admin/VendorService.ts
  47. 17 17
      src/services/sales/HospitalService.ts
  48. 9 9
      src/services/sales/StatusHistoryService.ts
  49. 211 168
      src/services/sales/VendorExperienceService.ts
  50. 4 4
      src/types/admin/category/CategoryDTO.ts
  51. 16 4
      src/types/admin/schedule_visitation/ScheduleVisitationDTO.ts
  52. 43 28
      src/types/admin/vendor_experience/VendorExperienceDTO.ts
  53. 16 4
      src/types/sales/schedule_visitation/ScheduleVisitationDTO.ts
  54. 40 28
      src/types/sales/vendor_experience/VendorExperienceDTO.ts
  55. 25 25
      src/validators/admin/category/CategoryValidators.ts
  56. 38 34
      src/validators/admin/vendor_experience/VendorExperienceValidators.ts
  57. 39 34
      src/validators/sales/vendor_experience/VendorExperienceValidators.ts
  58. 6 4
      tsconfig.json

+ 48 - 0
prisma/migrations/20250908013400_update_erd_vendor_experience/migration.sql

@@ -0,0 +1,48 @@
1
+/*
2
+  Warnings:
3
+
4
+  - You are about to drop the column `tag` on the `categories` table. All the data in the column will be lost.
5
+  - You are about to drop the column `contract_expired_date` on the `vendor_experiences` table. All the data in the column will be lost.
6
+  - You are about to drop the column `contract_start_date` on the `vendor_experiences` table. All the data in the column will be lost.
7
+  - You are about to drop the column `contract_value_max` on the `vendor_experiences` table. All the data in the column will be lost.
8
+  - You are about to drop the column `contract_value_min` on the `vendor_experiences` table. All the data in the column will be lost.
9
+  - You are about to drop the column `negative_notes` on the `vendor_experiences` table. All the data in the column will be lost.
10
+  - You are about to drop the column `positive_notes` on the `vendor_experiences` table. All the data in the column will be lost.
11
+  - You are about to drop the column `simrs_type` on the `vendor_experiences` table. All the data in the column will be lost.
12
+  - You are about to drop the column `status` on the `vendor_experiences` table. All the data in the column will be lost.
13
+  - You are about to drop the `category_links` table. If the table is not empty, all the data it contains will be lost.
14
+  - Added the required column `name` to the `categories` table without a default value. This is not possible if the table is not empty.
15
+  - Added the required column `user_id` to the `vendor_experiences` table without a default value. This is not possible if the table is not empty.
16
+
17
+*/
18
+-- DropForeignKey
19
+ALTER TABLE "category_links" DROP CONSTRAINT "category_links_category_id_fkey";
20
+
21
+-- AlterTable
22
+ALTER TABLE "categories" DROP COLUMN "tag",
23
+ADD COLUMN     "name" TEXT NOT NULL;
24
+
25
+-- AlterTable
26
+ALTER TABLE "vendor_experiences" DROP COLUMN "contract_expired_date",
27
+DROP COLUMN "contract_start_date",
28
+DROP COLUMN "contract_value_max",
29
+DROP COLUMN "contract_value_min",
30
+DROP COLUMN "negative_notes",
31
+DROP COLUMN "positive_notes",
32
+DROP COLUMN "simrs_type",
33
+DROP COLUMN "status",
34
+ADD COLUMN     "category_id" TEXT,
35
+ADD COLUMN     "userKeycloakId" TEXT,
36
+ADD COLUMN     "user_id" TEXT NOT NULL;
37
+
38
+-- DropTable
39
+DROP TABLE "category_links";
40
+
41
+-- AddForeignKey
42
+ALTER TABLE "vendor_experiences" ADD CONSTRAINT "vendor_experiences_category_id_fkey" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE SET NULL ON UPDATE CASCADE;
43
+
44
+-- AddForeignKey
45
+ALTER TABLE "vendor_experiences" ADD CONSTRAINT "vendor_experiences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
46
+
47
+-- AddForeignKey
48
+ALTER TABLE "vendor_experiences" ADD CONSTRAINT "vendor_experiences_userKeycloakId_fkey" FOREIGN KEY ("userKeycloakId") REFERENCES "keycloak_users"("id") ON DELETE SET NULL ON UPDATE CASCADE;

+ 11 - 0
prisma/migrations/20250908020610_update/migration.sql

@@ -0,0 +1,11 @@
1
+-- DropForeignKey
2
+ALTER TABLE "vendor_experiences" DROP CONSTRAINT "vendor_experiences_userKeycloakId_fkey";
3
+
4
+-- DropForeignKey
5
+ALTER TABLE "vendor_experiences" DROP CONSTRAINT "vendor_experiences_user_id_fkey";
6
+
7
+-- AlterTable
8
+ALTER TABLE "vendor_experiences" ADD COLUMN     "userId" TEXT;
9
+
10
+-- AddForeignKey
11
+ALTER TABLE "vendor_experiences" ADD CONSTRAINT "vendor_experiences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "keycloak_users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

+ 11 - 0
prisma/migrations/20250908023150_update/migration.sql

@@ -0,0 +1,11 @@
1
+/*
2
+  Warnings:
3
+
4
+  - You are about to drop the column `userId` on the `vendor_experiences` table. All the data in the column will be lost.
5
+  - You are about to drop the column `userKeycloakId` on the `vendor_experiences` table. All the data in the column will be lost.
6
+
7
+*/
8
+-- AlterTable
9
+ALTER TABLE "vendor_experiences" DROP COLUMN "userId",
10
+DROP COLUMN "userKeycloakId",
11
+ADD COLUMN     "content" TEXT;

+ 2 - 0
prisma/migrations/20250908065231_add_field_status_archieve_in_table_category/migration.sql

@@ -0,0 +1,2 @@
1
+-- AlterTable
2
+ALTER TABLE "categories" ADD COLUMN     "status_archieve" TEXT;

+ 9 - 0
prisma/migrations/20250908065458_add_field_status_archieve_in_table_category_update_type/migration.sql

@@ -0,0 +1,9 @@
1
+/*
2
+  Warnings:
3
+
4
+  - The `status_archieve` column on the `categories` table would be dropped and recreated. This will lead to data loss if there is data in the column.
5
+
6
+*/
7
+-- AlterTable
8
+ALTER TABLE "categories" DROP COLUMN "status_archieve",
9
+ADD COLUMN     "status_archieve" BOOLEAN;

+ 2 - 0
prisma/migrations/20250908070214_add_field_status_archieve_in_table_category_update_type_add_default/migration.sql

@@ -0,0 +1,2 @@
1
+-- AlterTable
2
+ALTER TABLE "categories" ALTER COLUMN "status_archieve" SET DEFAULT false;

+ 9 - 0
prisma/migrations/20250908071236_add_field_status_archieve_in_table_category_update_type_add_default_edit/migration.sql

@@ -0,0 +1,9 @@
1
+/*
2
+  Warnings:
3
+
4
+  - You are about to drop the column `status_archieve` on the `categories` table. All the data in the column will be lost.
5
+
6
+*/
7
+-- AlterTable
8
+ALTER TABLE "categories" DROP COLUMN "status_archieve",
9
+ADD COLUMN     "status_archive" BOOLEAN DEFAULT false;

+ 43 - 35
prisma/schema.prisma

@@ -67,6 +67,7 @@ model UserKeycloak {
67 67
   UserArea           UserArea[]
68 68
   Vendor             Vendor[]
69 69
   StatusHistory      StatusHistory[]
70
+  VendorExperience   VendorExperience[]
70 71
   CreatedVisitations ScheduleVisitation[] @relation("CreatedVisitations")
71 72
   SalesVisitations   ScheduleVisitation[] @relation("SalesVisitations")
72 73
 
@@ -181,22 +182,27 @@ model UserArea {
181 182
 // }
182 183
 
183 184
 model VendorExperience {
184
-  id                    String    @id @default(uuid())
185
-  hospital_id           String
186
-  vendor_id             String?
187
-  status                String?
188
-  contract_start_date   DateTime?
189
-  contract_expired_date DateTime?
190
-  contract_value_min    BigInt?
191
-  contract_value_max    BigInt?
192
-  positive_notes        String?   @db.Text
193
-  negative_notes        String?   @db.Text
194
-  simrs_type            String
195
-  hospital              Hospital  @relation(fields: [hospital_id], references: [id])
196
-  vendor                Vendor?   @relation(fields: [vendor_id], references: [id])
197
-  createdAt             DateTime  @default(now())
198
-  updatedAt             DateTime  @updatedAt
199
-  deletedAt             DateTime?
185
+  id          String       @id @default(uuid())
186
+  hospital_id String
187
+  vendor_id   String?
188
+  category_id String?
189
+  user_id     String
190
+  content     String?      @db.Text
191
+  hospital    Hospital     @relation(fields: [hospital_id], references: [id])
192
+  vendor      Vendor?      @relation(fields: [vendor_id], references: [id])
193
+  category    Category?    @relation(fields: [category_id], references: [id])
194
+  user        UserKeycloak @relation(fields: [user_id], references: [id])
195
+  createdAt   DateTime     @default(now())
196
+  updatedAt   DateTime     @updatedAt
197
+  deletedAt   DateTime?
198
+  // status                String?
199
+  // contract_start_date   DateTime?
200
+  // contract_expired_date DateTime?
201
+  // contract_value_min    BigInt?
202
+  // contract_value_max    BigInt?
203
+  // positive_notes        String?   @db.Text
204
+  // negative_notes        String?   @db.Text
205
+  // simrs_type            String
200 206
 
201 207
   @@map("vendor_experiences")
202 208
 }
@@ -234,29 +240,31 @@ model StatusHistory {
234 240
 }
235 241
 
236 242
 model Category {
237
-  id           String         @id @default(uuid())
238
-  tag          String
239
-  description  String?        @db.Text
240
-  CategoryLink CategoryLink[]
241
-  createdAt    DateTime       @default(now())
242
-  updatedAt    DateTime       @updatedAt
243
-  deletedAt    DateTime?
243
+  id               String             @id @default(uuid())
244
+  name             String
245
+  description      String?            @db.Text
246
+  status_archive   Boolean?           @default(false)
247
+  // CategoryLink CategoryLink[]
248
+  createdAt        DateTime           @default(now())
249
+  updatedAt        DateTime           @updatedAt
250
+  deletedAt        DateTime?
251
+  VendorExperience VendorExperience[]
244 252
 
245 253
   @@map("categories")
246 254
 }
247 255
 
248
-model CategoryLink {
249
-  id          String    @id @default(uuid())
250
-  category_id String
251
-  source_type String?
252
-  source_id   String?
253
-  createdAt   DateTime  @default(now())
254
-  updatedAt   DateTime  @updatedAt
255
-  deletedAt   DateTime?
256
-  Category    Category? @relation(fields: [category_id], references: [id])
257
-
258
-  @@map("category_links")
259
-}
256
+// model CategoryLink {
257
+//   id          String    @id @default(uuid())
258
+//   category_id String
259
+//   source_type String?
260
+//   source_id   String?
261
+//   createdAt   DateTime  @default(now())
262
+//   updatedAt   DateTime  @updatedAt
263
+//   deletedAt   DateTime?
264
+//   Category    Category? @relation(fields: [category_id], references: [id])
265
+
266
+//   @@map("category_links")
267
+// }
260 268
 
261 269
 model ScheduleVisitation {
262 270
   id           String       @id @default(uuid())

+ 43 - 43
prisma/seeders/DatabaseSeeder.ts

@@ -44,49 +44,49 @@ import { seedUserAreas } from './UserAreaSeeder';
44 44
 import { seedHospitals } from './HospitalSeeder';
45 45
 
46 46
 async function main(): Promise<void> {
47
-    await seedProvinces();
48
-    await seedAcehCities();
49
-    await seedBaliCities();
50
-    await seedBantenCities();
51
-    await seedBengkuluCities();
52
-    await seedDIYogyakartaCities();
53
-    await seedDKIJakartaCities();
54
-    await seedGorontaloCities();
55
-    await seedJambiCities();
56
-    await seedJawaBaratCities();
57
-    await seedJawaTengahCities();
58
-    await seedJawaTimurCities();
59
-    await seedKalimantanBaratCities();
60
-    await seedKalimantanSelatanCities();
61
-    await seedKalimantanTengahCities();
62
-    await seedKalimantanTimurCities();
63
-    await seedKalimantanUtaraCities();
64
-    await seedKepulauanBangkaBelitungCities();
65
-    await seedKepulauanRiauCities();
66
-    await seedLampungCities();
67
-    await seedMalukuCities();
68
-    await seedMalukuUtaraCities();
69
-    await seedNusaTenggaraBaratCities();
70
-    await seedNusaTenggaraTimurCities();
71
-    await seedPapuaCities();
72
-    await seedPapuaBaratCities();
73
-    await seedPapuaBaratDayaCities();
74
-    await seedPapuaPegununganCities();
75
-    await seedPapuaTengahCities();
76
-    await seedRiauCities();
77
-    await seedSulawesiBaratCities();
78
-    await seedSulawesiSelatanCities();
79
-    await seedSulawesiTengahCities();
80
-    await seedSulawesiTenggaraCities();
81
-    await seedSulawesiUtaraCities();
82
-    await seedSumateraBaratCities();
83
-    await seedSumateraSelatanCities();
84
-    await seedSumateraUtaraCities();
85
-    await seedPapuaSelatanCities();
86
-    await seedUsers();
87
-    // await seedVendors();
88
-    // await seedUserAreas();
89
-    // await seedHospitals();
47
+    // await seedProvinces();
48
+    // await seedAcehCities();
49
+    // await seedBaliCities();
50
+    // await seedBantenCities();
51
+    // await seedBengkuluCities();
52
+    // await seedDIYogyakartaCities();
53
+    // await seedDKIJakartaCities();
54
+    // await seedGorontaloCities();
55
+    // await seedJambiCities();
56
+    // await seedJawaBaratCities();
57
+    // await seedJawaTengahCities();
58
+    // await seedJawaTimurCities();
59
+    // await seedKalimantanBaratCities();
60
+    // await seedKalimantanSelatanCities();
61
+    // await seedKalimantanTengahCities();
62
+    // await seedKalimantanTimurCities();
63
+    // await seedKalimantanUtaraCities();
64
+    // await seedKepulauanBangkaBelitungCities();
65
+    // await seedKepulauanRiauCities();
66
+    // await seedLampungCities();
67
+    // await seedMalukuCities();
68
+    // await seedMalukuUtaraCities();
69
+    // await seedNusaTenggaraBaratCities();
70
+    // await seedNusaTenggaraTimurCities();
71
+    // await seedPapuaCities();
72
+    // await seedPapuaBaratCities();
73
+    // await seedPapuaBaratDayaCities();
74
+    // await seedPapuaPegununganCities();
75
+    // await seedPapuaTengahCities();
76
+    // await seedRiauCities();
77
+    // await seedSulawesiBaratCities();
78
+    // await seedSulawesiSelatanCities();
79
+    // await seedSulawesiTengahCities();
80
+    // await seedSulawesiTenggaraCities();
81
+    // await seedSulawesiUtaraCities();
82
+    // await seedSumateraBaratCities();
83
+    // await seedSumateraSelatanCities();
84
+    // await seedSumateraUtaraCities();
85
+    // await seedPapuaSelatanCities();
86
+    // await seedUsers();
87
+    await seedVendors();
88
+    await seedUserAreas();
89
+    await seedHospitals();
90 90
 }
91 91
 
92 92
 main()

+ 2 - 2
prisma/seeders/HospitalSeeder.ts

@@ -5,8 +5,8 @@ const prisma = new PrismaClient();
5 5
 
6 6
 export async function seedHospitals(): Promise<void> {
7 7
     try {
8
-        const sales1 = await prisma.userKeycloak.findFirst({ where: { id: '00c7e427-cbb7-408c-af44-e04747fd61fd' } });
9
-        const sales2 = await prisma.userKeycloak.findFirst({ where: { id: 'd27994a4-07b9-4ea8-bd62-3d6c51afed0e' } });
8
+        const sales1 = await prisma.userKeycloak.findFirst({ where: { id: '1d750cae-45ac-4aff-b20c-d2c5e54185e1' } });
9
+        const sales2 = await prisma.userKeycloak.findFirst({ where: { id: '5064d1f3-74fc-42bd-bd85-9842eed60ac2' } });
10 10
 
11 11
         if (!sales1 || !sales2) {
12 12
             throw new Error('User sales1 or sales2 not found');

+ 2 - 2
prisma/seeders/UserAreaSeeder.ts

@@ -3,8 +3,8 @@ import prisma from '../../src/prisma/PrismaClient';
3 3
 export async function seedUserAreas(): Promise<void> {
4 4
     try {
5 5
         // Ambil user dengan username 'sales1' dan 'sales2'
6
-        const sales1 = await prisma.userKeycloak.findFirst({ where: { id: '00c7e427-cbb7-408c-af44-e04747fd61fd' } });
7
-        const sales2 = await prisma.userKeycloak.findFirst({ where: { id: 'd27994a4-07b9-4ea8-bd62-3d6c51afed0e' } });
6
+        const sales1 = await prisma.userKeycloak.findFirst({ where: { id: '1d750cae-45ac-4aff-b20c-d2c5e54185e1' } });
7
+        const sales2 = await prisma.userKeycloak.findFirst({ where: { id: '5064d1f3-74fc-42bd-bd85-9842eed60ac2' } });
8 8
 
9 9
         if (!sales1 || !sales2) {
10 10
             throw new Error('User sales1 or sales2 not found');

+ 1 - 1
prisma/seeders/VendorSeeder.ts

@@ -13,7 +13,7 @@ export async function seedVendors(): Promise<void> {
13 13
         // Cari user dengan username admin1
14 14
         const adminUser = await prisma.userKeycloak.findFirst({
15 15
             where: {
16
-                id: '06ccc7a6-9f6d-437f-9e1f-501a36077796',
16
+                id: '6471416f-e24e-4d27-815a-9f12a1344e18',
17 17
             },
18 18
         });
19 19
 

+ 9 - 25
src/controllers/admin/CategoryController.ts

@@ -2,18 +2,20 @@ import { Request, Response } from 'express';
2 2
 import * as CategoryService from '../../services/admin/CategoryService';
3 3
 import { PaginationParam } from '../../utils/PaginationParams';
4 4
 import { errorResponse, messageSuccessResponse } from '../../utils/Response';
5
-import { validateCategoryStoreRequest, validateCategoryUpdateRequest, validateMergeCategoryStoreRequest } from '../../validators/admin/category/CategoryValidators';
5
+import { validateCategoryStoreRequest, validateCategoryUpdateRequest } from '../../validators/admin/category/CategoryValidators';
6 6
 import { CustomRequest } from '../../types/token/CustomRequest';
7 7
 import { CategoryCollection } from '../../resources/admin/category/CategoryCollection';
8 8
 import { CategoryResource } from '../../resources/admin/category/CategoryResource';
9
-import { CategoryLinkCollection } from '../../resources/admin/category/CategoryUseCollection';
9
+// import { CategoryLinkCollection } from '../../resources/admin/category/CategoryUseCollection';
10 10
 
11 11
 export const getAllCategory = async (req: Request, res: Response): Promise<Response> => {
12 12
     try {
13 13
         const { page, limit, search, sortBy, orderBy } = PaginationParam(req);
14
+        const filter = req.query.filter as 'archive' | 'all' | undefined;
15
+        const usage = req.query.usage as 'unused' | 'used' | undefined;
14 16
 
15 17
         const { categories, total } = await CategoryService.getAllCategoryService({
16
-            page, limit, search, sortBy, orderBy
18
+            page, limit, search, sortBy, orderBy, filter, usage
17 19
         });
18 20
 
19 21
         return CategoryCollection(req, res, categories, total, page, limit, 'Category data successfully retrieved');
@@ -63,29 +65,11 @@ export const deleteCategory = async (req: Request, res: Response): Promise<Respo
63 65
     }
64 66
 };
65 67
 
66
-export const showUseCategory = async (req: Request, res: Response): Promise<Response> => {
68
+export const archiveCategory = async (req: Request, res: Response): Promise<Response> => {
67 69
     try {
68
-        const categoryId = req.params.id;
69
-        const { page, limit, search } = PaginationParam(req);
70
-
71
-        const { data, total } = await CategoryService.showUseCategoryService({
72
-            page,
73
-            limit,
74
-            search,
75
-            categoryId,
76
-        });
77
-
78
-        return CategoryLinkCollection(req, res, data, total, page, limit, 'Category usage data successfully retrieved');
79
-    } catch (err) {
80
-        return errorResponse(res, err);
81
-    }
82
-};
83
-
84
-export const mergeCategory = async (req: Request, res: Response): Promise<Response> => {
85
-    try {
86
-        const validatedData = validateMergeCategoryStoreRequest(req.body);
87
-        await CategoryService.mergeCategoryService(validatedData, req as CustomRequest);
88
-        return messageSuccessResponse(res, 'Success merge category', 200);
70
+        const id = req.params.id;
71
+        await CategoryService.archiveCategoryService(id, req as CustomRequest);
72
+        return messageSuccessResponse(res, 'Success archive category');
89 73
     } catch (err) {
90 74
         return errorResponse(res, err);
91 75
     }

+ 3 - 64
src/controllers/admin/VendorExperienceController.ts

@@ -9,10 +9,10 @@ import { CustomRequest } from '../../types/token/CustomRequest';
9 9
 
10 10
 export const getAllVendorExperience = async (req: Request, res: Response): Promise<Response> => {
11 11
     try {
12
-        const { page, limit, search, sortBy, orderBy } = PaginationParam(req);
12
+        const { page, limit, search, sortBy, orderBy, category_id } = PaginationParam(req, ['category_id']);
13 13
 
14 14
         const { vendor_experiences, total } = await VendorExperienceService.getAllVendorExperienceService(
15
-            { page, limit, search, sortBy, orderBy },
15
+            { page, limit, search, sortBy, orderBy, category_id },
16 16
             req
17 17
         );
18 18
 
@@ -58,65 +58,4 @@ export const deleteVendorExperience = async (req: Request, res: Response): Promi
58 58
     } catch (err) {
59 59
         return errorResponse(res, err);
60 60
     }
61
-};
62
-
63
-
64
-// const { VendorExperienceCollection } = require('../../resources/admin/vendor_experience/VendorExperienceCollection.js');
65
-// const { VendorExperienceResource } = require('../../resources/admin/vendor_experience/VendorExperienceResource.js');
66
-// const vendorHistoryService = require('../../services/admin/VendorExperienceService.js');
67
-// const { PaginationParam } = require('../../utils/PaginationParams.js');
68
-// const { errorResponse, messageSuccessResponse } = require('../../utils/Response.js');
69
-// const { validateStoreVendorHistoryRequest, validateUpdateVendorHistoryRequest } = require('../../validators/admin/vendor_experience/VendorExperienceValidators.js');
70
-
71
-// exports.getAllVendorHistory = async (req, res) => {
72
-//     try {
73
-//         const { page, limit, search, sortBy, orderBy } = PaginationParam(req);
74
-
75
-//         const { vendor_histories, total } = await vendorHistoryService.getAllVendorHistoryService({
76
-//             page, limit, search, sortBy, orderBy
77
-//         }, req);
78
-
79
-//         return VendorExperienceCollection(req, res, vendor_histories, total, page, limit, 'Vendor experience successfully retrieved');
80
-
81
-//     } catch (err) {
82
-//         return errorResponse(res, err);
83
-//     }
84
-// };
85
-
86
-// exports.showVendorHistory = async (req, res) => {
87
-//     try {
88
-//         const data = await vendorHistoryService.showVendorHistoryService(req);
89
-//         return VendorExperienceResource(res, data, 'Success show vendor experience');
90
-//     } catch (err) {
91
-//         return errorResponse(res, err);
92
-//     }
93
-// };
94
-
95
-// exports.storeVendorHistory = async (req, res) => {
96
-//     try {
97
-//         const validatedData = validateStoreVendorHistoryRequest(req.body);
98
-//         await vendorHistoryService.storeVendorHistoryService(validatedData, req);
99
-//         return messageSuccessResponse(res, 'Success added vendor experience', 201);
100
-//     } catch (err) {
101
-//         return errorResponse(res, err);
102
-//     }
103
-// }
104
-
105
-// exports.updateVendorHistory = async (req, res) => {
106
-//     try {
107
-//         const validatedData = validateUpdateVendorHistoryRequest(req.body);
108
-//         await vendorHistoryService.updateVendorHistoryService(validatedData, req);
109
-//         return messageSuccessResponse(res, 'Success update vendor experience');
110
-//     } catch (err) {
111
-//         return errorResponse(res, err);
112
-//     }
113
-// }
114
-
115
-// exports.deleteVendorHistory = async (req, res) => {
116
-//     try {
117
-//         await vendorHistoryService.deleteVendorHistoryService(req);
118
-//         return messageSuccessResponse(res, 'Success delete vendor experience');
119
-//     } catch (err) {
120
-//         return errorResponse(res, err);
121
-//     }
122
-// };
61
+};

+ 1 - 52
src/controllers/sales/HospitalController.ts

@@ -54,55 +54,4 @@ export const showHospital = async (req: Request, res: Response): Promise<Respons
54 54
     } catch (err) {
55 55
         return errorResponse(res, err);
56 56
     }
57
-};
58
-
59
-
60
-// const { HospitalCollection } = require("../../resources/sales/hospital/HospitalCollection.js");
61
-// const { HospitalResource } = require("../../resources/sales/hospital/HospitalResource.js");
62
-// const { getAllHospitalByAreaService, storeHospitalService, updateHospitalService, showHospitalService } = require("../../services/sales/HospitalService");
63
-// const { PaginationParam } = require("../../utils/PaginationParams");
64
-// const { errorResponse, messageSuccessResponse } = require("../../utils/Response");
65
-// const { validateStoreHospitalRequest, validateUpdateHospitalRequest } = require('../../validators/admin/hospital/HospitalValidators.js');
66
-
67
-// exports.getAllHospitalByArea = async (req, res) => {
68
-//     try {
69
-//         const { page, limit, search, sortBy, orderBy, province, city, type, ownership, progress_status } = PaginationParam(req, ['province', 'city', 'type', 'ownership', 'progress_status']);
70
-
71
-//         const { hospitals, total } = await getAllHospitalByAreaService({ page, limit, search, sortBy, orderBy, province, city, type, ownership, progress_status }, req);
72
-
73
-//         return HospitalCollection({ req, res, data: hospitals, total, page, limit, message: 'Hospital data successfully retrieved' });
74
-//     } catch (err) {
75
-//         return errorResponse(res, err);
76
-//     }
77
-// };
78
-
79
-// exports.storeHospital = async (req, res) => {
80
-//     try {
81
-//         const validatedData = validateStoreHospitalRequest(req.body);
82
-//         await storeHospitalService(validatedData, req);
83
-//         return messageSuccessResponse(res, 'Success added hospital', 201);
84
-//     } catch (err) {
85
-//         return errorResponse(res, err);
86
-//     }
87
-// }
88
-
89
-// exports.updateHospital = async (req, res) => {
90
-//     try {
91
-//         const id = req.params.id;
92
-//         const validatedData = validateUpdateHospitalRequest(req.body);
93
-//         await updateHospitalService(validatedData, id, req);
94
-//         return messageSuccessResponse(res, 'Success update hospital');
95
-//     } catch (err) {
96
-//         return errorResponse(res, err);
97
-//     }
98
-// }
99
-
100
-// exports.showHospital = async (req, res) => {
101
-//     try {
102
-//         const id = req.params.id;
103
-//         const { hospital } = await showHospitalService(id);
104
-//         return HospitalResource(res, hospital, 'Success show hospital');
105
-//     } catch (err) {
106
-//         return errorResponse(res, err);
107
-//     }
108
-// };
57
+};

+ 2 - 2
src/controllers/sales/VendorExperienceController.ts

@@ -9,10 +9,10 @@ import { CustomRequest } from '../../types/token/CustomRequest';
9 9
 
10 10
 export const getAllVendorExperience = async (req: Request, res: Response): Promise<Response> => {
11 11
     try {
12
-        const { page, limit, search, sortBy, orderBy } = PaginationParam(req);
12
+        const { page, limit, search, sortBy, orderBy, category_id } = PaginationParam(req, ['category_id']);
13 13
 
14 14
         const { vendor_experiences, total } = await VendorExperienceService.getAllVendorExperienceService(
15
-            { page, limit, search, sortBy, orderBy },
15
+            { page, limit, search, sortBy, orderBy, category_id },
16 16
             req as CustomRequest
17 17
         );
18 18
 

+ 65 - 64
src/repository/admin/CategoryRepository.ts

@@ -8,12 +8,12 @@ interface FindAllParams {
8 8
     orderBy?: Prisma.CategoryOrderByWithRelationInput;
9 9
 }
10 10
 
11
-interface FindAllCategoryLinkParams {
12
-    skip?: number;
13
-    take?: number;
14
-    where?: Prisma.CategoryLinkWhereInput;
15
-    orderBy?: Prisma.CategoryLinkOrderByWithRelationInput;
16
-}
11
+// interface FindAllCategoryLinkParams {
12
+//     skip?: number;
13
+//     take?: number;
14
+//     where?: Prisma.CategoryLinkWhereInput;
15
+//     orderBy?: Prisma.CategoryLinkOrderByWithRelationInput;
16
+// }
17 17
 
18 18
 const CategoryRepository = {
19 19
     findAll: async ({ skip, take, where, orderBy }: FindAllParams) => {
@@ -24,13 +24,13 @@ const CategoryRepository = {
24 24
             orderBy,
25 25
             select: {
26 26
                 id: true,
27
-                tag: true,
27
+                name: true,
28 28
                 description: true,
29 29
                 createdAt: true,
30 30
                 updatedAt: true,
31 31
                 _count: {
32 32
                     select: {
33
-                        CategoryLink: {
33
+                        VendorExperience: {
34 34
                             where: {
35 35
                                 deletedAt: null,
36 36
                             },
@@ -44,7 +44,7 @@ const CategoryRepository = {
44 44
             const { _count, ...rest } = v;
45 45
             return {
46 46
                 ...rest,
47
-                count_use_tags: _count.CategoryLink || 0,
47
+                count_use_category: _count.VendorExperience || 0,
48 48
             };
49 49
         });
50 50
 
@@ -56,43 +56,44 @@ const CategoryRepository = {
56 56
     },
57 57
 
58 58
     findById: async (id: string) => {
59
-        const category = await prisma.category.findFirst({
59
+        return await prisma.category.findFirst({
60 60
             where: {
61 61
                 id,
62 62
                 deletedAt: null,
63 63
             },
64 64
             select: {
65 65
                 id: true,
66
-                tag: true,
66
+                name: true,
67 67
                 description: true,
68
+                status_archive: true,
68 69
                 createdAt: true,
69 70
                 updatedAt: true,
70
-                _count: {
71
-                    select: {
72
-                        CategoryLink: {
73
-                            where: {
74
-                                deletedAt: null,
75
-                            },
76
-                        },
77
-                    },
78
-                },
71
+                // _count: {
72
+                //     select: {
73
+                //         CategoryLink: {
74
+                //             where: {
75
+                //                 deletedAt: null,
76
+                //             },
77
+                //         },
78
+                //     },
79
+                // },
79 80
             },
80 81
         });
81 82
 
82
-        if (!category) return null;
83
+        // if (!category) return null;
83 84
 
84
-        const { _count, ...rest } = category;
85
-        return {
86
-            ...rest,
87
-            count_use: _count.CategoryLink || 0,
88
-        };
85
+        // const { _count, ...rest } = category;
86
+        // return {
87
+        //     ...rest,
88
+        //     count_use: _count.CategoryLink || 0,
89
+        // };
89 90
     },
90 91
 
91
-    findByTag: async (tag: string) => {
92
+    findByName: async (name: string) => {
92 93
         return prisma.category.findFirst({
93 94
             where: {
94
-                tag: {
95
-                    equals: tag,
95
+                name: {
96
+                    equals: name,
96 97
                     mode: "insensitive",
97 98
                 },
98 99
                 deletedAt: null,
@@ -111,41 +112,41 @@ const CategoryRepository = {
111 112
         });
112 113
     },
113 114
 
114
-    findByCategoryId: async (categoryId: string) => {
115
-        return prisma.categoryLink.findMany({
116
-            where: {
117
-                category_id: categoryId,
118
-                deletedAt: null
119
-            },
120
-            select: {
121
-                id: true,
122
-                source_id: true,
123
-                source_type: true,
124
-                // category_id: true,
125
-                createdAt: true,
126
-                updatedAt: true,
127
-            }
128
-        });
129
-    },
130
-
131
-    findAllCategoryLink: async ({ skip, take, where, }: FindAllCategoryLinkParams) => {
132
-        return prisma.categoryLink.findMany({
133
-            where,
134
-            skip,
135
-            take,
136
-            select: {
137
-                id: true,
138
-                source_id: true,
139
-                source_type: true,
140
-                createdAt: true,
141
-                updatedAt: true,
142
-            },
143
-        });
144
-    },
145
-
146
-    countAllCategoryLink: async (where: Prisma.CategoryLinkWhereInput) => {
147
-        return prisma.categoryLink.count({ where });
148
-    },
115
+    // findByCategoryId: async (categoryId: string) => {
116
+    //     return prisma.categoryLink.findMany({
117
+    //         where: {
118
+    //             category_id: categoryId,
119
+    //             deletedAt: null
120
+    //         },
121
+    //         select: {
122
+    //             id: true,
123
+    //             source_id: true,
124
+    //             source_type: true,
125
+    //             // category_id: true,
126
+    //             createdAt: true,
127
+    //             updatedAt: true,
128
+    //         }
129
+    //     });
130
+    // },
131
+
132
+    // findAllCategoryLink: async ({ skip, take, where, }: FindAllCategoryLinkParams) => {
133
+    //     return prisma.categoryLink.findMany({
134
+    //         where,
135
+    //         skip,
136
+    //         take,
137
+    //         select: {
138
+    //             id: true,
139
+    //             source_id: true,
140
+    //             source_type: true,
141
+    //             createdAt: true,
142
+    //             updatedAt: true,
143
+    //         },
144
+    //     });
145
+    // },
146
+
147
+    // countAllCategoryLink: async (where: Prisma.CategoryLinkWhereInput) => {
148
+    //     return prisma.categoryLink.count({ where });
149
+    // },
149 150
 };
150 151
 
151 152
 export default CategoryRepository;

+ 2 - 2
src/repository/admin/HospitalRepository.ts

@@ -39,7 +39,7 @@ const HospitalRepository = {
39 39
                 user: { select: { id: true, fullname: true } },
40 40
                 vendor_experiences: {
41 41
                     where: {
42
-                        status: 'active',
42
+                        // status: 'active',
43 43
                         deletedAt: null,
44 44
                     },
45 45
                     select: {
@@ -101,7 +101,7 @@ const HospitalRepository = {
101 101
                 user: { select: { id: true, fullname: true } },
102 102
                 vendor_experiences: {
103 103
                     where: {
104
-                        status: 'active',
104
+                        // status: 'active',
105 105
                         deletedAt: null,
106 106
                     },
107 107
                     take: 1,

+ 24 - 5
src/repository/admin/ScheduleVisitationRepository.ts

@@ -92,15 +92,34 @@ const ScheduleVisitationRepository = {
92 92
                             },
93 93
                         },
94 94
                         vendor_experiences: {
95
-                            where: { status: "active", deletedAt: null },
95
+                            where: {
96
+                                // status: "active",
97
+                                deletedAt: null
98
+                            },
96 99
                             select: {
97 100
                                 id: true,
98 101
                                 vendor: {
99
-                                    select: { id: true, name: true }
102
+                                    select: {
103
+                                        id: true,
104
+                                        name: true
105
+                                    }
106
+                                },
107
+                                user: {
108
+                                    select: {
109
+                                        id: true,
110
+                                        fullname: true
111
+                                    }
112
+                                },
113
+                                category: {
114
+                                    select: {
115
+                                        id: true,
116
+                                        name: true,
117
+                                    }
100 118
                                 },
101
-                                contract_start_date: true,
102
-                                contract_expired_date: true,
103
-                                simrs_type: true,
119
+                                content: true
120
+                                // contract_start_date: true,
121
+                                // contract_expired_date: true,
122
+                                // simrs_type: true,
104 123
                             }
105 124
                         },
106 125
                         executives_histories: {

+ 51 - 161
src/repository/admin/VendorExperienceRepository.ts

@@ -1,4 +1,5 @@
1 1
 import { PrismaClient, Prisma } from '@prisma/client';
2
+import tr from 'zod/v4/locales/tr.cjs';
2 3
 const prisma = new PrismaClient();
3 4
 
4 5
 interface FindAllParams {
@@ -17,6 +18,7 @@ const VendorExperienceRepository = {
17 18
             orderBy,
18 19
             select: {
19 20
                 id: true,
21
+                content: true,
20 22
                 vendor: {
21 23
                     select: {
22 24
                         id: true,
@@ -28,14 +30,29 @@ const VendorExperienceRepository = {
28 30
                         created_by: true,
29 31
                     },
30 32
                 },
31
-                status: true,
32
-                simrs_type: true,
33
-                contract_value_min: true,
34
-                contract_value_max: true,
35
-                contract_start_date: true,
36
-                contract_expired_date: true,
37
-                positive_notes: true,
38
-                negative_notes: true,
33
+                // category_id: true,
34
+                category: {
35
+                    select: {
36
+                        id: true,
37
+                        name: true,
38
+                        description: true,
39
+                    },
40
+                },
41
+                // user_id: true,
42
+                user: {
43
+                    select: {
44
+                        id: true,
45
+                        fullname: true,
46
+                    },
47
+                },
48
+                // status: true,
49
+                // simrs_type: true,
50
+                // contract_value_min: true,
51
+                // contract_value_max: true,
52
+                // contract_start_date: true,
53
+                // contract_expired_date: true,
54
+                // positive_notes: true,
55
+                // negative_notes: true,
39 56
                 createdAt: true,
40 57
                 updatedAt: true,
41 58
             },
@@ -54,7 +71,8 @@ const VendorExperienceRepository = {
54 71
             },
55 72
             select: {
56 73
                 id: true,
57
-                vendor_id: true,
74
+                content: true,
75
+                // vendor_id: true,
58 76
                 vendor: {
59 77
                     select: {
60 78
                         id: true,
@@ -66,14 +84,29 @@ const VendorExperienceRepository = {
66 84
                         created_by: true,
67 85
                     },
68 86
                 },
69
-                status: true,
70
-                simrs_type: true,
71
-                contract_value_min: true,
72
-                contract_value_max: true,
73
-                contract_start_date: true,
74
-                contract_expired_date: true,
75
-                positive_notes: true,
76
-                negative_notes: true,
87
+                // category_id: true,
88
+                category: {
89
+                    select: {
90
+                        id: true,
91
+                        name: true,
92
+                        description: true,
93
+                    },
94
+                },
95
+                // user_id: true,
96
+                user: {
97
+                    select: {
98
+                        id: true,
99
+                        fullname: true,
100
+                    },
101
+                },
102
+                // status: true,
103
+                // simrs_type: true,
104
+                // contract_value_min: true,
105
+                // contract_value_max: true,
106
+                // contract_start_date: true,
107
+                // contract_expired_date: true,
108
+                // positive_notes: true,
109
+                // negative_notes: true,
77 110
                 createdAt: true,
78 111
                 updatedAt: true,
79 112
             },
@@ -92,147 +125,4 @@ const VendorExperienceRepository = {
92 125
     },
93 126
 };
94 127
 
95
-export default VendorExperienceRepository;
96
-
97
-// const prisma = require('../../prisma/PrismaClient.js');
98
-
99
-// const VendorExperienceRepository = {
100
-//     findAll: async ({ skip, take, where, orderBy }) => {
101
-//         return prisma.vendorExperience.findMany({
102
-//             where,
103
-//             skip,
104
-//             take,
105
-//             orderBy,
106
-//             select: {
107
-//                 id: true,
108
-//                 // hospital: {
109
-//                 //     select: {
110
-//                 //         id: true,
111
-//                 //         name: true,
112
-//                 //         hospital_code: true,
113
-//                 //         type: true,
114
-//                 //         ownership: true,
115
-//                 //         province: {
116
-//                 //             select: {
117
-//                 //                 id: true,
118
-//                 //                 name: true
119
-//                 //             }
120
-//                 //         },
121
-//                 //         city: {
122
-//                 //             select: {
123
-//                 //                 id: true,
124
-//                 //                 name: true
125
-//                 //             }
126
-//                 //         },
127
-//                 //         address: true,
128
-//                 //         simrs_type: true,
129
-//                 //         contact: true,
130
-//                 //         image: true,
131
-//                 //         progress_status: true,
132
-//                 //         note: true,
133
-//                 //         created_by: true
134
-//                 //     }
135
-//                 // },
136
-//                 vendor: {
137
-//                     select: {
138
-//                         id: true,
139
-//                         name: true,
140
-//                         name_pt: true,
141
-//                         strengths: true,
142
-//                         weaknesses: true,
143
-//                         website: true,
144
-//                         created_by: true,
145
-//                     }
146
-//                 },
147
-//                 status: true,
148
-//                 simrs_type: true,
149
-//                 contract_value_min: true,
150
-//                 contract_value_max: true,
151
-//                 contract_start_date: true,
152
-//                 contract_expired_date: true,
153
-//                 positive_notes: true,
154
-//                 negative_notes: true,
155
-//                 createdAt: true,
156
-//                 updatedAt: true,
157
-//             },
158
-//         });
159
-//     },
160
-
161
-//     countAll: async (where) => {
162
-//         return prisma.vendorExperience.count({ where });
163
-//     },
164
-
165
-//     findById: async (id) => {
166
-//         return prisma.vendorExperience.findFirst({
167
-//             where: {
168
-//                 id,
169
-//                 deletedAt: null
170
-//             },
171
-//             select: {
172
-//                 id: true,
173
-//                 // hospital: {
174
-//                 //     select: {
175
-//                 //         id: true,
176
-//                 //         name: true,
177
-//                 //         hospital_code: true,
178
-//                 //         type: true,
179
-//                 //         ownership: true,
180
-//                 //         province: {
181
-//                 //             select: {
182
-//                 //                 id: true,
183
-//                 //                 name: true
184
-//                 //             }
185
-//                 //         },
186
-//                 //         city: {
187
-//                 //             select: {
188
-//                 //                 id: true,
189
-//                 //                 name: true
190
-//                 //             }
191
-//                 //         },
192
-//                 //         address: true,
193
-//                 //         simrs_type: true,
194
-//                 //         contact: true,
195
-//                 //         image: true,
196
-//                 //         progress_status: true,
197
-//                 //         note: true,
198
-//                 //         created_by: true
199
-//                 //     }
200
-//                 // },
201
-//                 vendor: {
202
-//                     select: {
203
-//                         id: true,
204
-//                         name: true,
205
-//                         name_pt: true,
206
-//                         strengths: true,
207
-//                         weaknesses: true,
208
-//                         website: true,
209
-//                         created_by: true,
210
-//                     }
211
-//                 },
212
-//                 status: true,
213
-//                 simrs_type: true,
214
-//                 contract_value_min: true,
215
-//                 contract_value_max: true,
216
-//                 contract_start_date: true,
217
-//                 contract_expired_date: true,
218
-//                 positive_notes: true,
219
-//                 negative_notes: true,
220
-//                 createdAt: true,
221
-//                 updatedAt: true,
222
-//             },
223
-//         });
224
-//     },
225
-
226
-//     create: async (data) => {
227
-//         return prisma.vendorExperience.create({ data });
228
-//     },
229
-
230
-//     update: async (id, data) => {
231
-//         return prisma.vendorExperience.update({
232
-//             where: { id },
233
-//             data
234
-//         });
235
-//     },
236
-// };
237
-
238
-// module.exports = VendorExperienceRepository;
128
+export default VendorExperienceRepository;

+ 2 - 1
src/repository/admin/VendorRepository.ts

@@ -29,7 +29,7 @@ const VendorRepository = {
29 29
                         vendor_experiences: {
30 30
                             where: {
31 31
                                 deletedAt: null,
32
-                                status: "active"
32
+                                // status: "active"
33 33
                             },
34 34
                         },
35 35
                     },
@@ -73,6 +73,7 @@ const VendorRepository = {
73 73
                         vendor_experiences: {
74 74
                             where: {
75 75
                                 deletedAt: null,
76
+                                // status: "active"
76 77
                             },
77 78
                         },
78 79
                     },

+ 3 - 138
src/repository/sales/HospitalRepository.ts

@@ -37,7 +37,7 @@ const HospitalRepository = {
37 37
                 user: { select: { id: true, fullname: true } },
38 38
                 vendor_experiences: {
39 39
                     where: {
40
-                        status: 'active',
40
+                        // status: 'active',
41 41
                         deletedAt: null,
42 42
                     },
43 43
                     select: {
@@ -101,7 +101,7 @@ const HospitalRepository = {
101 101
                 user: { select: { id: true, fullname: true } },
102 102
                 vendor_experiences: {
103 103
                     where: {
104
-                        status: 'active',
104
+                        // status: 'active',
105 105
                         deletedAt: null,
106 106
                     },
107 107
                     take: 1,
@@ -138,139 +138,4 @@ const HospitalRepository = {
138 138
     },
139 139
 };
140 140
 
141
-export default HospitalRepository;
142
-
143
-
144
-// const prisma = require('../../prisma/PrismaClient.js');
145
-
146
-// const HospitalRepository = {
147
-//     findAll: async ({ skip, take, where, orderBy }) => {
148
-//         const hospitalsRaw = await prisma.hospital.findMany({
149
-//             where,
150
-//             skip,
151
-//             take,
152
-//             orderBy,
153
-//             select: {
154
-//                 id: true,
155
-//                 name: true,
156
-//                 hospital_code: true,
157
-//                 type: true,
158
-//                 ownership: true,
159
-//                 province: { select: { id: true, name: true } },
160
-//                 city: { select: { id: true, name: true } },
161
-//                 address: true,
162
-//                 contact: true,
163
-//                 image: true,
164
-//                 progress_status: true,
165
-//                 note: true,
166
-//                 latitude: true,
167
-//                 longitude: true,
168
-//                 gmaps_url: true,
169
-//                 created_by: true,
170
-//                 createdAt: true,
171
-//                 updatedAt: true,
172
-//                 user: { select: { id: true, fullname: true } },
173
-//                 vendor_experiences: {
174
-//                     where: {
175
-//                         status: "active",
176
-//                         deletedAt: null
177
-//                     },
178
-//                     select: {
179
-//                         vendor: {
180
-//                             select: {
181
-//                                 id: true,
182
-//                                 name: true,
183
-//                                 name_pt: true,
184
-//                                 strengths: true,
185
-//                                 weaknesses: true,
186
-//                                 website: true,
187
-//                             }
188
-//                         }
189
-//                     }
190
-//                 }
191
-//             }
192
-//         });
193
-
194
-//         return hospitalsRaw.map(hospital => {
195
-//             const { vendor_experiences, ...rest } = hospital;
196
-//             return {
197
-//                 ...rest,
198
-//                 vendor: vendor_experiences?.[0]?.vendor || null
199
-//             };
200
-//         });
201
-//     },
202
-
203
-//     countAll: async (where) => {
204
-//         return prisma.hospital.count({ where });
205
-//     },
206
-
207
-//     create: async (data) => {
208
-//         return prisma.hospital.create({ data });
209
-//     },
210
-
211
-//     findById: async (id) => {
212
-//         const hospitalRaw = await prisma.hospital.findFirst({
213
-//             where: {
214
-//                 id,
215
-//                 deletedAt: null
216
-//             },
217
-//             select: {
218
-//                 id: true,
219
-//                 name: true,
220
-//                 hospital_code: true,
221
-//                 type: true,
222
-//                 ownership: true,
223
-//                 province: { select: { id: true, name: true } },
224
-//                 city: { select: { id: true, name: true } },
225
-//                 address: true,
226
-//                 contact: true,
227
-//                 image: true,
228
-//                 progress_status: true,
229
-//                 note: true,
230
-//                 latitude: true,
231
-//                 longitude: true,
232
-//                 gmaps_url: true,
233
-//                 created_by: true,
234
-//                 createdAt: true,
235
-//                 updatedAt: true,
236
-//                 user: { select: { id: true, fullname: true } },
237
-//                 vendor_experiences: {
238
-//                     where: {
239
-//                         status: "active",
240
-//                         deletedAt: null
241
-//                     },
242
-//                     take: 1,
243
-//                     select: {
244
-//                         vendor: {
245
-//                             select: {
246
-//                                 id: true,
247
-//                                 name: true,
248
-//                                 name_pt: true,
249
-//                                 strengths: true,
250
-//                                 weaknesses: true,
251
-//                                 website: true,
252
-//                             }
253
-//                         }
254
-//                     }
255
-//                 }
256
-//             }
257
-//         });
258
-
259
-//         if (!hospitalRaw) return null;
260
-
261
-//         const { vendor_experiences, ...rest } = hospitalRaw;
262
-//         return {
263
-//             ...rest,
264
-//             vendor: vendor_experiences?.[0]?.vendor || null
265
-//         };
266
-//     },
267
-
268
-//     update: async (id, data) => {
269
-//         return prisma.hospital.update({
270
-//             where: { id },
271
-//             data
272
-//         });
273
-//     },
274
-// };
275
-
276
-// module.exports = HospitalRepository;
141
+export default HospitalRepository;

+ 14 - 4
src/repository/sales/ScheduleVisitationRepository.ts

@@ -93,15 +93,25 @@ const ScheduleVisitationRepository = {
93 93
                             },
94 94
                         },
95 95
                         vendor_experiences: {
96
-                            where: { status: "active", deletedAt: null },
96
+                            where: {
97
+                                // status: "active",
98
+                                deletedAt: null
99
+                            },
97 100
                             select: {
98 101
                                 id: true,
99 102
                                 vendor: {
100 103
                                     select: { id: true, name: true }
101 104
                                 },
102
-                                contract_start_date: true,
103
-                                contract_expired_date: true,
104
-                                simrs_type: true,
105
+                                category: {
106
+                                    select: { id: true, name: true }
107
+                                },
108
+                                user: {
109
+                                    select: { id: true, fullname: true }
110
+                                },
111
+                                content: true
112
+                                // contract_start_date: true,
113
+                                // contract_expired_date: true,
114
+                                // simrs_type: true,
105 115
                             }
106 116
                         },
107 117
                         executives_histories: {

+ 49 - 105
src/repository/sales/VendorExperienceRepository.ts

@@ -17,6 +17,7 @@ const VendorExperienceRepository = {
17 17
             orderBy,
18 18
             select: {
19 19
                 id: true,
20
+                content: true,
20 21
                 vendor: {
21 22
                     select: {
22 23
                         id: true,
@@ -28,14 +29,29 @@ const VendorExperienceRepository = {
28 29
                         created_by: true,
29 30
                     },
30 31
                 },
31
-                status: true,
32
-                simrs_type: true,
33
-                contract_value_min: true,
34
-                contract_value_max: true,
35
-                contract_start_date: true,
36
-                contract_expired_date: true,
37
-                positive_notes: true,
38
-                negative_notes: true,
32
+                // category_id: true,
33
+                category: {
34
+                    select: {
35
+                        id: true,
36
+                        name: true,
37
+                        description: true,
38
+                    },
39
+                },
40
+                // user_id: true,
41
+                user: {
42
+                    select: {
43
+                        id: true,
44
+                        fullname: true,
45
+                    },
46
+                },
47
+                // status: true,
48
+                // simrs_type: true,
49
+                // contract_value_min: true,
50
+                // contract_value_max: true,
51
+                // contract_start_date: true,
52
+                // contract_expired_date: true,
53
+                // positive_notes: true,
54
+                // negative_notes: true,
39 55
                 createdAt: true,
40 56
                 updatedAt: true,
41 57
             },
@@ -54,7 +70,7 @@ const VendorExperienceRepository = {
54 70
             },
55 71
             select: {
56 72
                 id: true,
57
-                vendor_id: true,
73
+                content: true,
58 74
                 vendor: {
59 75
                     select: {
60 76
                         id: true,
@@ -66,14 +82,29 @@ const VendorExperienceRepository = {
66 82
                         created_by: true,
67 83
                     },
68 84
                 },
69
-                status: true,
70
-                simrs_type: true,
71
-                contract_value_min: true,
72
-                contract_value_max: true,
73
-                contract_start_date: true,
74
-                contract_expired_date: true,
75
-                positive_notes: true,
76
-                negative_notes: true,
85
+                // category_id: true,
86
+                category: {
87
+                    select: {
88
+                        id: true,
89
+                        name: true,
90
+                        description: true,
91
+                    },
92
+                },
93
+                // user_id: true,
94
+                user: {
95
+                    select: {
96
+                        id: true,
97
+                        fullname: true,
98
+                    },
99
+                },
100
+                // status: true,
101
+                // simrs_type: true,
102
+                // contract_value_min: true,
103
+                // contract_value_max: true,
104
+                // contract_start_date: true,
105
+                // contract_expired_date: true,
106
+                // positive_notes: true,
107
+                // negative_notes: true,
77 108
                 createdAt: true,
78 109
                 updatedAt: true,
79 110
             },
@@ -92,91 +123,4 @@ const VendorExperienceRepository = {
92 123
     },
93 124
 };
94 125
 
95
-export default VendorExperienceRepository;
96
-
97
-// const prisma = require('../../prisma/PrismaClient.js');
98
-
99
-// const VendorExperienceRepository = {
100
-//     findAll: async ({ skip, take, where, orderBy }) => {
101
-//         return prisma.vendorExperience.findMany({
102
-//             where,
103
-//             skip,
104
-//             take,
105
-//             orderBy,
106
-//             select: {
107
-//                 id: true,
108
-//                 vendor: {
109
-//                     select: {
110
-//                         id: true,
111
-//                         name: true,
112
-//                         name_pt: true,
113
-//                         strengths: true,
114
-//                         weaknesses: true,
115
-//                         website: true,
116
-//                         created_by: true,
117
-//                     }
118
-//                 },
119
-//                 status: true,
120
-//                 simrs_type: true,
121
-//                 contract_value_min: true,
122
-//                 contract_value_max: true,
123
-//                 contract_start_date: true,
124
-//                 contract_expired_date: true,
125
-//                 positive_notes: true,
126
-//                 negative_notes: true,
127
-//                 createdAt: true,
128
-//                 updatedAt: true,
129
-//             },
130
-//         });
131
-//     },
132
-
133
-//     countAll: async (where) => {
134
-//         return prisma.vendorExperience.count({ where });
135
-//     },
136
-
137
-//     findById: async (id) => {
138
-//         return prisma.vendorExperience.findFirst({
139
-//             where: {
140
-//                 id,
141
-//                 deletedAt: null
142
-//             },
143
-//             select: {
144
-//                 id: true,
145
-//                 vendor: {
146
-//                     select: {
147
-//                         id: true,
148
-//                         name: true,
149
-//                         name_pt: true,
150
-//                         strengths: true,
151
-//                         weaknesses: true,
152
-//                         website: true,
153
-//                         created_by: true,
154
-//                     }
155
-//                 },
156
-//                 status: true,
157
-//                 simrs_type: true,
158
-//                 contract_value_min: true,
159
-//                 contract_value_max: true,
160
-//                 contract_start_date: true,
161
-//                 contract_expired_date: true,
162
-//                 positive_notes: true,
163
-//                 negative_notes: true,
164
-//                 createdAt: true,
165
-//                 updatedAt: true,
166
-//             },
167
-//         });
168
-//     },
169
-
170
-//     create: async (data) => {
171
-//         return prisma.vendorExperience.create({ data });
172
-//     },
173
-
174
-//     update: async (id, data) => {
175
-//         return prisma.vendorExperience.update({
176
-//             where: { id },
177
-//             data
178
-//         });
179
-//     },
180
-// };
181
-
182
-// module.exports = VendorExperienceRepository;
126
+export default VendorExperienceRepository;

+ 25 - 25
src/resources/admin/hospital/HospitalCollection.ts

@@ -14,40 +14,40 @@ export const HospitalCollection = async (req: Request, res: Response, data: Hosp
14 14
     const ids = data.map(item => item.id);
15 15
 
16 16
     // Ambil tags dari category_links yang relevan
17
-    const allTags = await prisma.categoryLink.findMany({
18
-        where: {
19
-            source_id: { in: ids },
20
-            source_type: { in: ['hospital_notes'] },
21
-            deletedAt: null,
22
-        },
23
-        include: {
24
-            Category: true,
25
-        },
26
-    });
17
+    // const allTags = await prisma.categoryLink.findMany({
18
+    //     where: {
19
+    //         source_id: { in: ids },
20
+    //         source_type: { in: ['hospital_notes'] },
21
+    //         deletedAt: null,
22
+    //     },
23
+    //     include: {
24
+    //         Category: true,
25
+    //     },
26
+    // });
27 27
 
28 28
     // Kelompokkan tags berdasarkan source_type dan source_id
29
-    const tagMap = new Map<string, { note: string[] }>();
30
-    for (const id of ids) {
31
-        tagMap.set(id, { note: [] });
32
-    }
29
+    // const tagMap = new Map<string, { note: string[] }>();
30
+    // for (const id of ids) {
31
+    //     tagMap.set(id, { note: [] });
32
+    // }
33 33
 
34
-    for (const tag of allTags) {
35
-        const id = tag.source_id!;
36
-        const categoryTag = tag.Category?.tag ?? '';
37
-        const current = tagMap.get(id);
38
-        if (!current) continue;
34
+    // for (const tag of allTags) {
35
+    //     const id = tag.source_id!;
36
+    //     const categoryTag = tag.Category?.tag ?? '';
37
+    //     const current = tagMap.get(id);
38
+    //     if (!current) continue;
39 39
 
40
-        if (tag.source_type === 'hospital_notes') {
41
-            current.note.push(categoryTag);
42
-        }
43
-    }
40
+    //     if (tag.source_type === 'hospital_notes') {
41
+    //         current.note.push(categoryTag);
42
+    //     }
43
+    // }
44 44
 
45 45
     const formattedData = data.map(item => {
46 46
         const { created_by, ...rest } = item;
47
-        const tags = tagMap.get(item.id);
47
+        // const tags = tagMap.get(item.id);
48 48
         return formatItem({
49 49
             ...rest,
50
-            note_tags: tags?.note ?? [],
50
+            // note_tags: tags?.note ?? [],
51 51
         });
52 52
     });
53 53
 

+ 14 - 14
src/resources/admin/hospital/HospitalResource.ts

@@ -10,26 +10,26 @@ const formatItem = (item: HospitalDTO) => ({
10 10
 });
11 11
 
12 12
 export const HospitalResource = async (res: Response, data: HospitalDTO, message: string = 'Success'): Promise<Response> => {
13
-    const tags = await prisma.categoryLink.findMany({
14
-        where: {
15
-            source_id: data.id,
16
-            source_type: { in: ['hospital_notes'] },
17
-            deletedAt: null,
18
-        },
19
-        include: {
20
-            Category: true,
21
-        },
22
-    });
13
+    // const tags = await prisma.categoryLink.findMany({
14
+    //     where: {
15
+    //         source_id: data.id,
16
+    //         source_type: { in: ['hospital_notes'] },
17
+    //         deletedAt: null,
18
+    //     },
19
+    //     include: {
20
+    //         Category: true,
21
+    //     },
22
+    // });
23 23
 
24
-    const note_tags = tags
25
-        .filter(t => t.source_type === 'hospital_notes')
26
-        .map(t => t.Category?.tag ?? '');
24
+    // const note_tags = tags
25
+    //     .filter(t => t.source_type === 'hospital_notes')
26
+    //     .map(t => t.Category?.tag ?? '');
27 27
 
28 28
     const { created_by, ...cleanedData } = data;
29 29
 
30 30
     const formatted = {
31 31
         ...formatItem(cleanedData),
32
-        note_tags,
32
+        // note_tags,
33 33
     };
34 34
 
35 35
     return res.status(200).json({

+ 2 - 2
src/resources/admin/schedule_visitation/ScheduleVisitationResource.ts

@@ -10,8 +10,8 @@ const formatItem = (item: ShowScheduleVisitationDTO) => ({
10 10
         ...item.hospital,
11 11
         vendor_experiences: item.hospital.vendor_experiences.map((vendor) => ({
12 12
             ...vendor,
13
-            contract_start_date: formatDateOnly(vendor.contract_start_date),
14
-            contract_expired_date: formatDateOnly(vendor.contract_expired_date),
13
+            // contract_start_date: formatDateOnly(vendor.contract_start_date),
14
+            // contract_expired_date: formatDateOnly(vendor.contract_expired_date),
15 15
         })),
16 16
         executives_histories: item.hospital.executives_histories.map((exec) => ({
17 17
             ...exec,

+ 26 - 26
src/resources/admin/status_history/StatusHistoryCollection.ts

@@ -14,40 +14,40 @@ export const StatusHistoryCollection = async (req: Request, res: Response, data:
14 14
     const ids = data.map(item => item.id);
15 15
 
16 16
     // Ambil tags dari category_links yang relevan
17
-    const allTags = await prisma.categoryLink.findMany({
18
-        where: {
19
-            source_id: { in: ids },
20
-            source_type: { in: ['status_history_notes'] },
21
-            deletedAt: null,
22
-        },
23
-        include: {
24
-            Category: true,
25
-        },
26
-    });
17
+    // const allTags = await prisma.categoryLink.findMany({
18
+    //     where: {
19
+    //         source_id: { in: ids },
20
+    //         source_type: { in: ['status_history_notes'] },
21
+    //         deletedAt: null,
22
+    //     },
23
+    //     include: {
24
+    //         Category: true,
25
+    //     },
26
+    // });
27 27
 
28
-    // Kelompokkan tags berdasarkan source_type dan source_id
29
-    const tagMap = new Map<string, { note: string[]; }>();
30
-    for (const id of ids) {
31
-        tagMap.set(id, { note: [] });
32
-    }
28
+    // // Kelompokkan tags berdasarkan source_type dan source_id
29
+    // const tagMap = new Map<string, { note: string[]; }>();
30
+    // for (const id of ids) {
31
+    //     tagMap.set(id, { note: [] });
32
+    // }
33 33
 
34
-    for (const tag of allTags) {
35
-        const id = tag.source_id!;
36
-        const categoryTag = tag.Category?.tag ?? '';
37
-        const current = tagMap.get(id);
38
-        if (!current) continue;
34
+    // for (const tag of allTags) {
35
+    //     const id = tag.source_id!;
36
+    //     const categoryTag = tag.Category?.tag ?? '';
37
+    //     const current = tagMap.get(id);
38
+    //     if (!current) continue;
39 39
 
40
-        if (tag.source_type === 'status_history_notes') {
41
-            current.note.push(categoryTag);
42
-        }
43
-    }
40
+    //     if (tag.source_type === 'status_history_notes') {
41
+    //         current.note.push(categoryTag);
42
+    //     }
43
+    // }
44 44
 
45 45
     // Gabungkan dan format
46 46
     const formattedData = data.map(item => {
47
-        const tags = tagMap.get(item.id);
47
+        // const tags = tagMap.get(item.id);
48 48
         return formatItem({
49 49
             ...item,
50
-            note_tags: tags?.note ?? [],
50
+            // note_tags: tags?.note ?? [],
51 51
         });
52 52
     });
53 53
 

+ 21 - 21
src/resources/admin/vendor/VendorCollection.ts

@@ -14,16 +14,16 @@ export const VendorCollection = async (req: Request, res: Response, data: Vendor
14 14
     const ids = data.map(item => item.id);
15 15
 
16 16
     // Ambil tags dari category_links yang relevan
17
-    const allTags = await prisma.categoryLink.findMany({
18
-        where: {
19
-            source_id: { in: ids },
20
-            source_type: { in: ['vendor_strength_notes', 'vendor_weaknesses_notes'] },
21
-            deletedAt: null,
22
-        },
23
-        include: {
24
-            Category: true,
25
-        },
26
-    });
17
+    // const allTags = await prisma.categoryLink.findMany({
18
+    //     where: {
19
+    //         source_id: { in: ids },
20
+    //         source_type: { in: ['vendor_strength_notes', 'vendor_weaknesses_notes'] },
21
+    //         deletedAt: null,
22
+    //     },
23
+    //     include: {
24
+    //         Category: true,
25
+    //     },
26
+    // });
27 27
 
28 28
     // Kelompokkan tags berdasarkan source_type dan source_id
29 29
     const tagMap = new Map<string, { strength: string[]; weaknesses: string[] }>();
@@ -31,18 +31,18 @@ export const VendorCollection = async (req: Request, res: Response, data: Vendor
31 31
         tagMap.set(id, { strength: [], weaknesses: [] });
32 32
     }
33 33
 
34
-    for (const tag of allTags) {
35
-        const id = tag.source_id!;
36
-        const categoryTag = tag.Category?.tag ?? '';
37
-        const current = tagMap.get(id);
38
-        if (!current) continue;
34
+    // for (const tag of allTags) {
35
+    //     const id = tag.source_id!;
36
+    //     const categoryTag = tag.Category?.tag ?? '';
37
+    //     const current = tagMap.get(id);
38
+    //     if (!current) continue;
39 39
 
40
-        if (tag.source_type === 'vendor_strength_notes') {
41
-            current.strength.push(categoryTag);
42
-        } else if (tag.source_type === 'vendor_weaknesses_notes') {
43
-            current.weaknesses.push(categoryTag);
44
-        }
45
-    }
40
+    //     if (tag.source_type === 'vendor_strength_notes') {
41
+    //         current.strength.push(categoryTag);
42
+    //     } else if (tag.source_type === 'vendor_weaknesses_notes') {
43
+    //         current.weaknesses.push(categoryTag);
44
+    //     }
45
+    // }
46 46
 
47 47
     // Gabungkan dan format
48 48
     const formattedData = data.map(item => {

+ 18 - 18
src/resources/admin/vendor/VendorResource.ts

@@ -4,24 +4,24 @@ import { VendorDTO } from '../../../types/admin/vendor/VendorDTO';
4 4
 import prisma from '../../../prisma/PrismaClient';
5 5
 
6 6
 export const VendorResource = async (res: Response, data: VendorDTO, message: string = 'Success'): Promise<Response> => {
7
-    const tags = await prisma.categoryLink.findMany({
8
-        where: {
9
-            source_id: data.id,
10
-            source_type: { in: ['vendor_strength_notes', 'vendor_weaknesses_notes'] },
11
-            deletedAt: null,
12
-        },
13
-        include: {
14
-            Category: true,
15
-        },
16
-    });
7
+    // const tags = await prisma.categoryLink.findMany({
8
+    //     where: {
9
+    //         source_id: data.id,
10
+    //         source_type: { in: ['vendor_strength_notes', 'vendor_weaknesses_notes'] },
11
+    //         deletedAt: null,
12
+    //     },
13
+    //     include: {
14
+    //         Category: true,
15
+    //     },
16
+    // });
17 17
 
18
-    const strengths_tags = tags
19
-        .filter(t => t.source_type === 'vendor_strength_notes')
20
-        .map(t => t.Category?.tag ?? '');
18
+    // const strengths_tags = tags
19
+    //     .filter(t => t.source_type === 'vendor_strength_notes')
20
+    //     .map(t => t.Category?.tag ?? '');
21 21
 
22
-    const weaknesses_tags = tags
23
-        .filter(t => t.source_type === 'vendor_weaknesses_notes')
24
-        .map(t => t.Category?.tag ?? '');
22
+    // const weaknesses_tags = tags
23
+    //     .filter(t => t.source_type === 'vendor_weaknesses_notes')
24
+    //     .map(t => t.Category?.tag ?? '');
25 25
 
26 26
     const formatted = {
27 27
         ...data,
@@ -29,8 +29,8 @@ export const VendorResource = async (res: Response, data: VendorDTO, message: st
29 29
         updatedAt: formatISOWithoutTimezone(data.updatedAt),
30 30
         strengths: data.strengths,
31 31
         weaknesses: data.weaknesses,
32
-        strengths_tags,
33
-        weaknesses_tags,
32
+        // strengths_tags,
33
+        // weaknesses_tags,
34 34
     };
35 35
 
36 36
     return res.status(200).json({

+ 32 - 32
src/resources/admin/vendor_experience/VendorExperienceCollection.ts

@@ -6,10 +6,10 @@ import prisma from '../../../prisma/PrismaClient';
6 6
 
7 7
 const formatItem = (item: VendorExperienceDTO) => ({
8 8
     ...item,
9
-    contract_value_min: item.contract_value_min !== null ? Number(item.contract_value_min) : null,
10
-    contract_value_max: item.contract_value_max !== null ? Number(item.contract_value_max) : null,
11
-    contract_start_date: formatDateOnly(item.contract_start_date),
12
-    contract_expired_date: formatDateOnly(item.contract_expired_date),
9
+    // contract_value_min: item.contract_value_min !== null ? Number(item.contract_value_min) : null,
10
+    // contract_value_max: item.contract_value_max !== null ? Number(item.contract_value_max) : null,
11
+    // contract_start_date: formatDateOnly(item.contract_start_date),
12
+    // contract_expired_date: formatDateOnly(item.contract_expired_date),
13 13
     createdAt: formatISOWithoutTimezone(item.createdAt),
14 14
     updatedAt: formatISOWithoutTimezone(item.updatedAt),
15 15
 });
@@ -26,43 +26,43 @@ export const VendorExperienceCollection = async (
26 26
     const ids = data.map(item => item.id);
27 27
 
28 28
     // Ambil tags dari category_links yang relevan
29
-    const allTags = await prisma.categoryLink.findMany({
30
-        where: {
31
-            source_id: { in: ids },
32
-            source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
33
-            deletedAt: null,
34
-        },
35
-        include: {
36
-            Category: true,
37
-        },
38
-    });
29
+    // const allTags = await prisma.categoryLink.findMany({
30
+    //     where: {
31
+    //         source_id: { in: ids },
32
+    //         source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
33
+    //         deletedAt: null,
34
+    //     },
35
+    //     include: {
36
+    //         Category: true,
37
+    //     },
38
+    // });
39 39
 
40 40
     // Kelompokkan tags berdasarkan source_type dan source_id
41
-    const tagMap = new Map<string, { positive: string[]; negative: string[] }>();
42
-    for (const id of ids) {
43
-        tagMap.set(id, { positive: [], negative: [] });
44
-    }
41
+    // const tagMap = new Map<string, { positive: string[]; negative: string[] }>();
42
+    // for (const id of ids) {
43
+    //     tagMap.set(id, { positive: [], negative: [] });
44
+    // }
45 45
 
46
-    for (const tag of allTags) {
47
-        const id = tag.source_id!;
48
-        const categoryTag = tag.Category?.tag ?? '';
49
-        const current = tagMap.get(id);
50
-        if (!current) continue;
46
+    // for (const tag of allTags) {
47
+    //     const id = tag.source_id!;
48
+    //     const categoryTag = tag.Category?.tag ?? '';
49
+    //     const current = tagMap.get(id);
50
+    //     if (!current) continue;
51 51
 
52
-        if (tag.source_type === 'vendor_experience_positive_notes') {
53
-            current.positive.push(categoryTag);
54
-        } else if (tag.source_type === 'vendor_experience_negative_notes') {
55
-            current.negative.push(categoryTag);
56
-        }
57
-    }
52
+    //     if (tag.source_type === 'vendor_experience_positive_notes') {
53
+    //         current.positive.push(categoryTag);
54
+    //     } else if (tag.source_type === 'vendor_experience_negative_notes') {
55
+    //         current.negative.push(categoryTag);
56
+    //     }
57
+    // }
58 58
 
59 59
     // Gabungkan dan format
60 60
     const formattedData = data.map(item => {
61
-        const tags = tagMap.get(item.id);
61
+        // const tags = tagMap.get(item.id);
62 62
         return formatItem({
63 63
             ...item,
64
-            positive_notes_tags: tags?.positive ?? [],
65
-            negative_notes_tags: tags?.negative ?? [],
64
+            // positive_notes_tags: tags?.positive ?? [],
65
+            // negative_notes_tags: tags?.negative ?? [],
66 66
         });
67 67
     });
68 68
 

+ 38 - 25
src/resources/admin/vendor_experience/VendorExperienceResource.ts

@@ -1,29 +1,29 @@
1 1
 import { Response } from 'express';
2
-import { formatDateOnly, formatISOWithoutTimezone } from '../../../utils/FormatDate';
2
+import { formatISOWithoutTimezone } from '../../../utils/FormatDate';
3 3
 import { VendorExperienceDTO } from '../../../types/admin/vendor_experience/VendorExperienceDTO';
4
-import prisma from '../../../prisma/PrismaClient';
5 4
 
6 5
 export const VendorExperienceResource = async (res: Response, data: VendorExperienceDTO, message: string = 'Success'): Promise<Response> => {
7
-    const tags = await prisma.categoryLink.findMany({
8
-        where: {
9
-            source_id: data.id,
10
-            source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
11
-            deletedAt: null,
12
-        },
13
-        include: {
14
-            Category: true,
15
-        },
16
-    });
6
+    // const tags = await prisma.categoryLink.findMany({
7
+    //     where: {
8
+    //         source_id: data.id,
9
+    //         source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
10
+    //         deletedAt: null,
11
+    //     },
12
+    //     include: {
13
+    //         Category: true,
14
+    //     },
15
+    // });
17 16
 
18
-    const positive_notes_tags = tags
19
-        .filter(t => t.source_type === 'vendor_experience_positive_notes')
20
-        .map(t => t.Category?.tag ?? '');
17
+    // const positive_notes_tags = tags
18
+    //     .filter(t => t.source_type === 'vendor_experience_positive_notes')
19
+    //     .map(t => t.Category?.tag ?? '');
21 20
 
22
-    const negative_notes_tags = tags
23
-        .filter(t => t.source_type === 'vendor_experience_negative_notes')
24
-        .map(t => t.Category?.tag ?? '');
21
+    // const negative_notes_tags = tags
22
+    //     .filter(t => t.source_type === 'vendor_experience_negative_notes')
23
+    //     .map(t => t.Category?.tag ?? '');
25 24
 
26
-    const { vendor_id, ...restData } = data;
25
+    // const { vendor_id, ...restData } = data;
26
+    const restData = data;
27 27
 
28 28
     const formatted = {
29 29
         ...restData,
@@ -38,12 +38,25 @@ export const VendorExperienceResource = async (res: Response, data: VendorExperi
38 38
                 created_by: data.vendor.created_by,
39 39
             }
40 40
             : null,
41
-        contract_start_date: formatDateOnly(data.contract_start_date),
42
-        contract_expired_date: formatDateOnly(data.contract_expired_date),
43
-        contract_value_min: data.contract_value_min !== null ? Number(data.contract_value_min) : null,
44
-        contract_value_max: data.contract_value_max !== null ? Number(data.contract_value_max) : null,
45
-        positive_notes_tags,
46
-        negative_notes_tags,
41
+        category: data.category
42
+            ? {
43
+                id: data.category.id,
44
+                name: data.category.name,
45
+                description: data.category.description,
46
+            }
47
+            : null,
48
+        user: data.user
49
+            ? {
50
+                id: data.user.id,
51
+                name: data.user.fullname,
52
+            } : null,
53
+        content: data.content,
54
+        // contract_start_date: formatDateOnly(data.contract_start_date),
55
+        // contract_expired_date: formatDateOnly(data.contract_expired_date),
56
+        // contract_value_min: data.contract_value_min !== null ? Number(data.contract_value_min) : null,
57
+        // contract_value_max: data.contract_value_max !== null ? Number(data.contract_value_max) : null,
58
+        // positive_notes_tags,
59
+        // negative_notes_tags,
47 60
         createdAt: formatISOWithoutTimezone(data.createdAt),
48 61
         updatedAt: formatISOWithoutTimezone(data.updatedAt),
49 62
     };

+ 25 - 25
src/resources/sales/hospital/HospitalCollection.ts

@@ -27,41 +27,41 @@ export const HospitalCollection = async ({
27 27
     limit: number;
28 28
     message?: string;
29 29
 }) => {
30
-    const ids = data.map(item => item.id);
30
+    // const ids = data.map(item => item.id);
31 31
 
32 32
     // Ambil tags dari category_links yang relevan
33
-    const allTags = await prisma.categoryLink.findMany({
34
-        where: {
35
-            source_id: { in: ids },
36
-            source_type: 'hospital_notes',
37
-            deletedAt: null,
38
-        },
39
-        include: {
40
-            Category: true,
41
-        },
42
-    });
33
+    // const allTags = await prisma.categoryLink.findMany({
34
+    //     where: {
35
+    //         source_id: { in: ids },
36
+    //         source_type: 'hospital_notes',
37
+    //         deletedAt: null,
38
+    //     },
39
+    //     include: {
40
+    //         Category: true,
41
+    //     },
42
+    // });
43 43
 
44
-    // Kelompokkan tags berdasarkan source_id
45
-    const tagMap = new Map<string, { note: string[] }>();
46
-    for (const id of ids) {
47
-        tagMap.set(id, { note: [] });
48
-    }
44
+    // // Kelompokkan tags berdasarkan source_id
45
+    // const tagMap = new Map<string, { note: string[] }>();
46
+    // for (const id of ids) {
47
+    //     tagMap.set(id, { note: [] });
48
+    // }
49 49
 
50
-    for (const tag of allTags) {
51
-        const id = tag.source_id!;
52
-        const categoryTag = tag.Category?.tag ?? '';
53
-        const current = tagMap.get(id);
54
-        if (!current) continue;
50
+    // for (const tag of allTags) {
51
+    //     const id = tag.source_id!;
52
+    //     const categoryTag = tag.Category?.tag ?? '';
53
+    //     const current = tagMap.get(id);
54
+    //     if (!current) continue;
55 55
 
56
-        current.note.push(categoryTag);
57
-    }
56
+    //     current.note.push(categoryTag);
57
+    // }
58 58
 
59 59
     const formattedData = data.map(item => {
60 60
         const { created_by, ...rest } = item;
61
-        const tags = tagMap.get(item.id);
61
+        // const tags = tagMap.get(item.id);
62 62
         return formatItem({
63 63
             ...rest,
64
-            note_tags: tags?.note ?? [],
64
+            // note_tags: tags?.note ?? [],
65 65
         });
66 66
     });
67 67
 

+ 14 - 14
src/resources/sales/hospital/HospitalResource.ts

@@ -10,26 +10,26 @@ const formatItem = (item: HospitalDTO) => ({
10 10
 });
11 11
 
12 12
 export const HospitalResource = async (res: Response, data: HospitalDTO, message: string = 'Success'): Promise<Response> => {
13
-    const tags = await prisma.categoryLink.findMany({
14
-        where: {
15
-            source_id: data.id,
16
-            source_type: { in: ['hospital_notes'] },
17
-            deletedAt: null,
18
-        },
19
-        include: {
20
-            Category: true,
21
-        },
22
-    });
13
+    // const tags = await prisma.categoryLink.findMany({
14
+    //     where: {
15
+    //         source_id: data.id,
16
+    //         source_type: { in: ['hospital_notes'] },
17
+    //         deletedAt: null,
18
+    //     },
19
+    //     include: {
20
+    //         Category: true,
21
+    //     },
22
+    // });
23 23
 
24
-    const note_tags = tags
25
-        .filter(t => t.source_type === 'hospital_notes')
26
-        .map(t => t.Category?.tag ?? '');
24
+    // const note_tags = tags
25
+    //     .filter(t => t.source_type === 'hospital_notes')
26
+    //     .map(t => t.Category?.tag ?? '');
27 27
 
28 28
     const { created_by, ...cleanedData } = data;
29 29
 
30 30
     const formatted = {
31 31
         ...formatItem(cleanedData),
32
-        note_tags,
32
+        // note_tags,
33 33
     };
34 34
 
35 35
     return res.status(200).json({

+ 2 - 2
src/resources/sales/schedule_visitation/ScheduleVisitationResource.ts

@@ -10,8 +10,8 @@ const formatItem = (item: ShowScheduleVisitationDTO) => ({
10 10
         ...item.hospital,
11 11
         vendor_experiences: item.hospital.vendor_experiences.map((vendor) => ({
12 12
             ...vendor,
13
-            contract_start_date: formatDateOnly(vendor.contract_start_date),
14
-            contract_expired_date: formatDateOnly(vendor.contract_expired_date),
13
+            // contract_start_date: formatDateOnly(vendor.contract_start_date),
14
+            // contract_expired_date: formatDateOnly(vendor.contract_expired_date),
15 15
         })),
16 16
         executives_histories: item.hospital.executives_histories.map((exec) => ({
17 17
             ...exec,

+ 25 - 25
src/resources/sales/status_history/StatusHistoryCollection.ts

@@ -14,40 +14,40 @@ export const StatusHistoryCollection = async (req: Request, res: Response, data:
14 14
     const ids = data.map(item => item.id);
15 15
 
16 16
     // Ambil tags dari category_links yang relevan
17
-    const allTags = await prisma.categoryLink.findMany({
18
-        where: {
19
-            source_id: { in: ids },
20
-            source_type: { in: ['status_history_notes'] },
21
-            deletedAt: null,
22
-        },
23
-        include: {
24
-            Category: true,
25
-        },
26
-    });
17
+    // const allTags = await prisma.categoryLink.findMany({
18
+    //     where: {
19
+    //         source_id: { in: ids },
20
+    //         source_type: { in: ['status_history_notes'] },
21
+    //         deletedAt: null,
22
+    //     },
23
+    //     include: {
24
+    //         Category: true,
25
+    //     },
26
+    // });
27 27
 
28 28
     // Kelompokkan tags berdasarkan source_type dan source_id
29
-    const tagMap = new Map<string, { note: string[]; }>();
30
-    for (const id of ids) {
31
-        tagMap.set(id, { note: [] });
32
-    }
29
+    // const tagMap = new Map<string, { note: string[]; }>();
30
+    // for (const id of ids) {
31
+    //     tagMap.set(id, { note: [] });
32
+    // }
33 33
 
34
-    for (const tag of allTags) {
35
-        const id = tag.source_id!;
36
-        const categoryTag = tag.Category?.tag ?? '';
37
-        const current = tagMap.get(id);
38
-        if (!current) continue;
34
+    // for (const tag of allTags) {
35
+    //     const id = tag.source_id!;
36
+    //     const categoryTag = tag.Category?.tag ?? '';
37
+    //     const current = tagMap.get(id);
38
+    //     if (!current) continue;
39 39
 
40
-        if (tag.source_type === 'status_history_notes') {
41
-            current.note.push(categoryTag);
42
-        }
43
-    }
40
+    //     if (tag.source_type === 'status_history_notes') {
41
+    //         current.note.push(categoryTag);
42
+    //     }
43
+    // }
44 44
 
45 45
     // Gabungkan dan format
46 46
     const formattedData = data.map(item => {
47
-        const tags = tagMap.get(item.id);
47
+        // const tags = tagMap.get(item.id);
48 48
         return formatItem({
49 49
             ...item,
50
-            note_tags: tags?.note ?? [],
50
+            // note_tags: tags?.note ?? [],
51 51
         });
52 52
     });
53 53
 

+ 33 - 34
src/resources/sales/vendor_experience/VendorExperienceCollection.ts

@@ -1,15 +1,14 @@
1 1
 import { Request, Response } from 'express';
2 2
 import { ListResponse } from '../../../utils/ListResponse';
3
-import { formatDateOnly, formatISOWithoutTimezone } from '../../../utils/FormatDate';
3
+import { formatISOWithoutTimezone } from '../../../utils/FormatDate';
4 4
 import { VendorExperienceDTO } from '../../../types/sales/vendor_experience/VendorExperienceDTO';
5
-import prisma from '../../../prisma/PrismaClient';
6 5
 
7 6
 const formatItem = (item: VendorExperienceDTO) => ({
8 7
     ...item,
9
-    contract_value_min: item.contract_value_min !== null ? Number(item.contract_value_min) : null,
10
-    contract_value_max: item.contract_value_max !== null ? Number(item.contract_value_max) : null,
11
-    contract_start_date: formatDateOnly(item.contract_start_date),
12
-    contract_expired_date: formatDateOnly(item.contract_expired_date),
8
+    // contract_value_min: item.contract_value_min !== null ? Number(item.contract_value_min) : null,
9
+    // contract_value_max: item.contract_value_max !== null ? Number(item.contract_value_max) : null,
10
+    // contract_start_date: formatDateOnly(item.contract_start_date),
11
+    // contract_expired_date: formatDateOnly(item.contract_expired_date),
13 12
     createdAt: formatISOWithoutTimezone(item.createdAt),
14 13
     updatedAt: formatISOWithoutTimezone(item.updatedAt),
15 14
 });
@@ -26,43 +25,43 @@ export const VendorExperienceCollection = async (
26 25
     const ids = data.map(item => item.id);
27 26
 
28 27
     // Ambil tags dari category_links yang relevan
29
-    const allTags = await prisma.categoryLink.findMany({
30
-        where: {
31
-            source_id: { in: ids },
32
-            source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
33
-            deletedAt: null,
34
-        },
35
-        include: {
36
-            Category: true,
37
-        },
38
-    });
28
+    // const allTags = await prisma.categoryLink.findMany({
29
+    //     where: {
30
+    //         source_id: { in: ids },
31
+    //         source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
32
+    //         deletedAt: null,
33
+    //     },
34
+    //     include: {
35
+    //         Category: true,
36
+    //     },
37
+    // });
39 38
 
40 39
     // Kelompokkan tags berdasarkan source_type dan source_id
41
-    const tagMap = new Map<string, { positive: string[]; negative: string[] }>();
42
-    for (const id of ids) {
43
-        tagMap.set(id, { positive: [], negative: [] });
44
-    }
40
+    // const tagMap = new Map<string, { positive: string[]; negative: string[] }>();
41
+    // for (const id of ids) {
42
+    //     tagMap.set(id, { positive: [], negative: [] });
43
+    // }
45 44
 
46
-    for (const tag of allTags) {
47
-        const id = tag.source_id!;
48
-        const categoryTag = tag.Category?.tag ?? '';
49
-        const current = tagMap.get(id);
50
-        if (!current) continue;
45
+    // for (const tag of allTags) {
46
+    //     const id = tag.source_id!;
47
+    //     const categoryTag = tag.Category?.tag ?? '';
48
+    //     const current = tagMap.get(id);
49
+    //     if (!current) continue;
51 50
 
52
-        if (tag.source_type === 'vendor_experience_positive_notes') {
53
-            current.positive.push(categoryTag);
54
-        } else if (tag.source_type === 'vendor_experience_negative_notes') {
55
-            current.negative.push(categoryTag);
56
-        }
57
-    }
51
+    //     if (tag.source_type === 'vendor_experience_positive_notes') {
52
+    //         current.positive.push(categoryTag);
53
+    //     } else if (tag.source_type === 'vendor_experience_negative_notes') {
54
+    //         current.negative.push(categoryTag);
55
+    //     }
56
+    // }
58 57
 
59 58
     // Gabungkan dan format
60 59
     const formattedData = data.map(item => {
61
-        const tags = tagMap.get(item.id);
60
+        // const tags = tagMap.get(item.id);
62 61
         return formatItem({
63 62
             ...item,
64
-            positive_notes_tags: tags?.positive ?? [],
65
-            negative_notes_tags: tags?.negative ?? [],
63
+            // positive_notes_tags: tags?.positive ?? [],
64
+            // negative_notes_tags: tags?.negative ?? [],
66 65
         });
67 66
     });
68 67
 

+ 38 - 25
src/resources/sales/vendor_experience/VendorExperienceResource.ts

@@ -1,29 +1,29 @@
1 1
 import { Response } from 'express';
2
-import { formatDateOnly, formatISOWithoutTimezone } from '../../../utils/FormatDate';
2
+import { formatISOWithoutTimezone } from '../../../utils/FormatDate';
3 3
 import { VendorExperienceDTO } from '../../../types/sales/vendor_experience/VendorExperienceDTO';
4
-import prisma from '../../../prisma/PrismaClient';
5 4
 
6 5
 export const VendorExperienceResource = async (res: Response, data: VendorExperienceDTO, message: string = 'Success'): Promise<Response> => {
7
-    const tags = await prisma.categoryLink.findMany({
8
-        where: {
9
-            source_id: data.id,
10
-            source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
11
-            deletedAt: null,
12
-        },
13
-        include: {
14
-            Category: true,
15
-        },
16
-    });
6
+    // const tags = await prisma.categoryLink.findMany({
7
+    //     where: {
8
+    //         source_id: data.id,
9
+    //         source_type: { in: ['vendor_experience_positive_notes', 'vendor_experience_negative_notes'] },
10
+    //         deletedAt: null,
11
+    //     },
12
+    //     include: {
13
+    //         Category: true,
14
+    //     },
15
+    // });
17 16
 
18
-    const positive_notes_tags = tags
19
-        .filter(t => t.source_type === 'vendor_experience_positive_notes')
20
-        .map(t => t.Category?.tag ?? '');
17
+    // const positive_notes_tags = tags
18
+    //     .filter(t => t.source_type === 'vendor_experience_positive_notes')
19
+    //     .map(t => t.Category?.tag ?? '');
21 20
 
22
-    const negative_notes_tags = tags
23
-        .filter(t => t.source_type === 'vendor_experience_negative_notes')
24
-        .map(t => t.Category?.tag ?? '');
21
+    // const negative_notes_tags = tags
22
+    //     .filter(t => t.source_type === 'vendor_experience_negative_notes')
23
+    //     .map(t => t.Category?.tag ?? '');
25 24
 
26
-    const { vendor_id, ...restData } = data;
25
+    // const { vendor_id, ...restData } = data;
26
+    const restData = data;
27 27
 
28 28
     const formatted = {
29 29
         ...restData,
@@ -38,12 +38,25 @@ export const VendorExperienceResource = async (res: Response, data: VendorExperi
38 38
                 created_by: data.vendor.created_by,
39 39
             }
40 40
             : null,
41
-        contract_start_date: formatDateOnly(data.contract_start_date),
42
-        contract_expired_date: formatDateOnly(data.contract_expired_date),
43
-        contract_value_min: data.contract_value_min !== null ? Number(data.contract_value_min) : null,
44
-        contract_value_max: data.contract_value_max !== null ? Number(data.contract_value_max) : null,
45
-        positive_notes_tags,
46
-        negative_notes_tags,
41
+        category: data.category
42
+            ? {
43
+                id: data.category.id,
44
+                name: data.category.name,
45
+                description: data.category.description,
46
+            }
47
+            : null,
48
+        user: data.user
49
+            ? {
50
+                id: data.user.id,
51
+                name: data.user.fullname,
52
+            } : null,
53
+        content: data.content,
54
+        // contract_start_date: formatDateOnly(data.contract_start_date),
55
+        // contract_expired_date: formatDateOnly(data.contract_expired_date),
56
+        // contract_value_min: data.contract_value_min !== null ? Number(data.contract_value_min) : null,
57
+        // contract_value_max: data.contract_value_max !== null ? Number(data.contract_value_max) : null,
58
+        // positive_notes_tags,
59
+        // negative_notes_tags,
47 60
         createdAt: formatISOWithoutTimezone(data.createdAt),
48 61
         updatedAt: formatISOWithoutTimezone(data.updatedAt),
49 62
     };

+ 4 - 3
src/routes/admin/CategoryRoute.ts

@@ -6,13 +6,14 @@ import checkRoles from '../../middleware/CheckRoles';
6 6
 
7 7
 const router: Router = express.Router();
8 8
 
9
-router.get('/', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.getAllCategory);
9
+router.get('/', [keycloak.protect(), extractToken, checkRoles(["admin", "sales"])], CategoryController.getAllCategory);
10 10
 router.post('/', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.storeCategory);
11 11
 router.get('/:id', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.showCategory);
12 12
 router.patch('/:id', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.updateCategory);
13 13
 router.delete('/:id', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.deleteCategory);
14
+router.patch('/:id/archive', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.archiveCategory);
14 15
 
15
-router.get('/:id/use', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.showUseCategory);
16
-router.post('/merge', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.mergeCategory);
16
+// router.get('/:id/use', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.showUseCategory);
17
+// router.post('/merge', [keycloak.protect(), extractToken, checkRoles(["admin"])], CategoryController.mergeCategory);
17 18
 
18 19
 export default router;

+ 55 - 55
src/services/admin/CategoryLinkService.ts

@@ -3,58 +3,58 @@ import CategoryLinkRepository from '../../repository/admin/CategoryLinkRepositor
3 3
 import { createLog, updateLog } from '../../utils/LogActivity';
4 4
 import { CustomRequest } from '../../types/token/CustomRequest';
5 5
 
6
-export const storeCategoryLinkService = async (tags: string[], source_type: string, source_id: string, req: CustomRequest) => {
7
-    const result = [];
8
-
9
-    for (let i = 0; i < tags.length; i++) {
10
-        const tag = tags[i];
11
-
12
-        const existCategoryTag = await CategoryRepository.findByTag(tag);
13
-
14
-        let categoryId: string = "";
15
-        if (!existCategoryTag) {
16
-            const created = await CategoryRepository.create({ tag: tag, description: null });
17
-            categoryId = created.id;
18
-            await createLog(req, created);
19
-        } else {
20
-            categoryId = existCategoryTag.id;
21
-        }
22
-
23
-        const data = await CategoryLinkRepository.create({
24
-            category_id: categoryId,
25
-            source_type: source_type,
26
-            source_id: source_id,
27
-        });
28
-
29
-        await createLog(req, data);
30
-        result.push(data);
31
-    }
32
-};
33
-export const updateCategoryLinkService = async (newTags: string[], source_type: string, source_id: string, req: CustomRequest) => {
34
-    const result = [];
35
-
36
-    const oldLinks = await CategoryLinkRepository.findBySource(source_type, source_id);
37
-
38
-    for (const link of oldLinks) {
39
-        await CategoryLinkRepository.deleteById(link.id);
40
-    }
41
-
42
-    for (const tag of newTags) {
43
-        let category = await CategoryRepository.findByTag(tag);
44
-        if (!category) {
45
-            category = await CategoryRepository.create({ tag, description: null });
46
-            await createLog(req, category);
47
-        }
48
-
49
-        const newLink = await CategoryLinkRepository.create({
50
-            category_id: category.id,
51
-            source_type,
52
-            source_id,
53
-        });
54
-
55
-        await updateLog(req, newLink);
56
-        result.push(newLink);
57
-    }
58
-
59
-    return result;
60
-};
6
+// export const storeCategoryLinkService = async (tags: string[], source_type: string, source_id: string, req: CustomRequest) => {
7
+//     const result = [];
8
+
9
+//     for (let i = 0; i < tags.length; i++) {
10
+//         const tag = tags[i];
11
+
12
+//         const existCategoryTag = await CategoryRepository.findByTag(tag);
13
+
14
+//         let categoryId: string = "";
15
+//         if (!existCategoryTag) {
16
+//             const created = await CategoryRepository.create({ tag: tag, description: null });
17
+//             categoryId = created.id;
18
+//             await createLog(req, created);
19
+//         } else {
20
+//             categoryId = existCategoryTag.id;
21
+//         }
22
+
23
+//         const data = await CategoryLinkRepository.create({
24
+//             category_id: categoryId,
25
+//             source_type: source_type,
26
+//             source_id: source_id,
27
+//         });
28
+
29
+//         await createLog(req, data);
30
+//         result.push(data);
31
+//     }
32
+// };
33
+// export const updateCategoryLinkService = async (newTags: string[], source_type: string, source_id: string, req: CustomRequest) => {
34
+//     const result = [];
35
+
36
+//     const oldLinks = await CategoryLinkRepository.findBySource(source_type, source_id);
37
+
38
+//     for (const link of oldLinks) {
39
+//         await CategoryLinkRepository.deleteById(link.id);
40
+//     }
41
+
42
+//     for (const tag of newTags) {
43
+//         let category = await CategoryRepository.findByTag(tag);
44
+//         if (!category) {
45
+//             category = await CategoryRepository.create({ tag, description: null });
46
+//             await createLog(req, category);
47
+//         }
48
+
49
+//         const newLink = await CategoryLinkRepository.create({
50
+//             category_id: category.id,
51
+//             source_type,
52
+//             source_id,
53
+//         });
54
+
55
+//         await updateLog(req, newLink);
56
+//         result.push(newLink);
57
+//     }
58
+
59
+//     return result;
60
+// };

+ 154 - 114
src/services/admin/CategoryService.ts

@@ -17,23 +17,39 @@ interface GetAllCategoryParams {
17 17
     search?: string;
18 18
     sortBy: string;
19 19
     orderBy: 'asc' | 'desc';
20
+    filter?: 'archive' | 'all';
21
+    usage?: 'unused' | 'used'
20 22
 }
21 23
 
22
-interface GetAllCategoryLinkParams {
23
-    page: number;
24
-    limit: number;
25
-    search?: string;
26
-    categoryId: string;
27
-}
28
-
29
-export const getAllCategoryService = async ({ page, limit, search, sortBy, orderBy }: GetAllCategoryParams) => {
24
+// interface GetAllCategoryLinkParams {
25
+//     page: number;
26
+//     limit: number;
27
+//     search?: string;
28
+//     categoryId: string;
29
+// }
30
+export const getAllCategoryService = async ({ page, limit, search, sortBy, orderBy, filter, usage }: GetAllCategoryParams) => {
30 31
     const skip = (page - 1) * limit;
31 32
 
32
-    const where: Prisma.CategoryWhereInput = {
33
-        ...SearchFilter(search, ['tag']),
33
+    // Default filter: only active (not archived, not deleted)
34
+    let where: Prisma.CategoryWhereInput = {
35
+        ...SearchFilter(search, ['name']),
36
+        status_archive: false,
34 37
         deletedAt: null,
35 38
     };
36 39
 
40
+    if (filter === 'archive') {
41
+        where = {
42
+            ...SearchFilter(search, ['name']),
43
+            status_archive: true,
44
+            deletedAt: null,
45
+        };
46
+    } else if (filter === 'all') {
47
+        where = {
48
+            ...SearchFilter(search, ['name']),
49
+            deletedAt: null, // ignore status_archive
50
+        };
51
+    }
52
+
37 53
     const [categories, total] = await Promise.all([
38 54
         CategoryRepository.findAll({
39 55
             skip,
@@ -43,8 +59,16 @@ export const getAllCategoryService = async ({ page, limit, search, sortBy, order
43 59
         }),
44 60
         CategoryRepository.countAll(where),
45 61
     ]);
62
+    
63
+    let filteredCategories = categories;
64
+
65
+    if (usage === 'unused') {
66
+        filteredCategories = categories.filter(c => c.count_use_category === 0);
67
+    } else if (usage === 'used') {
68
+        filteredCategories = categories.filter(c => c.count_use_category > 0);
69
+    }
46 70
 
47
-    return { categories, total };
71
+    return { categories: filteredCategories, total };
48 72
 };
49 73
 
50 74
 export const showCategoryService = async (id: string) => {
@@ -57,14 +81,14 @@ export const showCategoryService = async (id: string) => {
57 81
 };
58 82
 
59 83
 export const storeCategoryService = async (validateData: CategoryRequestDTO, req: CustomRequest) => {
60
-    const existingCategory = await CategoryRepository.findByTag(validateData.tag);
84
+    const existingCategory = await CategoryRepository.findByName(validateData.name);
61 85
     if (existingCategory && !existingCategory.deletedAt) {
62
-        throw new HttpException('Category with this tag already exists and may not be duplicated.', 400);
86
+        throw new HttpException('Category with this name already exists and may not be duplicated.', 400);
63 87
     }
64 88
 
65 89
     const data = await CategoryRepository.create(validateData);
66 90
     await createLog(req, data);
67
-    return data;
91
+    // return data;
68 92
 };
69 93
 
70 94
 export const updateCategoryService = async (validateData: CategoryRequestDTO, id: string, req: CustomRequest) => {
@@ -73,16 +97,16 @@ export const updateCategoryService = async (validateData: CategoryRequestDTO, id
73 97
         throw new HttpException('Data category not found', 404);
74 98
     }
75 99
 
76
-    if (validateData.tag) {
77
-        const existingCategory = await CategoryRepository.findByTag(validateData.tag);
100
+    if (validateData.name) {
101
+        const existingCategory = await CategoryRepository.findByName(validateData.name);
78 102
         if (existingCategory && existingCategory.id !== id) {
79
-            throw new HttpException('Category with this tag already exists and may not be duplicated.', 400);
103
+            throw new HttpException('Category with this name already exists and may not be duplicated.', 400);
80 104
         }
81 105
     }
82 106
 
83 107
     const data = await CategoryRepository.update(id, validateData);
84 108
     await updateLog(req, data);
85
-    return data;
109
+    // return data;
86 110
 };
87 111
 
88 112
 export const deleteCategoryService = async (id: string, req: CustomRequest) => {
@@ -96,108 +120,124 @@ export const deleteCategoryService = async (id: string, req: CustomRequest) => {
96 120
     });
97 121
 
98 122
     await deleteLog(req, data);
99
-    return data;
100
-};
101
-
102
-export const showUseCategoryService = async ({ page, limit, search, categoryId }: GetAllCategoryLinkParams) => {
103
-    const skip = (page - 1) * limit;
104
-
105
-    const where: Prisma.CategoryLinkWhereInput = {
106
-        ...SearchFilter(search, ['source_type']),
107
-        category_id: categoryId,
108
-        deletedAt: null,
109
-    };
110
-
111
-    const [links, total] = await Promise.all([
112
-        CategoryRepository.findAllCategoryLink({ skip, take: limit, where }),
113
-        CategoryRepository.countAllCategoryLink(where),
114
-    ]);
115
-
116
-    const result: CategoryLinkUseDTO[] = [];
117
-
118
-    for (const link of links) {
119
-        const { source_id, source_type } = link;
120
-        if (!source_id || !source_type) continue;
121
-
122
-        const sourceData = await GetSourceDataByType(source_type, source_id);
123
-        if (!sourceData) continue;
124
-
125
-        result.push(TransformCategoryLinkUse(link, source_type, sourceData));
126
-    }
127
-
128
-    return { data: result, total, page, limit };
123
+    // return data;
129 124
 };
130 125
 
131
-export const mergeCategoryService = async (validateData: MergeCategoryRequestDTO, req: CustomRequest) => {
132
-    // Soft delete old categories
133
-    for (const id of validateData.category_id) {
134
-        const category = await CategoryRepository.findById(id);
135
-        if (!category) {
136
-            throw new HttpException(`Category with tag ${validateData.tag} not found`, 404);
137
-        }
138
-    }
139
-
140
-    // Check tag uniqueness
141
-    const existingCategory = await CategoryRepository.findByTag(validateData.tag);
142
-    if (existingCategory && !existingCategory.deletedAt) {
143
-        throw new HttpException('Category with this tag already exists and may not be duplicated.', 400);
126
+export const archiveCategoryService = async (id: string, req: CustomRequest) => {
127
+    const category = await CategoryRepository.findById(id);
128
+    if (!category) {
129
+        throw new HttpException('Data category not found', 404);
144 130
     }
145 131
 
146
-    // Create new merged category
147
-    const data = await CategoryRepository.create({
148
-        tag: validateData.tag,
149
-        description: validateData.description ?? null,
150
-    });
151
-
152
-    await createLog(req, data);
132
+    const newStatus = !category.status_archive;
153 133
 
154
-    await prisma.categoryLink.updateMany({
155
-        where: {
156
-            category_id: { in: validateData.category_id },
157
-            deletedAt: null,
158
-        },
159
-        data: {
160
-            category_id: data.id,
161
-        },
162
-    });
163
-
164
-    await prisma.category.updateMany({
165
-        where: {
166
-            id: { in: validateData.category_id },
167
-            deletedAt: null,
168
-        },
169
-        data: {
170
-            deletedAt: now().toDate(),
171
-        },
134
+    const data = await CategoryRepository.update(id, {
135
+        status_archive: newStatus,
172 136
     });
173 137
 
174
-    // Remove duplicate category links (same category_id, source_type, source_id, deletedAt: null)
175
-    const links = await prisma.categoryLink.findMany({
176
-        where: {
177
-            category_id: data.id,
178
-            deletedAt: null,
179
-        },
180
-    });
138
+    await updateLog(req, data);
181 139
 
182
-    // Group by source_type + source_id
183
-    const grouped: Record<string, typeof links> = {};
184
-    for (const link of links) {
185
-        const key = `${link.source_type}_${link.source_id}`;
186
-        if (!grouped[key]) grouped[key] = [];
187
-        grouped[key].push(link);
188
-    }
140
+}
189 141
 
190
-    for (const group of Object.values(grouped)) {
191
-        if (group.length > 1) {
192
-            // Sort by createdAt, keep the earliest, delete the rest
193
-            const sorted = group.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
194
-            const toDelete = sorted.slice(1);
195
-            for (const link of toDelete) {
196
-                await prisma.categoryLink.update({
197
-                    where: { id: link.id },
198
-                    data: { deletedAt: now().toDate() },
199
-                });
200
-            }
201
-        }
202
-    }
203
-};
142
+// export const showUseCategoryService = async ({ page, limit, search, categoryId }: GetAllCategoryLinkParams) => {
143
+//     const skip = (page - 1) * limit;
144
+
145
+//     const where: Prisma.CategoryLinkWhereInput = {
146
+//         ...SearchFilter(search, ['source_type']),
147
+//         category_id: categoryId,
148
+//         deletedAt: null,
149
+//     };
150
+
151
+//     const [links, total] = await Promise.all([
152
+//         CategoryRepository.findAllCategoryLink({ skip, take: limit, where }),
153
+//         CategoryRepository.countAllCategoryLink(where),
154
+//     ]);
155
+
156
+//     const result: CategoryLinkUseDTO[] = [];
157
+
158
+//     for (const link of links) {
159
+//         const { source_id, source_type } = link;
160
+//         if (!source_id || !source_type) continue;
161
+
162
+//         const sourceData = await GetSourceDataByType(source_type, source_id);
163
+//         if (!sourceData) continue;
164
+
165
+//         result.push(TransformCategoryLinkUse(link, source_type, sourceData));
166
+//     }
167
+
168
+//     return { data: result, total, page, limit };
169
+// };
170
+
171
+// export const mergeCategoryService = async (validateData: MergeCategoryRequestDTO, req: CustomRequest) => {
172
+//     // Soft delete old categories
173
+//     for (const id of validateData.category_id) {
174
+//         const category = await CategoryRepository.findById(id);
175
+//         if (!category) {
176
+//             throw new HttpException(`Category with tag ${validateData.tag} not found`, 404);
177
+//         }
178
+//     }
179
+
180
+//     // Check tag uniqueness
181
+//     const existingCategory = await CategoryRepository.findByTag(validateData.tag);
182
+//     if (existingCategory && !existingCategory.deletedAt) {
183
+//         throw new HttpException('Category with this tag already exists and may not be duplicated.', 400);
184
+//     }
185
+
186
+//     // Create new merged category
187
+//     const data = await CategoryRepository.create({
188
+//         tag: validateData.tag,
189
+//         description: validateData.description ?? null,
190
+//     });
191
+
192
+//     await createLog(req, data);
193
+
194
+//     await prisma.categoryLink.updateMany({
195
+//         where: {
196
+//             category_id: { in: validateData.category_id },
197
+//             deletedAt: null,
198
+//         },
199
+//         data: {
200
+//             category_id: data.id,
201
+//         },
202
+//     });
203
+
204
+//     await prisma.category.updateMany({
205
+//         where: {
206
+//             id: { in: validateData.category_id },
207
+//             deletedAt: null,
208
+//         },
209
+//         data: {
210
+//             deletedAt: now().toDate(),
211
+//         },
212
+//     });
213
+
214
+//     // Remove duplicate category links (same category_id, source_type, source_id, deletedAt: null)
215
+//     const links = await prisma.categoryLink.findMany({
216
+//         where: {
217
+//             category_id: data.id,
218
+//             deletedAt: null,
219
+//         },
220
+//     });
221
+
222
+//     // Group by source_type + source_id
223
+//     const grouped: Record<string, typeof links> = {};
224
+//     for (const link of links) {
225
+//         const key = `${link.source_type}_${link.source_id}`;
226
+//         if (!grouped[key]) grouped[key] = [];
227
+//         grouped[key].push(link);
228
+//     }
229
+
230
+//     for (const group of Object.values(grouped)) {
231
+//         if (group.length > 1) {
232
+//             // Sort by createdAt, keep the earliest, delete the rest
233
+//             const sorted = group.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
234
+//             const toDelete = sorted.slice(1);
235
+//             for (const link of toDelete) {
236
+//                 await prisma.categoryLink.update({
237
+//                     where: { id: link.id },
238
+//                     data: { deletedAt: now().toDate() },
239
+//                 });
240
+//             }
241
+//         }
242
+//     }
243
+// };

+ 1 - 75
src/services/admin/CityService.ts

@@ -125,78 +125,4 @@ export const deleteCityService = async (id: string, req: CustomRequest) => {
125 125
 
126 126
     await deleteLog(req, data);
127 127
     return data;
128
-};
129
-
130
-// const CityRepository = require('../../repository/admin/CityRepository.js');
131
-// const HttpException = require('../../utils/HttpException.js');
132
-// const { SearchFilter } = require('../../utils/SearchFilter.js');
133
-// const timeLocal = require('../../utils/TimeLocal.js');
134
-// const { createLog, updateLog, deleteLog } = require('../../utils/LogActivity.js');
135
-// const ProvinceRepository = require('../../repository/admin/ProvinceRepository.js');
136
-// const { formatISOWithoutTimezone } = require('../../utils/FormatDate.js');
137
-
138
-// exports.getAllCityService = async ({ page, limit, search, sortBy, orderBy }) => {
139
-//     const skip = (page - 1) * limit;
140
-
141
-//     const where = {
142
-//         ...SearchFilter(search, ['id', 'name', 'province.id']),
143
-//         deletedAt: null
144
-//     };
145
-
146
-//     const [cities, total] = await Promise.all([
147
-//         CityRepository.findAll({ skip, take: limit, where, orderBy: { [sortBy]: orderBy } }),
148
-//         CityRepository.countAll(where)
149
-//     ]);
150
-
151
-//     return { cities, total };
152
-// };
153
-
154
-// exports.showCityService = async (id) => {
155
-//     const city = await CityRepository.findById(id);
156
-//     if (!city) {
157
-//         throw new HttpException("Data city not found", 404);
158
-//     }
159
-
160
-//     return city;
161
-// };
162
-
163
-// exports.storeCityService = async (validateData, req) => {
164
-//     const province = await ProvinceRepository.findById(validateData.province_id);
165
-//     if (!province) {
166
-//         throw new HttpException('Province not found', 404);
167
-//     }
168
-
169
-//     const data = await CityRepository.create(validateData);
170
-//     await createLog(req, data);
171
-// };
172
-
173
-// exports.updateCityService = async (validateData, id, req) => {
174
-//     const city = await CityRepository.findById(id);
175
-//     if (!city) {
176
-//         throw new HttpException("Data city not found", 404);
177
-//     }
178
-
179
-//     if (validateData.province_id) {
180
-//         const province = await ProvinceRepository.findById(validateData.province_id);
181
-//         if (!province) {
182
-//             throw new HttpException('Province not found', 404);
183
-//         }
184
-//     }
185
-
186
-//     const data = await CityRepository.update(id, validateData);
187
-//     await updateLog(req, data);
188
-// };
189
-
190
-// exports.deleteCityService = async (id, req) => {
191
-//     const city = await CityRepository.findById(id);
192
-
193
-//     if (!city) {
194
-//         throw new HttpException('City not found', 404);
195
-//     }
196
-
197
-//     const data = await CityRepository.update(id, {
198
-//         deletedAt: now().toDate()
199
-//     });
200
-
201
-//     await deleteLog(req, data);
202
-// };
128
+};

+ 25 - 25
src/services/admin/HospitalService.ts

@@ -13,7 +13,7 @@ import path from 'path';
13 13
 import fs from 'fs/promises';
14 14
 import sharp from 'sharp';
15 15
 import * as XLSX from "xlsx";
16
-import { storeCategoryLinkService, updateCategoryLinkService } from './CategoryLinkService';
16
+// import { storeCategoryLinkService, updateCategoryLinkService } from './CategoryLinkService';
17 17
 import { validateStoreHospitalRequest } from '../../validators/admin/hospital/HospitalValidators';
18 18
 
19 19
 interface PaginationParams {
@@ -172,14 +172,14 @@ export const storeHospitalService = async (validateData: HospitalRequestDTO, req
172 172
     };
173 173
 
174 174
     const data = await HospitalRepository.create(payload);
175
-    if (validateData.tags?.length) {
176
-        await storeCategoryLinkService(
177
-            validateData.tags,
178
-            'hospital_notes',
179
-            data.id,
180
-            req
181
-        );
182
-    }
175
+    // if (validateData.tags?.length) {
176
+    //     await storeCategoryLinkService(
177
+    //         validateData.tags,
178
+    //         'hospital_notes',
179
+    //         data.id,
180
+    //         req
181
+    //     );
182
+    // }
183 183
 
184 184
     await createLog(req, data);
185 185
 };
@@ -301,14 +301,14 @@ export const updateHospitalService = async (validateData: Partial<HospitalReques
301 301
     };
302 302
 
303 303
     const data = await HospitalRepository.update(id, payload);
304
-    if (validateData.tags?.length) {
305
-        await updateCategoryLinkService(
306
-            validateData.tags,
307
-            'hospital_notes',
308
-            id,
309
-            req
310
-        );
311
-    }
304
+    // if (validateData.tags?.length) {
305
+    //     await updateCategoryLinkService(
306
+    //         validateData.tags,
307
+    //         'hospital_notes',
308
+    //         id,
309
+    //         req
310
+    //     );
311
+    // }
312 312
     await updateLog(req, data);
313 313
 };
314 314
 
@@ -410,14 +410,14 @@ export const importHospitalService = async (file: Express.Multer.File, req: Cust
410 410
         const data = await HospitalRepository.create(payload);
411 411
 
412 412
         // tags kategori kalau ada
413
-        if (validatedData.tags?.length) {
414
-            await storeCategoryLinkService(
415
-                validatedData.tags,
416
-                'hospital_notes',
417
-                data.id,
418
-                req
419
-            );
420
-        }
413
+        // if (validatedData.tags?.length) {
414
+        //     await storeCategoryLinkService(
415
+        //         validatedData.tags,
416
+        //         'hospital_notes',
417
+        //         data.id,
418
+        //         req
419
+        //     );
420
+        // }
421 421
 
422 422
         await createLog(req, data);
423 423
     }

+ 9 - 9
src/services/admin/StatusHistoryService.ts

@@ -5,7 +5,7 @@ import { createLog } from '../../utils/LogActivity';
5 5
 import StatusHistoryRepository from '../../repository/admin/StatusHistoryRepository';
6 6
 import { CustomRequest } from '../../types/token/CustomRequest';
7 7
 import { StatusHistoryRequestDTO } from '../../types/admin/status_history/StatusHistoryDTO';
8
-import { storeCategoryLinkService } from './CategoryLinkService';
8
+// import { storeCategoryLinkService } from './CategoryLinkService';
9 9
 
10 10
 const prisma = new PrismaClient();
11 11
 
@@ -95,14 +95,14 @@ export const storeStatusHistoryService = async (validateData: StatusHistoryReque
95 95
         data: { progress_status: validateData.new_status as ProgressStatus },
96 96
     });
97 97
 
98
-    if (validateData.note?.tags?.length) {
99
-        await storeCategoryLinkService(
100
-            validateData.note.tags,
101
-            'status_history_notes',
102
-            data.id,
103
-            req
104
-        );
105
-    }
98
+    // if (validateData.note?.tags?.length) {
99
+    //     await storeCategoryLinkService(
100
+    //         validateData.note.tags,
101
+    //         'status_history_notes',
102
+    //         data.id,
103
+    //         req
104
+    //     );
105
+    // }
106 106
 
107 107
     await createLog(req, data);
108 108
 };

+ 213 - 445
src/services/admin/VendorExperienceService.ts

@@ -6,7 +6,9 @@ import { createLog, updateLog, deleteLog } from '../../utils/LogActivity';
6 6
 import VendorExperienceRepository from '../../repository/admin/VendorExperienceRepository';
7 7
 import { CustomRequest } from '../../types/token/CustomRequest';
8 8
 import { VendorExperienceRequestDTO } from '../../types/admin/vendor_experience/VendorExperienceDTO';
9
-import { storeCategoryLinkService, updateCategoryLinkService } from './CategoryLinkService';
9
+import { connect } from 'http2';
10
+import { Prisma } from '@prisma/client';
11
+// import { storeCategoryLinkService, updateCategoryLinkService } from './CategoryLinkService';
10 12
 
11 13
 interface PaginationParams {
12 14
     page: number;
@@ -14,20 +16,24 @@ interface PaginationParams {
14 16
     search?: string;
15 17
     sortBy: string;
16 18
     orderBy: 'asc' | 'desc';
19
+    category_id: string;
17 20
 }
18 21
 
19
-export const getAllVendorExperienceService = async ({ page, limit, search, sortBy, orderBy }: PaginationParams, req: Request) => {
22
+export const getAllVendorExperienceService = async ({ page, limit, search, sortBy, orderBy, category_id }: PaginationParams, req: Request) => {
20 23
     const skip = (page - 1) * limit;
24
+
25
+    const where: Prisma.VendorExperienceWhereInput = {
26
+        hospital_id: req.params.id,
27
+        // ...SearchFilter(search, ['id', 'name', 'province.id']),
28
+        ...(category_id ? { category_id: category_id } : {}),
29
+        deletedAt: null,
30
+    };
31
+
21 32
     const hospitalId = req.params.id;
22 33
 
23 34
     const hospital = await prisma.hospital.findFirst({ where: { id: hospitalId } });
24 35
     if (!hospital) throw new HttpException('Hospital not found', 404);
25 36
 
26
-    const where: any = {
27
-        hospital_id: req.params.id,
28
-        deletedAt: null
29
-    };
30
-
31 37
     const [vendor_experiences, total] = await Promise.all([
32 38
         VendorExperienceRepository.findAll({ skip, take: limit, where, orderBy: { [sortBy]: orderBy } }),
33 39
         VendorExperienceRepository.countAll(where)
@@ -51,6 +57,7 @@ export const showVendorExperienceService = async (req: Request) => {
51 57
 
52 58
 export const storeVendorExperienceService = async (validateData: VendorExperienceRequestDTO, req: CustomRequest) => {
53 59
     const hospitalId = req.params.id;
60
+    const userId = req.tokenData.sub;
54 61
 
55 62
     const hospital = await prisma.hospital.findFirst({ where: { id: hospitalId } });
56 63
     if (!hospital) throw new HttpException('Hospital not found', 404);
@@ -60,92 +67,99 @@ export const storeVendorExperienceService = async (validateData: VendorExperienc
60 67
         if (!vendor) throw new HttpException('Vendor not found', 404);
61 68
     }
62 69
 
63
-    const SimrsType = ['vendor', 'in house', 'gratis'];
64
-    if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
65
-        throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
70
+    if (validateData.category_id) {
71
+        const category = await prisma.category.findFirst({ where: { id: validateData.category_id } });
72
+        if (!category) throw new HttpException('Category not found', 404);
66 73
     }
67 74
 
68
-    if (validateData.contract_start_date && validateData.contract_expired_date) {
69
-        if (validateData.contract_start_date >= validateData.contract_expired_date) {
70
-            throw new HttpException('Contract expired date must be after contract date', 400);
71
-        }
72
-    }
73
-
74
-    if (validateData.contract_value_min && validateData.contract_value_max) {
75
-        if (validateData.contract_value_min >= validateData.contract_value_max) {
76
-            throw new HttpException('Contract value max must be after contract value min', 400);
77
-        }
78
-    }
79
-
80
-    if (validateData.simrs_type) {
81
-        const existingActiveVendors = await prisma.vendorExperience.findMany({
82
-            where: {
83
-                hospital_id: hospitalId,
84
-                status: 'active',
85
-                deletedAt: null
86
-            }
87
-        });
88
-
89
-        if (existingActiveVendors.length > 0) {
90
-            await prisma.vendorExperience.updateMany({
91
-                where: {
92
-                    hospital_id: hospitalId,
93
-                    status: 'active',
94
-                    deletedAt: null
95
-                },
96
-                data: {
97
-                    status: 'inactive'
98
-                }
99
-            });
100
-        }
101
-
102
-        validateData.status = 'active';
103
-    }
75
+    // const SimrsType = ['vendor', 'in house', 'gratis'];
76
+    // if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
77
+    //     throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
78
+    // }
79
+
80
+    // if (validateData.contract_start_date && validateData.contract_expired_date) {
81
+    //     if (validateData.contract_start_date >= validateData.contract_expired_date) {
82
+    //         throw new HttpException('Contract expired date must be after contract date', 400);
83
+    //     }
84
+    // }
85
+
86
+    // if (validateData.contract_value_min && validateData.contract_value_max) {
87
+    //     if (validateData.contract_value_min >= validateData.contract_value_max) {
88
+    //         throw new HttpException('Contract value max must be after contract value min', 400);
89
+    //     }
90
+    // }
91
+
92
+    // if (validateData.simrs_type) {
93
+    //     const existingActiveVendors = await prisma.vendorExperience.findMany({
94
+    //         where: {
95
+    //             hospital_id: hospitalId,
96
+    //             status: 'active',
97
+    //             deletedAt: null
98
+    //         }
99
+    //     });
100
+
101
+    //     if (existingActiveVendors.length > 0) {
102
+    //         await prisma.vendorExperience.updateMany({
103
+    //             where: {
104
+    //                 hospital_id: hospitalId,
105
+    //                 status: 'active',
106
+    //                 deletedAt: null
107
+    //             },
108
+    //             data: {
109
+    //                 status: 'inactive'
110
+    //             }
111
+    //         });
112
+    //     }
113
+
114
+    //     validateData.status = 'active';
115
+    // }
104 116
 
105 117
     const payload = {
106
-        ...(validateData.vendor_id && {
107
-            vendor: {
108
-                connect: { id: validateData.vendor_id }
109
-            }
110
-        }),
111
-        simrs_type: validateData.simrs_type,
112
-        status: validateData.status,
113
-        contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : null,
114
-        contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : null,
115
-        contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : null,
116
-        contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : null,
117
-        positive_notes: validateData.positive_notes?.note,
118
-        negative_notes: validateData.negative_notes?.note,
119
-        hospital: {
120
-            connect: { id: hospitalId }
121
-        },
118
+        content: validateData.content,
119
+        vendor: validateData.vendor_id
120
+            ? { connect: { id: validateData.vendor_id } }
121
+            : undefined,
122
+        category: validateData.category_id
123
+            ? { connect: { id: validateData.category_id } }
124
+            : undefined,
125
+        hospital: { connect: { id: hospitalId } },
126
+        user: { connect: { id: userId } },
127
+        // simrs_type: validateData.simrs_type,
128
+        // status: validateData.status,
129
+        // contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : null,
130
+        // contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : null,
131
+        // contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : null,
132
+        // contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : null,
133
+        // positive_notes: validateData.positive_notes?.note,
134
+        // negative_notes: validateData.negative_notes?.note,
122 135
     };
123 136
 
124 137
     const data = await VendorExperienceRepository.create(payload);
125 138
 
126 139
     // Setelah data berhasil disimpan
127
-    if (validateData.positive_notes?.tags?.length) {
128
-        await storeCategoryLinkService(
129
-            validateData.positive_notes.tags,
130
-            'vendor_experience_positive_notes',
131
-            data.id,
132
-            req
133
-        );
134
-    }
135
-
136
-    if (validateData.negative_notes?.tags?.length) {
137
-        await storeCategoryLinkService(
138
-            validateData.negative_notes.tags,
139
-            'vendor_experience_negative_notes',
140
-            data.id,
141
-            req
142
-        );
143
-    }
140
+    // if (validateData.positive_notes?.tags?.length) {
141
+    //     await storeCategoryLinkService(
142
+    //         validateData.positive_notes.tags,
143
+    //         'vendor_experience_positive_notes',
144
+    //         data.id,
145
+    //         req
146
+    //     );
147
+    // }
148
+
149
+    // if (validateData.negative_notes?.tags?.length) {
150
+    //     await storeCategoryLinkService(
151
+    //         validateData.negative_notes.tags,
152
+    //         'vendor_experience_negative_notes',
153
+    //         data.id,
154
+    //         req
155
+    //     );
156
+    // }
144 157
     await createLog(req, data);
145 158
 };
146 159
 
147 160
 export const updateVendorExperienceService = async (validateData: Partial<VendorExperienceRequestDTO>, req: CustomRequest) => {
148 161
     const id_hospital = req.params.id;
162
+    const id_user = req.tokenData.sub;
149 163
     const id_vendor_experience = req.params.id_vendor_experience;
150 164
 
151 165
     const hospital = await prisma.hospital.findFirst({ where: { id: id_hospital } });
@@ -159,116 +173,135 @@ export const updateVendorExperienceService = async (validateData: Partial<Vendor
159 173
         if (!existVendor) throw new HttpException('Vendor not found', 404);
160 174
     }
161 175
 
162
-    const SimrsType = ['vendor', 'in house', 'gratis'];
163
-    if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
164
-        throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
165
-    }
166
-
167
-    if (
168
-        validateData.simrs_type &&
169
-        vendorHistory.simrs_type === 'vendor' &&
170
-        vendorHistory.vendor_id !== null &&
171
-        validateData.simrs_type !== 'vendor'
172
-    ) {
173
-        await prisma.vendorExperience.update({
174
-            where: {
175
-                id: id_vendor_experience,
176
-                deletedAt: null
177
-            },
178
-            data: {
179
-                vendor_id: null
180
-            }
181
-        });
182
-    }
183
-
184
-    if (
185
-        validateData.contract_value_min &&
186
-        validateData.contract_value_min >= vendorHistory.contract_value_max!
187
-    ) {
188
-        throw new HttpException('Contract value min must be less than contract value max.', 400);
189
-    }
190
-
191
-    if (
192
-        validateData.contract_value_max &&
193
-        validateData.contract_value_max <= vendorHistory.contract_value_min!
194
-    ) {
195
-        throw new HttpException('Contract value max must be greater than contract value min.', 400);
196
-    }
197
-
198
-    if (
199
-        validateData.contract_start_date &&
200
-        validateData.contract_start_date >= vendorHistory.contract_expired_date!
201
-    ) {
202
-        throw new HttpException('Contract start date must be before contract expired date.', 400);
176
+    if (validateData.category_id) {
177
+        const existCategory = await prisma.category.findFirst({ where: { id: validateData.category_id } });
178
+        if (!existCategory) throw new HttpException('Category not found', 404);
203 179
     }
204 180
 
205
-    if (
206
-        validateData.contract_expired_date &&
207
-        validateData.contract_expired_date <= vendorHistory.contract_start_date!
208
-    ) {
209
-        throw new HttpException('Contract expired date must be after contract start date.', 400);
210
-    }
211
-
212
-    if (validateData.contract_start_date && validateData.contract_expired_date) {
213
-        if (validateData.contract_start_date >= validateData.contract_expired_date) {
214
-            throw new HttpException('Contract expired date must be after contract date', 400);
215
-        }
216
-    }
217
-
218
-    if (validateData.contract_value_min && validateData.contract_value_max) {
219
-        if (validateData.contract_value_min >= validateData.contract_value_max) {
220
-            throw new HttpException('Contract value max must be after contract value min', 400);
221
-        }
222
-    }
223
-
224
-    if (validateData.status === 'active') {
225
-        await prisma.vendorExperience.updateMany({
226
-            where: {
227
-                hospital_id: id_hospital,
228
-                status: 'active',
229
-                deletedAt: null,
230
-                NOT: { id: id_vendor_experience }
231
-            },
232
-            data: {
233
-                status: 'inactive'
234
-            }
235
-        });
236
-    }
181
+    // if (validateData.user_id) {
182
+    //     const existUser = await prisma.userKeycloak.findFirst({ where: { id: validateData.user_id } });
183
+    //     if (!existUser) throw new HttpException('User not found', 404);
184
+    // }
185
+
186
+    // const SimrsType = ['vendor', 'in house', 'gratis'];
187
+    // if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
188
+    //     throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
189
+    // }
190
+
191
+    // if (
192
+    //     validateData.simrs_type &&
193
+    //     vendorHistory.simrs_type === 'vendor' &&
194
+    //     vendorHistory.vendor_id !== null &&
195
+    //     validateData.simrs_type !== 'vendor'
196
+    // ) {
197
+    //     await prisma.vendorExperience.update({
198
+    //         where: {
199
+    //             id: id_vendor_experience,
200
+    //             deletedAt: null
201
+    //         },
202
+    //         data: {
203
+    //             vendor_id: null
204
+    //         }
205
+    //     });
206
+    // }
207
+
208
+    // if (
209
+    //     validateData.contract_value_min &&
210
+    //     validateData.contract_value_min >= vendorHistory.contract_value_max!
211
+    // ) {
212
+    //     throw new HttpException('Contract value min must be less than contract value max.', 400);
213
+    // }
214
+
215
+    // if (
216
+    //     validateData.contract_value_max &&
217
+    //     validateData.contract_value_max <= vendorHistory.contract_value_min!
218
+    // ) {
219
+    //     throw new HttpException('Contract value max must be greater than contract value min.', 400);
220
+    // }
221
+
222
+    // if (
223
+    //     validateData.contract_start_date &&
224
+    //     validateData.contract_start_date >= vendorHistory.contract_expired_date!
225
+    // ) {
226
+    //     throw new HttpException('Contract start date must be before contract expired date.', 400);
227
+    // }
228
+
229
+    // if (
230
+    //     validateData.contract_expired_date &&
231
+    //     validateData.contract_expired_date <= vendorHistory.contract_start_date!
232
+    // ) {
233
+    //     throw new HttpException('Contract expired date must be after contract start date.', 400);
234
+    // }
235
+
236
+    // if (validateData.contract_start_date && validateData.contract_expired_date) {
237
+    //     if (validateData.contract_start_date >= validateData.contract_expired_date) {
238
+    //         throw new HttpException('Contract expired date must be after contract date', 400);
239
+    //     }
240
+    // }
241
+
242
+    // if (validateData.contract_value_min && validateData.contract_value_max) {
243
+    //     if (validateData.contract_value_min >= validateData.contract_value_max) {
244
+    //         throw new HttpException('Contract value max must be after contract value min', 400);
245
+    //     }
246
+    // }
247
+
248
+    // if (validateData.status === 'active') {
249
+    //     await prisma.vendorExperience.updateMany({
250
+    //         where: {
251
+    //             hospital_id: id_hospital,
252
+    //             status: 'active',
253
+    //             deletedAt: null,
254
+    //             NOT: { id: id_vendor_experience }
255
+    //         },
256
+    //         data: {
257
+    //             status: 'inactive'
258
+    //         }
259
+    //     });
260
+    // }
237 261
 
238 262
     const payload = {
239
-        status: validateData.status,
240
-        contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : vendorHistory.contract_start_date,
241
-        contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : vendorHistory.contract_expired_date,
242
-        contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : vendorHistory.contract_value_min,
243
-        contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : vendorHistory.contract_value_max,
244
-        positive_notes: validateData.positive_notes?.note || vendorHistory.positive_notes,
245
-        negative_notes: validateData.negative_notes?.note || vendorHistory.negative_notes,
246
-        simrs_type: validateData.simrs_type,
247
-        vendor_id: validateData.vendor_id
263
+        content: validateData.content,
264
+        vendor: validateData.vendor_id
265
+            ? { connect: { id: validateData.vendor_id } }
266
+            : undefined,
267
+        category: validateData.category_id
268
+            ? { connect: { id: validateData.category_id } }
269
+            : undefined,
270
+        user: {
271
+            connect: { id: id_user }
272
+        },
273
+
274
+        // contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : vendorHistory.contract_start_date,
275
+        // contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : vendorHistory.contract_expired_date,
276
+        // contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : vendorHistory.contract_value_min,
277
+        // contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : vendorHistory.contract_value_max,
278
+        // positive_notes: validateData.positive_notes?.note || vendorHistory.positive_notes,
279
+        // negative_notes: validateData.negative_notes?.note || vendorHistory.negative_notes,
280
+        // simrs_type: validateData.simrs_type,
248 281
     };
249 282
 
250 283
     const data = await VendorExperienceRepository.update(id_vendor_experience, payload);
251 284
     await updateLog(req, data);
252 285
 
253 286
     // Positive Notes Tags
254
-    if (validateData.positive_notes?.tags?.length) {
255
-        await updateCategoryLinkService(
256
-            validateData.positive_notes.tags,
257
-            'vendor_experience_positive_notes',
258
-            id_vendor_experience,
259
-            req
260
-        );
261
-    }
262
-
263
-    // Negative Notes Tags
264
-    if (validateData.negative_notes?.tags?.length) {
265
-        await updateCategoryLinkService(
266
-            validateData.negative_notes.tags,
267
-            'vendor_experience_negative_notes',
268
-            id_vendor_experience,
269
-            req
270
-        );
271
-    }
287
+    // if (validateData.positive_notes?.tags?.length) {
288
+    //     await updateCategoryLinkService(
289
+    //         validateData.positive_notes.tags,
290
+    //         'vendor_experience_positive_notes',
291
+    //         id_vendor_experience,
292
+    //         req
293
+    //     );
294
+    // }
295
+
296
+    // // Negative Notes Tags
297
+    // if (validateData.negative_notes?.tags?.length) {
298
+    //     await updateCategoryLinkService(
299
+    //         validateData.negative_notes.tags,
300
+    //         'vendor_experience_negative_notes',
301
+    //         id_vendor_experience,
302
+    //         req
303
+    //     );
304
+    // }
272 305
 };
273 306
 
274 307
 export const deleteVendorExperienceService = async (req: CustomRequest) => {
@@ -286,269 +319,4 @@ export const deleteVendorExperienceService = async (req: CustomRequest) => {
286 319
     });
287 320
 
288 321
     await deleteLog(req, data);
289
-};
290
-
291
-// const HttpException = require('../../utils/HttpException.js');
292
-// const prisma = require('../../prisma/PrismaClient.js');
293
-// const { SearchFilter } = require('../../utils/SearchFilter.js');
294
-// const timeLocal = require('../../utils/TimeLocal.js');
295
-// const { createLog, updateLog, deleteLog } = require('../../utils/LogActivity.js');
296
-// const { formatDateOnly, formatISOWithoutTimezone } = require('../../utils/FormatDate.js');
297
-// const VendorExperienceRepository = require('../../repository/admin/VendorExperienceRepository.js');
298
-
299
-// exports.getAllVendorHistoryService = async ({ page, limit, search, sortBy, orderBy }, req) => {
300
-//     const skip = (page - 1) * limit;
301
-
302
-//     const hospitalId = req.params.id;
303
-//     const hospital = await prisma.hospital.findFirst({
304
-//         where: {
305
-//             id: hospitalId
306
-//         }
307
-//     })
308
-//     if (!hospital) {
309
-//         throw new HttpException("Hospital not found", 404)
310
-//     }
311
-
312
-//     const where = {
313
-//         // ...SearchFilter(search, ['name', 'name_pt']),
314
-//         hospital_id: req.params.id,
315
-//         deletedAt: null
316
-//     };
317
-
318
-//     const [vendor_histories, total] = await Promise.all([
319
-//         VendorExperienceRepository.findAll({ skip, take: limit, where, orderBy: { [sortBy]: orderBy } }),
320
-//         VendorExperienceRepository.countAll(where)
321
-//     ]);
322
-
323
-//     return { vendor_histories, total };
324
-// };
325
-
326
-// exports.showVendorHistoryService = async (req) => {
327
-//     const id_hospital = req.params.id;
328
-//     const id_vendor_experience = req.params.id_vendor_experience;
329
-
330
-//     const hospital = await prisma.hospital.findFirst({
331
-//         where: {
332
-//             id: id_hospital
333
-//         }
334
-//     })
335
-//     if (!hospital) {
336
-//         throw new HttpException("Hospital not found", 404)
337
-//     }
338
-
339
-//     const vendorHistory = await VendorExperienceRepository.findById(id_vendor_experience);
340
-//     if (!vendorHistory) {
341
-//         throw new HttpException("Vendor experience not found", 404);
342
-//     }
343
-
344
-//     return vendorHistory;
345
-// };
346
-
347
-// exports.storeVendorHistoryService = async (validateData, req) => {
348
-//     const hospitalId = req.params.id;
349
-
350
-//     const hospital = await prisma.hospital.findFirst({
351
-//         where: {
352
-//             id: hospitalId
353
-//         }
354
-//     });
355
-
356
-//     if (!hospital) {
357
-//         throw new HttpException("Hospital not found", 404)
358
-//     }
359
-
360
-//     if (validateData.vendor_id) {
361
-//         const vendor = await prisma.vendor.findFirst({
362
-//             where: {
363
-//                 id: validateData.vendor_id
364
-//             }
365
-//         });
366
-
367
-//         if (!vendor) {
368
-//             throw new HttpException("Vendor not found", 404)
369
-//         }
370
-//     }
371
-
372
-//     const SimrsType = ["vendor", "in house", "gratis"];
373
-//     if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
374
-//         throw new HttpException("Simrs type must be vendor, in house, or gratis", 400);
375
-//     }
376
-
377
-//     if (validateData.contract_start_date && validateData.contract_expired_date) {
378
-//         if (validateData.contract_start_date >= validateData.contract_expired_date) {
379
-//             throw new HttpException("Contract expired date must be after contract date", 400)
380
-//         }
381
-//     }
382
-
383
-//     if (validateData.contract_value_min && validateData.contract_value_max) {
384
-//         if (validateData.contract_value_min >= validateData.contract_value_max) {
385
-//             throw new HttpException("Contract value max must be after contract value min", 400)
386
-//         }
387
-//     }
388
-
389
-//     // await prisma.hospital.update({
390
-//     //     where: { id: hospitalId },
391
-//     //     data: {
392
-//     //         simrs_type: validateData.simrs_type
393
-//     //     }
394
-//     // });
395
-
396
-//     if (validateData.simrs_type) {
397
-//         const existingActiveVendors = await prisma.vendorExperience.findMany({
398
-//             where: {
399
-//                 hospital_id: hospitalId,
400
-//                 status: "active",
401
-//                 deletedAt: null
402
-//             }
403
-//         });
404
-
405
-//         if (existingActiveVendors.length > 0) {
406
-//             await prisma.vendorExperience.updateMany({
407
-//                 where: {
408
-//                     hospital_id: hospitalId,
409
-//                     status: "active",
410
-//                     deletedAt: null
411
-//                 },
412
-//                 data: {
413
-//                     status: "inactive"
414
-//                 }
415
-//             });
416
-//         }
417
-
418
-//         validateData.status = "active";
419
-//     }
420
-
421
-//     const payload = {
422
-//         vendor_id: validateData.vendor_id,
423
-//         simrs_type: validateData.simrs_type,
424
-//         status: validateData.status,
425
-//         contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : null,
426
-//         contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : null,
427
-//         contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : null,
428
-//         contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : null,
429
-//         positive_notes: validateData.positive_notes,
430
-//         negative_notes: validateData.negative_notes,
431
-//         hospital_id: hospitalId
432
-//     };
433
-
434
-//     const data = await VendorExperienceRepository.create(payload);
435
-//     await createLog(req, data);
436
-// };
437
-
438
-// exports.updateVendorHistoryService = async (validateData, req) => {
439
-//     const id_hospital = req.params.id;
440
-//     const id_vendor_experience = req.params.id_vendor_experience;
441
-
442
-//     const hospital = await prisma.hospital.findFirst({
443
-//         where: {
444
-//             id: id_hospital
445
-//         }
446
-//     })
447
-//     if (!hospital) {
448
-//         throw new HttpException("Hospital not found", 404)
449
-//     }
450
-
451
-//     const vendorHistory = await VendorExperienceRepository.findById(id_vendor_experience);
452
-//     if (!vendorHistory) {
453
-//         throw new HttpException("Vendor experience not found", 404);
454
-//     }
455
-
456
-//     if (validateData.vendor_id) {
457
-//         const existVendor = await prisma.vendor.findFirst({
458
-//             where: {
459
-//                 id: validateData.vendor_id
460
-//             }
461
-//         });
462
-//         if (!existVendor) {
463
-//             throw new HttpException("Vendor not found", 404)
464
-//         }
465
-//     }
466
-
467
-//     const SimrsType = ["vendor", "in house", "gratis"];
468
-//     if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
469
-//         throw new HttpException("Simrs type must be vendor, in house, or gratis", 400);
470
-//     }
471
-
472
-//     if (
473
-//         validateData.simrs_type &&
474
-//         vendorHistory.simrs_type === "vendor" &&
475
-//         vendorHistory.vendor_id !== null &&
476
-//         validateData.simrs_type !== "vendor"
477
-//     ) {
478
-//         await prisma.vendorExperience.update({
479
-//             where: {
480
-//                 id: id_vendor_experience,
481
-//                 deletedAt: null
482
-//             },
483
-//             data: {
484
-//                 vendor_id: null
485
-//             }
486
-//         });
487
-//     }
488
-
489
-//     if (validateData.contract_start_date && validateData.contract_expired_date) {
490
-//         if (validateData.contract_start_date >= validateData.contract_expired_date) {
491
-//             throw new HttpException("Contract expired date must be after contract date", 400)
492
-//         }
493
-//     }
494
-
495
-//     if (validateData.contract_value_min && validateData.contract_value_max) {
496
-//         if (validateData.contract_value_min >= validateData.contract_value_max) {
497
-//             throw new HttpException("Contract value max must be after contract value min", 400)
498
-//         }
499
-//     }
500
-
501
-//     if (validateData.status === "active") {
502
-//         await prisma.vendorExperience.updateMany({
503
-//             where: {
504
-//                 hospital_id: id_hospital,
505
-//                 status: "active",
506
-//                 deletedAt: null,
507
-//                 NOT: { id: id_vendor_experience },
508
-//             },
509
-//             data: {
510
-//                 status: "inactive",
511
-//             },
512
-//         });
513
-//     }
514
-
515
-//     const payload = {
516
-//         status: validateData.status,
517
-//         contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : vendorHistory.contract_start_date,
518
-//         contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : vendorHistory.contract_expired_date,
519
-//         contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : vendorHistory.contract_value_min,
520
-//         contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : vendorHistory.contract_value_max,
521
-//         positive_notes: validateData.positive_notes,
522
-//         negative_notes: validateData.negative_notes,
523
-//         simrs_type: validateData.simrs_type,
524
-//         vendor_id: validateData.vendor_id,
525
-//     };
526
-
527
-//     const data = await VendorExperienceRepository.update(id_vendor_experience, payload);
528
-//     await updateLog(req, data);
529
-// };
530
-
531
-// exports.deleteVendorHistoryService = async (req) => {
532
-//     const id_hospital = req.params.id;
533
-//     const id_vendor_experience = req.params.id_vendor_experience;
534
-
535
-//     const hospital = await prisma.hospital.findFirst({
536
-//         where: {
537
-//             id: id_hospital
538
-//         }
539
-//     })
540
-//     if (!hospital) {
541
-//         throw new HttpException("Hospital not found", 404)
542
-//     }
543
-
544
-//     const vendor = await VendorExperienceRepository.findById(id_vendor_experience);
545
-//     if (!vendor) {
546
-//         throw new HttpException("Vendor experience not found", 404);
547
-//     }
548
-
549
-//     const data = await VendorExperienceRepository.update(id_vendor_experience, {
550
-//         deletedAt: timeLocal.now().toDate()
551
-//     });
552
-
553
-//     await deleteLog(req, data);
554
-// };
322
+};

+ 41 - 42
src/services/admin/VendorService.ts

@@ -8,7 +8,7 @@ import { Prisma } from '@prisma/client';
8 8
 import { VendorRequestDTO } from '../../types/admin/vendor/VendorDTO';
9 9
 import { CustomRequest } from '../../types/token/CustomRequest';
10 10
 import * as XLSX from "xlsx";
11
-import { storeCategoryLinkService, updateCategoryLinkService } from './CategoryLinkService';
11
+// import { storeCategoryLinkService, updateCategoryLinkService } from './CategoryLinkService';
12 12
 import { validateStoreVendorRequest } from '../../validators/admin/vendor/VendorValidators';
13 13
 
14 14
 interface PaginationParams {
@@ -79,23 +79,23 @@ export const storeVendorService = async (validateData: VendorRequestDTO, req: Cu
79 79
     const data = await VendorRepository.create(payload);
80 80
     await createLog(req, data);
81 81
     // Setelah data berhasil disimpan
82
-    if (validateData.strengths?.tags?.length) {
83
-        await storeCategoryLinkService(
84
-            validateData.strengths.tags,
85
-            'vendor_strength_notes',
86
-            data.id,
87
-            req
88
-        );
89
-    }
90
-
91
-    if (validateData.weaknesses?.tags?.length) {
92
-        await storeCategoryLinkService(
93
-            validateData.weaknesses.tags,
94
-            'vendor_weaknesses_notes',
95
-            data.id,
96
-            req
97
-        );
98
-    }
82
+    // if (validateData.strengths?.tags?.length) {
83
+    //     await storeCategoryLinkService(
84
+    //         validateData.strengths.tags,
85
+    //         'vendor_strength_notes',
86
+    //         data.id,
87
+    //         req
88
+    //     );
89
+    // }
90
+
91
+    // if (validateData.weaknesses?.tags?.length) {
92
+    //     await storeCategoryLinkService(
93
+    //         validateData.weaknesses.tags,
94
+    //         'vendor_weaknesses_notes',
95
+    //         data.id,
96
+    //         req
97
+    //     );
98
+    // }
99 99
     await createLog(req, data);
100 100
 };
101 101
 
@@ -129,24 +129,23 @@ export const updateVendorService = async (validateData: Partial<VendorRequestDTO
129 129
     const data = await VendorRepository.update(id_vendor, payload);
130 130
     await updateLog(req, data);
131 131
 
132
-
133
-    if (validateData.strengths?.tags?.length) {
134
-        await updateCategoryLinkService(
135
-            validateData.strengths.tags,
136
-            'vendor_strength_notes',
137
-            id_vendor,
138
-            req
139
-        );
140
-    }
141
-
142
-    if (validateData.weaknesses?.tags?.length) {
143
-        await updateCategoryLinkService(
144
-            validateData.weaknesses.tags,
145
-            'vendor_weaknesses_notes',
146
-            id_vendor,
147
-            req
148
-        );
149
-    }
132
+    // if (validateData.strengths?.tags?.length) {
133
+    //     await updateCategoryLinkService(
134
+    //         validateData.strengths.tags,
135
+    //         'vendor_strength_notes',
136
+    //         id_vendor,
137
+    //         req
138
+    //     );
139
+    // }
140
+
141
+    // if (validateData.weaknesses?.tags?.length) {
142
+    //     await updateCategoryLinkService(
143
+    //         validateData.weaknesses.tags,
144
+    //         'vendor_weaknesses_notes',
145
+    //         id_vendor,
146
+    //         req
147
+    //     );
148
+    // }
150 149
 };
151 150
 
152 151
 export const deleteVendorService = async (id: string, req: CustomRequest) => {
@@ -188,12 +187,12 @@ export const importVendorService = async (file: Express.Multer.File, req: Custom
188 187
         const data = await VendorRepository.create(payload);
189 188
 
190 189
         // category links
191
-        if (validatedData.strengths?.tags?.length) {
192
-            await storeCategoryLinkService(validatedData.strengths.tags, "vendor_strength_notes", data.id, req);
193
-        }
194
-        if (validatedData.weaknesses?.tags?.length) {
195
-            await storeCategoryLinkService(validatedData.weaknesses.tags, "vendor_weaknesses_notes", data.id, req);
196
-        }
190
+        // if (validatedData.strengths?.tags?.length) {
191
+        //     await storeCategoryLinkService(validatedData.strengths.tags, "vendor_strength_notes", data.id, req);
192
+        // }
193
+        // if (validatedData.weaknesses?.tags?.length) {
194
+        //     await storeCategoryLinkService(validatedData.weaknesses.tags, "vendor_weaknesses_notes", data.id, req);
195
+        // }
197 196
 
198 197
         await createLog(req, data);
199 198
     }

+ 17 - 17
src/services/sales/HospitalService.ts

@@ -11,7 +11,7 @@ import { HospitalRequestDTO } from '../../types/sales/hospital/HospitalDTO';
11 11
 import path from 'path';
12 12
 import fs from 'fs/promises';
13 13
 import sharp from 'sharp';
14
-import { storeCategoryLinkService, updateCategoryLinkService } from '../admin/CategoryLinkService';
14
+// import { storeCategoryLinkService, updateCategoryLinkService } from '../admin/CategoryLinkService';
15 15
 
16 16
 const prisma = new PrismaClient();
17 17
 
@@ -150,14 +150,14 @@ export const storeHospitalService = async (validateData: HospitalRequestDTO, req
150 150
     };
151 151
 
152 152
     const data = await salesHospitalRepository.create(payload);
153
-    if (validateData.tags?.length) {
154
-        await storeCategoryLinkService(
155
-            validateData.tags,
156
-            'hospital_notes',
157
-            data.id,
158
-            req
159
-        );
160
-    }
153
+    // if (validateData.tags?.length) {
154
+    //     await storeCategoryLinkService(
155
+    //         validateData.tags,
156
+    //         'hospital_notes',
157
+    //         data.id,
158
+    //         req
159
+    //     );
160
+    // }
161 161
     await createLog(req, data);
162 162
 };
163 163
 
@@ -295,14 +295,14 @@ export const updateHospitalService = async (validateData: Partial<HospitalReques
295 295
     };
296 296
 
297 297
     const data = await salesHospitalRepository.update(id, payload);
298
-    if (validateData.tags?.length) {
299
-        await updateCategoryLinkService(
300
-            validateData.tags,
301
-            'hospital_notes',
302
-            id,
303
-            req
304
-        );
305
-    }
298
+    // if (validateData.tags?.length) {
299
+    //     await updateCategoryLinkService(
300
+    //         validateData.tags,
301
+    //         'hospital_notes',
302
+    //         id,
303
+    //         req
304
+    //     );
305
+    // }
306 306
     await updateLog(req, data);
307 307
 };
308 308
 

+ 9 - 9
src/services/sales/StatusHistoryService.ts

@@ -4,7 +4,7 @@ import { createLog } from '../../utils/LogActivity';
4 4
 import StatusHistoryRepository from '../../repository/sales/StatusHistoryRepository';
5 5
 import { CustomRequest } from '../../types/token/CustomRequest';
6 6
 import { StatusHistoryRequestDTO } from '../../types/sales/status_history/StatusHistoryDTO';
7
-import { storeCategoryLinkService } from '../admin/CategoryLinkService';
7
+// import { storeCategoryLinkService } from '../admin/CategoryLinkService';
8 8
 
9 9
 const prisma = new PrismaClient();
10 10
 
@@ -126,14 +126,14 @@ export const storeStatusHistoryService = async (validateData: StatusHistoryReque
126 126
         data: { progress_status: validateData.new_status as ProgressStatus },
127 127
     });
128 128
 
129
-    if (validateData.note?.tags?.length) {
130
-        await storeCategoryLinkService(
131
-            validateData.note.tags,
132
-            'status_history_notes',
133
-            data.id,
134
-            req
135
-        );
136
-    }
129
+    // if (validateData.note?.tags?.length) {
130
+    //     await storeCategoryLinkService(
131
+    //         validateData.note.tags,
132
+    //         'status_history_notes',
133
+    //         data.id,
134
+    //         req
135
+    //     );
136
+    // }
137 137
 
138 138
     await createLog(req, data);
139 139
 };

+ 211 - 168
src/services/sales/VendorExperienceService.ts

@@ -5,7 +5,8 @@ import { createLog, updateLog, deleteLog } from '../../utils/LogActivity';
5 5
 import VendorExperienceRepository from '../../repository/sales/VendorExperienceRepository';
6 6
 import { CustomRequest } from '../../types/token/CustomRequest';
7 7
 import { VendorExperienceRequestDTO } from '../../types/sales/vendor_experience/VendorExperienceDTO';
8
-import { storeCategoryLinkService, updateCategoryLinkService } from '../admin/CategoryLinkService';
8
+import { Prisma } from '@prisma/client';
9
+// import { storeCategoryLinkService, updateCategoryLinkService } from '../admin/CategoryLinkService';
9 10
 
10 11
 interface PaginationParams {
11 12
     page: number;
@@ -13,10 +14,19 @@ interface PaginationParams {
13 14
     search?: string;
14 15
     sortBy: string;
15 16
     orderBy: 'asc' | 'desc';
17
+    category_id: string;
16 18
 }
17 19
 
18
-export const getAllVendorExperienceService = async ({ page, limit, search, sortBy, orderBy }: PaginationParams, req: CustomRequest) => {
20
+export const getAllVendorExperienceService = async ({ page, limit, search, sortBy, orderBy, category_id }: PaginationParams, req: CustomRequest) => {
19 21
     const skip = (page - 1) * limit;
22
+
23
+    const where: Prisma.VendorExperienceWhereInput = {
24
+        hospital_id: req.params.id,
25
+        // ...SearchFilter(search, ['id', 'name', 'province.id']),
26
+        ...(category_id ? { category_id: category_id } : {}),
27
+        deletedAt: null,
28
+    };
29
+
20 30
     const hospitalId = req.params.id;
21 31
 
22 32
     const hospital = await prisma.hospital.findFirst({ where: { id: hospitalId } });
@@ -38,10 +48,10 @@ export const getAllVendorExperienceService = async ({ page, limit, search, sortB
38 48
         throw new HttpException('You are not authorized to access this hospital', 403);
39 49
     }
40 50
 
41
-    const where: any = {
42
-        hospital_id: req.params.id,
43
-        deletedAt: null
44
-    };
51
+    // const where: any = {
52
+    //     hospital_id: req.params.id,
53
+    //     deletedAt: null
54
+    // };
45 55
 
46 56
     const [vendor_experiences, total] = await Promise.all([
47 57
         VendorExperienceRepository.findAll({ skip, take: limit, where, orderBy: { [sortBy]: orderBy } }),
@@ -82,6 +92,7 @@ export const showVendorExperienceService = async (req: CustomRequest) => {
82 92
 
83 93
 export const storeVendorExperienceService = async (validateData: VendorExperienceRequestDTO, req: CustomRequest) => {
84 94
     const hospitalId = req.params.id;
95
+    const userId = req.tokenData.sub;
85 96
 
86 97
     const hospital = await prisma.hospital.findFirst({ where: { id: hospitalId } });
87 98
     if (!hospital) throw new HttpException('Hospital not found', 404);
@@ -107,47 +118,52 @@ export const storeVendorExperienceService = async (validateData: VendorExperienc
107 118
         if (!vendor) throw new HttpException('Vendor not found', 404);
108 119
     }
109 120
 
110
-    const SimrsType = ['vendor', 'in house', 'gratis'];
111
-    if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
112
-        throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
121
+    if (validateData.category_id) {
122
+        const category = await prisma.category.findFirst({ where: { id: validateData.category_id } });
123
+        if (!category) throw new HttpException('Category not found', 404);
113 124
     }
114 125
 
115
-    if (validateData.contract_start_date && validateData.contract_expired_date) {
116
-        if (validateData.contract_start_date >= validateData.contract_expired_date) {
117
-            throw new HttpException('Contract expired date must be after contract date', 400);
118
-        }
119
-    }
120
-
121
-    if (validateData.contract_value_min && validateData.contract_value_max) {
122
-        if (validateData.contract_value_min >= validateData.contract_value_max) {
123
-            throw new HttpException('Contract value max must be after contract value min', 400);
124
-        }
125
-    }
126
-
127
-    if (validateData.simrs_type) {
128
-        const existingActiveVendors = await prisma.vendorExperience.findMany({
129
-            where: {
130
-                hospital_id: hospitalId,
131
-                status: 'active',
132
-                deletedAt: null
133
-            }
134
-        });
135
-
136
-        if (existingActiveVendors.length > 0) {
137
-            await prisma.vendorExperience.updateMany({
138
-                where: {
139
-                    hospital_id: hospitalId,
140
-                    status: 'active',
141
-                    deletedAt: null
142
-                },
143
-                data: {
144
-                    status: 'inactive'
145
-                }
146
-            });
147
-        }
148
-
149
-        validateData.status = 'active';
150
-    }
126
+    // const SimrsType = ['vendor', 'in house', 'gratis'];
127
+    // if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
128
+    //     throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
129
+    // }
130
+
131
+    // if (validateData.contract_start_date && validateData.contract_expired_date) {
132
+    //     if (validateData.contract_start_date >= validateData.contract_expired_date) {
133
+    //         throw new HttpException('Contract expired date must be after contract date', 400);
134
+    //     }
135
+    // }
136
+
137
+    // if (validateData.contract_value_min && validateData.contract_value_max) {
138
+    //     if (validateData.contract_value_min >= validateData.contract_value_max) {
139
+    //         throw new HttpException('Contract value max must be after contract value min', 400);
140
+    //     }
141
+    // }
142
+
143
+    // if (validateData.simrs_type) {
144
+    //     const existingActiveVendors = await prisma.vendorExperience.findMany({
145
+    //         where: {
146
+    //             hospital_id: hospitalId,
147
+    //             status: 'active',
148
+    //             deletedAt: null
149
+    //         }
150
+    //     });
151
+
152
+    //     if (existingActiveVendors.length > 0) {
153
+    //         await prisma.vendorExperience.updateMany({
154
+    //             where: {
155
+    //                 hospital_id: hospitalId,
156
+    //                 status: 'active',
157
+    //                 deletedAt: null
158
+    //             },
159
+    //             data: {
160
+    //                 status: 'inactive'
161
+    //             }
162
+    //         });
163
+    //     }
164
+
165
+    //     validateData.status = 'active';
166
+    // }
151 167
 
152 168
     const payload = {
153 169
         ...(validateData.vendor_id && {
@@ -155,44 +171,53 @@ export const storeVendorExperienceService = async (validateData: VendorExperienc
155 171
                 connect: { id: validateData.vendor_id }
156 172
             }
157 173
         }),
158
-        simrs_type: validateData.simrs_type,
159
-        status: validateData.status,
160
-        contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : null,
161
-        contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : null,
162
-        contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : null,
163
-        contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : null,
164
-        positive_notes: validateData.positive_notes?.note,
165
-        negative_notes: validateData.negative_notes?.note,
174
+        ...(validateData.category_id && {
175
+            category: {
176
+                connect: { id: validateData.category_id }
177
+            }
178
+        }),
179
+        content: validateData.content,
180
+        // status: validateData.status,
181
+        // contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : null,
182
+        // contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : null,
183
+        // contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : null,
184
+        // contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : null,
185
+        // positive_notes: validateData.positive_notes?.note,
186
+        // negative_notes: validateData.negative_notes?.note,
166 187
         hospital: {
167 188
             connect: { id: hospitalId }
168 189
         },
190
+        user: {
191
+            connect: { id: userId }
192
+        },
169 193
     };
170 194
 
171 195
     const data = await VendorExperienceRepository.create(payload);
172 196
 
173
-    if (validateData.positive_notes?.tags?.length) {
174
-        await storeCategoryLinkService(
175
-            validateData.positive_notes.tags,
176
-            'vendor_experience_positive_notes',
177
-            data.id,
178
-            req
179
-        );
180
-    }
181
-
182
-    if (validateData.negative_notes?.tags?.length) {
183
-        await storeCategoryLinkService(
184
-            validateData.negative_notes.tags,
185
-            'vendor_experience_negative_notes',
186
-            data.id,
187
-            req
188
-        );
189
-    }
197
+    // if (validateData.positive_notes?.tags?.length) {
198
+    //     await storeCategoryLinkService(
199
+    //         validateData.positive_notes.tags,
200
+    //         'vendor_experience_positive_notes',
201
+    //         data.id,
202
+    //         req
203
+    //     );
204
+    // }
205
+
206
+    // if (validateData.negative_notes?.tags?.length) {
207
+    //     await storeCategoryLinkService(
208
+    //         validateData.negative_notes.tags,
209
+    //         'vendor_experience_negative_notes',
210
+    //         data.id,
211
+    //         req
212
+    //     );
213
+    // }
190 214
 
191 215
     await createLog(req, data);
192 216
 };
193 217
 
194 218
 export const updateVendorExperienceService = async (validateData: Partial<VendorExperienceRequestDTO>, req: CustomRequest) => {
195 219
     const id_hospital = req.params.id;
220
+    const id_user = req.tokenData.sub;
196 221
     const id_vendor_experience = req.params.id_vendor_experience;
197 222
 
198 223
     const hospital = await prisma.hospital.findFirst({ where: { id: id_hospital } });
@@ -222,115 +247,133 @@ export const updateVendorExperienceService = async (validateData: Partial<Vendor
222 247
         if (!existVendor) throw new HttpException('Vendor not found', 404);
223 248
     }
224 249
 
225
-    const SimrsType = ['vendor', 'in house', 'gratis'];
226
-    if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
227
-        throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
228
-    }
229
-
230
-    if (
231
-        validateData.simrs_type &&
232
-        vendorHistory.simrs_type === 'vendor' &&
233
-        vendorHistory.vendor_id !== null &&
234
-        validateData.simrs_type !== 'vendor'
235
-    ) {
236
-        await prisma.vendorExperience.update({
237
-            where: {
238
-                id: id_vendor_experience,
239
-                deletedAt: null
240
-            },
241
-            data: {
242
-                vendor_id: null
243
-            }
244
-        });
250
+    if (validateData.category_id) {
251
+        const existCategory = await prisma.category.findFirst({ where: { id: validateData.category_id } });
252
+        if (!existCategory) throw new HttpException('Category not found', 404);
245 253
     }
246 254
 
247
-    if (
248
-        validateData.contract_value_min &&
249
-        validateData.contract_value_min >= vendorHistory.contract_value_max!
250
-    ) {
251
-        throw new HttpException('Contract value min must be less than contract value max.', 400);
252
-    }
253
-
254
-    if (
255
-        validateData.contract_value_max &&
256
-        validateData.contract_value_max <= vendorHistory.contract_value_min!
257
-    ) {
258
-        throw new HttpException('Contract value max must be greater than contract value min.', 400);
259
-    }
260
-
261
-    if (
262
-        validateData.contract_start_date &&
263
-        validateData.contract_start_date >= vendorHistory.contract_expired_date!
264
-    ) {
265
-        throw new HttpException('Contract start date must be before contract expired date.', 400);
266
-    }
267
-
268
-    if (
269
-        validateData.contract_expired_date &&
270
-        validateData.contract_expired_date <= vendorHistory.contract_start_date!
271
-    ) {
272
-        throw new HttpException('Contract expired date must be after contract start date.', 400);
273
-    }
274
-
275
-    if (validateData.contract_start_date && validateData.contract_expired_date) {
276
-        if (validateData.contract_start_date >= validateData.contract_expired_date) {
277
-            throw new HttpException('Contract expired date must be after contract date', 400);
278
-        }
279
-    }
280
-
281
-    if (validateData.contract_value_min && validateData.contract_value_max) {
282
-        if (validateData.contract_value_min >= validateData.contract_value_max) {
283
-            throw new HttpException('Contract value max must be after contract value min', 400);
284
-        }
285
-    }
286
-
287
-    if (validateData.status === 'active') {
288
-        await prisma.vendorExperience.updateMany({
289
-            where: {
290
-                hospital_id: id_hospital,
291
-                status: 'active',
292
-                deletedAt: null,
293
-                NOT: { id: id_vendor_experience }
294
-            },
295
-            data: {
296
-                status: 'inactive'
297
-            }
298
-        });
299
-    }
255
+    // const SimrsType = ['vendor', 'in house', 'gratis'];
256
+    // if (validateData.simrs_type && !SimrsType.includes(validateData.simrs_type)) {
257
+    //     throw new HttpException('Simrs type must be vendor, in house, or gratis', 400);
258
+    // }
259
+
260
+    // if (
261
+    //     validateData.simrs_type &&
262
+    //     vendorHistory.simrs_type === 'vendor' &&
263
+    //     vendorHistory.vendor_id !== null &&
264
+    //     validateData.simrs_type !== 'vendor'
265
+    // ) {
266
+    //     await prisma.vendorExperience.update({
267
+    //         where: {
268
+    //             id: id_vendor_experience,
269
+    //             deletedAt: null
270
+    //         },
271
+    //         data: {
272
+    //             vendor_id: null
273
+    //         }
274
+    //     });
275
+    // }
276
+
277
+    // if (
278
+    //     validateData.contract_value_min &&
279
+    //     validateData.contract_value_min >= vendorHistory.contract_value_max!
280
+    // ) {
281
+    //     throw new HttpException('Contract value min must be less than contract value max.', 400);
282
+    // }
283
+
284
+    // if (
285
+    //     validateData.contract_value_max &&
286
+    //     validateData.contract_value_max <= vendorHistory.contract_value_min!
287
+    // ) {
288
+    //     throw new HttpException('Contract value max must be greater than contract value min.', 400);
289
+    // }
290
+
291
+    // if (
292
+    //     validateData.contract_start_date &&
293
+    //     validateData.contract_start_date >= vendorHistory.contract_expired_date!
294
+    // ) {
295
+    //     throw new HttpException('Contract start date must be before contract expired date.', 400);
296
+    // }
297
+
298
+    // if (
299
+    //     validateData.contract_expired_date &&
300
+    //     validateData.contract_expired_date <= vendorHistory.contract_start_date!
301
+    // ) {
302
+    //     throw new HttpException('Contract expired date must be after contract start date.', 400);
303
+    // }
304
+
305
+    // if (validateData.contract_start_date && validateData.contract_expired_date) {
306
+    //     if (validateData.contract_start_date >= validateData.contract_expired_date) {
307
+    //         throw new HttpException('Contract expired date must be after contract date', 400);
308
+    //     }
309
+    // }
310
+
311
+    // if (validateData.contract_value_min && validateData.contract_value_max) {
312
+    //     if (validateData.contract_value_min >= validateData.contract_value_max) {
313
+    //         throw new HttpException('Contract value max must be after contract value min', 400);
314
+    //     }
315
+    // }
316
+
317
+    // if (validateData.status === 'active') {
318
+    //     await prisma.vendorExperience.updateMany({
319
+    //         where: {
320
+    //             hospital_id: id_hospital,
321
+    //             status: 'active',
322
+    //             deletedAt: null,
323
+    //             NOT: { id: id_vendor_experience }
324
+    //         },
325
+    //         data: {
326
+    //             status: 'inactive'
327
+    //         }
328
+    //     });
329
+    // }
300 330
 
301 331
     const payload = {
302
-        status: validateData.status,
303
-        contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : vendorHistory.contract_start_date,
304
-        contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : vendorHistory.contract_expired_date,
305
-        contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : vendorHistory.contract_value_min,
306
-        contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : vendorHistory.contract_value_max,
307
-        positive_notes: validateData.positive_notes?.note,
308
-        negative_notes: validateData.negative_notes?.note,
309
-        simrs_type: validateData.simrs_type,
310
-        vendor_id: validateData.vendor_id
332
+        // status: validateData.status,
333
+        // contract_start_date: validateData.contract_start_date ? new Date(validateData.contract_start_date) : vendorHistory.contract_start_date,
334
+        // contract_expired_date: validateData.contract_expired_date ? new Date(validateData.contract_expired_date) : vendorHistory.contract_expired_date,
335
+        // contract_value_min: validateData.contract_value_min ? Number(validateData.contract_value_min) : vendorHistory.contract_value_min,
336
+        // contract_value_max: validateData.contract_value_max ? Number(validateData.contract_value_max) : vendorHistory.contract_value_max,
337
+        // positive_notes: validateData.positive_notes?.note,
338
+        // negative_notes: validateData.negative_notes?.note,
339
+        // simrs_type: validateData.simrs_type,
340
+        content: validateData.content,
341
+        ...(validateData.vendor_id && {
342
+            vendor: {
343
+                connect: { id: validateData.vendor_id }
344
+            }
345
+        }),
346
+        ...(validateData.category_id && {
347
+            category: {
348
+                connect: { id: validateData.category_id }
349
+            }
350
+        }),
351
+        user: {
352
+            connect: { id: id_user }
353
+        }
311 354
     };
312 355
 
313 356
     const data = await VendorExperienceRepository.update(id_vendor_experience, payload);
314 357
 
315 358
     // Positive Notes Tags
316
-    if (validateData.positive_notes?.tags?.length) {
317
-        await updateCategoryLinkService(
318
-            validateData.positive_notes.tags,
319
-            'vendor_experience_positive_notes',
320
-            id_vendor_experience,
321
-            req
322
-        );
323
-    }
359
+    // if (validateData.positive_notes?.tags?.length) {
360
+    //     await updateCategoryLinkService(
361
+    //         validateData.positive_notes.tags,
362
+    //         'vendor_experience_positive_notes',
363
+    //         id_vendor_experience,
364
+    //         req
365
+    //     );
366
+    // }
324 367
 
325 368
     // Negative Notes Tags
326
-    if (validateData.negative_notes?.tags?.length) {
327
-        await updateCategoryLinkService(
328
-            validateData.negative_notes.tags,
329
-            'vendor_experience_negative_notes',
330
-            id_vendor_experience,
331
-            req
332
-        );
333
-    }
369
+    // if (validateData.negative_notes?.tags?.length) {
370
+    //     await updateCategoryLinkService(
371
+    //         validateData.negative_notes.tags,
372
+    //         'vendor_experience_negative_notes',
373
+    //         id_vendor_experience,
374
+    //         req
375
+    //     );
376
+    // }
334 377
 
335 378
     await updateLog(req, data);
336 379
 };

+ 4 - 4
src/types/admin/category/CategoryDTO.ts

@@ -1,19 +1,19 @@
1 1
 export interface CategoryRequestDTO {
2
-    tag: string;
2
+    name: string;
3 3
     description?: string | null;
4 4
 }
5 5
 
6 6
 export interface CategoryDTO {
7 7
     id: string;
8
-    tag: string;
8
+    name: string;
9 9
     description?: string | null;
10
-    count_use_tags?: number | null;
10
+    count_use_category?: number | null;
11 11
     createdAt: Date;
12 12
     updatedAt: Date;
13 13
 }
14 14
 
15 15
 export interface MergeCategoryRequestDTO {
16 16
     category_id: string[];
17
-    tag: string;
17
+    name: string;
18 18
     description?: string | null;
19 19
 }

+ 16 - 4
src/types/admin/schedule_visitation/ScheduleVisitationDTO.ts

@@ -61,10 +61,22 @@ export type ShowScheduleVisitationDTO = {
61 61
 
62 62
         vendor_experiences: {
63 63
             id: string;
64
-            vendor: { id: string; name: string } | null;
65
-            contract_start_date: Date | null;
66
-            contract_expired_date: Date | null;
67
-            simrs_type: string;
64
+            vendor: {
65
+                id: string;
66
+                name: string;
67
+            } | null;
68
+            category: {
69
+                id: string;
70
+                name: string;
71
+            } | null;
72
+            content: string | null;
73
+            user: {
74
+                id: string;
75
+                fullname: string;
76
+            }
77
+            // contract_start_date: Date | null;
78
+            // contract_expired_date: Date | null;
79
+            // simrs_type: string;
68 80
         }[];
69 81
 
70 82
         executives_histories: {

+ 43 - 28
src/types/admin/vendor_experience/VendorExperienceDTO.ts

@@ -1,36 +1,27 @@
1 1
 export interface VendorExperienceRequestDTO {
2
-    simrs_type: string;
3
-    vendor_id: string | null;
4
-    status?: string;
5
-    contract_start_date?: Date | null;
6
-    contract_expired_date?: Date | null;
7
-    contract_value_min?: number | null;
8
-    contract_value_max?: number | null;
9
-    positive_notes?: {
10
-        note: string;
11
-        tags: string[];
12
-    };
13
-    negative_notes?: {
14
-        note: string;
15
-        tags: string[];
16
-    };
2
+    // simrs_type: string;
3
+    vendor_id?: string | null;
4
+    category_id?: string | null;
5
+    content?: string | null;
6
+    // user_id: string;
7
+    // status?: string;
8
+    // contract_start_date?: Date | null;
9
+    // contract_expired_date?: Date | null;
10
+    // contract_value_min?: number | null;
11
+    // contract_value_max?: number | null;
12
+    // positive_notes?: {
13
+    //     note: string;
14
+    //     tags: string[];
15
+    // };
16
+    // negative_notes?: {
17
+    //     note: string;
18
+    //     tags: string[];
19
+    // };
17 20
 }
18 21
 
19 22
 export interface VendorExperienceDTO {
20 23
     id: string;
21
-    contract_start_date: Date | null;
22
-    contract_expired_date: Date | null;
23
-    contract_value_min: bigint | null;
24
-    contract_value_max: bigint | null;
25
-    positive_notes: string | null;
26
-    negative_notes: string | null;
27
-    positive_notes_tags?: string[];
28
-    negative_notes_tags?: string[];
29
-    status: string | null;
30
-    simrs_type: string;
31
-    createdAt: Date;
32
-    updatedAt: Date;
33
-    vendor_id?: string | null;
24
+    content: string | null;
34 25
     vendor: {
35 26
         id: string;
36 27
         name: string;
@@ -40,4 +31,28 @@ export interface VendorExperienceDTO {
40 31
         website: string | null;
41 32
         created_by: string;
42 33
     } | null;
34
+    category: {
35
+        id: string;
36
+        name: string;
37
+        description: string | null;
38
+    } | null;
39
+    user: {
40
+        id: string;
41
+        fullname: string;
42
+    };
43
+    createdAt: Date;
44
+    updatedAt: Date;
45
+    // contract_start_date: Date | null;
46
+    // contract_expired_date: Date | null;
47
+    // contract_value_min: bigint | null;
48
+    // contract_value_max: bigint | null;
49
+    // positive_notes: string | null;
50
+    // negative_notes: string | null;
51
+    // positive_notes_tags?: string[];
52
+    // negative_notes_tags?: string[];
53
+    // status: string | null;
54
+    // simrs_type: string;
55
+    // vendor_id?: string | null;
56
+    // category_id?: string | null;
57
+    // user_id: string
43 58
 }

+ 16 - 4
src/types/sales/schedule_visitation/ScheduleVisitationDTO.ts

@@ -61,10 +61,22 @@ export type ShowScheduleVisitationDTO = {
61 61
 
62 62
         vendor_experiences: {
63 63
             id: string;
64
-            vendor: { id: string; name: string } | null;
65
-            contract_start_date: Date | null;
66
-            contract_expired_date: Date | null;
67
-            simrs_type: string;
64
+            vendor: {
65
+                id: string;
66
+                name: string;
67
+            } | null;
68
+            category: {
69
+                id: string;
70
+                name: string;
71
+            } | null;
72
+            content: string | null;
73
+            user: {
74
+                id: string;
75
+                fullname: string;
76
+            }
77
+            // contract_start_date: Date | null;
78
+            // contract_expired_date: Date | null;
79
+            // simrs_type: string;
68 80
         }[];
69 81
 
70 82
         executives_histories: {

+ 40 - 28
src/types/sales/vendor_experience/VendorExperienceDTO.ts

@@ -1,36 +1,27 @@
1 1
 export interface VendorExperienceRequestDTO {
2
-    simrs_type: string;
3
-    vendor_id: string | null;
4
-    status?: string;
5
-    contract_start_date?: Date | null;
6
-    contract_expired_date?: Date | null;
7
-    contract_value_min?: number | null;
8
-    contract_value_max?: number | null;
9
-    positive_notes?: {
10
-        note: string;
11
-        tags: string[];
12
-    };
13
-    negative_notes?: {
14
-        note: string;
15
-        tags: string[];
16
-    };
2
+    vendor_id?: string | null;
3
+    category_id?: string | null;
4
+    // user_id: string;
5
+    content?: string | null;
6
+    // simrs_type: string;
7
+    // status?: string;
8
+    // contract_start_date?: Date | null;
9
+    // contract_expired_date?: Date | null;
10
+    // contract_value_min?: number | null;
11
+    // contract_value_max?: number | null;
12
+    // positive_notes?: {
13
+    //     note: string;
14
+    //     tags: string[];
15
+    // };
16
+    // negative_notes?: {
17
+    //     note: string;
18
+    //     tags: string[];
19
+    // };
17 20
 }
18 21
 
19 22
 export interface VendorExperienceDTO {
20 23
     id: string;
21
-    contract_start_date: Date | null;
22
-    contract_expired_date: Date | null;
23
-    contract_value_min: bigint | null;
24
-    contract_value_max: bigint | null;
25
-    positive_notes: string | null;
26
-    negative_notes: string | null;
27
-    positive_notes_tags?: string[];
28
-    negative_notes_tags?: string[];
29
-    status: string | null;
30
-    simrs_type: string;
31
-    createdAt: Date;
32
-    updatedAt: Date;
33
-    vendor_id?: string | null;
24
+    content: string | null;
34 25
     vendor: {
35 26
         id: string;
36 27
         name: string;
@@ -40,4 +31,25 @@ export interface VendorExperienceDTO {
40 31
         website: string | null;
41 32
         created_by: string;
42 33
     } | null;
34
+    category: {
35
+        id: string;
36
+        name: string;
37
+        description: string | null;
38
+    } | null;
39
+    user: {
40
+        id: string;
41
+        fullname: string;
42
+    };
43
+    createdAt: Date;
44
+    updatedAt: Date;
45
+    // simrs_type: string;
46
+    // contract_start_date: Date | null;
47
+    // contract_expired_date: Date | null;
48
+    // contract_value_min: bigint | null;
49
+    // contract_value_max: bigint | null;
50
+    // positive_notes: string | null;
51
+    // negative_notes: string | null;
52
+    // positive_notes_tags?: string[];
53
+    // negative_notes_tags?: string[];
54
+    // status: string | null;
43 55
 }

+ 25 - 25
src/validators/admin/category/CategoryValidators.ts

@@ -3,38 +3,38 @@ import { validateWithSchema } from '../../ValidateSchema';
3 3
 import { CategoryRequestDTO, MergeCategoryRequestDTO } from '../../../types/admin/category/CategoryDTO';
4 4
 
5 5
 const storeCategorySchema = Joi.object<CategoryRequestDTO>({
6
-    tag: Joi.string().trim().required().messages({
7
-        'string.empty': 'Tag is required',
6
+    name: Joi.string().trim().required().messages({
7
+        'string.empty': 'Name is required',
8 8
     }),
9 9
     description: Joi.string().trim().optional().allow(''),
10 10
 });
11 11
 
12 12
 const updateCategorySchema = Joi.object<Partial<CategoryRequestDTO>>({
13
-    tag: Joi.string().trim().optional().messages({
14
-        'string.empty': 'Tag is required',
13
+    name: Joi.string().trim().optional().messages({
14
+        'string.empty': 'Name is required',
15 15
     }),
16 16
     description: Joi.string().trim().optional().allow(''),
17 17
 });
18 18
 
19
-const mergeCategorySchema = Joi.object<MergeCategoryRequestDTO>({
20
-    category_id: Joi.array()
21
-        .items(Joi.string().trim().min(2))
22
-        .min(1)
23
-        .required()
24
-        .messages({
25
-            'any.required': 'Category ID is required',
26
-            'array.base': 'Category ID must be an array of strings',
27
-            'array.min': 'At least one category ID is required',
28
-            'string.empty': 'Each Category ID must not be empty',
29
-            'string.min': 'Each Category ID must not be empty',
30
-        }),
19
+// const mergeCategorySchema = Joi.object<MergeCategoryRequestDTO>({
20
+//     category_id: Joi.array()
21
+//         .items(Joi.string().trim().min(2))
22
+//         .min(1)
23
+//         .required()
24
+//         .messages({
25
+//             'any.required': 'Category ID is required',
26
+//             'array.base': 'Category ID must be an array of strings',
27
+//             'array.min': 'At least one category ID is required',
28
+//             'string.empty': 'Each Category ID must not be empty',
29
+//             'string.min': 'Each Category ID must not be empty',
30
+//         }),
31 31
 
32
-    tag: Joi.string().trim().required().messages({
33
-        'string.empty': 'Tag is required',
34
-        'any.required': 'Tag is required',
35
-    }),
36
-    description: Joi.string().trim().optional().allow(''),
37
-});
32
+//     name: Joi.string().trim().required().messages({
33
+//         'string.empty': 'Name is required',
34
+//         'any.required': 'Name is required',
35
+//     }),
36
+//     description: Joi.string().trim().optional().allow(''),
37
+// });
38 38
 
39 39
 export const validateCategoryStoreRequest = (body: unknown): CategoryRequestDTO => {
40 40
     return validateWithSchema<CategoryRequestDTO>(storeCategorySchema, body);
@@ -44,6 +44,6 @@ export const validateCategoryUpdateRequest = (body: unknown): CategoryRequestDTO
44 44
     return validateWithSchema<CategoryRequestDTO>(updateCategorySchema, body);
45 45
 }
46 46
 
47
-export const validateMergeCategoryStoreRequest = (body: unknown): MergeCategoryRequestDTO => {
48
-    return validateWithSchema<MergeCategoryRequestDTO>(mergeCategorySchema, body);
49
-};
47
+// export const validateMergeCategoryStoreRequest = (body: unknown): MergeCategoryRequestDTO => {
48
+//     return validateWithSchema<MergeCategoryRequestDTO>(mergeCategorySchema, body);
49
+// };

+ 38 - 34
src/validators/admin/vendor_experience/VendorExperienceValidators.ts

@@ -3,47 +3,51 @@ import { validateWithSchema } from '../../ValidateSchema';
3 3
 import { VendorExperienceRequestDTO } from '../../../types/admin/vendor_experience/VendorExperienceDTO';
4 4
 
5 5
 export const storeVendorExperienceSchema = Joi.object({
6
-    simrs_type: Joi.string().trim().required().messages({
7
-        'string.empty': 'Simrs type is required',
8
-        'string.base': 'Simrs type must be a string',
9
-    }),
10 6
     vendor_id: Joi.string().uuid().optional(),
11
-    status: Joi.string().trim().required().messages({
12
-        'string.empty': 'Status is required',
13
-        'string.base': 'Status must be a string',
14
-    }),
15
-    contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
16
-    contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
17
-    contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
18
-    contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
19
-    positive_notes: Joi.object({
20
-        note: Joi.string().allow('', null),
21
-        tags: Joi.array().items(Joi.string()).optional().default([]),
22
-    }).optional().allow(null),
7
+    category_id: Joi.string().uuid().optional(),
8
+    content: Joi.string().trim().allow('', null),
9
+    // simrs_type: Joi.string().trim().required().messages({
10
+    //     'string.empty': 'Simrs type is required',
11
+    //     'string.base': 'Simrs type must be a string',
12
+    // }),
13
+    // status: Joi.string().trim().required().messages({
14
+    //     'string.empty': 'Status is required',
15
+    //     'string.base': 'Status must be a string',
16
+    // }),
17
+    // contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
18
+    // contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
19
+    // contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
20
+    // contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
21
+    // positive_notes: Joi.object({
22
+    //     note: Joi.string().allow('', null),
23
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
24
+    // }).optional().allow(null),
23 25
 
24
-    negative_notes: Joi.object({
25
-        note: Joi.string().allow('', null),
26
-        tags: Joi.array().items(Joi.string()).optional().default([]),
27
-    }).optional().allow(null),
26
+    // negative_notes: Joi.object({
27
+    //     note: Joi.string().allow('', null),
28
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
29
+    // }).optional().allow(null),
28 30
 });
29 31
 
30 32
 export const updateVendorExperienceSchema = Joi.object({
31
-    simrs_type: Joi.string().trim().optional(),
32 33
     vendor_id: Joi.string().uuid().optional(),
33
-    status: Joi.string().trim().optional(),
34
-    contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
35
-    contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
36
-    contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
37
-    contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
38
-    positive_notes: Joi.object({
39
-        note: Joi.string().allow('', null),
40
-        tags: Joi.array().items(Joi.string()).optional().default([]),
41
-    }).optional().allow(null),
34
+    category_id: Joi.string().uuid().optional(),
35
+    content: Joi.string().trim().allow('', null),
36
+    // simrs_type: Joi.string().trim().optional(),
37
+    // status: Joi.string().trim().optional(),
38
+    // contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
39
+    // contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
40
+    // contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
41
+    // contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
42
+    // positive_notes: Joi.object({
43
+    //     note: Joi.string().allow('', null),
44
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
45
+    // }).optional().allow(null),
42 46
 
43
-    negative_notes: Joi.object({
44
-        note: Joi.string().allow('', null),
45
-        tags: Joi.array().items(Joi.string()).optional().default([]),
46
-    }).optional().allow(null),
47
+    // negative_notes: Joi.object({
48
+    //     note: Joi.string().allow('', null),
49
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
50
+    // }).optional().allow(null),
47 51
 });
48 52
 
49 53
 export const validateStoreVendorExperienceRequest = (body: unknown): VendorExperienceRequestDTO => {

+ 39 - 34
src/validators/sales/vendor_experience/VendorExperienceValidators.ts

@@ -3,47 +3,52 @@ import { validateWithSchema } from '../../ValidateSchema';
3 3
 import { VendorExperienceRequestDTO } from '../../../types/admin/vendor_experience/VendorExperienceDTO';
4 4
 
5 5
 export const storeVendorExperienceSchema = Joi.object({
6
-    simrs_type: Joi.string().trim().required().messages({
7
-        'string.empty': 'Simrs type is required',
8
-        'string.base': 'Simrs type must be a string',
9
-    }),
10 6
     vendor_id: Joi.string().uuid().optional(),
11
-    status: Joi.string().trim().required().messages({
12
-        'string.empty': 'Status is required',
13
-        'string.base': 'Status must be a string',
14
-    }),
15
-    contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
16
-    contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
17
-    contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
18
-    contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
19
-    positive_notes: Joi.object({
20
-        note: Joi.string().allow('', null),
21
-        tags: Joi.array().items(Joi.string()).optional().default([]),
22
-    }).optional().allow(null),
7
+    category_id: Joi.string().uuid().optional(),
8
+    content: Joi.string().trim().allow('', null),
9
+    // simrs_type: Joi.string().trim().required().messages({
10
+    //     'string.empty': 'Simrs type is required',
11
+    //     'string.base': 'Simrs type must be a string',
12
+    // }),
13
+    // status: Joi.string().trim().required().messages({
14
+    //     'string.empty': 'Status is required',
15
+    //     'string.base': 'Status must be a string',
16
+    // }),
17
+    // contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
18
+    // contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
19
+    // contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
20
+    // contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
21
+    // positive_notes: Joi.object({
22
+    //     note: Joi.string().allow('', null),
23
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
24
+    // }).optional().allow(null),
23 25
 
24
-    negative_notes: Joi.object({
25
-        note: Joi.string().allow('', null),
26
-        tags: Joi.array().items(Joi.string()).optional().default([]),
27
-    }).optional().allow(null),
26
+    // negative_notes: Joi.object({
27
+    //     note: Joi.string().allow('', null),
28
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
29
+    // }).optional().allow(null),
28 30
 });
29 31
 
30 32
 export const updateVendorExperienceSchema = Joi.object({
31
-    simrs_type: Joi.string().trim().optional(),
32 33
     vendor_id: Joi.string().uuid().optional(),
33
-    status: Joi.string().trim().optional(),
34
-    contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
35
-    contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
36
-    contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
37
-    contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
38
-    positive_notes: Joi.object({
39
-        note: Joi.string().allow('', null),
40
-        tags: Joi.array().items(Joi.string()).optional().default([]),
41
-    }).optional().allow(null),
34
+    category_id: Joi.string().uuid().optional(),
35
+    content: Joi.string().trim().allow('', null),
36
+    // simrs_type: Joi.string().trim().optional(),
37
+    // vendor_id: Joi.string().uuid().optional(),
38
+    // status: Joi.string().trim().optional(),
39
+    // contract_start_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract start date must be a valid date' }),
40
+    // contract_expired_date: Joi.date().optional().allow(null).messages({ 'date.format': 'Contract expired date must be a valid date' }),
41
+    // contract_value_min: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value min must be a number' }),
42
+    // contract_value_max: Joi.number().optional().allow(null).messages({ 'number.format': 'Contract value max must be a number' }),
43
+    // positive_notes: Joi.object({
44
+    //     note: Joi.string().allow('', null),
45
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
46
+    // }).optional().allow(null),
42 47
 
43
-    negative_notes: Joi.object({
44
-        note: Joi.string().allow('', null),
45
-        tags: Joi.array().items(Joi.string()).optional().default([]),
46
-    }).optional().allow(null),
48
+    // negative_notes: Joi.object({
49
+    //     note: Joi.string().allow('', null),
50
+    //     tags: Joi.array().items(Joi.string()).optional().default([]),
51
+    // }).optional().allow(null),
47 52
 });
48 53
 
49 54
 export const validateStoreVendorExperienceRequest = (body: unknown): VendorExperienceRequestDTO => {

+ 6 - 4
tsconfig.json

@@ -27,7 +27,7 @@
27 27
 
28 28
     /* Modules */
29 29
     "module": "CommonJS" /* Specify what module code is generated. */,
30
-    "rootDir": "./" /* Specify the root folder within your source files. */,
30
+    "rootDir": "./index.ts" /* Specify the root folder within your source files. */,
31 31
     "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
32 32
     // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
33 33
     // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
@@ -111,10 +111,12 @@
111 111
     "skipLibCheck": true /* Skip type checking all .d.ts files. */
112 112
   },
113 113
   "include": [
114
-    "./src",
114
+    "./",
115
+    "./storage/img",
116
+    "./config",
115 117
     "./prisma",
116 118
     "index.ts",
117
-    "./src/**/*.ts",
119
+    "./src/**/*.ts"
118 120
   ],
119 121
   "exclude": ["node_modules"]
120
-}
122
+}