rez_core 7.1.2 → 7.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/.idea/250218_ether_core.iml +12 -0
  2. package/.idea/codeStyles/Project.xml +58 -58
  3. package/.idea/codeStyles/codeStyleConfig.xml +4 -4
  4. package/.idea/modules.xml +7 -7
  5. package/.idea/vcs.xml +5 -5
  6. package/.prettierrc +3 -3
  7. package/README.md +99 -99
  8. package/dist/module/filter/repository/saved-filter.repository.js +2 -0
  9. package/dist/module/filter/repository/saved-filter.repository.js.map +1 -1
  10. package/dist/module/filter/service/filter.service.js +33 -28
  11. package/dist/module/filter/service/filter.service.js.map +1 -1
  12. package/dist/module/integration/examples/usage.example.js +9 -9
  13. package/dist/module/integration/service/integration.service.d.ts +6 -1
  14. package/dist/module/integration/service/integration.service.js +14 -2
  15. package/dist/module/integration/service/integration.service.js.map +1 -1
  16. package/dist/module/integration/service/oauth.service.js +2 -0
  17. package/dist/module/integration/service/oauth.service.js.map +1 -1
  18. package/dist/module/integration/service/wrapper.service.js +1 -0
  19. package/dist/module/integration/service/wrapper.service.js.map +1 -1
  20. package/dist/module/integration/strategies/email/gmail-api.strategy.js +23 -7
  21. package/dist/module/integration/strategies/email/gmail-api.strategy.js.map +1 -1
  22. package/dist/module/integration/strategies/email/sendgrid-api.strategy.js +8 -5
  23. package/dist/module/integration/strategies/email/sendgrid-api.strategy.js.map +1 -1
  24. package/dist/module/layout_preference/controller/layout_preference.controller.d.ts +0 -6
  25. package/dist/module/layout_preference/controller/layout_preference.controller.js +0 -16
  26. package/dist/module/layout_preference/controller/layout_preference.controller.js.map +1 -1
  27. package/dist/module/layout_preference/layout_preference.module.js +1 -1
  28. package/dist/module/layout_preference/layout_preference.module.js.map +1 -1
  29. package/dist/module/layout_preference/service/layout_preference.service.d.ts +0 -4
  30. package/dist/module/layout_preference/service/layout_preference.service.js +0 -67
  31. package/dist/module/layout_preference/service/layout_preference.service.js.map +1 -1
  32. package/dist/module/listmaster/controller/list-master.controller.d.ts +1 -1
  33. package/dist/module/listmaster/controller/list-master.controller.js +9 -6
  34. package/dist/module/listmaster/controller/list-master.controller.js.map +1 -1
  35. package/dist/module/listmaster/repository/list-master-items.repository.js +1 -1
  36. package/dist/module/listmaster/repository/list-master-items.repository.js.map +1 -1
  37. package/dist/module/listmaster/service/list-master.service.d.ts +1 -1
  38. package/dist/module/listmaster/service/list-master.service.js +7 -7
  39. package/dist/module/listmaster/service/list-master.service.js.map +1 -1
  40. package/dist/module/meta/controller/media.controller.d.ts +3 -0
  41. package/dist/module/meta/controller/media.controller.js +27 -0
  42. package/dist/module/meta/controller/media.controller.js.map +1 -1
  43. package/dist/module/meta/entity/media-data.entity.d.ts +1 -0
  44. package/dist/module/meta/entity/media-data.entity.js +4 -0
  45. package/dist/module/meta/entity/media-data.entity.js.map +1 -1
  46. package/dist/module/meta/entity.module.js +2 -0
  47. package/dist/module/meta/entity.module.js.map +1 -1
  48. package/dist/module/meta/repository/attribute-master.repository.js +14 -14
  49. package/dist/module/meta/service/entity-dynamic.service.js +16 -16
  50. package/dist/module/meta/service/entity-dynamic.service.js.map +1 -1
  51. package/dist/module/meta/service/entity-master.service.js +20 -20
  52. package/dist/module/meta/service/entity-service-impl.service.d.ts +0 -2
  53. package/dist/module/meta/service/entity-service-impl.service.js +0 -5
  54. package/dist/module/meta/service/entity-service-impl.service.js.map +1 -1
  55. package/dist/module/meta/service/entity-table.service.d.ts +3 -8
  56. package/dist/module/meta/service/entity-table.service.js +54 -52
  57. package/dist/module/meta/service/entity-table.service.js.map +1 -1
  58. package/dist/module/meta/service/media-data.service.d.ts +2 -0
  59. package/dist/module/meta/service/media-data.service.js +8 -0
  60. package/dist/module/meta/service/media-data.service.js.map +1 -1
  61. package/dist/module/meta/service/resolver.service.js +23 -13
  62. package/dist/module/meta/service/resolver.service.js.map +1 -1
  63. package/dist/module/notification/notification.module.js +2 -0
  64. package/dist/module/notification/notification.module.js.map +1 -1
  65. package/dist/module/notification/repository/notification.repository.d.ts +7 -0
  66. package/dist/module/notification/repository/notification.repository.js +43 -0
  67. package/dist/module/notification/repository/notification.repository.js.map +1 -0
  68. package/dist/module/notification/service/notification.service.d.ts +3 -1
  69. package/dist/module/notification/service/notification.service.js +27 -40
  70. package/dist/module/notification/service/notification.service.js.map +1 -1
  71. package/dist/module/workflow/controller/workflow.controller.js +1 -1
  72. package/dist/module/workflow/controller/workflow.controller.js.map +1 -1
  73. package/dist/module/workflow/repository/action-data.repository.js +10 -3
  74. package/dist/module/workflow/repository/action-data.repository.js.map +1 -1
  75. package/dist/module/workflow/repository/action.repository.js +2 -2
  76. package/dist/module/workflow/repository/activity-log.repository.js +4 -4
  77. package/dist/module/workflow/repository/activity-log.repository.js.map +1 -1
  78. package/dist/module/workflow/repository/comm-template.repository.js +4 -4
  79. package/dist/module/workflow/repository/comm-template.repository.js.map +1 -1
  80. package/dist/module/workflow/repository/stage.repository.js +8 -8
  81. package/dist/module/workflow/repository/task.repository.js +4 -4
  82. package/dist/module/workflow/repository/task.repository.js.map +1 -1
  83. package/dist/module/workflow/service/action-template-mapping.service.js +2 -2
  84. package/dist/module/workflow/service/action.service.js +5 -5
  85. package/dist/module/workflow/service/comm-template.service.js +1 -1
  86. package/dist/module/workflow/service/comm-template.service.js.map +1 -1
  87. package/dist/module/workflow/service/entity-modification.service.d.ts +4 -1
  88. package/dist/module/workflow/service/entity-modification.service.js +9 -5
  89. package/dist/module/workflow/service/entity-modification.service.js.map +1 -1
  90. package/dist/module/workflow/service/populate-workflow.service.d.ts +1 -1
  91. package/dist/module/workflow/service/populate-workflow.service.js +24 -24
  92. package/dist/module/workflow/service/populate-workflow.service.js.map +1 -1
  93. package/dist/module/workflow/service/task.service.js +10 -11
  94. package/dist/module/workflow/service/task.service.js.map +1 -1
  95. package/dist/module/workflow/service/workflow-list-master.service.js +2 -2
  96. package/dist/module/workflow/service/workflow-list-master.service.js.map +1 -1
  97. package/dist/module/workflow-automation/service/schedule-handler.service.js +9 -9
  98. package/dist/module/workflow-automation/service/workflow-automation.service.js +8 -6
  99. package/dist/module/workflow-automation/service/workflow-automation.service.js.map +1 -1
  100. package/dist/table.config.d.ts +1 -1
  101. package/dist/tsconfig.build.tsbuildinfo +1 -1
  102. package/dist/utils/service/reflection-helper.service.js +2 -2
  103. package/docs/modules/event-driven-integration-design.md +91 -91
  104. package/docs/modules/integration.md +250 -250
  105. package/eslint.config.mjs +34 -34
  106. package/nest-cli.json +14 -14
  107. package/package.json +128 -128
  108. package/src/app.controller.ts +12 -12
  109. package/src/app.module.ts +62 -62
  110. package/src/app.service.ts +8 -8
  111. package/src/config/bull.config.ts +72 -72
  112. package/src/config/config.module.ts +17 -17
  113. package/src/config/database.config.ts +48 -48
  114. package/src/config/redis.config.ts +55 -55
  115. package/src/constant/attribute.constant.ts +8 -8
  116. package/src/constant/db-data-type.constant.ts +160 -160
  117. package/src/constant/entity.constant.ts +3 -3
  118. package/src/constant/global.constant.ts +67 -67
  119. package/src/constant/status.constant.ts +3 -3
  120. package/src/core.module.ts +96 -96
  121. package/src/decorators/roles.decorator.ts +7 -7
  122. package/src/dtos/response.dto.ts +6 -6
  123. package/src/dtos/response.ts +5 -5
  124. package/src/index.ts +1 -1
  125. package/src/module/auth/auth.module.ts +65 -65
  126. package/src/module/auth/controller/auth.controller.ts +28 -28
  127. package/src/module/auth/dto/user.dto.ts +56 -56
  128. package/src/module/auth/guards/google-auth.guard.ts +9 -9
  129. package/src/module/auth/guards/jwt.guard.ts +22 -22
  130. package/src/module/auth/services/auth.service.ts +56 -56
  131. package/src/module/auth/services/jwt.service.ts +11 -11
  132. package/src/module/auth/strategies/google.strategy.ts +54 -54
  133. package/src/module/auth/strategies/jwt.strategy.ts +65 -65
  134. package/src/module/auth/strategies/local.strategy.ts +13 -13
  135. package/src/module/dashboard/controller/dashboard.controller.ts +38 -38
  136. package/src/module/dashboard/dashboard.module.ts +19 -19
  137. package/src/module/dashboard/entity/dashboard_page_data.entity.ts +23 -23
  138. package/src/module/dashboard/entity/widget_master.entity.ts +15 -15
  139. package/src/module/dashboard/repository/dashboard.repository.ts +49 -49
  140. package/src/module/dashboard/service/dashboard.service.ts +69 -69
  141. package/src/module/eav/EAV_USAGE_GUIDE.md +351 -351
  142. package/src/module/eav/controller/eav.controller.ts +119 -119
  143. package/src/module/eav/dto/eav-operation.dto.ts +62 -62
  144. package/src/module/eav/eav.module.ts +79 -79
  145. package/src/module/eav/entity/eav-boolean.entity.ts +25 -25
  146. package/src/module/eav/entity/eav-date.entity.ts +24 -24
  147. package/src/module/eav/entity/eav-decimal.entity.ts +24 -24
  148. package/src/module/eav/entity/eav-int.entity.ts +24 -24
  149. package/src/module/eav/entity/eav-json.entity.ts +24 -24
  150. package/src/module/eav/entity/eav-text.entity.ts +24 -24
  151. package/src/module/eav/entity/eav-time.entity.ts +24 -24
  152. package/src/module/eav/entity/eav-timestamp.entity.ts +24 -24
  153. package/src/module/eav/entity/eav-varchar.entity.ts +24 -24
  154. package/src/module/eav/interface/eav-strategy.interface.ts +32 -32
  155. package/src/module/eav/repository/eav-boolean.repository.ts +67 -67
  156. package/src/module/eav/repository/eav-date.repository.ts +67 -67
  157. package/src/module/eav/repository/eav-decimal.repository.ts +67 -67
  158. package/src/module/eav/repository/eav-int.repository.ts +67 -67
  159. package/src/module/eav/repository/eav-json.repository.ts +67 -67
  160. package/src/module/eav/repository/eav-text.repository.ts +67 -67
  161. package/src/module/eav/repository/eav-time.repository.ts +67 -67
  162. package/src/module/eav/repository/eav-timestamp.repository.ts +67 -67
  163. package/src/module/eav/repository/eav-varchar.repository.ts +67 -67
  164. package/src/module/eav/service/eav-boolean.service.ts +64 -64
  165. package/src/module/eav/service/eav-date.service.ts +64 -64
  166. package/src/module/eav/service/eav-decimal.service.ts +64 -64
  167. package/src/module/eav/service/eav-factory.service.ts +93 -93
  168. package/src/module/eav/service/eav-int.service.ts +64 -64
  169. package/src/module/eav/service/eav-json.service.ts +64 -64
  170. package/src/module/eav/service/eav-text.service.ts +64 -64
  171. package/src/module/eav/service/eav-time.service.ts +64 -64
  172. package/src/module/eav/service/eav-timestamp.service.ts +64 -64
  173. package/src/module/eav/service/eav-varchar.service.ts +65 -65
  174. package/src/module/eav/service/eav.service.ts +116 -116
  175. package/src/module/entity_json/controller/entity_json.controller.ts +75 -75
  176. package/src/module/entity_json/docs/FlatJson_Filterin_System.md +2803 -2803
  177. package/src/module/entity_json/entity/entityJson.entity.ts +42 -42
  178. package/src/module/entity_json/entity_json.module.ts +22 -22
  179. package/src/module/entity_json/service/entityJson.repository.ts +37 -37
  180. package/src/module/entity_json/service/entity_json.service.ts +492 -492
  181. package/src/module/export/controller/export.controller.ts +83 -83
  182. package/src/module/export/export.module.ts +14 -14
  183. package/src/module/export/service/export.service.ts +107 -107
  184. package/src/module/filter/controller/filter.controller.ts +214 -214
  185. package/src/module/filter/dto/filter-request.dto.ts +41 -41
  186. package/src/module/filter/entity/saved-filter-detail.entity.ts +37 -37
  187. package/src/module/filter/entity/saved-filter-master.entity.ts +30 -30
  188. package/src/module/filter/filter.module.ts +33 -33
  189. package/src/module/filter/repository/saved-filter.repository.ts +249 -247
  190. package/src/module/filter/repository/saved.filter-detail.repository.ts +19 -19
  191. package/src/module/filter/service/filter-evaluator.service.ts +82 -82
  192. package/src/module/filter/service/filter.service.ts +1752 -1722
  193. package/src/module/filter/service/saved-filter.service.ts +164 -164
  194. package/src/module/ics/controller/ics.controller.ts +21 -21
  195. package/src/module/ics/dto/ics.dto.ts +55 -55
  196. package/src/module/ics/ics.module.ts +13 -13
  197. package/src/module/ics/service/ics.service.ts +57 -57
  198. package/src/module/integration/controller/calender-event.controller.ts +31 -31
  199. package/src/module/integration/controller/integration.controller.ts +662 -662
  200. package/src/module/integration/controller/wrapper.controller.ts +37 -37
  201. package/src/module/integration/dto/create-config.dto.ts +526 -526
  202. package/src/module/integration/entity/integration-config.entity.ts +112 -112
  203. package/src/module/integration/entity/integration-entity-mapper.entity.ts +14 -14
  204. package/src/module/integration/entity/integration-source.entity.ts +17 -17
  205. package/src/module/integration/entity/user-integration.entity.ts +71 -71
  206. package/src/module/integration/examples/usage.example.ts +338 -338
  207. package/src/module/integration/factories/base.factory.ts +7 -7
  208. package/src/module/integration/factories/email.factory.ts +49 -49
  209. package/src/module/integration/factories/integration.factory.ts +121 -121
  210. package/src/module/integration/factories/sms.factory.ts +51 -51
  211. package/src/module/integration/factories/telephone.factory.ts +41 -41
  212. package/src/module/integration/factories/whatsapp.factory.ts +56 -56
  213. package/src/module/integration/integration.module.ts +110 -110
  214. package/src/module/integration/service/calendar-event.service.ts +118 -118
  215. package/src/module/integration/service/integration-entity-mapper.service.ts +17 -17
  216. package/src/module/integration/service/integration-queue.service.ts +229 -229
  217. package/src/module/integration/service/integration.service.ts +2651 -2632
  218. package/src/module/integration/service/oauth.service.ts +226 -224
  219. package/src/module/integration/service/wrapper.service.ts +754 -753
  220. package/src/module/integration/strategies/email/gmail-api.strategy.ts +307 -281
  221. package/src/module/integration/strategies/email/outlook-api.strategy.ts +44 -44
  222. package/src/module/integration/strategies/email/outlook.strategy.ts +64 -64
  223. package/src/module/integration/strategies/email/sendgrid-api.strategy.ts +263 -260
  224. package/src/module/integration/strategies/integration.strategy.ts +97 -97
  225. package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -146
  226. package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -164
  227. package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -163
  228. package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +238 -238
  229. package/src/module/integration/strategies/telephone/tubelight-voice.strategy.ts +210 -210
  230. package/src/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.ts +359 -359
  231. package/src/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.ts +372 -372
  232. package/src/module/integration/strategies/whatsapp/whatsapp-cloud.strategy.ts +403 -403
  233. package/src/module/integration/strategies/whatsapp/whatsapp.strategy.ts +57 -57
  234. package/src/module/layout/controller/layout.controller.ts +38 -38
  235. package/src/module/layout/entity/header-items.entity.ts +28 -28
  236. package/src/module/layout/entity/header-section.entity.ts +13 -13
  237. package/src/module/layout/layout.module.ts +20 -20
  238. package/src/module/layout/repository/header-items.repository.ts +18 -18
  239. package/src/module/layout/repository/header-section.repository.ts +16 -16
  240. package/src/module/layout/service/header-section.service.ts +25 -25
  241. package/src/module/layout_preference/controller/layout_preference.controller.ts +76 -76
  242. package/src/module/layout_preference/entity/layout_preference.entity.ts +28 -28
  243. package/src/module/layout_preference/layout_preference.module.ts +22 -22
  244. package/src/module/layout_preference/repository/layout_preference.repository.ts +65 -65
  245. package/src/module/layout_preference/service/layout_preference.service.ts +191 -191
  246. package/src/module/linked_attributes/controller/linked_attributes.controller.ts +137 -137
  247. package/src/module/linked_attributes/dto/create-linked-attribute-smart.dto.ts +54 -54
  248. package/src/module/linked_attributes/entity/linked_attribute.entity.ts +51 -51
  249. package/src/module/linked_attributes/linked_attributes.module.ts +23 -23
  250. package/src/module/linked_attributes/repository/linked_attribute.repository.ts +12 -12
  251. package/src/module/linked_attributes/service/linked_attributes.service.ts +650 -650
  252. package/src/module/linked_attributes/test/linked-attributes.service.spec.ts +244 -244
  253. package/src/module/listmaster/controller/list-master.controller.ts +215 -208
  254. package/src/module/listmaster/entity/list-master-items.entity.ts +30 -30
  255. package/src/module/listmaster/entity/list-master.entity.ts +25 -25
  256. package/src/module/listmaster/listmaster.module.ts +46 -46
  257. package/src/module/listmaster/repository/list-master-items.repository.ts +262 -261
  258. package/src/module/listmaster/repository/list-master.repository.ts +60 -60
  259. package/src/module/listmaster/service/list-master-engine.ts +19 -19
  260. package/src/module/listmaster/service/list-master-extension.interface.ts +4 -4
  261. package/src/module/listmaster/service/list-master-item.service.ts +382 -382
  262. package/src/module/listmaster/service/list-master-registry.ts +15 -15
  263. package/src/module/listmaster/service/list-master.service.ts +774 -768
  264. package/src/module/mapper/controller/field-mapper.controller.ts +76 -76
  265. package/src/module/mapper/controller/mapper.controller.ts +20 -20
  266. package/src/module/mapper/dto/field-mapper.dto.ts +14 -14
  267. package/src/module/mapper/entity/field-lovs.entity.ts +15 -15
  268. package/src/module/mapper/entity/field-mapper.entity.ts +49 -49
  269. package/src/module/mapper/entity/mapper.entity.ts +9 -9
  270. package/src/module/mapper/mapper.module.ts +35 -35
  271. package/src/module/mapper/repository/field-lovs.repository.ts +35 -35
  272. package/src/module/mapper/repository/field-mapper.repository.ts +42 -42
  273. package/src/module/mapper/repository/mapper.repository.ts +32 -32
  274. package/src/module/mapper/service/field-mapper.service.ts +268 -268
  275. package/src/module/mapper/service/mapper.service.ts +80 -80
  276. package/src/module/master/controller/master.controller.ts +71 -71
  277. package/src/module/master/service/master.service.ts +460 -460
  278. package/src/module/master/service/poupulate-meta.service.ts +210 -210
  279. package/src/module/meta/controller/attribute-master.controller.ts +83 -83
  280. package/src/module/meta/controller/entity-dynamic.controller.ts +123 -123
  281. package/src/module/meta/controller/entity-master.controller.ts +41 -41
  282. package/src/module/meta/controller/entity-relation.controller.ts +36 -36
  283. package/src/module/meta/controller/entity.controller.ts +301 -301
  284. package/src/module/meta/controller/entity.public.controller.ts +76 -76
  285. package/src/module/meta/controller/media.controller.ts +162 -135
  286. package/src/module/meta/controller/meta.controller.ts +80 -80
  287. package/src/module/meta/controller/view-master.controller.ts +79 -79
  288. package/src/module/meta/dto/entity-list-data.dto.ts +6 -6
  289. package/src/module/meta/dto/entity-tab.dto.ts +4 -4
  290. package/src/module/meta/dto/entity-table.dto.ts +12 -12
  291. package/src/module/meta/entity/attribute-master.entity.ts +62 -62
  292. package/src/module/meta/entity/base-entity.entity.ts +52 -52
  293. package/src/module/meta/entity/dynamic.entity.ts +5 -5
  294. package/src/module/meta/entity/entity-master.entity.ts +53 -53
  295. package/src/module/meta/entity/entity-relation-data.entity.ts +24 -24
  296. package/src/module/meta/entity/entity-relation.entity.ts +18 -18
  297. package/src/module/meta/entity/entity-table-column.entity.ts +56 -56
  298. package/src/module/meta/entity/entity-table.entity.ts +45 -45
  299. package/src/module/meta/entity/media-data.entity.ts +35 -32
  300. package/src/module/meta/entity/preference.entity.ts +57 -57
  301. package/src/module/meta/entity/view-master.entity.ts +36 -36
  302. package/src/module/meta/entity.module.ts +153 -151
  303. package/src/module/meta/repository/attribute-master.repository.ts +206 -206
  304. package/src/module/meta/repository/entity-attribute-update.repository.ts +48 -48
  305. package/src/module/meta/repository/entity-master.repository.ts +120 -120
  306. package/src/module/meta/repository/entity-relation.repository.ts +36 -36
  307. package/src/module/meta/repository/entity-table-column.repository.ts +39 -39
  308. package/src/module/meta/repository/entity-table.repository.ts +53 -53
  309. package/src/module/meta/repository/media-data.repository.ts +50 -50
  310. package/src/module/meta/repository/preference.repository.ts +20 -20
  311. package/src/module/meta/repository/user-app-mapping.repository.ts +28 -28
  312. package/src/module/meta/repository/view-master.repository.ts +42 -42
  313. package/src/module/meta/service/attribute-master.service.ts +329 -329
  314. package/src/module/meta/service/common.service.ts +9 -9
  315. package/src/module/meta/service/entity-attribute-update.service.ts +26 -26
  316. package/src/module/meta/service/entity-dynamic.service.ts +1038 -1037
  317. package/src/module/meta/service/entity-master.service.ts +288 -288
  318. package/src/module/meta/service/entity-realation-data.service.ts +9 -9
  319. package/src/module/meta/service/entity-relation.service.ts +85 -85
  320. package/src/module/meta/service/entity-service-impl.service.ts +390 -394
  321. package/src/module/meta/service/entity-table-column.service.ts +26 -26
  322. package/src/module/meta/service/entity-table.service.ts +144 -157
  323. package/src/module/meta/service/entity-validation.service.ts +187 -187
  324. package/src/module/meta/service/entity.service.ts +48 -48
  325. package/src/module/meta/service/field-group.service.ts +103 -103
  326. package/src/module/meta/service/media-data.service.ts +397 -385
  327. package/src/module/meta/service/preference.service.ts +16 -16
  328. package/src/module/meta/service/resolver.service.ts +293 -260
  329. package/src/module/meta/service/section-master.service.ts +104 -104
  330. package/src/module/meta/service/update-form-json.service.ts +22 -22
  331. package/src/module/meta/service/user-app-mapping.service.ts +17 -17
  332. package/src/module/meta/service/view-master.service.ts +127 -127
  333. package/src/module/microservice-client/microservice-clients.module.ts +13 -13
  334. package/src/module/microservice-client/service/microservice-client-factory.ts +37 -37
  335. package/src/module/microservice-client/service/microservice-clients.ts +4 -4
  336. package/src/module/notification/controller/notification.controller.ts +58 -58
  337. package/src/module/notification/entity/notification.entity.ts +76 -76
  338. package/src/module/notification/entity/otp.entity.ts +28 -28
  339. package/src/module/notification/firebase-admin.config.ts +22 -22
  340. package/src/module/notification/notification.module.ts +65 -63
  341. package/src/module/notification/repository/notification.repository.ts +33 -0
  342. package/src/module/notification/repository/otp.repository.ts +27 -27
  343. package/src/module/notification/service/email.service.ts +142 -142
  344. package/src/module/notification/service/notification.service.ts +145 -163
  345. package/src/module/preference_master/entity/preference.entity.ts +25 -25
  346. package/src/module/preference_master/preference.service.ts +27 -27
  347. package/src/module/preference_master/repo/preference.repository.ts +36 -36
  348. package/src/module/third-party-module/entity/third-party-api-registry.entity.ts +52 -52
  349. package/src/module/third-party-module/repository/third-party-api-registry.repository.ts +20 -20
  350. package/src/module/third-party-module/service/api-registry.service.ts +13 -13
  351. package/src/module/third-party-module/third-party.module.ts +12 -12
  352. package/src/module/workflow/controller/action-category.controller.ts +54 -54
  353. package/src/module/workflow/controller/action-resource-mapping.controller.ts +23 -23
  354. package/src/module/workflow/controller/action-template-mapping.controller.ts +35 -35
  355. package/src/module/workflow/controller/action.controller.ts +111 -111
  356. package/src/module/workflow/controller/activity-log.controller.ts +55 -55
  357. package/src/module/workflow/controller/comm-template.controller.ts +43 -43
  358. package/src/module/workflow/controller/entity-modification.controller.ts +35 -35
  359. package/src/module/workflow/controller/form-master.controller.ts +43 -43
  360. package/src/module/workflow/controller/stage-group.controller.ts +49 -49
  361. package/src/module/workflow/controller/stage.controller.ts +51 -51
  362. package/src/module/workflow/controller/task.controller.ts +77 -77
  363. package/src/module/workflow/controller/workflow-list-master.controller.ts +44 -44
  364. package/src/module/workflow/controller/workflow-meta.controller.ts +80 -80
  365. package/src/module/workflow/controller/workflow.controller.ts +66 -66
  366. package/src/module/workflow/entity/action-category.entity.ts +33 -33
  367. package/src/module/workflow/entity/action-data.entity.ts +51 -51
  368. package/src/module/workflow/entity/action-resources-mapping.entity.ts +21 -21
  369. package/src/module/workflow/entity/action-template-mapping.entity.ts +12 -12
  370. package/src/module/workflow/entity/action.entity.ts +48 -48
  371. package/src/module/workflow/entity/activity-log.entity.ts +39 -39
  372. package/src/module/workflow/entity/comm-template.entity.ts +38 -38
  373. package/src/module/workflow/entity/entity-modification.entity.ts +33 -33
  374. package/src/module/workflow/entity/form.entity.ts +21 -21
  375. package/src/module/workflow/entity/stage-action-mapping.entity.ts +12 -12
  376. package/src/module/workflow/entity/stage-group.entity.ts +18 -18
  377. package/src/module/workflow/entity/stage-movement-data.entity.ts +33 -33
  378. package/src/module/workflow/entity/stage.entity.ts +15 -15
  379. package/src/module/workflow/entity/task-data.entity.ts +84 -84
  380. package/src/module/workflow/entity/template-attach-mapper.entity.ts +30 -30
  381. package/src/module/workflow/entity/workflow-data.entity.ts +6 -6
  382. package/src/module/workflow/entity/workflow-level-mapping.entity.ts +18 -18
  383. package/src/module/workflow/entity/workflow.entity.ts +15 -15
  384. package/src/module/workflow/repository/action-category.repository.ts +78 -78
  385. package/src/module/workflow/repository/action-data.repository.ts +353 -345
  386. package/src/module/workflow/repository/action.repository.ts +339 -339
  387. package/src/module/workflow/repository/activity-log.repository.ts +148 -148
  388. package/src/module/workflow/repository/comm-template.repository.ts +157 -157
  389. package/src/module/workflow/repository/form-master.repository.ts +50 -50
  390. package/src/module/workflow/repository/stage-group.repository.ts +186 -186
  391. package/src/module/workflow/repository/stage-movement.repository.ts +217 -217
  392. package/src/module/workflow/repository/stage.repository.ts +160 -160
  393. package/src/module/workflow/repository/task.repository.ts +156 -154
  394. package/src/module/workflow/repository/workflow.repository.ts +42 -42
  395. package/src/module/workflow/service/action-category.service.ts +32 -32
  396. package/src/module/workflow/service/action-data.service.ts +62 -62
  397. package/src/module/workflow/service/action-resources-mapping.service.ts +10 -10
  398. package/src/module/workflow/service/action-template-mapping.service.ts +137 -137
  399. package/src/module/workflow/service/action.service.ts +300 -300
  400. package/src/module/workflow/service/activity-log.service.ts +106 -106
  401. package/src/module/workflow/service/comm-template.service.ts +179 -179
  402. package/src/module/workflow/service/entity-modification.service.ts +63 -55
  403. package/src/module/workflow/service/form-master.service.ts +35 -35
  404. package/src/module/workflow/service/populate-workflow.service.ts +313 -313
  405. package/src/module/workflow/service/stage-action-mapping.service.ts +5 -5
  406. package/src/module/workflow/service/stage-group.service.ts +325 -325
  407. package/src/module/workflow/service/stage.service.ts +196 -196
  408. package/src/module/workflow/service/task.service.ts +546 -547
  409. package/src/module/workflow/service/workflow-list-master.service.ts +68 -68
  410. package/src/module/workflow/service/workflow-meta.service.ts +638 -638
  411. package/src/module/workflow/service/workflow.service.ts +212 -212
  412. package/src/module/workflow/workflow.module.ts +180 -180
  413. package/src/module/workflow-automation/SCHEDULING_GUIDE.md +145 -145
  414. package/src/module/workflow-automation/controller/workflow-automation.controller.ts +43 -43
  415. package/src/module/workflow-automation/entity/workflow-automation-action.entity.ts +26 -26
  416. package/src/module/workflow-automation/entity/workflow-automation.entity.ts +35 -35
  417. package/src/module/workflow-automation/interface/action.decorator.ts +7 -7
  418. package/src/module/workflow-automation/interface/action.interface.ts +5 -5
  419. package/src/module/workflow-automation/service/action-registery.service.ts +35 -35
  420. package/src/module/workflow-automation/service/schedule-handler.service.ts +167 -167
  421. package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +219 -219
  422. package/src/module/workflow-automation/service/workflow-automation.service.ts +486 -486
  423. package/src/module/workflow-automation/workflow-automation.module.ts +55 -55
  424. package/src/module/workflow-schedule/INSTALLATION.md +244 -244
  425. package/src/module/workflow-schedule/MULTI_PROJECT_GUIDE.md +196 -196
  426. package/src/module/workflow-schedule/README.md +422 -422
  427. package/src/module/workflow-schedule/constants/schedule.constants.ts +48 -48
  428. package/src/module/workflow-schedule/controller/workflow-schedule.controller.ts +253 -253
  429. package/src/module/workflow-schedule/docs/CLAUDE_CODE_GUIDE.md +510 -510
  430. package/src/module/workflow-schedule/docs/CLAUDE_CODE_PROMPT.md +362 -362
  431. package/src/module/workflow-schedule/docs/RUN_CLAUDE_CODE.sh +68 -68
  432. package/src/module/workflow-schedule/dto/create-schedule.dto.ts +147 -147
  433. package/src/module/workflow-schedule/dto/get-execution-logs.dto.ts +119 -119
  434. package/src/module/workflow-schedule/dto/update-schedule.dto.ts +96 -96
  435. package/src/module/workflow-schedule/entities/scheduled-workflow.entity.ts +148 -148
  436. package/src/module/workflow-schedule/entities/workflow-execution-log.entity.ts +154 -154
  437. package/src/module/workflow-schedule/interfaces/schedule-job-data.interface.ts +51 -51
  438. package/src/module/workflow-schedule/interfaces/workflow-schedule-options.interface.ts +12 -12
  439. package/src/module/workflow-schedule/processors/schedule.processor.ts +616 -616
  440. package/src/module/workflow-schedule/service/workflow-schedule.service.ts +588 -588
  441. package/src/module/workflow-schedule/workflow-schedule.module.ts +67 -67
  442. package/src/resources/dev.properties.yaml +33 -33
  443. package/src/resources/local.properties.yaml +27 -27
  444. package/src/resources/properties.module.ts +12 -12
  445. package/src/resources/properties.yaml.ts +11 -11
  446. package/src/resources/uat.properties.yaml +31 -31
  447. package/src/table.config.ts +123 -123
  448. package/src/utils/dto/excel-data.dto.ts +14 -14
  449. package/src/utils/dto/excelsheet-data.dto.ts +5 -5
  450. package/src/utils/service/base64util.service.ts +18 -18
  451. package/src/utils/service/clockIDGenUtil.service.ts +21 -21
  452. package/src/utils/service/codeGenerator.service.ts +22 -22
  453. package/src/utils/service/dateUtil.service.ts +17 -17
  454. package/src/utils/service/encryptUtil.service.ts +97 -97
  455. package/src/utils/service/excel-helper.service.ts +72 -72
  456. package/src/utils/service/excelUtil.service.ts +15 -15
  457. package/src/utils/service/file-util.service.ts +11 -11
  458. package/src/utils/service/json-util.service.ts +23 -23
  459. package/src/utils/service/loggingUtil.service.ts +88 -88
  460. package/src/utils/service/reflection-helper.service.ts +62 -62
  461. package/src/utils/service/wbsCodeGen.service.ts +8 -8
  462. package/src/utils/utils.module.ts +27 -27
  463. package/tsconfig.build.json +4 -4
  464. package/tsconfig.json +24 -24
  465. package/.claude/settings.local.json +0 -26
  466. package/.idea/250218_nodejs_core.iml +0 -9
  467. package/.idea/copilot.data.migration.agent.xml +0 -6
  468. package/.idea/copilot.data.migration.ask.xml +0 -6
  469. package/.idea/copilot.data.migration.ask2agent.xml +0 -6
  470. package/.idea/copilot.data.migration.edit.xml +0 -6
  471. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  472. package/.idea/misc.xml +0 -6
  473. package/.idea/prettier.xml +0 -6
  474. package/server.log +0 -850
@@ -1,1037 +1,1038 @@
1
- import { BadRequestException, Injectable } from '@nestjs/common';
2
- import { STATUS_ACTIVE } from 'src/constant/global.constant';
3
- import { EntityManager, In } from 'typeorm';
4
- import { UserData } from 'src/module/auth/dto/user.dto';
5
- import { MediaDataService } from './media-data.service';
6
- import { EntityMasterRepository } from '../repository/entity-master.repository';
7
- import { ConfigService } from '@nestjs/config';
8
- import { EntityServiceImpl } from './entity-service-impl.service';
9
- import { EAVService } from '../../eav/service/eav.service';
10
- import { AttributeStorageType } from '../../../constant/attribute.constant';
11
- import { StorageType } from '../../../constant/entity.constant';
12
-
13
- @Injectable()
14
- export class EntityDynamicService extends EntityServiceImpl {
15
- constructor(
16
- private readonly entityManager: EntityManager,
17
- private readonly mediaDataService: MediaDataService,
18
- private readonly entityMasterRepo: EntityMasterRepository,
19
- private readonly configService: ConfigService,
20
- private readonly eavService: EAVService,
21
- ) {
22
- super();
23
- }
24
-
25
- schema = this.configService.get('DB_SCHEMA');
26
-
27
- // -----------------------------
28
- async createEntityData(
29
- entityType: string,
30
- entityData: Record<string, any>,
31
- loggedInUser: any,
32
- mainID?: number,
33
- ): Promise<any> {
34
- const enterprise_id = loggedInUser.enterprise_id;
35
- const entityMaster =
36
- await this.entityMasterRepo.getEntityByMappedEntityType(
37
- entityType,
38
- loggedInUser.enterprise_id,
39
- );
40
-
41
- if (!entityMaster) {
42
- throw new BadRequestException(
43
- `Entity With ${entityType} entity type not found`,
44
- );
45
- }
46
- let tableName: string;
47
- if (StorageType.SELF === entityMaster.storage_type) {
48
- tableName = entityMaster.db_table_name;
49
- } else {
50
- tableName = 'frm_entity_dynamic';
51
- }
52
-
53
- const validAttributes = await this.getAttributeCodes(
54
- entityType,
55
- enterprise_id,
56
- );
57
-
58
- // -------------------------------------------------------
59
- // AUTO fields
60
- // -------------------------------------------------------
61
- entityData.created_date = new Date();
62
-
63
- if (loggedInUser) {
64
- entityData.created_by = loggedInUser.id;
65
-
66
- if (!entityData.enterprise_id)
67
- entityData.enterprise_id = loggedInUser.enterprise_id;
68
-
69
- if (!entityData.level_type)
70
- entityData.level_type = loggedInUser.level_type;
71
-
72
- if (!entityData.level_id) entityData.level_id = loggedInUser.level_id;
73
-
74
- if (!entityData.entity_type) entityData.entity_type = entityType;
75
- }
76
-
77
- // -------------------------------------------------------
78
- // STATUS
79
- // -------------------------------------------------------
80
- const listMasterItemsRepo =
81
- this.reflectionHelper.getRepoService('ListMasterItems');
82
- const statusList = listMasterItemsRepo.find({
83
- where: {
84
- code: STATUS_ACTIVE,
85
- enterprise_id: enterprise_id,
86
- },
87
- });
88
-
89
- if (!entityData.status) entityData.status = statusList[0]?.id;
90
-
91
- // -------------------------------------------------------
92
- // AUTO-CODE GENERATION (POSTGRES SAFE)
93
- // -------------------------------------------------------
94
-
95
- const maxSeqResult = this.entityManager.query(
96
- `SELECT MAX(id) as seq_no
97
- FROM ${this.schema}.${tableName}`,
98
- );
99
-
100
- let maxSeq = Number(maxSeqResult[0]?.seq_no) || 0;
101
- maxSeq++;
102
- entityData.code = `${entityData.entity_type}${maxSeq}`;
103
-
104
- // -------------------------------------------------------
105
- // Parent ID
106
- // -------------------------------------------------------
107
- if (mainID) {
108
- entityData.parent_id = mainID;
109
- }
110
-
111
- // -------------------------------------------------------
112
- // BYPASS COLUMNS
113
- // -------------------------------------------------------
114
- const bypassColumns = [
115
- 'created_date',
116
- 'created_by',
117
- 'enterprise_id',
118
- 'level_type',
119
- 'level_id',
120
- 'status',
121
- 'entity_type',
122
- 'code',
123
- 'parent_id',
124
- ];
125
-
126
- for (const col of bypassColumns) {
127
- if (!validAttributes.some((a) => a.attribute_key === col)) {
128
- validAttributes.push({
129
- attribute_key: col,
130
- is_hidden: false,
131
- db_datatype: 'text',
132
- element_type: 'text',
133
- storage_type: AttributeStorageType.DB_COL,
134
- });
135
- }
136
- }
137
-
138
- // -------------------------------------------------------
139
- // BUILD INSERT QUERY (POSTGRES FORMAT)
140
- // -------------------------------------------------------
141
- const columns: string[] = [];
142
- const values: any[] = [];
143
- let idx = 1;
144
- const placeholders: string[] = [];
145
- const eavAttributes: any[] = [];
146
-
147
- for (const attr of validAttributes) {
148
- if (attr.attribute_key === 'id' && !entityData.id) continue;
149
-
150
- if (
151
- attr.storage_type.toLowerCase() ===
152
- AttributeStorageType.EAV.toLowerCase()
153
- ) {
154
- if (entityData[attr.attribute_key] !== undefined) {
155
- eavAttributes.push({
156
- key: attr.attribute_key,
157
- value: entityData[attr.attribute_key],
158
- data_type: attr.db_datatype,
159
- });
160
- }
161
- } else {
162
- columns.push(attr.attribute_key);
163
- values.push(entityData[attr.attribute_key] ?? null);
164
- placeholders.push(`$${idx++}`);
165
- }
166
- }
167
-
168
- const colList = columns.map((c) => `"${c}"`).join(', ');
169
- const placeholderList = placeholders.join(', ');
170
-
171
- const sql = `
172
- INSERT INTO ${this.schema}.${tableName} (${colList})
173
- VALUES (${placeholderList}) RETURNING *
174
- `;
175
-
176
- const result = await this.entityManager.query(sql, values);
177
- const newId = result[0]?.id;
178
-
179
- // Save EAV attributes
180
- if (newId && eavAttributes.length > 0) {
181
- for (const eavAttr of eavAttributes) {
182
- if (this.eavService.isTypeSupported(eavAttr.data_type)) {
183
- await this.eavService.create(
184
- eavAttr.data_type,
185
- {
186
- entity_type: entityType,
187
- entity_id: newId,
188
- key: eavAttr.key,
189
- value: eavAttr.value,
190
- },
191
- loggedInUser?.id,
192
- );
193
- }
194
- }
195
- }
196
-
197
- return result[0];
198
- }
199
-
200
- // ----------------------------- get entity with relations
201
-
202
- // ----------------------------- create entity with relations
203
- async createEntity(
204
- data: Record<string, any>,
205
- loggedInUser: any,
206
- ): Promise<any> {
207
- const entityType = data.entity_type;
208
- const enterpriseId = loggedInUser.enterprise_id;
209
-
210
- const repo = this.reflectionHelper.getRepoService('EntityRelation');
211
-
212
- const getRelation = await repo.find({
213
- where: {
214
- enterprise_id: enterpriseId,
215
- source_entity_type: entityType,
216
- },
217
- });
218
-
219
- const { mappedEntities, ...mainData } = data;
220
-
221
- // create main entity
222
- const createdEntityData = await this.createEntityData(
223
- entityType,
224
- mainData,
225
- loggedInUser,
226
- );
227
- const mainID = createdEntityData.insertId || createdEntityData.id;
228
-
229
- if (mappedEntities && getRelation.length > 0) {
230
- for (const relation of getRelation) {
231
- const targetEntityType = relation.target_entity_type;
232
- const relationType = relation.relation_type;
233
-
234
- if (!mappedEntities[targetEntityType]) continue;
235
-
236
- // normalize: always array
237
- const entityDataArray = Array.isArray(mappedEntities[targetEntityType])
238
- ? mappedEntities[targetEntityType]
239
- : [mappedEntities[targetEntityType]];
240
-
241
- for (const item of entityDataArray) {
242
- const itemWithRef = {
243
- ...item,
244
- entity_type: targetEntityType,
245
- };
246
-
247
- const createdRelatedEntity = await this.createEntityData(
248
- targetEntityType,
249
- itemWithRef,
250
- loggedInUser,
251
- mainID, // this will pass for parent_id
252
- );
253
-
254
- const relationRepo =
255
- this.reflectionHelper.getRepoService('EntityRelationData');
256
-
257
- await relationRepo.save({
258
- enterprise_id: enterpriseId,
259
- source_entity_id: mainID,
260
- source_entity_type: entityType,
261
- target_entity_id: createdRelatedEntity.id,
262
- target_entity_type: targetEntityType,
263
- relation_type: relationType,
264
- });
265
- }
266
- }
267
- }
268
-
269
- return {
270
- mainEntity: {
271
- id: mainID,
272
- entityType,
273
- data: createdEntityData,
274
- },
275
- };
276
- }
277
-
278
- // ----------------------------- get entity with relations
279
- async getEntityData(
280
- entityType: string,
281
- id: number | string,
282
- loggedInUser: any,
283
- resolved?: boolean,
284
- ): Promise<any> {
285
- let mainEntity = await this.getEntityByDataSource(
286
- entityType,
287
- id,
288
- loggedInUser,
289
- );
290
-
291
- if (resolved) {
292
- mainEntity = await this.resolverService.getResolvedData(
293
- loggedInUser,
294
- mainEntity,
295
- entityType,
296
- );
297
- }
298
-
299
- const relationRepo = this.reflectionHelper.getRepoService('EntityRelation');
300
- const relatedEntityRepo =
301
- this.reflectionHelper.getRepoService('EntityRelationData');
302
-
303
- const relations = await relationRepo.find({
304
- where: {
305
- source_entity_type: entityType,
306
- enterprise_id: loggedInUser.enterprise_id,
307
- },
308
- });
309
-
310
- const targetTypes = relations.map((r) => r.target_entity_type);
311
-
312
- if (targetTypes.length === 0) {
313
- return {
314
- entity_type: entityType,
315
- ...mainEntity,
316
- };
317
- }
318
-
319
- const relatedEntities = await relatedEntityRepo.find({
320
- where: {
321
- source_entity_id: id,
322
- target_entity_type: In(targetTypes),
323
- },
324
- });
325
-
326
- // Format response to match create entity structure
327
- const response: any = {
328
- entity_type: entityType,
329
- ...mainEntity,
330
- };
331
-
332
- if (relatedEntities.length > 0) {
333
- response.mappedEntities = await this.formatMappedEntities(
334
- relatedEntities,
335
- loggedInUser,
336
- resolved,
337
- );
338
- }
339
-
340
- return response;
341
- }
342
-
343
- // ----------------------------- formatMappedEntities
344
- async formatMappedEntities(
345
- relatedEntities: any[],
346
- loggedInUser: any,
347
- resolved?: boolean,
348
- ): Promise<any> {
349
- const mappedEntities: any = {};
350
-
351
- for (const relation of relatedEntities) {
352
- const targetEntityType = relation.target_entity_type;
353
- const targetEntityId = relation.target_entity_id;
354
-
355
- const entityData = await this.getEntityData(
356
- targetEntityType,
357
- targetEntityId,
358
- loggedInUser,
359
- resolved,
360
- );
361
-
362
- if (!mappedEntities[targetEntityType]) {
363
- mappedEntities[targetEntityType] = [];
364
- }
365
-
366
- mappedEntities[targetEntityType].push(entityData);
367
- }
368
-
369
- return mappedEntities;
370
- }
371
-
372
- // ----------------------------- update with relations
373
-
374
- // ----------------------------- update entity with relations
375
- async updateEntity(
376
- data: Record<string, any>,
377
- loggedInUser: any,
378
- ): Promise<any> {
379
- const entityType = data.entity_type;
380
- const enterpriseId = loggedInUser.enterprise_id;
381
- const { mappedEntities, ...mainData } = data;
382
-
383
- // Update main entity
384
- const updatedMainEntity = await this.updateEntityData(
385
- entityType,
386
- data.id,
387
- mainData,
388
- loggedInUser,
389
- );
390
-
391
- const updatedRelations: Record<string, any> = {};
392
-
393
- if (mappedEntities) {
394
- const entityRelationRepo =
395
- this.reflectionHelper.getRepoService('EntityRelation');
396
- const getRelationDefs = await entityRelationRepo.find({
397
- where: {
398
- enterprise_id: enterpriseId,
399
- source_entity_type: entityType,
400
- },
401
- });
402
-
403
- for (const [targetEntityType, rawEntityData] of Object.entries(
404
- mappedEntities,
405
- )) {
406
- const relationDef = getRelationDefs.find(
407
- (r) => r.target_entity_type === targetEntityType,
408
- );
409
- if (!relationDef) continue;
410
-
411
- const relationType = relationDef.relation_type;
412
- const entityArray = Array.isArray(rawEntityData)
413
- ? rawEntityData
414
- : [rawEntityData];
415
-
416
- // Delete previous relations and related entities
417
- // Create/update new entities & relations
418
- const updatedEntities: any[] = [];
419
-
420
- for (const item of entityArray) {
421
- let targetEntityId;
422
- let entityData;
423
-
424
- if (item.id) {
425
- // Update existing entity
426
- await this.updateEntityData(
427
- targetEntityType,
428
- item.id,
429
- item,
430
- loggedInUser,
431
- Number(data.id), // pass main entity id as parent_id
432
- );
433
- targetEntityId = item.id;
434
- entityData = await this.getEntity(
435
- targetEntityType,
436
- targetEntityId,
437
- loggedInUser,
438
- );
439
- } else {
440
- // Create new entity
441
- const createdEntity = await this.createEntityData(
442
- targetEntityType,
443
- item,
444
- loggedInUser,
445
- Number(data.id), // pass main entity id as parent_id
446
- );
447
- targetEntityId = createdEntity.insertId || createdEntity.id;
448
- entityData = await this.getEntity(
449
- targetEntityType,
450
- targetEntityId,
451
- loggedInUser,
452
- );
453
-
454
- // Insert relation as per new entity created
455
- const entityRelationDataRepo =
456
- this.reflectionHelper.getRepoService('EntityRelationData');
457
- await entityRelationDataRepo.save({
458
- enterprise_id: enterpriseId,
459
- source_entity_id: data.id,
460
- source_entity_type: entityType,
461
- target_entity_id: targetEntityId,
462
- target_entity_type: targetEntityType,
463
- relation_type: relationType,
464
- });
465
- }
466
-
467
- if (relationType === 'ONE_TO_MANY') {
468
- updatedEntities.push(entityData);
469
- } else if (
470
- relationType === 'ONE_TO_ONE' ||
471
- relationType === 'MANY_TO_ONE'
472
- ) {
473
- updatedEntities[0] = entityData; // single object
474
- }
475
- }
476
-
477
- // Assign to response mappedEntities
478
- updatedRelations[targetEntityType] =
479
- relationType === 'ONE_TO_MANY' ? updatedEntities : updatedEntities[0];
480
- }
481
- }
482
-
483
- return {
484
- mainEntity: {
485
- id: data.id,
486
- entityType,
487
- data: updatedMainEntity,
488
- },
489
- relatedEntities: updatedRelations,
490
- };
491
- }
492
-
493
- // -----------------------------
494
- async updateEntityData(
495
- entityType: string,
496
- id: number | string,
497
- entityData: Record<string, any>,
498
- loggedInUser: any,
499
- mainID?: number,
500
- ): Promise<any> {
501
- const enterprise_id = loggedInUser.enterprise_id;
502
-
503
- const tableName = await this.getTableName(entityType, enterprise_id);
504
- const validAttributes = await this.getAttributeCodes(
505
- entityType,
506
- enterprise_id,
507
- );
508
-
509
- const updates: string[] = [];
510
- const values: any[] = [];
511
- let idx = 1;
512
-
513
- // Auto fields
514
- entityData.modified_date = new Date();
515
- if (loggedInUser) {
516
- entityData.modified_by = loggedInUser.id;
517
-
518
- if (!entityData.enterprise_id)
519
- entityData.enterprise_id = loggedInUser.enterprise_id;
520
-
521
- if (!entityData.level_type)
522
- entityData.level_type = loggedInUser.level_type;
523
-
524
- if (!entityData.level_id) entityData.level_id = loggedInUser.level_id;
525
-
526
- if (!entityData.entity_type) entityData.entity_type = entityType;
527
- }
528
-
529
- if (mainID) {
530
- entityData.parent_id = mainID;
531
- }
532
-
533
- // Add bypass columns if needed
534
- const bypassColumns = [
535
- 'created_date',
536
- 'created_by',
537
- 'modified_date',
538
- 'modified_by',
539
- 'enterprise_id',
540
- 'level_type',
541
- 'level_id',
542
- 'status',
543
- 'entity_type',
544
- 'code',
545
- 'parent_id',
546
- ];
547
-
548
- for (const col of bypassColumns) {
549
- if (!validAttributes.some((attr) => attr.attribute_key === col)) {
550
- validAttributes.push({
551
- attribute_key: col,
552
- db_datatype: 'text',
553
- element_type: 'text',
554
- is_hidden: false,
555
- storage_type: AttributeStorageType.DB_COL,
556
- });
557
- }
558
- }
559
-
560
- const eavAttributes: any[] = [];
561
-
562
- // Build SET clause
563
- for (const key of Object.keys(entityData)) {
564
- const attr = validAttributes.find((attr) => attr.attribute_key === key);
565
- if (attr) {
566
- if (
567
- attr.storage_type.toLowerCase() ===
568
- AttributeStorageType.EAV.toLowerCase()
569
- ) {
570
- eavAttributes.push({
571
- key: attr.attribute_key,
572
- value: entityData[key],
573
- data_type: attr.db_datatype,
574
- });
575
- } else {
576
- updates.push(`${key} = $${idx++}`);
577
- values.push(entityData[key]);
578
- }
579
- }
580
- }
581
-
582
- if (updates.length === 0 && eavAttributes.length === 0) {
583
- throw new Error('No valid attributes to update.');
584
- }
585
-
586
- let result;
587
-
588
- if (updates.length > 0) {
589
- // WHERE clause placeholder
590
- const idPlaceholder = `$${idx}`;
591
- values.push(id);
592
-
593
- const updateQuery = `
594
- UPDATE ${this.schema}.${tableName}
595
- SET ${updates.join(', ')}
596
- WHERE id = ${idPlaceholder}
597
- `;
598
-
599
- result = await this.entityManager.query(updateQuery, values);
600
- }
601
-
602
- // Process EAV Updates
603
- if (eavAttributes.length > 0) {
604
- for (const eavAttr of eavAttributes) {
605
- if (this.eavService.isTypeSupported(eavAttr.data_type)) {
606
- await this.eavService.upsert(
607
- eavAttr.data_type,
608
- {
609
- entity_type: entityType,
610
- entity_id: id,
611
- key: eavAttr.key,
612
- value: eavAttr.value,
613
- },
614
- loggedInUser?.id,
615
- );
616
- }
617
- }
618
- }
619
-
620
- return result || { message: 'EAV updated' };
621
- }
622
-
623
- async getEntityByDataSource(
624
- entityType: string,
625
- id: number | string,
626
- loggedInUser: any,
627
- ): Promise<any> {
628
- const enterprise_id = loggedInUser.enterprise_id;
629
-
630
- const entityMaster = await this.entityMasterService.getEntityData(
631
- entityType,
632
- loggedInUser,
633
- );
634
-
635
- let dataSource: string;
636
- if (StorageType.SELF === entityMaster.storage_type) {
637
- dataSource = entityMaster.db_table_name;
638
- } else {
639
- dataSource = 'frm_entity_dynamic';
640
- }
641
-
642
- const validAttributes = await this.getAttributeCodes(
643
- entityType,
644
- enterprise_id,
645
- false,
646
- );
647
-
648
- // Filter out EAV attributes from SQL query
649
- const dbColumns = validAttributes.filter(
650
- (attr) => attr.storage_type !== AttributeStorageType.EAV,
651
- );
652
- const columns = dbColumns
653
- .map((attr) => `"${attr.attribute_key}"`)
654
- .join(', ');
655
-
656
- // Add id if not present (required)
657
- // Note: If columns is empty (only EAV attributes), we still need to select something.
658
- let selectColumns = columns;
659
- if (!columns) {
660
- selectColumns = 'id';
661
- } else if (!dbColumns.some((c) => c.attribute_key === 'id')) {
662
- selectColumns += ', id';
663
- }
664
-
665
- const selectQuery = `SELECT ${selectColumns}
666
- FROM ${this.schema}.${dataSource}
667
- WHERE id = $1`;
668
-
669
- const result = await this.entityManager.query(selectQuery, [id]);
670
- if (!result.length) return null;
671
-
672
- const row = result[0];
673
-
674
- // Fetch EAV attributes
675
- const eavAttributes = validAttributes.filter(
676
- (attr) => attr.storage_type === AttributeStorageType.EAV,
677
- );
678
- if (eavAttributes.length > 0) {
679
- for (const attr of eavAttributes) {
680
- if (this.eavService.isTypeSupported(attr.db_datatype)) {
681
- const eavData = await this.eavService.findOne(attr.db_datatype, {
682
- entity_type: entityType,
683
- entity_id: id,
684
- key: attr.attribute_key,
685
- });
686
-
687
- if (eavData) {
688
- row[attr.attribute_key] = eavData.value;
689
- }
690
- }
691
- }
692
- }
693
-
694
- // Convert boolean columns (1/0) into true/false
695
- for (const attr of validAttributes) {
696
- if (
697
- attr.db_datatype == 'boolean' &&
698
- row[attr.attribute_key] !== undefined
699
- ) {
700
- row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
701
- } else if (
702
- attr.element_type == 'upload' &&
703
- row[attr.attribute_key] !== undefined
704
- ) {
705
- row[attr.attribute_key] =
706
- row[attr.attribute_key] != null
707
- ? await this.mediaDataService.getMediaDownloadUrl(
708
- Number(row[attr.attribute_key]),
709
- loggedInUser,
710
- )
711
- : null;
712
- }
713
- }
714
-
715
- return row;
716
- }
717
-
718
- // -----------------------------
719
- //TODO : make it normal getEntity function make another function if for resolve data
720
- async getEntity(
721
- entityType: string,
722
- id: number | string,
723
- loggedInUser: any,
724
- ): Promise<any> {
725
- const enterprise_id = loggedInUser.enterprise_id;
726
-
727
- const entityMaster =
728
- await this.entityMasterRepo.getEntityByMappedEntityType(
729
- entityType,
730
- enterprise_id,
731
- );
732
- if (!entityMaster) return null;
733
-
734
- const validAttributes = await this.getAttributeCodes(
735
- entityType,
736
- enterprise_id,
737
- );
738
-
739
- // const entityRepo = this.reflectionHelper.getRepoService(entityMaster?.entity_data_class);
740
-
741
- // Filter out EAV attributes from SQL query
742
- const dbColumns = validAttributes.filter(
743
- (attr) => attr.storage_type !== AttributeStorageType.EAV,
744
- );
745
- const columns = dbColumns.map((attr) => `t.${attr.attribute_key}`);
746
-
747
- // Add id if not present (required)
748
- if (!columns.some((c) => c.includes('.id'))) {
749
- columns.push('t.id');
750
- }
751
-
752
- // const result = await entityRepo.find({
753
- // where: {
754
- // id: id
755
- // },
756
- // select: columns
757
- // });
758
- const selectQuery = `SELECT ${columns.join(', ')}
759
- FROM ${this.schema}.${entityMaster.db_table_name} t
760
- WHERE id = $1`;
761
-
762
- const result = await this.entityManager.query(selectQuery, [id]);
763
- if (!result.length) return null;
764
-
765
- const row = result[0];
766
-
767
- // Fetch EAV attributes
768
- const eavAttributes = validAttributes.filter(
769
- (attr) => attr.storage_type === AttributeStorageType.EAV,
770
- );
771
- if (eavAttributes.length > 0) {
772
- for (const attr of eavAttributes) {
773
- if (this.eavService.isTypeSupported(attr.db_datatype)) {
774
- const eavData = await this.eavService.findOne(attr.db_datatype, {
775
- entity_type: entityType,
776
- entity_id: id,
777
- key: attr.attribute_key,
778
- });
779
-
780
- if (eavData) {
781
- row[attr.attribute_key] = eavData.value;
782
- }
783
- }
784
- }
785
- }
786
-
787
- // Convert boolean columns (1/0) into true/false
788
- for (const attr of validAttributes) {
789
- if (
790
- attr.db_datatype == 'boolean' &&
791
- row[attr.attribute_key] !== undefined
792
- ) {
793
- row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
794
- } else if (
795
- attr.element_type == 'upload' &&
796
- row[attr.attribute_key] !== undefined
797
- ) {
798
- row[attr.attribute_key] =
799
- row[attr.attribute_key] != null
800
- ? await this.mediaDataService.getMediaDownloadUrl(
801
- Number(row[attr.attribute_key]),
802
- loggedInUser,
803
- )
804
- : null;
805
- }
806
- }
807
-
808
- return row;
809
- }
810
-
811
- private async getEntitySourceTableName(
812
- entityType: string,
813
- enterprise_id: string,
814
- ): Promise<string> {
815
- const result = await this.entityMasterRepo.getEntityByMappedEntityType(
816
- entityType,
817
- enterprise_id,
818
- );
819
-
820
- if (!result) {
821
- console.log(`Entity type '${entityType}' not found in frm_entity_master`);
822
- throw new BadRequestException();
823
- }
824
-
825
- return result.data_source;
826
- }
827
-
828
- // -----------------------------
829
- private async getTableName(
830
- entityType: string,
831
- enterprise_id: string,
832
- ): Promise<string> {
833
- let entityMaster = await this.entityMasterRepo.getEntityByMappedEntityType(
834
- entityType,
835
- enterprise_id,
836
- );
837
-
838
- if (!entityMaster) {
839
- console.log(`Entity type '${entityType}' not found in frm_entity_master`);
840
- throw new BadRequestException();
841
- }
842
-
843
- if (entityMaster.storage_type === StorageType.SELF) {
844
- return entityMaster.db_table_name;
845
- } else {
846
- return 'frm_entity_dynamic';
847
- }
848
- }
849
-
850
- private async getAttributeCodes(
851
- entityType: string,
852
- enterprise_id: string,
853
- isHidden = true,
854
- ) {
855
- const attributeMasterRepo =
856
- this.reflectionHelper.getRepoService('AttributeMaster');
857
-
858
- const qb = attributeMasterRepo
859
- .createQueryBuilder('fea')
860
- .select('fea.attribute_key', 'attribute_key')
861
- .addSelect('MAX(fea.db_datatype)', 'db_datatype')
862
- .addSelect('MAX(fea.element_type)', 'element_type')
863
- .addSelect('MAX(fea.storage_type)', 'storage_type')
864
- .addSelect('bool_or(fea.is_hidden)', 'is_hidden')
865
- .where('fea.mapped_entity_type = :entityType', { entityType })
866
- .andWhere('fea.enterprise_id = :enterprise_id', { enterprise_id });
867
-
868
- if (isHidden) {
869
- qb.andWhere('(fea.is_hidden IS NULL OR fea.is_hidden = false)');
870
- }
871
-
872
- qb.groupBy('fea.attribute_key');
873
-
874
- const result = await qb.getRawMany();
875
-
876
- return result.map((row: any) => ({
877
- attribute_key: row.attribute_key,
878
- db_datatype: row.db_datatype,
879
- element_type: row.element_type,
880
- storage_type: row.storage_type,
881
- is_hidden: row.is_hidden != null ? row.is_hidden === true : undefined,
882
- }));
883
- }
884
-
885
- async deleteEntity(
886
- entityType: string,
887
- id: number | string,
888
- loggedInUser: any,
889
- ): Promise<any> {
890
- const enterprise_id = loggedInUser.enterprise_id;
891
-
892
- const tableName = await this.getTableName(entityType, enterprise_id);
893
-
894
- // Delete EAV records first
895
- const validAttributes = await this.getAttributeCodes(
896
- entityType,
897
- enterprise_id,
898
- false,
899
- );
900
- const eavAttributes = validAttributes.filter(
901
- (attr) => attr.storage_type === AttributeStorageType.EAV,
902
- );
903
-
904
- if (eavAttributes.length > 0) {
905
- // Group by data type to minimize calls
906
- const dataTypes = [
907
- ...new Set(eavAttributes.map((attr) => attr.db_datatype)),
908
- ];
909
-
910
- for (const dataType of dataTypes) {
911
- if (this.eavService.isTypeSupported(dataType)) {
912
- // We need to delete all attributes for this entity_id and data source
913
- // Since delete accepts key, we iterate over keys or finding a way to delete all for entity
914
- // The current EAV service delete method requires a key.
915
- // Ideally EAV service should support delete by entity_id alone, but sticking to interface:
916
- const attrsOfType = eavAttributes.filter(
917
- (attr) => attr.db_datatype === dataType,
918
- );
919
- for (const attr of attrsOfType) {
920
- await this.eavService.delete(dataType, {
921
- entity_type: entityType,
922
- entity_id: id,
923
- key: attr.attribute_key,
924
- });
925
- }
926
- }
927
- }
928
- }
929
-
930
- const deleteQuery = `DELETE
931
- FROM ${this.schema}.${tableName}
932
- WHERE id = $1`;
933
- const result = await this.entityManager.query(deleteQuery, [id]);
934
- return result;
935
- }
936
-
937
- // -----------------------------
938
-
939
- async getEntitiesDropdownList(
940
- loggedInUser: any,
941
- appcode?: string,
942
- ): Promise<any> {
943
- const entityMasters =
944
- await this.entityMasterRepo.findByEnterpriseIdAndAppCode(
945
- loggedInUser.enterprise_id,
946
- appcode,
947
- );
948
-
949
- let dropdown = [] as any;
950
- entityMasters.map((entityMaster) =>
951
- dropdown.push({
952
- label: entityMaster.name,
953
- value: entityMaster.mapped_entity_type,
954
- }),
955
- );
956
-
957
- return dropdown;
958
- }
959
-
960
- async getCode(entityType: string, loggedInUser: any): Promise<string> {
961
- const enterprise_id = loggedInUser.enterprise_id;
962
-
963
- // 1. Get db_table_name from entity master
964
-
965
- const result = await this.entityMasterRepo.getEntityByMappedEntityType(
966
- entityType,
967
- enterprise_id,
968
- );
969
-
970
- if (!result) {
971
- throw new Error(
972
- `Entity type '${entityType}' not found in frm_entity_master for enterprise '${enterprise_id}'`,
973
- );
974
- }
975
-
976
- const tableName = result.db_table_name;
977
-
978
- // 2. Get current max sequence number from that table
979
- const seqResult = await this.entityManager.query(
980
- `SELECT MAX(id) AS max_seq_no
981
- FROM ${this.schema}.${tableName}
982
- WHERE entity_type = $1`,
983
- [entityType],
984
- );
985
-
986
- let maxSeqNo = seqResult?.[0]?.max_seq_no
987
- ? Number(seqResult[0].max_seq_no)
988
- : 0;
989
-
990
- maxSeqNo += 1;
991
-
992
- // 3. Return generated code
993
- return `${entityType}${maxSeqNo}`;
994
- }
995
-
996
- async getResolvedEntity(
997
- id: number,
998
- entity: string,
999
- loggedInUser: UserData,
1000
- ): Promise<any> {
1001
- const leadData = await this.getEntityData(entity, id, loggedInUser);
1002
-
1003
- const { mappedEntities, ...data } = leadData as any;
1004
-
1005
- const resolvedData = await this.resolverService.getResolvedData(
1006
- loggedInUser,
1007
- data,
1008
- entity,
1009
- );
1010
-
1011
- if (mappedEntities) {
1012
- resolvedData.mappedEntities = {};
1013
- for (const [entityType, entities] of Object.entries(mappedEntities)) {
1014
- if (Array.isArray(entities)) {
1015
- resolvedData.mappedEntities[entityType] = [];
1016
- for (const item of entities) {
1017
- const resolvedItem = await this.resolverService.getResolvedData(
1018
- loggedInUser,
1019
- item,
1020
- entityType,
1021
- );
1022
- resolvedData.mappedEntities[entityType].push(resolvedItem);
1023
- }
1024
- } else {
1025
- resolvedData.mappedEntities[entityType] =
1026
- await this.resolverService.getResolvedData(
1027
- loggedInUser,
1028
- entities,
1029
- entityType,
1030
- );
1031
- }
1032
- }
1033
- }
1034
-
1035
- return resolvedData;
1036
- }
1037
- }
1
+ import { BadRequestException, Injectable } from '@nestjs/common';
2
+ import { STATUS_ACTIVE } from 'src/constant/global.constant';
3
+ import { EntityManager, In } from 'typeorm';
4
+ import { UserData } from 'src/module/auth/dto/user.dto';
5
+ import { MediaDataService } from './media-data.service';
6
+ import { EntityMasterRepository } from '../repository/entity-master.repository';
7
+ import { ConfigService } from '@nestjs/config';
8
+ import { EntityServiceImpl } from './entity-service-impl.service';
9
+ import { EAVService } from '../../eav/service/eav.service';
10
+ import { AttributeStorageType } from '../../../constant/attribute.constant';
11
+ import { StorageType } from '../../../constant/entity.constant';
12
+
13
+ @Injectable()
14
+ export class EntityDynamicService extends EntityServiceImpl {
15
+ constructor(
16
+ private readonly entityManager: EntityManager,
17
+ private readonly mediaDataService: MediaDataService,
18
+ private readonly entityMasterRepo: EntityMasterRepository,
19
+ private readonly configService: ConfigService,
20
+ private readonly eavService: EAVService,
21
+ ) {
22
+ super();
23
+ }
24
+
25
+ schema = this.configService.get('DB_SCHEMA');
26
+
27
+ // -----------------------------
28
+ async createEntityData(
29
+ entityType: string,
30
+ entityData: Record<string, any>,
31
+ loggedInUser: any,
32
+ mainID?: number,
33
+ ): Promise<any> {
34
+ const enterprise_id = loggedInUser.enterprise_id;
35
+ const entityMaster =
36
+ await this.entityMasterRepo.getEntityByMappedEntityType(
37
+ entityType,
38
+ loggedInUser.enterprise_id,
39
+ );
40
+
41
+ if (!entityMaster) {
42
+ throw new BadRequestException(
43
+ `Entity With ${entityType} entity type not found`,
44
+ );
45
+ }
46
+ let tableName: string;
47
+ if (StorageType.SELF === entityMaster.storage_type) {
48
+ tableName = entityMaster.db_table_name;
49
+ } else {
50
+ tableName = 'frm_entity_dynamic';
51
+ }
52
+
53
+ const validAttributes = await this.getAttributeCodes(
54
+ entityType,
55
+ enterprise_id,
56
+ );
57
+
58
+ // -------------------------------------------------------
59
+ // AUTO fields
60
+ // -------------------------------------------------------
61
+ entityData.created_date = new Date();
62
+
63
+ if (loggedInUser) {
64
+ entityData.created_by = loggedInUser.id;
65
+
66
+ if (!entityData.enterprise_id)
67
+ entityData.enterprise_id = loggedInUser.enterprise_id;
68
+
69
+ if (!entityData.level_type)
70
+ entityData.level_type = loggedInUser.level_type;
71
+
72
+ if (!entityData.level_id) entityData.level_id = loggedInUser.level_id;
73
+
74
+ if (!entityData.entity_type) entityData.entity_type = entityType;
75
+ }
76
+
77
+ // -------------------------------------------------------
78
+ // STATUS
79
+ // -------------------------------------------------------
80
+ const listMasterItemsRepo =
81
+ this.reflectionHelper.getRepoService('ListMasterItems');
82
+ const statusList = listMasterItemsRepo.find({
83
+ where: {
84
+ code: STATUS_ACTIVE,
85
+ enterprise_id: enterprise_id,
86
+ },
87
+ });
88
+
89
+ if (!entityData.status) entityData.status = statusList[0]?.id;
90
+
91
+ // -------------------------------------------------------
92
+ // AUTO-CODE GENERATION (POSTGRES SAFE)
93
+ // -------------------------------------------------------
94
+
95
+
96
+ const maxSeqResult = this.entityManager.query(
97
+ `SELECT MAX(id) as seq_no
98
+ FROM ${this.schema}.${tableName}`,
99
+ );
100
+
101
+ let maxSeq = Number(maxSeqResult[0]?.seq_no) || 0;
102
+ maxSeq++;
103
+ entityData.code = `${entityData.entity_type}${maxSeq}`;
104
+
105
+ // -------------------------------------------------------
106
+ // Parent ID
107
+ // -------------------------------------------------------
108
+ if (mainID) {
109
+ entityData.parent_id = mainID;
110
+ }
111
+
112
+ // -------------------------------------------------------
113
+ // BYPASS COLUMNS
114
+ // -------------------------------------------------------
115
+ const bypassColumns = [
116
+ 'created_date',
117
+ 'created_by',
118
+ 'enterprise_id',
119
+ 'level_type',
120
+ 'level_id',
121
+ 'status',
122
+ 'entity_type',
123
+ 'code',
124
+ 'parent_id',
125
+ ];
126
+
127
+ for (const col of bypassColumns) {
128
+ if (!validAttributes.some((a) => a.attribute_key === col)) {
129
+ validAttributes.push({
130
+ attribute_key: col,
131
+ is_hidden: false,
132
+ db_datatype: 'text',
133
+ element_type: 'text',
134
+ storage_type: AttributeStorageType.DB_COL,
135
+ });
136
+ }
137
+ }
138
+
139
+ // -------------------------------------------------------
140
+ // BUILD INSERT QUERY (POSTGRES FORMAT)
141
+ // -------------------------------------------------------
142
+ const columns: string[] = [];
143
+ const values: any[] = [];
144
+ let idx = 1;
145
+ const placeholders: string[] = [];
146
+ const eavAttributes: any[] = [];
147
+
148
+ for (const attr of validAttributes) {
149
+ if (attr.attribute_key === 'id' && !entityData.id) continue;
150
+
151
+ if (
152
+ attr.storage_type.toLowerCase() ===
153
+ AttributeStorageType.EAV.toLowerCase()
154
+ ) {
155
+ if (entityData[attr.attribute_key] !== undefined) {
156
+ eavAttributes.push({
157
+ key: attr.attribute_key,
158
+ value: entityData[attr.attribute_key],
159
+ data_type: attr.db_datatype,
160
+ });
161
+ }
162
+ } else {
163
+ columns.push(attr.attribute_key);
164
+ values.push(entityData[attr.attribute_key] ?? null);
165
+ placeholders.push(`$${idx++}`);
166
+ }
167
+ }
168
+
169
+ const colList = columns.map((c) => `"${c}"`).join(', ');
170
+ const placeholderList = placeholders.join(', ');
171
+
172
+ const sql = `
173
+ INSERT INTO ${this.schema}.${tableName} (${colList})
174
+ VALUES (${placeholderList}) RETURNING *
175
+ `;
176
+
177
+ const result = await this.entityManager.query(sql, values);
178
+ const newId = result[0]?.id;
179
+
180
+ // Save EAV attributes
181
+ if (newId && eavAttributes.length > 0) {
182
+ for (const eavAttr of eavAttributes) {
183
+ if (this.eavService.isTypeSupported(eavAttr.data_type)) {
184
+ await this.eavService.create(
185
+ eavAttr.data_type,
186
+ {
187
+ entity_type: entityType,
188
+ entity_id: newId,
189
+ key: eavAttr.key,
190
+ value: eavAttr.value,
191
+ },
192
+ loggedInUser?.id,
193
+ );
194
+ }
195
+ }
196
+ }
197
+
198
+ return result[0];
199
+ }
200
+
201
+ // ----------------------------- get entity with relations
202
+
203
+ // ----------------------------- create entity with relations
204
+ async createEntity(
205
+ data: Record<string, any>,
206
+ loggedInUser: any,
207
+ ): Promise<any> {
208
+ const entityType = data.entity_type;
209
+ const enterpriseId = loggedInUser.enterprise_id;
210
+
211
+ const repo = this.reflectionHelper.getRepoService('EntityRelation');
212
+
213
+ const getRelation = await repo.find({
214
+ where: {
215
+ enterprise_id: enterpriseId,
216
+ source_entity_type: entityType,
217
+ },
218
+ });
219
+
220
+ const { mappedEntities, ...mainData } = data;
221
+
222
+ // create main entity
223
+ const createdEntityData = await this.createEntityData(
224
+ entityType,
225
+ mainData,
226
+ loggedInUser,
227
+ );
228
+ const mainID = createdEntityData.insertId || createdEntityData.id;
229
+
230
+ if (mappedEntities && getRelation.length > 0) {
231
+ for (const relation of getRelation) {
232
+ const targetEntityType = relation.target_entity_type;
233
+ const relationType = relation.relation_type;
234
+
235
+ if (!mappedEntities[targetEntityType]) continue;
236
+
237
+ // normalize: always array
238
+ const entityDataArray = Array.isArray(mappedEntities[targetEntityType])
239
+ ? mappedEntities[targetEntityType]
240
+ : [mappedEntities[targetEntityType]];
241
+
242
+ for (const item of entityDataArray) {
243
+ const itemWithRef = {
244
+ ...item,
245
+ entity_type: targetEntityType,
246
+ };
247
+
248
+ const createdRelatedEntity = await this.createEntityData(
249
+ targetEntityType,
250
+ itemWithRef,
251
+ loggedInUser,
252
+ mainID, // this will pass for parent_id
253
+ );
254
+
255
+ const relationRepo =
256
+ this.reflectionHelper.getRepoService('EntityRelationData');
257
+
258
+ await relationRepo.save({
259
+ enterprise_id: enterpriseId,
260
+ source_entity_id: mainID,
261
+ source_entity_type: entityType,
262
+ target_entity_id: createdRelatedEntity.id,
263
+ target_entity_type: targetEntityType,
264
+ relation_type: relationType,
265
+ });
266
+ }
267
+ }
268
+ }
269
+
270
+ return {
271
+ mainEntity: {
272
+ id: mainID,
273
+ entityType,
274
+ data: createdEntityData,
275
+ },
276
+ };
277
+ }
278
+
279
+ // ----------------------------- get entity with relations
280
+ async getEntityData(
281
+ entityType: string,
282
+ id: number | string,
283
+ loggedInUser: any,
284
+ resolved?: boolean,
285
+ ): Promise<any> {
286
+ let mainEntity = await this.getEntityByDataSource(
287
+ entityType,
288
+ id,
289
+ loggedInUser,
290
+ );
291
+
292
+ if (resolved) {
293
+ mainEntity = await this.resolverService.getResolvedData(
294
+ loggedInUser,
295
+ mainEntity,
296
+ entityType,
297
+ );
298
+ }
299
+
300
+ const relationRepo = this.reflectionHelper.getRepoService('EntityRelation');
301
+ const relatedEntityRepo =
302
+ this.reflectionHelper.getRepoService('EntityRelationData');
303
+
304
+ const relations = await relationRepo.find({
305
+ where: {
306
+ source_entity_type: entityType,
307
+ enterprise_id: loggedInUser.enterprise_id,
308
+ },
309
+ });
310
+
311
+ const targetTypes = relations.map((r) => r.target_entity_type);
312
+
313
+ if (targetTypes.length === 0) {
314
+ return {
315
+ entity_type: entityType,
316
+ ...mainEntity,
317
+ };
318
+ }
319
+
320
+ const relatedEntities = await relatedEntityRepo.find({
321
+ where: {
322
+ source_entity_id: id,
323
+ target_entity_type: In(targetTypes),
324
+ },
325
+ });
326
+
327
+ // Format response to match create entity structure
328
+ const response: any = {
329
+ entity_type: entityType,
330
+ ...mainEntity,
331
+ };
332
+
333
+ if (relatedEntities.length > 0) {
334
+ response.mappedEntities = await this.formatMappedEntities(
335
+ relatedEntities,
336
+ loggedInUser,
337
+ resolved,
338
+ );
339
+ }
340
+
341
+ return response;
342
+ }
343
+
344
+ // ----------------------------- formatMappedEntities
345
+ async formatMappedEntities(
346
+ relatedEntities: any[],
347
+ loggedInUser: any,
348
+ resolved?: boolean,
349
+ ): Promise<any> {
350
+ const mappedEntities: any = {};
351
+
352
+ for (const relation of relatedEntities) {
353
+ const targetEntityType = relation.target_entity_type;
354
+ const targetEntityId = relation.target_entity_id;
355
+
356
+ const entityData = await this.getEntityData(
357
+ targetEntityType,
358
+ targetEntityId,
359
+ loggedInUser,
360
+ resolved,
361
+ );
362
+
363
+ if (!mappedEntities[targetEntityType]) {
364
+ mappedEntities[targetEntityType] = [];
365
+ }
366
+
367
+ mappedEntities[targetEntityType].push(entityData);
368
+ }
369
+
370
+ return mappedEntities;
371
+ }
372
+
373
+ // ----------------------------- update with relations
374
+
375
+ // ----------------------------- update entity with relations
376
+ async updateEntity(
377
+ data: Record<string, any>,
378
+ loggedInUser: any,
379
+ ): Promise<any> {
380
+ const entityType = data.entity_type;
381
+ const enterpriseId = loggedInUser.enterprise_id;
382
+ const { mappedEntities, ...mainData } = data;
383
+
384
+ // Update main entity
385
+ const updatedMainEntity = await this.updateEntityData(
386
+ entityType,
387
+ data.id,
388
+ mainData,
389
+ loggedInUser,
390
+ );
391
+
392
+ const updatedRelations: Record<string, any> = {};
393
+
394
+ if (mappedEntities) {
395
+ const entityRelationRepo =
396
+ this.reflectionHelper.getRepoService('EntityRelation');
397
+ const getRelationDefs = await entityRelationRepo.find({
398
+ where: {
399
+ enterprise_id: enterpriseId,
400
+ source_entity_type: entityType,
401
+ },
402
+ });
403
+
404
+ for (const [targetEntityType, rawEntityData] of Object.entries(
405
+ mappedEntities,
406
+ )) {
407
+ const relationDef = getRelationDefs.find(
408
+ (r) => r.target_entity_type === targetEntityType,
409
+ );
410
+ if (!relationDef) continue;
411
+
412
+ const relationType = relationDef.relation_type;
413
+ const entityArray = Array.isArray(rawEntityData)
414
+ ? rawEntityData
415
+ : [rawEntityData];
416
+
417
+ // Delete previous relations and related entities
418
+ // Create/update new entities & relations
419
+ const updatedEntities: any[] = [];
420
+
421
+ for (const item of entityArray) {
422
+ let targetEntityId;
423
+ let entityData;
424
+
425
+ if (item.id) {
426
+ // Update existing entity
427
+ await this.updateEntityData(
428
+ targetEntityType,
429
+ item.id,
430
+ item,
431
+ loggedInUser,
432
+ Number(data.id), // pass main entity id as parent_id
433
+ );
434
+ targetEntityId = item.id;
435
+ entityData = await this.getEntity(
436
+ targetEntityType,
437
+ targetEntityId,
438
+ loggedInUser,
439
+ );
440
+ } else {
441
+ // Create new entity
442
+ const createdEntity = await this.createEntityData(
443
+ targetEntityType,
444
+ item,
445
+ loggedInUser,
446
+ Number(data.id), // pass main entity id as parent_id
447
+ );
448
+ targetEntityId = createdEntity.insertId || createdEntity.id;
449
+ entityData = await this.getEntity(
450
+ targetEntityType,
451
+ targetEntityId,
452
+ loggedInUser,
453
+ );
454
+
455
+ // Insert relation as per new entity created
456
+ const entityRelationDataRepo =
457
+ this.reflectionHelper.getRepoService('EntityRelationData');
458
+ await entityRelationDataRepo.save({
459
+ enterprise_id: enterpriseId,
460
+ source_entity_id: data.id,
461
+ source_entity_type: entityType,
462
+ target_entity_id: targetEntityId,
463
+ target_entity_type: targetEntityType,
464
+ relation_type: relationType,
465
+ });
466
+ }
467
+
468
+ if (relationType === 'ONE_TO_MANY') {
469
+ updatedEntities.push(entityData);
470
+ } else if (
471
+ relationType === 'ONE_TO_ONE' ||
472
+ relationType === 'MANY_TO_ONE'
473
+ ) {
474
+ updatedEntities[0] = entityData; // single object
475
+ }
476
+ }
477
+
478
+ // Assign to response mappedEntities
479
+ updatedRelations[targetEntityType] =
480
+ relationType === 'ONE_TO_MANY' ? updatedEntities : updatedEntities[0];
481
+ }
482
+ }
483
+
484
+ return {
485
+ mainEntity: {
486
+ id: data.id,
487
+ entityType,
488
+ data: updatedMainEntity,
489
+ },
490
+ relatedEntities: updatedRelations,
491
+ };
492
+ }
493
+
494
+ // -----------------------------
495
+ async updateEntityData(
496
+ entityType: string,
497
+ id: number | string,
498
+ entityData: Record<string, any>,
499
+ loggedInUser: any,
500
+ mainID?: number,
501
+ ): Promise<any> {
502
+ const enterprise_id = loggedInUser.enterprise_id;
503
+
504
+ const tableName = await this.getTableName(entityType, enterprise_id);
505
+ const validAttributes = await this.getAttributeCodes(
506
+ entityType,
507
+ enterprise_id,
508
+ );
509
+
510
+ const updates: string[] = [];
511
+ const values: any[] = [];
512
+ let idx = 1;
513
+
514
+ // Auto fields
515
+ entityData.modified_date = new Date();
516
+ if (loggedInUser) {
517
+ entityData.modified_by = loggedInUser.id;
518
+
519
+ if (!entityData.enterprise_id)
520
+ entityData.enterprise_id = loggedInUser.enterprise_id;
521
+
522
+ if (!entityData.level_type)
523
+ entityData.level_type = loggedInUser.level_type;
524
+
525
+ if (!entityData.level_id) entityData.level_id = loggedInUser.level_id;
526
+
527
+ if (!entityData.entity_type) entityData.entity_type = entityType;
528
+ }
529
+
530
+ if (mainID) {
531
+ entityData.parent_id = mainID;
532
+ }
533
+
534
+ // Add bypass columns if needed
535
+ const bypassColumns = [
536
+ 'created_date',
537
+ 'created_by',
538
+ 'modified_date',
539
+ 'modified_by',
540
+ 'enterprise_id',
541
+ 'level_type',
542
+ 'level_id',
543
+ 'status',
544
+ 'entity_type',
545
+ 'code',
546
+ 'parent_id',
547
+ ];
548
+
549
+ for (const col of bypassColumns) {
550
+ if (!validAttributes.some((attr) => attr.attribute_key === col)) {
551
+ validAttributes.push({
552
+ attribute_key: col,
553
+ db_datatype: 'text',
554
+ element_type: 'text',
555
+ is_hidden: false,
556
+ storage_type: AttributeStorageType.DB_COL,
557
+ });
558
+ }
559
+ }
560
+
561
+ const eavAttributes: any[] = [];
562
+
563
+ // Build SET clause
564
+ for (const key of Object.keys(entityData)) {
565
+ const attr = validAttributes.find((attr) => attr.attribute_key === key);
566
+ if (attr) {
567
+ if (
568
+ attr.storage_type.toLowerCase() ===
569
+ AttributeStorageType.EAV.toLowerCase()
570
+ ) {
571
+ eavAttributes.push({
572
+ key: attr.attribute_key,
573
+ value: entityData[key],
574
+ data_type: attr.db_datatype,
575
+ });
576
+ } else {
577
+ updates.push(`${key} = $${idx++}`);
578
+ values.push(entityData[key]);
579
+ }
580
+ }
581
+ }
582
+
583
+ if (updates.length === 0 && eavAttributes.length === 0) {
584
+ throw new Error('No valid attributes to update.');
585
+ }
586
+
587
+ let result;
588
+
589
+ if (updates.length > 0) {
590
+ // WHERE clause placeholder
591
+ const idPlaceholder = `$${idx}`;
592
+ values.push(id);
593
+
594
+ const updateQuery = `
595
+ UPDATE ${this.schema}.${tableName}
596
+ SET ${updates.join(', ')}
597
+ WHERE id = ${idPlaceholder}
598
+ `;
599
+
600
+ result = await this.entityManager.query(updateQuery, values);
601
+ }
602
+
603
+ // Process EAV Updates
604
+ if (eavAttributes.length > 0) {
605
+ for (const eavAttr of eavAttributes) {
606
+ if (this.eavService.isTypeSupported(eavAttr.data_type)) {
607
+ await this.eavService.upsert(
608
+ eavAttr.data_type,
609
+ {
610
+ entity_type: entityType,
611
+ entity_id: id,
612
+ key: eavAttr.key,
613
+ value: eavAttr.value,
614
+ },
615
+ loggedInUser?.id,
616
+ );
617
+ }
618
+ }
619
+ }
620
+
621
+ return result || { message: 'EAV updated' };
622
+ }
623
+
624
+ async getEntityByDataSource(
625
+ entityType: string,
626
+ id: number | string,
627
+ loggedInUser: any,
628
+ ): Promise<any> {
629
+ const enterprise_id = loggedInUser.enterprise_id;
630
+
631
+ const entityMaster = await this.entityMasterService.getEntityData(
632
+ entityType,
633
+ loggedInUser,
634
+ );
635
+
636
+ let dataSource: string;
637
+ if (StorageType.SELF === entityMaster.storage_type) {
638
+ dataSource = entityMaster.db_table_name;
639
+ } else {
640
+ dataSource = 'frm_entity_dynamic';
641
+ }
642
+
643
+ const validAttributes = await this.getAttributeCodes(
644
+ entityType,
645
+ enterprise_id,
646
+ false,
647
+ );
648
+
649
+ // Filter out EAV attributes from SQL query
650
+ const dbColumns = validAttributes.filter(
651
+ (attr) => attr.storage_type !== AttributeStorageType.EAV,
652
+ );
653
+ const columns = dbColumns
654
+ .map((attr) => `"${attr.attribute_key}"`)
655
+ .join(', ');
656
+
657
+ // Add id if not present (required)
658
+ // Note: If columns is empty (only EAV attributes), we still need to select something.
659
+ let selectColumns = columns;
660
+ if (!columns) {
661
+ selectColumns = 'id';
662
+ } else if (!dbColumns.some((c) => c.attribute_key === 'id')) {
663
+ selectColumns += ', id';
664
+ }
665
+
666
+ const selectQuery = `SELECT ${selectColumns}
667
+ FROM ${this.schema}.${dataSource}
668
+ WHERE id = $1`;
669
+
670
+ const result = await this.entityManager.query(selectQuery, [id]);
671
+ if (!result.length) return null;
672
+
673
+ const row = result[0];
674
+
675
+ // Fetch EAV attributes
676
+ const eavAttributes = validAttributes.filter(
677
+ (attr) => attr.storage_type === AttributeStorageType.EAV,
678
+ );
679
+ if (eavAttributes.length > 0) {
680
+ for (const attr of eavAttributes) {
681
+ if (this.eavService.isTypeSupported(attr.db_datatype)) {
682
+ const eavData = await this.eavService.findOne(attr.db_datatype, {
683
+ entity_type: entityType,
684
+ entity_id: id,
685
+ key: attr.attribute_key,
686
+ });
687
+
688
+ if (eavData) {
689
+ row[attr.attribute_key] = eavData.value;
690
+ }
691
+ }
692
+ }
693
+ }
694
+
695
+ // Convert boolean columns (1/0) into true/false
696
+ for (const attr of validAttributes) {
697
+ if (
698
+ attr.db_datatype == 'boolean' &&
699
+ row[attr.attribute_key] !== undefined
700
+ ) {
701
+ row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
702
+ } else if (
703
+ attr.element_type == 'upload' &&
704
+ row[attr.attribute_key] !== undefined
705
+ ) {
706
+ row[attr.attribute_key] =
707
+ row[attr.attribute_key] != null
708
+ ? await this.mediaDataService.getMediaDownloadUrl(
709
+ Number(row[attr.attribute_key]),
710
+ loggedInUser,
711
+ )
712
+ : null;
713
+ }
714
+ }
715
+
716
+ return row;
717
+ }
718
+
719
+ // -----------------------------
720
+ //TODO : make it normal getEntity function make another function if for resolve data
721
+ async getEntity(
722
+ entityType: string,
723
+ id: number | string,
724
+ loggedInUser: any,
725
+ ): Promise<any> {
726
+ const enterprise_id = loggedInUser.enterprise_id;
727
+
728
+ const entityMaster =
729
+ await this.entityMasterRepo.getEntityByMappedEntityType(
730
+ entityType,
731
+ enterprise_id,
732
+ );
733
+ if (!entityMaster) return null;
734
+
735
+ const validAttributes = await this.getAttributeCodes(
736
+ entityType,
737
+ enterprise_id,
738
+ );
739
+
740
+ // const entityRepo = this.reflectionHelper.getRepoService(entityMaster?.entity_data_class);
741
+
742
+ // Filter out EAV attributes from SQL query
743
+ const dbColumns = validAttributes.filter(
744
+ (attr) => attr.storage_type !== AttributeStorageType.EAV,
745
+ );
746
+ const columns = dbColumns.map((attr) => `t.${attr.attribute_key}`);
747
+
748
+ // Add id if not present (required)
749
+ if (!columns.some((c) => c.includes('.id'))) {
750
+ columns.push('t.id');
751
+ }
752
+
753
+ // const result = await entityRepo.find({
754
+ // where: {
755
+ // id: id
756
+ // },
757
+ // select: columns
758
+ // });
759
+ const selectQuery = `SELECT ${columns.join(', ')}
760
+ FROM ${this.schema}.${entityMaster.db_table_name} t
761
+ WHERE id = $1`;
762
+
763
+ const result = await this.entityManager.query(selectQuery, [id]);
764
+ if (!result.length) return null;
765
+
766
+ const row = result[0];
767
+
768
+ // Fetch EAV attributes
769
+ const eavAttributes = validAttributes.filter(
770
+ (attr) => attr.storage_type === AttributeStorageType.EAV,
771
+ );
772
+ if (eavAttributes.length > 0) {
773
+ for (const attr of eavAttributes) {
774
+ if (this.eavService.isTypeSupported(attr.db_datatype)) {
775
+ const eavData = await this.eavService.findOne(attr.db_datatype, {
776
+ entity_type: entityType,
777
+ entity_id: id,
778
+ key: attr.attribute_key,
779
+ });
780
+
781
+ if (eavData) {
782
+ row[attr.attribute_key] = eavData.value;
783
+ }
784
+ }
785
+ }
786
+ }
787
+
788
+ // Convert boolean columns (1/0) into true/false
789
+ for (const attr of validAttributes) {
790
+ if (
791
+ attr.db_datatype == 'boolean' &&
792
+ row[attr.attribute_key] !== undefined
793
+ ) {
794
+ row[attr.attribute_key] = row[attr.attribute_key] == 1 ? true : false;
795
+ } else if (
796
+ attr.element_type == 'upload' &&
797
+ row[attr.attribute_key] !== undefined
798
+ ) {
799
+ row[attr.attribute_key] =
800
+ row[attr.attribute_key] != null
801
+ ? await this.mediaDataService.getMediaDownloadUrl(
802
+ Number(row[attr.attribute_key]),
803
+ loggedInUser,
804
+ )
805
+ : null;
806
+ }
807
+ }
808
+
809
+ return row;
810
+ }
811
+
812
+ private async getEntitySourceTableName(
813
+ entityType: string,
814
+ enterprise_id: string,
815
+ ): Promise<string> {
816
+ const result = await this.entityMasterRepo.getEntityByMappedEntityType(
817
+ entityType,
818
+ enterprise_id,
819
+ );
820
+
821
+ if (!result) {
822
+ console.log(`Entity type '${entityType}' not found in frm_entity_master`);
823
+ throw new BadRequestException();
824
+ }
825
+
826
+ return result.data_source;
827
+ }
828
+
829
+ // -----------------------------
830
+ private async getTableName(
831
+ entityType: string,
832
+ enterprise_id: string,
833
+ ): Promise<string> {
834
+ let entityMaster = await this.entityMasterRepo.getEntityByMappedEntityType(
835
+ entityType,
836
+ enterprise_id,
837
+ );
838
+
839
+ if (!entityMaster) {
840
+ console.log(`Entity type '${entityType}' not found in frm_entity_master`);
841
+ throw new BadRequestException();
842
+ }
843
+
844
+ if (entityMaster.storage_type === StorageType.SELF) {
845
+ return entityMaster.db_table_name;
846
+ } else {
847
+ return 'frm_entity_dynamic';
848
+ }
849
+ }
850
+
851
+ private async getAttributeCodes(
852
+ entityType: string,
853
+ enterprise_id: string,
854
+ isHidden = true,
855
+ ) {
856
+ const attributeMasterRepo =
857
+ this.reflectionHelper.getRepoService('AttributeMaster');
858
+
859
+ const qb = attributeMasterRepo
860
+ .createQueryBuilder('fea')
861
+ .select('fea.attribute_key', 'attribute_key')
862
+ .addSelect('MAX(fea.db_datatype)', 'db_datatype')
863
+ .addSelect('MAX(fea.element_type)', 'element_type')
864
+ .addSelect('MAX(fea.storage_type)', 'storage_type')
865
+ .addSelect('bool_or(fea.is_hidden)', 'is_hidden')
866
+ .where('fea.mapped_entity_type = :entityType', { entityType })
867
+ .andWhere('fea.enterprise_id = :enterprise_id', { enterprise_id });
868
+
869
+ if (isHidden) {
870
+ qb.andWhere('(fea.is_hidden IS NULL OR fea.is_hidden = false)');
871
+ }
872
+
873
+ qb.groupBy('fea.attribute_key');
874
+
875
+ const result = await qb.getRawMany();
876
+
877
+ return result.map((row: any) => ({
878
+ attribute_key: row.attribute_key,
879
+ db_datatype: row.db_datatype,
880
+ element_type: row.element_type,
881
+ storage_type: row.storage_type,
882
+ is_hidden: row.is_hidden != null ? row.is_hidden === true : undefined,
883
+ }));
884
+ }
885
+
886
+ async deleteEntity(
887
+ entityType: string,
888
+ id: number | string,
889
+ loggedInUser: any,
890
+ ): Promise<any> {
891
+ const enterprise_id = loggedInUser.enterprise_id;
892
+
893
+ const tableName = await this.getTableName(entityType, enterprise_id);
894
+
895
+ // Delete EAV records first
896
+ const validAttributes = await this.getAttributeCodes(
897
+ entityType,
898
+ enterprise_id,
899
+ false,
900
+ );
901
+ const eavAttributes = validAttributes.filter(
902
+ (attr) => attr.storage_type === AttributeStorageType.EAV,
903
+ );
904
+
905
+ if (eavAttributes.length > 0) {
906
+ // Group by data type to minimize calls
907
+ const dataTypes = [
908
+ ...new Set(eavAttributes.map((attr) => attr.db_datatype)),
909
+ ];
910
+
911
+ for (const dataType of dataTypes) {
912
+ if (this.eavService.isTypeSupported(dataType)) {
913
+ // We need to delete all attributes for this entity_id and data source
914
+ // Since delete accepts key, we iterate over keys or finding a way to delete all for entity
915
+ // The current EAV service delete method requires a key.
916
+ // Ideally EAV service should support delete by entity_id alone, but sticking to interface:
917
+ const attrsOfType = eavAttributes.filter(
918
+ (attr) => attr.db_datatype === dataType,
919
+ );
920
+ for (const attr of attrsOfType) {
921
+ await this.eavService.delete(dataType, {
922
+ entity_type: entityType,
923
+ entity_id: id,
924
+ key: attr.attribute_key,
925
+ });
926
+ }
927
+ }
928
+ }
929
+ }
930
+
931
+ const deleteQuery = `DELETE
932
+ FROM ${this.schema}.${tableName}
933
+ WHERE id = $1`;
934
+ const result = await this.entityManager.query(deleteQuery, [id]);
935
+ return result;
936
+ }
937
+
938
+ // -----------------------------
939
+
940
+ async getEntitiesDropdownList(
941
+ loggedInUser: any,
942
+ appcode?: string,
943
+ ): Promise<any> {
944
+ const entityMasters =
945
+ await this.entityMasterRepo.findByEnterpriseIdAndAppCode(
946
+ loggedInUser.enterprise_id,
947
+ appcode,
948
+ );
949
+
950
+ let dropdown = [] as any;
951
+ entityMasters.map((entityMaster) =>
952
+ dropdown.push({
953
+ label: entityMaster.name,
954
+ value: entityMaster.mapped_entity_type,
955
+ }),
956
+ );
957
+
958
+ return dropdown;
959
+ }
960
+
961
+ async getCode(entityType: string, loggedInUser: any): Promise<string> {
962
+ const enterprise_id = loggedInUser.enterprise_id;
963
+
964
+ // 1. Get db_table_name from entity master
965
+
966
+ const result = await this.entityMasterRepo.getEntityByMappedEntityType(
967
+ entityType,
968
+ enterprise_id,
969
+ );
970
+
971
+ if (!result) {
972
+ throw new Error(
973
+ `Entity type '${entityType}' not found in frm_entity_master for enterprise '${enterprise_id}'`,
974
+ );
975
+ }
976
+
977
+ const tableName = result.db_table_name;
978
+
979
+ // 2. Get current max sequence number from that table
980
+ const seqResult = await this.entityManager.query(
981
+ `SELECT MAX(id) AS max_seq_no
982
+ FROM ${this.schema}.${tableName}
983
+ WHERE entity_type = $1`,
984
+ [entityType],
985
+ );
986
+
987
+ let maxSeqNo = seqResult?.[0]?.max_seq_no
988
+ ? Number(seqResult[0].max_seq_no)
989
+ : 0;
990
+
991
+ maxSeqNo += 1;
992
+
993
+ // 3. Return generated code
994
+ return `${entityType}${maxSeqNo}`;
995
+ }
996
+
997
+ async getResolvedEntity(
998
+ id: number,
999
+ entity: string,
1000
+ loggedInUser: UserData,
1001
+ ): Promise<any> {
1002
+ const leadData = await this.getEntityData(entity, id, loggedInUser);
1003
+
1004
+ const { mappedEntities, ...data } = leadData as any;
1005
+
1006
+ const resolvedData = await this.resolverService.getResolvedData(
1007
+ loggedInUser,
1008
+ data,
1009
+ entity,
1010
+ );
1011
+
1012
+ if (mappedEntities) {
1013
+ resolvedData.mappedEntities = {};
1014
+ for (const [entityType, entities] of Object.entries(mappedEntities)) {
1015
+ if (Array.isArray(entities)) {
1016
+ resolvedData.mappedEntities[entityType] = [];
1017
+ for (const item of entities) {
1018
+ const resolvedItem = await this.resolverService.getResolvedData(
1019
+ loggedInUser,
1020
+ item,
1021
+ entityType,
1022
+ );
1023
+ resolvedData.mappedEntities[entityType].push(resolvedItem);
1024
+ }
1025
+ } else {
1026
+ resolvedData.mappedEntities[entityType] =
1027
+ await this.resolverService.getResolvedData(
1028
+ loggedInUser,
1029
+ entities,
1030
+ entityType,
1031
+ );
1032
+ }
1033
+ }
1034
+ }
1035
+
1036
+ return resolvedData;
1037
+ }
1038
+ }