@open-mercato/core 0.6.8-develop.7013.1.48f7adca80 → 0.6.8-develop.7016.1.4ed7b1e49d
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/api_keys/api/keys/route.js +1 -1
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/di.js +9 -0
- package/dist/modules/api_keys/di.js.map +7 -0
- package/dist/modules/api_keys/services/principalService.js +31 -0
- package/dist/modules/api_keys/services/principalService.js.map +7 -0
- package/dist/modules/attachments/di.js +11 -1
- package/dist/modules/attachments/di.js.map +2 -2
- package/dist/modules/attachments/index.js.map +1 -1
- package/dist/modules/attachments/lib/attachment-service.js +313 -0
- package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
- package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
- package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
- package/dist/modules/attachments/lib/upload-limits.js +6 -2
- package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/di.js +35 -9
- package/dist/modules/auth/di.js.map +2 -2
- package/dist/modules/auth/services/principalService.js +200 -0
- package/dist/modules/auth/services/principalService.js.map +7 -0
- package/dist/modules/auth/services/rbacService.js +67 -24
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
- package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
- package/dist/modules/customers/api/companies/[id]/people/route.js +19 -63
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +9 -85
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
- package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/data/validators.js +10 -2
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +5 -0
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +100 -2
- package/dist/modules/customers/lib/personCompanies.js.map +2 -2
- package/dist/modules/directory/di.js +9 -0
- package/dist/modules/directory/di.js.map +2 -2
- package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
- package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
- package/dist/modules/directory/services/organizationScopeService.js +56 -0
- package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -0
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/api_keys/api/keys/route.ts +3 -1
- package/src/modules/api_keys/di.ts +7 -0
- package/src/modules/api_keys/services/principalService.ts +33 -0
- package/src/modules/attachments/AGENTS.md +15 -0
- package/src/modules/attachments/di.ts +16 -0
- package/src/modules/attachments/i18n/de.json +5 -0
- package/src/modules/attachments/i18n/en.json +5 -0
- package/src/modules/attachments/i18n/es.json +5 -0
- package/src/modules/attachments/i18n/ko.json +5 -0
- package/src/modules/attachments/i18n/pl.json +5 -0
- package/src/modules/attachments/index.ts +10 -0
- package/src/modules/attachments/lib/attachment-service.ts +468 -0
- package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
- package/src/modules/attachments/lib/upload-limits.ts +6 -2
- package/src/modules/auth/data/entities.ts +4 -1
- package/src/modules/auth/di.ts +46 -16
- package/src/modules/auth/services/principalService.ts +266 -0
- package/src/modules/auth/services/rbacService.ts +110 -24
- package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +20 -72
- package/src/modules/customers/api/companies/[id]/route.ts +11 -97
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
- package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
- package/src/modules/customers/data/validators.ts +18 -3
- package/src/modules/customers/events.ts +5 -0
- package/src/modules/customers/lib/personCompanies.ts +136 -1
- package/src/modules/directory/di.ts +14 -2
- package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
- package/src/modules/directory/services/organizationScopeService.ts +85 -0
- package/src/modules/directory/utils/organizationScope.ts +4 -15
- package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
- package/src/modules/workflows/lib/activity-executor.ts +9 -0
|
@@ -5,17 +5,10 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
|
5
5
|
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
6
6
|
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
7
7
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
8
|
-
import { findOneWithDecryption
|
|
8
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
9
9
|
import { isOrganizationReadAccessAllowed } from "@open-mercato/core/modules/directory/utils/organizationScopeGuard";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
CustomerPersonCompanyLink,
|
|
13
|
-
CustomerPersonProfile
|
|
14
|
-
} from "../../../../data/entities.js";
|
|
15
|
-
import {
|
|
16
|
-
filterActivePersonCompanyLinks,
|
|
17
|
-
withActiveCustomerPersonCompanyLinkFilter
|
|
18
|
-
} from "../../../../lib/personCompanyLinkTable.js";
|
|
10
|
+
import { CustomerEntity } from "../../../../data/entities.js";
|
|
11
|
+
import { loadCompanyPeopleUnion } from "../../../../lib/personCompanies.js";
|
|
19
12
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
20
13
|
const logger = createLogger("customers");
|
|
21
14
|
const paramsSchema = z.object({
|
|
@@ -91,59 +84,22 @@ async function GET(req, ctx) {
|
|
|
91
84
|
throw new CrudHttpError(403, { error: translate("customers.errors.access_denied", "Access denied") });
|
|
92
85
|
}
|
|
93
86
|
const entityScope = { tenantId: auth.tenantId, organizationId: company.organizationId };
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
)
|
|
111
|
-
);
|
|
112
|
-
const personIds = links.map((link) => link.person?.id).filter((personId) => typeof personId === "string" && personId.length > 0);
|
|
113
|
-
const profiles = personIds.length > 0 ? await findWithDecryption(
|
|
114
|
-
em,
|
|
115
|
-
CustomerPersonProfile,
|
|
116
|
-
{
|
|
117
|
-
entity: { $in: personIds },
|
|
118
|
-
tenantId: company.tenantId,
|
|
119
|
-
organizationId: company.organizationId
|
|
120
|
-
},
|
|
121
|
-
{},
|
|
122
|
-
entityScope
|
|
123
|
-
) : [];
|
|
124
|
-
const profileByPersonId = new Map(
|
|
125
|
-
profiles.map((profile) => [profile.entity.id, profile])
|
|
126
|
-
);
|
|
127
|
-
const items = links.map((link) => {
|
|
128
|
-
const person = link.person;
|
|
129
|
-
if (!person?.id) return null;
|
|
130
|
-
const profile = profileByPersonId.get(person.id) ?? null;
|
|
131
|
-
return {
|
|
132
|
-
id: person.id,
|
|
133
|
-
displayName: person.displayName ?? person.primaryEmail ?? person.id,
|
|
134
|
-
primaryEmail: person.primaryEmail ?? null,
|
|
135
|
-
primaryPhone: person.primaryPhone ?? null,
|
|
136
|
-
status: person.status ?? null,
|
|
137
|
-
lifecycleStage: person.lifecycleStage ?? null,
|
|
138
|
-
jobTitle: profile?.jobTitle ?? null,
|
|
139
|
-
department: profile?.department ?? null,
|
|
140
|
-
createdAt: person.createdAt.toISOString(),
|
|
141
|
-
organizationId: person.organizationId,
|
|
142
|
-
temperature: person.temperature ?? null,
|
|
143
|
-
source: person.source ?? null,
|
|
144
|
-
linkedAt: link.createdAt ? link.createdAt.toISOString() : null
|
|
145
|
-
};
|
|
146
|
-
}).filter((item) => item !== null);
|
|
87
|
+
const union = await loadCompanyPeopleUnion(em, company, entityScope);
|
|
88
|
+
const items = union.map(({ entity: person, profile, linkedAt }) => ({
|
|
89
|
+
id: person.id,
|
|
90
|
+
displayName: person.displayName ?? person.primaryEmail ?? person.id,
|
|
91
|
+
primaryEmail: person.primaryEmail ?? null,
|
|
92
|
+
primaryPhone: person.primaryPhone ?? null,
|
|
93
|
+
status: person.status ?? null,
|
|
94
|
+
lifecycleStage: person.lifecycleStage ?? null,
|
|
95
|
+
jobTitle: profile?.jobTitle ?? null,
|
|
96
|
+
department: profile?.department ?? null,
|
|
97
|
+
createdAt: person.createdAt.toISOString(),
|
|
98
|
+
organizationId: person.organizationId,
|
|
99
|
+
temperature: person.temperature ?? null,
|
|
100
|
+
source: person.source ?? null,
|
|
101
|
+
linkedAt
|
|
102
|
+
}));
|
|
147
103
|
const filtered = query.search?.trim().length ? items.filter((item) => matchesSearch(item, query.search ?? "")) : items;
|
|
148
104
|
const sorted = sortItems(filtered, query.sort);
|
|
149
105
|
const total = sorted.length;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/customers/api/companies/%5Bid%5D/people/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAElB,SAAS,eAAe,iBAAiB,gBAAgB;AACzD,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AACnD,SAAS,2BAA2B;AAEpC,SAAS,
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport { CustomerEntity } from '../../../../data/entities'\nimport { loadCompanyPeopleUnion } from '../../../../lib/personCompanies'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst querySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(20),\n search: z.string().optional(),\n sort: z.enum(['name-asc', 'name-desc', 'recent']).default('name-asc'),\n})\n\ntype CompanyPersonItem = {\n id: string\n displayName: string\n primaryEmail: string | null\n primaryPhone: string | null\n status: string | null\n lifecycleStage: string | null\n jobTitle: string | null\n department: string | null\n createdAt: string\n organizationId: string\n temperature: string | null\n source: string | null\n linkedAt: string | null\n}\n\nfunction matchesSearch(item: CompanyPersonItem, query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized.length) return true\n return [\n item.displayName,\n item.primaryEmail,\n item.primaryPhone,\n item.jobTitle,\n item.department,\n item.status,\n item.lifecycleStage,\n item.source,\n ]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .some((value) => value.toLowerCase().includes(normalized))\n}\n\nfunction sortItems(items: CompanyPersonItem[], sort: 'name-asc' | 'name-desc' | 'recent'): CompanyPersonItem[] {\n if (sort === 'recent') {\n return [...items].sort((left, right) => {\n const leftTimestamp = left.linkedAt ? new Date(left.linkedAt).getTime() : new Date(left.createdAt).getTime()\n const rightTimestamp = right.linkedAt ? new Date(right.linkedAt).getTime() : new Date(right.createdAt).getTime()\n if (leftTimestamp === rightTimestamp) return left.displayName.localeCompare(right.displayName)\n return rightTimestamp - leftTimestamp\n })\n }\n\n return [...items].sort((left, right) => {\n const compare = left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n return sort === 'name-asc' ? compare : -compare\n })\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nexport async function GET(req: Request, ctx: { params?: { id?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id } = paramsSchema.parse({ id: ctx.params?.id })\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) throw new CrudHttpError(401, { error: 'Unauthorized' })\n\n const query = querySchema.parse({\n page: new URL(req.url).searchParams.get('page') ?? undefined,\n pageSize: new URL(req.url).searchParams.get('pageSize') ?? undefined,\n search: new URL(req.url).searchParams.get('search') ?? undefined,\n sort: new URL(req.url).searchParams.get('sort') ?? undefined,\n })\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n const decryptionScope = {\n tenantId: auth.tenantId,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n }\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id, kind: 'company', tenantId: auth.tenantId, deletedAt: null },\n {},\n decryptionScope,\n )\n if (!company) {\n throw notFound(translate('customers.errors.company_not_found', 'Company not found'))\n }\n\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: company.organizationId })) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n\n const entityScope = { tenantId: auth.tenantId, organizationId: company.organizationId }\n const union = await loadCompanyPeopleUnion(em, company, entityScope)\n\n const items = union.map(({ entity: person, profile, linkedAt }) => ({\n id: person.id,\n displayName: person.displayName ?? person.primaryEmail ?? person.id,\n primaryEmail: person.primaryEmail ?? null,\n primaryPhone: person.primaryPhone ?? null,\n status: person.status ?? null,\n lifecycleStage: person.lifecycleStage ?? null,\n jobTitle: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n createdAt: person.createdAt.toISOString(),\n organizationId: person.organizationId,\n temperature: person.temperature ?? null,\n source: person.source ?? null,\n linkedAt,\n } satisfies CompanyPersonItem))\n\n const filtered = query.search?.trim().length ? items.filter((item) => matchesSearch(item, query.search ?? '')) : items\n const sorted = sortItems(filtered, query.sort)\n const total = sorted.length\n const totalPages = Math.max(1, Math.ceil(total / query.pageSize))\n const page = Math.min(query.page, totalPages)\n const start = (page - 1) * query.pageSize\n\n return NextResponse.json({\n items: sorted.slice(start, start + query.pageSize),\n total,\n page,\n pageSize: query.pageSize,\n totalPages,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n logger.error('customers.companies.people.GET', { err: error })\n return NextResponse.json({ error: translate('customers.errors.company_people_load_failed', 'Failed to load linked people') }, { status: 500 })\n }\n}\n\nconst companyPeopleItemSchema = z.object({\n id: z.string().uuid(),\n displayName: z.string(),\n primaryEmail: z.string().nullable(),\n primaryPhone: z.string().nullable(),\n status: z.string().nullable(),\n lifecycleStage: z.string().nullable(),\n jobTitle: z.string().nullable(),\n department: z.string().nullable(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable(),\n temperature: z.string().nullable(),\n source: z.string().nullable(),\n linkedAt: z.string().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n GET: {\n summary: 'List linked people for a company',\n query: querySchema,\n responses: [\n {\n status: 200,\n description: 'Paginated linked people',\n schema: z.object({\n items: z.array(companyPeopleItemSchema),\n total: z.number().int().nonnegative(),\n page: z.number().int().min(1),\n pageSize: z.number().int().min(1),\n totalPages: z.number().int().min(1),\n }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -13,8 +13,6 @@ import {
|
|
|
13
13
|
CustomerLabelAssignment,
|
|
14
14
|
CustomerDealCompanyLink,
|
|
15
15
|
CustomerTodoLink,
|
|
16
|
-
CustomerPersonCompanyLink,
|
|
17
|
-
CustomerPersonProfile,
|
|
18
16
|
CustomerInteraction
|
|
19
17
|
} from "../../../data/entities.js";
|
|
20
18
|
import { User } from "@open-mercato/core/modules/auth/data/entities";
|
|
@@ -40,9 +38,9 @@ import { resolveCustomerDetailTenantScope } from "../../../lib/detailTenantScope
|
|
|
40
38
|
import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
41
39
|
import { parseBooleanFromUnknown } from "@open-mercato/shared/lib/boolean";
|
|
42
40
|
import {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} from "../../../lib/
|
|
41
|
+
countCompanyPeopleUnion,
|
|
42
|
+
loadCompanyPeopleUnion
|
|
43
|
+
} from "../../../lib/personCompanies.js";
|
|
46
44
|
import { normalizeCustomerDetailCustomFields } from "../../detailCustomFields.js";
|
|
47
45
|
import { isOrganizationReadAccessAllowed } from "@open-mercato/core/modules/directory/utils/organizationScopeGuard";
|
|
48
46
|
import { runWithCacheTenant } from "@open-mercato/cache";
|
|
@@ -631,68 +629,13 @@ async function GET(_req, ctx) {
|
|
|
631
629
|
)).map((link) => link.deal ?? null).filter(
|
|
632
630
|
(deal) => !!deal && typeof deal !== "string" && deal.tenantId === company.tenantId && deal.organizationId === company.organizationId
|
|
633
631
|
);
|
|
632
|
+
const peopleUnionScope = {
|
|
633
|
+
tenantId: company.tenantId ?? auth.tenantId ?? null,
|
|
634
|
+
organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null
|
|
635
|
+
};
|
|
634
636
|
let relatedPeople = [];
|
|
635
637
|
if (includePeople) {
|
|
636
|
-
|
|
637
|
-
tenantId: company.tenantId ?? auth.tenantId ?? null,
|
|
638
|
-
organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null
|
|
639
|
-
};
|
|
640
|
-
const relatedPeopleById = /* @__PURE__ */ new Map();
|
|
641
|
-
const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(
|
|
642
|
-
em,
|
|
643
|
-
{
|
|
644
|
-
company: company.id,
|
|
645
|
-
organizationId: company.organizationId,
|
|
646
|
-
tenantId: company.tenantId
|
|
647
|
-
},
|
|
648
|
-
"customers.companies.GET"
|
|
649
|
-
);
|
|
650
|
-
const companyLinks = filterActivePersonCompanyLinks(
|
|
651
|
-
await findWithDecryption(
|
|
652
|
-
em,
|
|
653
|
-
CustomerPersonCompanyLink,
|
|
654
|
-
companyLinkWhere,
|
|
655
|
-
{
|
|
656
|
-
populate: ["person", "person.personProfile"],
|
|
657
|
-
orderBy: { isPrimary: "desc", createdAt: "asc" }
|
|
658
|
-
},
|
|
659
|
-
peopleDecryptionScope
|
|
660
|
-
)
|
|
661
|
-
);
|
|
662
|
-
companyLinks.forEach((link) => {
|
|
663
|
-
const entity = typeof link.person === "string" ? null : link.person;
|
|
664
|
-
if (!entity || entity.kind !== "person" || entity.deletedAt) return;
|
|
665
|
-
const personProfile = entity.personProfile && typeof entity.personProfile !== "string" ? entity.personProfile : null;
|
|
666
|
-
relatedPeopleById.set(entity.id, {
|
|
667
|
-
entity,
|
|
668
|
-
profile: personProfile,
|
|
669
|
-
linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null
|
|
670
|
-
});
|
|
671
|
-
});
|
|
672
|
-
const profiles = await findWithDecryption(
|
|
673
|
-
em,
|
|
674
|
-
CustomerPersonProfile,
|
|
675
|
-
{
|
|
676
|
-
company: company.id,
|
|
677
|
-
tenantId: company.tenantId,
|
|
678
|
-
organizationId: company.organizationId,
|
|
679
|
-
entity: { deletedAt: null }
|
|
680
|
-
},
|
|
681
|
-
{ populate: ["entity"] },
|
|
682
|
-
peopleDecryptionScope
|
|
683
|
-
);
|
|
684
|
-
profiles.forEach((entry) => {
|
|
685
|
-
const entity = entry.entity;
|
|
686
|
-
if (!entity || entity.kind !== "person" || entity.deletedAt) return;
|
|
687
|
-
if (!relatedPeopleById.has(entity.id)) {
|
|
688
|
-
relatedPeopleById.set(entity.id, {
|
|
689
|
-
entity,
|
|
690
|
-
profile: entry ?? null,
|
|
691
|
-
linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
});
|
|
695
|
-
relatedPeople = Array.from(relatedPeopleById.values());
|
|
638
|
+
relatedPeople = await loadCompanyPeopleUnion(em, company, peopleUnionScope);
|
|
696
639
|
}
|
|
697
640
|
const profileId = profile?.id ?? null;
|
|
698
641
|
const [entityCustomFieldValues, profileCustomFieldValues, routing] = await Promise.all([
|
|
@@ -725,26 +668,7 @@ async function GET(_req, ctx) {
|
|
|
725
668
|
profileId ? profileCustomFieldValues?.[profileId] ?? {} : {}
|
|
726
669
|
)
|
|
727
670
|
);
|
|
728
|
-
const peopleCountQuery = includePeople ? Promise.resolve(relatedPeople.length) : (
|
|
729
|
-
const peopleLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(
|
|
730
|
-
em,
|
|
731
|
-
{
|
|
732
|
-
company: company.id,
|
|
733
|
-
organizationId: company.organizationId,
|
|
734
|
-
tenantId: company.tenantId
|
|
735
|
-
},
|
|
736
|
-
"customers.companies.GET"
|
|
737
|
-
);
|
|
738
|
-
return filterActivePersonCompanyLinks(
|
|
739
|
-
await findWithDecryption(
|
|
740
|
-
em,
|
|
741
|
-
CustomerPersonCompanyLink,
|
|
742
|
-
peopleLinkWhere,
|
|
743
|
-
{},
|
|
744
|
-
{ tenantId: company.tenantId, organizationId: company.organizationId }
|
|
745
|
-
)
|
|
746
|
-
).length;
|
|
747
|
-
})();
|
|
671
|
+
const peopleCountQuery = includePeople ? Promise.resolve(relatedPeople.length) : countCompanyPeopleUnion(em, company);
|
|
748
672
|
const [
|
|
749
673
|
activityCount,
|
|
750
674
|
interactionCount,
|