@open-mercato/core 0.6.6-develop.6257.1.6d0af84d26 → 0.6.6-develop.6286.1.d985c5c374

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 (208) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/carrier_shipment_idempotency_key/index.js +19 -0
  3. package/dist/generated/entities/carrier_shipment_idempotency_key/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +2 -1
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +10 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/catalog/lib/productResolution.js +45 -0
  9. package/dist/modules/catalog/lib/productResolution.js.map +7 -0
  10. package/dist/modules/communication_channels/workers/channel-import-history.js +1 -1
  11. package/dist/modules/communication_channels/workers/channel-import-history.js.map +2 -2
  12. package/dist/modules/currencies/api/fetch-configs/route.js +34 -0
  13. package/dist/modules/currencies/api/fetch-configs/route.js.map +2 -2
  14. package/dist/modules/currencies/components/CurrencyFetchingConfig.js +17 -15
  15. package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
  16. package/dist/modules/customers/api/companies/[id]/route.js +176 -161
  17. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  18. package/dist/modules/customers/api/people/[id]/route.js +75 -59
  19. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  20. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +17 -10
  21. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
  22. package/dist/modules/customers/components/detail/ActivitiesAddNewMenu.js +6 -4
  23. package/dist/modules/customers/components/detail/ActivitiesAddNewMenu.js.map +2 -2
  24. package/dist/modules/customers/components/detail/AiActionChips.js +5 -2
  25. package/dist/modules/customers/components/detail/AiActionChips.js.map +2 -2
  26. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +19 -21
  27. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
  28. package/dist/modules/data_sync/api/runs/[id]/cancel.js +1 -1
  29. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  30. package/dist/modules/data_sync/backend/data-sync/page.js +9 -45
  31. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  32. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +11 -17
  33. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  34. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +12 -10
  35. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  36. package/dist/modules/data_sync/lib/id-mapping.js +46 -1
  37. package/dist/modules/data_sync/lib/id-mapping.js.map +2 -2
  38. package/dist/modules/data_sync/lib/sync-engine.js +2 -2
  39. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  40. package/dist/modules/data_sync/lib/syncRunStatus.js +30 -0
  41. package/dist/modules/data_sync/lib/syncRunStatus.js.map +7 -0
  42. package/dist/modules/entities/api/records.js +6 -0
  43. package/dist/modules/entities/api/records.js.map +2 -2
  44. package/dist/modules/feature_toggles/api/global/route.js +17 -15
  45. package/dist/modules/feature_toggles/api/global/route.js.map +2 -2
  46. package/dist/modules/feature_toggles/api/openapi.js +2 -2
  47. package/dist/modules/feature_toggles/api/openapi.js.map +2 -2
  48. package/dist/modules/feature_toggles/commands/global.js +14 -0
  49. package/dist/modules/feature_toggles/commands/global.js.map +2 -2
  50. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +6 -0
  51. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  52. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +3 -1
  53. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +2 -2
  54. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +12 -5
  55. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +2 -2
  56. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js +10 -1
  57. package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js.map +2 -2
  58. package/dist/modules/payment_gateways/api/cancel/route.js +5 -0
  59. package/dist/modules/payment_gateways/api/cancel/route.js.map +2 -2
  60. package/dist/modules/payment_gateways/api/capture/route.js +5 -0
  61. package/dist/modules/payment_gateways/api/capture/route.js.map +2 -2
  62. package/dist/modules/payment_gateways/api/refund/route.js +5 -0
  63. package/dist/modules/payment_gateways/api/refund/route.js.map +2 -2
  64. package/dist/modules/payment_gateways/lib/gateway-service.js +52 -25
  65. package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
  66. package/dist/modules/payment_gateways/lib/status-machine.js +13 -0
  67. package/dist/modules/payment_gateways/lib/status-machine.js.map +2 -2
  68. package/dist/modules/perspectives/api/[tableId]/route.js +8 -2
  69. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  70. package/dist/modules/perspectives/data/entities.js +33 -3
  71. package/dist/modules/perspectives/data/entities.js.map +2 -2
  72. package/dist/modules/perspectives/migrations/Migration20260619120000_perspectives_live_row_uniqueness.js +63 -0
  73. package/dist/modules/perspectives/migrations/Migration20260619120000_perspectives_live_row_uniqueness.js.map +7 -0
  74. package/dist/modules/perspectives/services/perspectiveService.js +17 -0
  75. package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
  76. package/dist/modules/planner/commands/availability-weekly.js +33 -1
  77. package/dist/modules/planner/commands/availability-weekly.js.map +2 -2
  78. package/dist/modules/planner/components/AvailabilityRulesEditor.js +14 -2
  79. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  80. package/dist/modules/progress/api/active/route.js +1 -1
  81. package/dist/modules/progress/api/active/route.js.map +2 -2
  82. package/dist/modules/progress/lib/progressService.js.map +1 -1
  83. package/dist/modules/progress/lib/progressServiceImpl.js +33 -8
  84. package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
  85. package/dist/modules/query_index/api/status.js +19 -24
  86. package/dist/modules/query_index/api/status.js.map +3 -3
  87. package/dist/modules/query_index/lib/coverage.js +35 -0
  88. package/dist/modules/query_index/lib/coverage.js.map +2 -2
  89. package/dist/modules/query_index/lib/engine.js +11 -6
  90. package/dist/modules/query_index/lib/engine.js.map +2 -2
  91. package/dist/modules/resources/api/resource-types.js +5 -37
  92. package/dist/modules/resources/api/resource-types.js.map +2 -2
  93. package/dist/modules/resources/api/resourceTypeCounts.js +35 -0
  94. package/dist/modules/resources/api/resourceTypeCounts.js.map +7 -0
  95. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -1
  96. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +1 -1
  97. package/dist/modules/resources/backend/resources/resource-types/page.js +2 -1
  98. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  99. package/dist/modules/sales/components/documents/ReturnDialog.js +4 -1
  100. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  101. package/dist/modules/sales/components/documents/ShipmentDialog.js +17 -2
  102. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  103. package/dist/modules/sales/di.js +4 -0
  104. package/dist/modules/sales/di.js.map +2 -2
  105. package/dist/modules/sales/services/salesOrderService.js +26 -0
  106. package/dist/modules/sales/services/salesOrderService.js.map +7 -0
  107. package/dist/modules/shipping_carriers/api/shipments/route.js +8 -0
  108. package/dist/modules/shipping_carriers/api/shipments/route.js.map +2 -2
  109. package/dist/modules/shipping_carriers/data/entities.js +38 -0
  110. package/dist/modules/shipping_carriers/data/entities.js.map +2 -2
  111. package/dist/modules/shipping_carriers/data/validators.js +2 -1
  112. package/dist/modules/shipping_carriers/data/validators.js.map +2 -2
  113. package/dist/modules/shipping_carriers/lib/shipment-idempotency.js +76 -0
  114. package/dist/modules/shipping_carriers/lib/shipment-idempotency.js.map +7 -0
  115. package/dist/modules/shipping_carriers/lib/shipment-wizard/hooks/shipmentApi.js +2 -1
  116. package/dist/modules/shipping_carriers/lib/shipment-wizard/hooks/shipmentApi.js.map +2 -2
  117. package/dist/modules/shipping_carriers/lib/shipment-wizard/hooks/useShipmentWizard.js +20 -2
  118. package/dist/modules/shipping_carriers/lib/shipment-wizard/hooks/useShipmentWizard.js.map +2 -2
  119. package/dist/modules/shipping_carriers/lib/shipping-service.js +82 -43
  120. package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
  121. package/dist/modules/shipping_carriers/migrations/Migration20260618173616_shipping_carriers.js +14 -0
  122. package/dist/modules/shipping_carriers/migrations/Migration20260618173616_shipping_carriers.js.map +7 -0
  123. package/dist/modules/staff/lib/timesheets-ui/ListView.js +15 -6
  124. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
  125. package/dist/modules/translations/components/TranslationManager.js +9 -18
  126. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  127. package/generated/entities/carrier_shipment_idempotency_key/index.ts +8 -0
  128. package/generated/entities.ids.generated.ts +2 -1
  129. package/generated/entity-fields-registry.ts +10 -0
  130. package/package.json +9 -8
  131. package/src/modules/catalog/lib/productResolution.ts +75 -0
  132. package/src/modules/communication_channels/workers/channel-import-history.ts +1 -1
  133. package/src/modules/currencies/api/fetch-configs/route.ts +36 -0
  134. package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +20 -17
  135. package/src/modules/currencies/i18n/de.json +2 -1
  136. package/src/modules/currencies/i18n/en.json +2 -1
  137. package/src/modules/currencies/i18n/es.json +2 -1
  138. package/src/modules/currencies/i18n/pl.json +2 -1
  139. package/src/modules/customers/api/companies/[id]/route.ts +214 -189
  140. package/src/modules/customers/api/people/[id]/route.ts +106 -80
  141. package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +19 -12
  142. package/src/modules/customers/components/detail/ActivitiesAddNewMenu.tsx +8 -6
  143. package/src/modules/customers/components/detail/AiActionChips.tsx +6 -3
  144. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +16 -18
  145. package/src/modules/data_sync/api/runs/[id]/cancel.ts +1 -1
  146. package/src/modules/data_sync/backend/data-sync/page.tsx +11 -58
  147. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +13 -20
  148. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +10 -8
  149. package/src/modules/data_sync/lib/id-mapping.ts +58 -1
  150. package/src/modules/data_sync/lib/sync-engine.ts +2 -2
  151. package/src/modules/data_sync/lib/syncRunStatus.ts +39 -0
  152. package/src/modules/entities/api/records.ts +14 -0
  153. package/src/modules/feature_toggles/api/global/route.ts +16 -14
  154. package/src/modules/feature_toggles/api/openapi.ts +2 -2
  155. package/src/modules/feature_toggles/commands/global.ts +15 -0
  156. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +7 -0
  157. package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +2 -0
  158. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +14 -4
  159. package/src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts +15 -1
  160. package/src/modules/payment_gateways/api/cancel/route.ts +5 -0
  161. package/src/modules/payment_gateways/api/capture/route.ts +5 -0
  162. package/src/modules/payment_gateways/api/refund/route.ts +5 -0
  163. package/src/modules/payment_gateways/lib/gateway-service.ts +58 -25
  164. package/src/modules/payment_gateways/lib/status-machine.ts +16 -0
  165. package/src/modules/perspectives/api/[tableId]/route.ts +8 -2
  166. package/src/modules/perspectives/data/entities.ts +43 -3
  167. package/src/modules/perspectives/migrations/.snapshot-open-mercato.json +69 -25
  168. package/src/modules/perspectives/migrations/Migration20260619120000_perspectives_live_row_uniqueness.ts +65 -0
  169. package/src/modules/perspectives/services/perspectiveService.ts +17 -0
  170. package/src/modules/planner/commands/availability-weekly.ts +48 -1
  171. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +31 -10
  172. package/src/modules/progress/api/active/route.ts +1 -1
  173. package/src/modules/progress/lib/progressService.ts +2 -2
  174. package/src/modules/progress/lib/progressServiceImpl.ts +33 -8
  175. package/src/modules/query_index/api/status.ts +28 -32
  176. package/src/modules/query_index/lib/coverage.ts +63 -0
  177. package/src/modules/query_index/lib/engine.ts +37 -24
  178. package/src/modules/resources/api/resource-types.ts +4 -44
  179. package/src/modules/resources/api/resourceTypeCounts.ts +74 -0
  180. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +1 -1
  181. package/src/modules/resources/backend/resources/resource-types/page.tsx +1 -0
  182. package/src/modules/sales/components/documents/ReturnDialog.tsx +4 -1
  183. package/src/modules/sales/components/documents/ShipmentDialog.tsx +20 -2
  184. package/src/modules/sales/di.ts +6 -0
  185. package/src/modules/sales/services/salesOrderService.ts +38 -0
  186. package/src/modules/shipping_carriers/api/shipments/route.ts +8 -0
  187. package/src/modules/shipping_carriers/data/entities.ts +33 -0
  188. package/src/modules/shipping_carriers/data/validators.ts +1 -0
  189. package/src/modules/shipping_carriers/i18n/de.json +1 -0
  190. package/src/modules/shipping_carriers/i18n/en.json +1 -0
  191. package/src/modules/shipping_carriers/i18n/es.json +1 -0
  192. package/src/modules/shipping_carriers/i18n/pl.json +1 -0
  193. package/src/modules/shipping_carriers/lib/shipment-idempotency.ts +119 -0
  194. package/src/modules/shipping_carriers/lib/shipment-wizard/hooks/shipmentApi.ts +3 -1
  195. package/src/modules/shipping_carriers/lib/shipment-wizard/hooks/useShipmentWizard.ts +24 -2
  196. package/src/modules/shipping_carriers/lib/shipping-service.ts +87 -43
  197. package/src/modules/shipping_carriers/migrations/.snapshot-open-mercato.json +197 -0
  198. package/src/modules/shipping_carriers/migrations/Migration20260618173616_shipping_carriers.ts +14 -0
  199. package/src/modules/staff/i18n/de.json +1 -0
  200. package/src/modules/staff/i18n/en.json +1 -0
  201. package/src/modules/staff/i18n/es.json +1 -0
  202. package/src/modules/staff/i18n/pl.json +1 -0
  203. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +15 -7
  204. package/src/modules/translations/components/TranslationManager.tsx +17 -24
  205. package/src/modules/translations/i18n/de.json +1 -0
  206. package/src/modules/translations/i18n/en.json +1 -0
  207. package/src/modules/translations/i18n/es.json +1 -0
  208. package/src/modules/translations/i18n/pl.json +1 -0
@@ -414,102 +414,106 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
414
414
  userFeatures: undefined,
415
415
  })
416
416
 
417
- const profile = company.companyProfile
418
- ? await findOneWithDecryption(
419
- em,
420
- CustomerCompanyProfile,
421
- {
422
- id: company.companyProfile.id,
423
- tenantId: company.tenantId,
424
- organizationId: company.organizationId,
425
- },
426
- {},
427
- companyScope,
428
- )
429
- : await findOneWithDecryption(
430
- em,
431
- CustomerCompanyProfile,
432
- {
433
- entity: company,
434
- tenantId: company.tenantId,
435
- organizationId: company.organizationId,
436
- },
437
- {},
438
- companyScope,
439
- )
440
-
441
- const addresses = includeAddresses
442
- ? await findWithDecryption(
443
- em,
444
- CustomerAddress,
445
- {
446
- entity: company.id,
447
- tenantId: company.tenantId,
448
- organizationId: company.organizationId,
449
- },
450
- { orderBy: { isPrimary: 'desc', createdAt: 'desc' } },
451
- companyScope,
452
- )
453
- : []
454
- const tagAssignments = await findWithDecryption(
455
- em,
456
- CustomerTagAssignment,
457
- {
458
- entity: company.id,
459
- tenantId: company.tenantId,
460
- organizationId: company.organizationId,
461
- },
462
- { populate: ['tag'] },
463
- companyScope,
464
- )
465
- const labelAssignments = await findWithDecryption(
466
- em,
467
- CustomerLabelAssignment,
468
- {
469
- entity: company.id,
470
- tenantId: company.tenantId,
471
- organizationId: company.organizationId,
472
- },
473
- { populate: ['label'] },
474
- companyScope,
475
- )
476
-
477
- const comments = includeComments
478
- ? await findWithDecryption(
479
- em,
480
- CustomerComment,
481
- {
482
- entity: company.id,
483
- tenantId: company.tenantId,
484
- organizationId: company.organizationId,
485
- },
486
- { orderBy: { createdAt: 'desc' }, limit: 50 },
487
- companyScope,
488
- )
489
- : []
490
417
  const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos
491
- const canonicalInteractionRows = shouldLoadCanonicalInteractions
492
- ? await findWithDecryption(
493
- em,
494
- CustomerInteraction,
495
- interactionFlags.unified
496
- ? {
497
- entity: company.id,
498
- tenantId: company.tenantId,
499
- organizationId: company.organizationId,
500
- deletedAt: null,
501
- ...emailVisibilityFilter,
502
- }
503
- : {
504
- entity: company.id,
505
- tenantId: company.tenantId,
506
- organizationId: company.organizationId,
507
- ...emailVisibilityFilter,
508
- },
509
- { orderBy: { scheduledAt: 'asc', createdAt: 'desc' }, limit: 100 },
510
- companyScope,
511
- )
512
- : []
418
+
419
+ // These reads only depend on the resolved company + scope + email visibility
420
+ // filter, so dispatch them together to avoid a server-side request waterfall
421
+ // before the detail surface can render (issue #3203).
422
+ const [profile, addresses, tagAssignments, labelAssignments, comments, canonicalInteractionRows] = await Promise.all([
423
+ company.companyProfile
424
+ ? findOneWithDecryption(
425
+ em,
426
+ CustomerCompanyProfile,
427
+ {
428
+ id: company.companyProfile.id,
429
+ tenantId: company.tenantId,
430
+ organizationId: company.organizationId,
431
+ },
432
+ {},
433
+ companyScope,
434
+ )
435
+ : findOneWithDecryption(
436
+ em,
437
+ CustomerCompanyProfile,
438
+ {
439
+ entity: company,
440
+ tenantId: company.tenantId,
441
+ organizationId: company.organizationId,
442
+ },
443
+ {},
444
+ companyScope,
445
+ ),
446
+ includeAddresses
447
+ ? findWithDecryption(
448
+ em,
449
+ CustomerAddress,
450
+ {
451
+ entity: company.id,
452
+ tenantId: company.tenantId,
453
+ organizationId: company.organizationId,
454
+ },
455
+ { orderBy: { isPrimary: 'desc', createdAt: 'desc' } },
456
+ companyScope,
457
+ )
458
+ : Promise.resolve<CustomerAddress[]>([]),
459
+ findWithDecryption(
460
+ em,
461
+ CustomerTagAssignment,
462
+ {
463
+ entity: company.id,
464
+ tenantId: company.tenantId,
465
+ organizationId: company.organizationId,
466
+ },
467
+ { populate: ['tag'] },
468
+ companyScope,
469
+ ),
470
+ findWithDecryption(
471
+ em,
472
+ CustomerLabelAssignment,
473
+ {
474
+ entity: company.id,
475
+ tenantId: company.tenantId,
476
+ organizationId: company.organizationId,
477
+ },
478
+ { populate: ['label'] },
479
+ companyScope,
480
+ ),
481
+ includeComments
482
+ ? findWithDecryption(
483
+ em,
484
+ CustomerComment,
485
+ {
486
+ entity: company.id,
487
+ tenantId: company.tenantId,
488
+ organizationId: company.organizationId,
489
+ },
490
+ { orderBy: { createdAt: 'desc' }, limit: 50 },
491
+ companyScope,
492
+ )
493
+ : Promise.resolve<CustomerComment[]>([]),
494
+ shouldLoadCanonicalInteractions
495
+ ? findWithDecryption(
496
+ em,
497
+ CustomerInteraction,
498
+ interactionFlags.unified
499
+ ? {
500
+ entity: company.id,
501
+ tenantId: company.tenantId,
502
+ organizationId: company.organizationId,
503
+ deletedAt: null,
504
+ ...emailVisibilityFilter,
505
+ }
506
+ : {
507
+ entity: company.id,
508
+ tenantId: company.tenantId,
509
+ organizationId: company.organizationId,
510
+ ...emailVisibilityFilter,
511
+ },
512
+ { orderBy: { scheduledAt: 'asc', createdAt: 'desc' }, limit: 100 },
513
+ companyScope,
514
+ )
515
+ : Promise.resolve<CustomerInteraction[]>([]),
516
+ ])
513
517
  const canonicalActiveInteractions = canonicalInteractionRows.filter((interaction) => !interaction.deletedAt)
514
518
  const canonicalInteractions = shouldLoadCanonicalInteractions
515
519
  ? await hydrateCanonicalInteractions({
@@ -775,32 +779,35 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
775
779
  relatedPeople = Array.from(relatedPeopleById.values())
776
780
  }
777
781
 
778
- const entityCustomFieldValues = await loadCustomFieldValues({
779
- em,
780
- entityId: E.customers.customer_entity,
781
- recordIds: [company.id],
782
- tenantIdByRecord: { [company.id]: company.tenantId ?? null },
783
- organizationIdByRecord: { [company.id]: company.organizationId ?? null },
784
- tenantFallbacks: [
785
- company.tenantId ?? auth.tenantId ?? null,
786
- ].filter((v): v is string => !!v),
787
- })
788
- let profileCustomFieldValues: Record<string, Record<string, unknown>> = {}
782
+ // Entity custom fields, profile custom fields, and the routing lookup do not
783
+ // depend on each other (profileId is already resolved above), so load them in
784
+ // parallel instead of three sequential awaits (issue #3203).
789
785
  const profileId = profile?.id ?? null
790
- if (profileId) {
791
- profileCustomFieldValues = await loadCustomFieldValues({
786
+ const [entityCustomFieldValues, profileCustomFieldValues, routing] = await Promise.all([
787
+ loadCustomFieldValues({
792
788
  em,
793
- entityId: E.customers.customer_company_profile,
794
- recordIds: [profileId],
795
- tenantIdByRecord: { [profileId]: profile?.tenantId ?? null },
796
- organizationIdByRecord: { [profileId]: profile?.organizationId ?? null },
789
+ entityId: E.customers.customer_entity,
790
+ recordIds: [company.id],
791
+ tenantIdByRecord: { [company.id]: company.tenantId ?? null },
792
+ organizationIdByRecord: { [company.id]: company.organizationId ?? null },
797
793
  tenantFallbacks: [
798
- profile?.tenantId ?? company.tenantId ?? auth.tenantId ?? null,
794
+ company.tenantId ?? auth.tenantId ?? null,
799
795
  ].filter((v): v is string => !!v),
800
- })
801
- }
802
-
803
- const routing = await resolveCompanyCustomFieldRouting(em, company.tenantId ?? null, company.organizationId ?? null)
796
+ }),
797
+ profileId
798
+ ? loadCustomFieldValues({
799
+ em,
800
+ entityId: E.customers.customer_company_profile,
801
+ recordIds: [profileId],
802
+ tenantIdByRecord: { [profileId]: profile?.tenantId ?? null },
803
+ organizationIdByRecord: { [profileId]: profile?.organizationId ?? null },
804
+ tenantFallbacks: [
805
+ profile?.tenantId ?? company.tenantId ?? auth.tenantId ?? null,
806
+ ].filter((v): v is string => !!v),
807
+ })
808
+ : Promise.resolve<Record<string, Record<string, unknown>>>({}),
809
+ resolveCompanyCustomFieldRouting(em, company.tenantId ?? null, company.organizationId ?? null),
810
+ ])
804
811
  const customFields = normalizeCustomerDetailCustomFields(
805
812
  mergeCompanyCustomFieldValues(
806
813
  routing,
@@ -809,85 +816,103 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
809
816
  ),
810
817
  )
811
818
 
812
- const activityCount = await em.count(CustomerInteraction, {
813
- entity: company.id,
814
- organizationId: company.organizationId,
815
- tenantId: company.tenantId,
816
- deletedAt: null,
817
- interactionType: { $ne: 'task' },
818
- ...emailVisibilityFilter,
819
- })
820
- const interactionCount = await em.count(CustomerInteraction, {
821
- entity: company.id,
822
- organizationId: company.organizationId,
823
- tenantId: company.tenantId,
824
- deletedAt: null,
825
- ...emailVisibilityFilter,
826
- })
827
- const todoCount = interactionFlags.unified
828
- ? await em.count(CustomerInteraction, {
829
- entity: company.id,
830
- organizationId: company.organizationId,
831
- tenantId: company.tenantId,
832
- deletedAt: null,
833
- interactionType: 'task',
834
- })
835
- : await em.count(CustomerTodoLink, {
836
- entity: company.id,
837
- organizationId: company.organizationId,
838
- tenantId: company.tenantId,
839
- })
840
- const commentsCount = includeComments
841
- ? comments.length
842
- : await em.count(CustomerComment, {
843
- entity: company.id,
844
- organizationId: company.organizationId,
845
- tenantId: company.tenantId,
846
- })
847
- const addressesCount = includeAddresses
848
- ? addresses.length
849
- : await em.count(CustomerAddress, {
850
- entity: company.id,
851
- organizationId: company.organizationId,
852
- tenantId: company.tenantId,
853
- })
854
- const peopleCount = includePeople
855
- ? relatedPeople.length
856
- : filterActivePersonCompanyLinks(
857
- await findWithDecryption(
819
+ // The count queries, related-people fallback, and KPI interaction fallback are
820
+ // all independent of each other; dispatch them together rather than awaiting
821
+ // each inline so the response counts/KPIs are assembled in one parallel round
822
+ // instead of a waterfall (issue #3203).
823
+ const peopleCountQuery = includePeople
824
+ ? Promise.resolve(relatedPeople.length)
825
+ : (async () => {
826
+ const peopleLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(
858
827
  em,
859
- CustomerPersonCompanyLink,
860
- await withActiveCustomerPersonCompanyLinkFilter(
828
+ {
829
+ company: company.id,
830
+ organizationId: company.organizationId,
831
+ tenantId: company.tenantId,
832
+ },
833
+ 'customers.companies.GET',
834
+ )
835
+ return filterActivePersonCompanyLinks(
836
+ await findWithDecryption(
861
837
  em,
862
- {
863
- company: company.id,
864
- organizationId: company.organizationId,
865
- tenantId: company.tenantId,
866
- },
867
- 'customers.companies.GET',
838
+ CustomerPersonCompanyLink,
839
+ peopleLinkWhere,
840
+ {},
841
+ { tenantId: company.tenantId, organizationId: company.organizationId },
868
842
  ),
869
- {},
870
- { tenantId: company.tenantId, organizationId: company.organizationId },
871
- ),
872
- ).length
873
- const kpiInteractionRows = canonicalActiveInteractions.length
874
- ? canonicalActiveInteractions
875
- : await findWithDecryption(
876
- em,
877
- CustomerInteraction,
878
- {
843
+ ).length
844
+ })()
845
+ const [
846
+ activityCount,
847
+ interactionCount,
848
+ todoCount,
849
+ commentsCount,
850
+ addressesCount,
851
+ peopleCount,
852
+ kpiInteractionRows,
853
+ ] = await Promise.all([
854
+ em.count(CustomerInteraction, {
855
+ entity: company.id,
856
+ organizationId: company.organizationId,
857
+ tenantId: company.tenantId,
858
+ deletedAt: null,
859
+ interactionType: { $ne: 'task' },
860
+ ...emailVisibilityFilter,
861
+ }),
862
+ em.count(CustomerInteraction, {
863
+ entity: company.id,
864
+ organizationId: company.organizationId,
865
+ tenantId: company.tenantId,
866
+ deletedAt: null,
867
+ ...emailVisibilityFilter,
868
+ }),
869
+ interactionFlags.unified
870
+ ? em.count(CustomerInteraction, {
879
871
  entity: company.id,
880
872
  organizationId: company.organizationId,
881
873
  tenantId: company.tenantId,
882
874
  deletedAt: null,
883
- ...emailVisibilityFilter,
884
- },
885
- {
886
- fields: ['id', 'occurredAt', 'scheduledAt', 'createdAt'],
887
- orderBy: { createdAt: 'DESC' },
888
- },
889
- { tenantId: company.tenantId, organizationId: company.organizationId },
890
- )
875
+ interactionType: 'task',
876
+ })
877
+ : em.count(CustomerTodoLink, {
878
+ entity: company.id,
879
+ organizationId: company.organizationId,
880
+ tenantId: company.tenantId,
881
+ }),
882
+ includeComments
883
+ ? Promise.resolve(comments.length)
884
+ : em.count(CustomerComment, {
885
+ entity: company.id,
886
+ organizationId: company.organizationId,
887
+ tenantId: company.tenantId,
888
+ }),
889
+ includeAddresses
890
+ ? Promise.resolve(addresses.length)
891
+ : em.count(CustomerAddress, {
892
+ entity: company.id,
893
+ organizationId: company.organizationId,
894
+ tenantId: company.tenantId,
895
+ }),
896
+ peopleCountQuery,
897
+ canonicalActiveInteractions.length
898
+ ? Promise.resolve(canonicalActiveInteractions)
899
+ : findWithDecryption(
900
+ em,
901
+ CustomerInteraction,
902
+ {
903
+ entity: company.id,
904
+ organizationId: company.organizationId,
905
+ tenantId: company.tenantId,
906
+ deletedAt: null,
907
+ ...emailVisibilityFilter,
908
+ },
909
+ {
910
+ fields: ['id', 'occurredAt', 'scheduledAt', 'createdAt'],
911
+ orderBy: { createdAt: 'DESC' },
912
+ },
913
+ { tenantId: company.tenantId, organizationId: company.organizationId },
914
+ ),
915
+ ])
891
916
  const activityTrend = computeActivityTrend(
892
917
  kpiInteractionRows
893
918
  .map((interaction) => interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt)