@open-mercato/core 0.9.0 → 0.9.1-develop.7459.1.99e3accd30
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/generated/entities/customer_dictionary_entry/index.js +2 -0
- package/dist/generated/entities/customer_dictionary_entry/index.js.map +2 -2
- package/dist/generated/entities/customer_interaction/index.js +2 -0
- package/dist/generated/entities/customer_interaction/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/catalog/commands/categories.js +1 -1
- package/dist/modules/catalog/commands/categories.js.map +2 -2
- package/dist/modules/catalog/commands/productDeleteChildren.js +389 -0
- package/dist/modules/catalog/commands/productDeleteChildren.js.map +7 -0
- package/dist/modules/catalog/commands/products.js +52 -17
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js +4 -6
- package/dist/modules/communication_channels/api/post/channels/connect/credentials/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js +4 -6
- package/dist/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js +47 -11
- package/dist/modules/communication_channels/api/post/oauth/[provider]/initiate/route.js.map +3 -3
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js +5 -1
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
- package/dist/modules/communication_channels/lib/inbound-message-origin.js +1 -1
- package/dist/modules/communication_channels/lib/inbound-message-origin.js.map +2 -2
- package/dist/modules/communication_channels/lib/oauth-state.js +4 -1
- package/dist/modules/communication_channels/lib/oauth-state.js.map +2 -2
- package/dist/modules/communication_channels/lib/use-connect-channel.js +10 -0
- package/dist/modules/communication_channels/lib/use-connect-channel.js.map +2 -2
- package/dist/modules/customers/api/activity-types/route.js +151 -0
- package/dist/modules/customers/api/activity-types/route.js.map +7 -0
- package/dist/modules/customers/api/deals/[id]/people/route.js +58 -5
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +13 -5
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +20 -5
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +3 -0
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +1 -0
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js +18 -0
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +0 -23
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -17
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/calendar-event-types.js +548 -0
- package/dist/modules/customers/calendar-event-types.js.map +7 -0
- package/dist/modules/customers/commands/dictionaries.js +70 -10
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +187 -22
- package/dist/modules/customers/commands/interactions.js.map +3 -3
- package/dist/modules/customers/components/ActivityTypeEditor.js +288 -0
- package/dist/modules/customers/components/ActivityTypeEditor.js.map +7 -0
- package/dist/modules/customers/components/DictionarySettings.js +3 -1
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -297
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +3 -3
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +9 -74
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/TimeGrid.js +20 -16
- package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/EventTypePanel.js +218 -0
- package/dist/modules/customers/components/calendar/editor/EventTypePanel.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/LocationField.js +7 -3
- package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +5 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PriorityField.js +3 -1
- package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/RepeatField.js +9 -1
- package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/ResourcesField.js +4 -1
- package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +15 -7
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +3 -1
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +28 -13
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +3 -3
- package/dist/modules/customers/components/calendar/editor/inputs.js +14 -6
- package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js +54 -0
- package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js +82 -0
- package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js.map +7 -0
- package/dist/modules/customers/components/calendar/types.js +1 -0
- package/dist/modules/customers/components/calendar/types.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +78 -343
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/CreatePersonDialog.js +12 -11
- package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +7 -3
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealPeopleSection.js +206 -0
- package/dist/modules/customers/components/detail/DealPeopleSection.js.map +7 -0
- package/dist/modules/customers/components/detail/LinkedPeopleSection.js +342 -0
- package/dist/modules/customers/components/detail/LinkedPeopleSection.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonCard.js +5 -2
- package/dist/modules/customers/components/detail/PersonCard.js.map +2 -2
- package/dist/modules/customers/components/linking/adapters/personAdapter.js +3 -0
- package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +2 -2
- package/dist/modules/customers/data/entities.js +6 -0
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/data/validators.js +39 -10
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/di.js +20 -1
- package/dist/modules/customers/di.js.map +2 -2
- package/dist/modules/customers/extension-points.js +13 -0
- package/dist/modules/customers/extension-points.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +59 -16
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +34 -16
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/eventTypeResolver.js +197 -0
- package/dist/modules/customers/lib/calendar/eventTypeResolver.js.map +7 -0
- package/dist/modules/customers/lib/calendar/interactionApplicability.js +67 -0
- package/dist/modules/customers/lib/calendar/interactionApplicability.js.map +7 -0
- package/dist/modules/customers/lib/calendar/mapItem.js +5 -2
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/calendar/recurrence.js +62 -1
- package/dist/modules/customers/lib/calendar/recurrence.js.map +2 -2
- package/dist/modules/customers/lib/calendar/timezone.js +111 -0
- package/dist/modules/customers/lib/calendar/timezone.js.map +7 -0
- package/dist/modules/customers/lib/interactionReadModel.js +1 -0
- package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +1 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260928175058_customers.js +17 -0
- package/dist/modules/customers/migrations/Migration20260928175058_customers.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260930110235_customers.js +17 -0
- package/dist/modules/customers/migrations/Migration20260930110235_customers.js.map +7 -0
- package/dist/modules/dictionaries/components/DictionaryTable.js +60 -51
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- package/dist/modules/messages/subscribers/message-notification.js +13 -1
- package/dist/modules/messages/subscribers/message-notification.js.map +2 -2
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +201 -53
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +37 -11
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/planner/lib/availabilityMerge.js +101 -38
- package/dist/modules/planner/lib/availabilityMerge.js.map +3 -3
- package/dist/modules/planner/services/plannerAvailabilityService.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +159 -81
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/lineItemUtils.js +7 -0
- package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +12 -7
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +28 -25
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/generated/entities/customer_dictionary_entry/index.ts +1 -0
- package/generated/entities/customer_interaction/index.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +9 -8
- package/src/modules/auth/i18n/de.json +3 -0
- package/src/modules/auth/i18n/en.json +3 -0
- package/src/modules/auth/i18n/es.json +3 -0
- package/src/modules/auth/i18n/ko.json +3 -0
- package/src/modules/auth/i18n/pl.json +3 -0
- package/src/modules/catalog/commands/categories.ts +1 -1
- package/src/modules/catalog/commands/productDeleteChildren.ts +557 -0
- package/src/modules/catalog/commands/products.ts +58 -17
- package/src/modules/communication_channels/api/post/channels/connect/credentials/route.ts +4 -6
- package/src/modules/communication_channels/api/post/channels/connect/tenant-credentials/route.ts +4 -6
- package/src/modules/communication_channels/api/post/oauth/[provider]/initiate/route.ts +46 -10
- package/src/modules/communication_channels/commands/deliver-outbound-message.ts +6 -1
- package/src/modules/communication_channels/i18n/de.json +4 -0
- package/src/modules/communication_channels/i18n/en.json +4 -0
- package/src/modules/communication_channels/i18n/es.json +4 -0
- package/src/modules/communication_channels/i18n/ko.json +4 -0
- package/src/modules/communication_channels/i18n/pl.json +4 -0
- package/src/modules/communication_channels/lib/inbound-message-origin.ts +2 -6
- package/src/modules/communication_channels/lib/oauth-state.ts +4 -1
- package/src/modules/communication_channels/lib/use-connect-channel.ts +10 -0
- package/src/modules/customers/api/activity-types/route.ts +154 -0
- package/src/modules/customers/api/deals/[id]/people/route.ts +82 -3
- package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -1
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +18 -2
- package/src/modules/customers/api/interactions/route.ts +4 -0
- package/src/modules/customers/api/interactions/tasks/route.ts +1 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.meta.ts +20 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +0 -29
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +15 -17
- package/src/modules/customers/calendar-event-types.ts +674 -0
- package/src/modules/customers/commands/dictionaries.ts +84 -8
- package/src/modules/customers/commands/interactions.ts +244 -21
- package/src/modules/customers/components/ActivityTypeEditor.tsx +239 -0
- package/src/modules/customers/components/DictionarySettings.tsx +5 -3
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +347 -218
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +18 -96
- package/src/modules/customers/components/calendar/TimeGrid.tsx +20 -18
- package/src/modules/customers/components/calendar/editor/EventTypePanel.tsx +230 -0
- package/src/modules/customers/components/calendar/editor/LocationField.tsx +7 -1
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +4 -0
- package/src/modules/customers/components/calendar/editor/PriorityField.tsx +3 -0
- package/src/modules/customers/components/calendar/editor/RepeatField.tsx +10 -0
- package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +4 -0
- package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +16 -4
- package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +3 -0
- package/src/modules/customers/components/calendar/editor/hooks.ts +29 -13
- package/src/modules/customers/components/calendar/editor/inputs.tsx +17 -5
- package/src/modules/customers/components/calendar/editor/useCalendarCustomFields.ts +49 -0
- package/src/modules/customers/components/calendar/editor/useEventTypeCatalog.ts +100 -0
- package/src/modules/customers/components/calendar/types.ts +1 -0
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +94 -388
- package/src/modules/customers/components/detail/CreatePersonDialog.tsx +39 -19
- package/src/modules/customers/components/detail/DealForm.tsx +7 -3
- package/src/modules/customers/components/detail/DealPeopleSection.tsx +256 -0
- package/src/modules/customers/components/detail/LinkedPeopleSection.tsx +474 -0
- package/src/modules/customers/components/detail/PersonCard.tsx +12 -4
- package/src/modules/customers/components/detail/types.ts +1 -0
- package/src/modules/customers/components/linking/adapters/personAdapter.tsx +4 -0
- package/src/modules/customers/data/entities.ts +8 -1
- package/src/modules/customers/data/validators.ts +42 -7
- package/src/modules/customers/di.ts +21 -0
- package/src/modules/customers/extension-points.ts +13 -0
- package/src/modules/customers/i18n/de.json +104 -8
- package/src/modules/customers/i18n/en.json +104 -8
- package/src/modules/customers/i18n/es.json +104 -8
- package/src/modules/customers/i18n/ko.json +104 -8
- package/src/modules/customers/i18n/pl.json +104 -8
- package/src/modules/customers/lib/calendar/conflicts.ts +106 -27
- package/src/modules/customers/lib/calendar/editorPayload.ts +39 -19
- package/src/modules/customers/lib/calendar/eventTypeResolver.ts +258 -0
- package/src/modules/customers/lib/calendar/interactionApplicability.ts +99 -0
- package/src/modules/customers/lib/calendar/mapItem.ts +6 -2
- package/src/modules/customers/lib/calendar/recurrence.ts +65 -1
- package/src/modules/customers/lib/calendar/timezone.ts +117 -0
- package/src/modules/customers/lib/interactionReadModel.ts +1 -0
- package/src/modules/customers/lib/todoCompatibility.ts +2 -0
- package/src/modules/customers/migrations/.snapshot-open-mercato.json +34 -0
- package/src/modules/customers/migrations/Migration20260928175058_customers.ts +15 -0
- package/src/modules/customers/migrations/Migration20260930110235_customers.ts +15 -0
- package/src/modules/dictionaries/components/DictionaryTable.tsx +63 -56
- package/src/modules/messages/subscribers/message-notification.ts +13 -3
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +243 -62
- package/src/modules/payment_gateways/lib/gateway-service.ts +39 -12
- package/src/modules/planner/lib/availabilityMerge.ts +106 -41
- package/src/modules/planner/services/plannerAvailabilityService.ts +4 -0
- package/src/modules/sales/components/documents/LineItemDialog.tsx +194 -111
- package/src/modules/sales/components/documents/lineItemUtils.ts +18 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +25 -13
- package/src/modules/sync_excel/lib/adapters/customers.ts +33 -27
|
@@ -2,6 +2,8 @@ import { z } from 'zod'
|
|
|
2
2
|
import { isValidPhoneNumber } from '@open-mercato/shared/lib/phone'
|
|
3
3
|
import { COORDINATE_RANGES } from '@open-mercato/shared/lib/location/coordinates'
|
|
4
4
|
import { dictionaryEntrySortModeSchema } from '@open-mercato/core/modules/dictionaries/lib/entrySort'
|
|
5
|
+
import { calendarEventTypeBehaviorSchema } from '../calendar-event-types'
|
|
6
|
+
import { calendarDayStartInstant, calendarWallTimeToInstant, isCalendarTimezone } from '../lib/calendar/timezone'
|
|
5
7
|
|
|
6
8
|
const uuid = () => z.string().uuid()
|
|
7
9
|
|
|
@@ -350,13 +352,27 @@ const dictionaryColorSchema = z
|
|
|
350
352
|
)
|
|
351
353
|
const dictionaryIconSchema = z.string().trim().max(48)
|
|
352
354
|
|
|
355
|
+
function validateDictionaryBehavior(
|
|
356
|
+
payload: { kind: string; behavior?: unknown },
|
|
357
|
+
ctx: z.RefinementCtx,
|
|
358
|
+
): void {
|
|
359
|
+
if (payload.behavior !== undefined && payload.kind !== 'activity_type') {
|
|
360
|
+
ctx.addIssue({
|
|
361
|
+
code: z.ZodIssueCode.custom,
|
|
362
|
+
path: ['behavior'],
|
|
363
|
+
message: 'Behavior is only supported for activity types',
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
353
368
|
export const customerDictionaryEntryCreateSchema = scopedSchema.extend({
|
|
354
369
|
kind: dictionaryKindEnum,
|
|
355
370
|
value: dictionaryValueSchema,
|
|
356
371
|
label: dictionaryLabelSchema.optional(),
|
|
357
372
|
color: dictionaryColorSchema.nullable().optional(),
|
|
358
373
|
icon: dictionaryIconSchema.nullable().optional(),
|
|
359
|
-
|
|
374
|
+
behavior: calendarEventTypeBehaviorSchema.nullable().optional(),
|
|
375
|
+
}).superRefine(validateDictionaryBehavior)
|
|
360
376
|
|
|
361
377
|
export type CustomerDictionaryEntryCreateInput = z.infer<typeof customerDictionaryEntryCreateSchema>
|
|
362
378
|
|
|
@@ -368,18 +384,21 @@ export const customerDictionaryEntryUpdateSchema = scopedSchema
|
|
|
368
384
|
label: dictionaryLabelSchema.optional(),
|
|
369
385
|
color: dictionaryColorSchema.nullable().optional(),
|
|
370
386
|
icon: dictionaryIconSchema.nullable().optional(),
|
|
387
|
+
behavior: calendarEventTypeBehaviorSchema.nullable().optional(),
|
|
371
388
|
})
|
|
372
389
|
.refine(
|
|
373
390
|
(payload) =>
|
|
374
391
|
payload.value !== undefined ||
|
|
375
392
|
payload.label !== undefined ||
|
|
376
393
|
payload.color !== undefined ||
|
|
377
|
-
payload.icon !== undefined
|
|
394
|
+
payload.icon !== undefined ||
|
|
395
|
+
payload.behavior !== undefined,
|
|
378
396
|
{
|
|
379
397
|
message: 'Provide at least one field to update.',
|
|
380
398
|
path: ['value'],
|
|
381
399
|
}
|
|
382
400
|
)
|
|
401
|
+
.superRefine(validateDictionaryBehavior)
|
|
383
402
|
|
|
384
403
|
export type CustomerDictionaryEntryUpdateInput = z.infer<typeof customerDictionaryEntryUpdateSchema>
|
|
385
404
|
|
|
@@ -477,7 +496,10 @@ const interactionGuestPermissionsSchema = z
|
|
|
477
496
|
})
|
|
478
497
|
.strict()
|
|
479
498
|
|
|
499
|
+
export const calendarTimezoneSchema = z.string().trim().min(1).max(120).refine(isCalendarTimezone, { message: 'customers.calendar.editor.validation.timezoneInvalid' })
|
|
500
|
+
|
|
480
501
|
const interactionExtendedFields = {
|
|
502
|
+
timezone: calendarTimezoneSchema.optional().nullable(),
|
|
481
503
|
durationMinutes: z.number().int().min(0).optional().nullable(),
|
|
482
504
|
location: z.string().trim().max(500).optional().nullable(),
|
|
483
505
|
allDay: z.boolean().optional().nullable(),
|
|
@@ -494,6 +516,7 @@ const interactionCreateBaseSchema = scopedSchema.extend({
|
|
|
494
516
|
id: z.string().uuid().optional(),
|
|
495
517
|
entityId: z.string().uuid(),
|
|
496
518
|
interactionType: z.string().trim().min(1).max(100),
|
|
519
|
+
enforceSelectableType: z.boolean().optional(),
|
|
497
520
|
title: z.string().trim().max(500).optional().nullable(),
|
|
498
521
|
body: z.string().trim().max(10000).optional().nullable(),
|
|
499
522
|
// Lenient like `deal_status` (status: z.string().max(50)). The `interaction-statuses`
|
|
@@ -518,11 +541,13 @@ const interactionCreateBaseSchema = scopedSchema.extend({
|
|
|
518
541
|
...interactionExtendedFields,
|
|
519
542
|
})
|
|
520
543
|
|
|
521
|
-
function deriveScheduledAtFromDateTime(date?: string | null, time?: string | null): Date | null {
|
|
544
|
+
function deriveScheduledAtFromDateTime(date?: string | null, time?: string | null, timezone?: string | null, allDay?: boolean | null): Date | null {
|
|
522
545
|
if (!date || typeof date !== 'string') return null
|
|
523
546
|
const trimmedDate = date.trim()
|
|
524
547
|
if (!trimmedDate) return null
|
|
525
548
|
const trimmedTime = typeof time === 'string' ? time.trim() : ''
|
|
549
|
+
if (timezone && allDay) return calendarDayStartInstant(trimmedDate, timezone)
|
|
550
|
+
if (timezone) return calendarWallTimeToInstant(trimmedDate, trimmedTime || '00:00', timezone)
|
|
526
551
|
const iso = trimmedTime ? `${trimmedDate}T${trimmedTime}:00` : `${trimmedDate}T00:00:00`
|
|
527
552
|
const parsed = new Date(iso)
|
|
528
553
|
return Number.isNaN(parsed.getTime()) ? null : parsed
|
|
@@ -551,9 +576,13 @@ export const interactionCreateSchema = interactionCreateBaseSchema
|
|
|
551
576
|
// external API consumers don't silently persist `scheduled_at: null` after
|
|
552
577
|
// the validator already enforced non-empty date/time. The form already
|
|
553
578
|
// computes `scheduledAt` itself, so this branch is a no-op for the form path.
|
|
554
|
-
.transform((value) => {
|
|
579
|
+
.transform((value, ctx) => {
|
|
555
580
|
if (value.scheduledAt) return value
|
|
556
|
-
const derived = deriveScheduledAtFromDateTime(value.date, value.time)
|
|
581
|
+
const derived = deriveScheduledAtFromDateTime(value.date, value.time, value.timezone, value.allDay)
|
|
582
|
+
if (value.timezone && value.date && !derived) {
|
|
583
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['time'], message: 'customers.calendar.editor.validation.timezoneGap' })
|
|
584
|
+
return z.NEVER
|
|
585
|
+
}
|
|
557
586
|
return derived ? { ...value, scheduledAt: derived } : value
|
|
558
587
|
})
|
|
559
588
|
|
|
@@ -572,6 +601,8 @@ const interactionUpdateBaseSchema = z
|
|
|
572
601
|
// state to express — that depends on #5935 making the column nullable first.
|
|
573
602
|
entityId: z.string().uuid().optional(),
|
|
574
603
|
interactionType: z.string().trim().min(1).max(100).optional(),
|
|
604
|
+
enforceSelectableType: z.boolean().optional(),
|
|
605
|
+
confirmDiscardInapplicableValues: z.boolean().optional(),
|
|
575
606
|
title: z.string().trim().max(500).optional().nullable(),
|
|
576
607
|
body: z.string().trim().max(10000).optional().nullable(),
|
|
577
608
|
status: z.string().max(50).optional(),
|
|
@@ -614,13 +645,17 @@ export const interactionUpdateSchema = interactionUpdateBaseSchema
|
|
|
614
645
|
// Mirror the create-schema derivation for partial updates: when an external
|
|
615
646
|
// caller supplies `date+time` without `scheduledAt`, derive the timestamp so
|
|
616
647
|
// the update doesn't silently leave `scheduled_at` stale.
|
|
617
|
-
.transform((value) => {
|
|
648
|
+
.transform((value, ctx) => {
|
|
618
649
|
if (value.scheduledAt !== undefined) return value
|
|
619
650
|
// An explicit `date: null` is how a caller drops the due date; mirror it
|
|
620
651
|
// onto `scheduledAt` rather than leaving the old timestamp behind (#5941).
|
|
621
652
|
if (value.date === null) return { ...value, scheduledAt: null }
|
|
622
653
|
if (!value.date && !value.time) return value
|
|
623
|
-
const derived = deriveScheduledAtFromDateTime(value.date, value.time)
|
|
654
|
+
const derived = deriveScheduledAtFromDateTime(value.date, value.time, value.timezone, value.allDay)
|
|
655
|
+
if (value.timezone && value.date && !derived) {
|
|
656
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['time'], message: 'customers.calendar.editor.validation.timezoneGap' })
|
|
657
|
+
return z.NEVER
|
|
658
|
+
}
|
|
624
659
|
return derived ? { ...value, scheduledAt: derived } : value
|
|
625
660
|
})
|
|
626
661
|
|
|
@@ -3,6 +3,9 @@ import type { EntityManager } from '@mikro-orm/postgresql'
|
|
|
3
3
|
import type { AppContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
4
|
import type { OptimisticLockCurrentReader } from '@open-mercato/shared/lib/crud/optimistic-lock'
|
|
5
5
|
import { registerOptimisticLockReaders } from '@open-mercato/shared/lib/crud/optimistic-lock-store'
|
|
6
|
+
import { createCalendarEventTypeRegistry } from './calendar-event-types'
|
|
7
|
+
import { resolveCatalogEventType, resolveScopedCalendarEventTypes } from './lib/calendar/eventTypeResolver'
|
|
8
|
+
import type { OrganizationHierarchyService } from '@open-mercato/shared/lib/auth/principal-service'
|
|
6
9
|
import { CustomerEntity, CustomerAddress, CustomerInteraction } from './data/entities'
|
|
7
10
|
|
|
8
11
|
const RESOURCE_KIND_COMPANY = 'customers.company'
|
|
@@ -64,11 +67,29 @@ registerOptimisticLockReaders({
|
|
|
64
67
|
[RESOURCE_KIND_PEOPLE]: readCustomerPersonUpdatedAt,
|
|
65
68
|
})
|
|
66
69
|
|
|
70
|
+
const calendarEventTypeRegistry = createCalendarEventTypeRegistry()
|
|
71
|
+
|
|
67
72
|
export function register(container: AppContainer) {
|
|
68
73
|
container.register({
|
|
69
74
|
CustomerEntity: asValue(CustomerEntity),
|
|
70
75
|
CustomerAddress: asValue(CustomerAddress),
|
|
71
76
|
CustomerInteraction: asValue(CustomerInteraction),
|
|
77
|
+
calendarEventTypeRegistry: asValue(calendarEventTypeRegistry),
|
|
78
|
+
calendarEventTypeCatalogService: asValue({
|
|
79
|
+
async resolveBehavior(input: { tenantId: string; organizationId: string; key: string }) {
|
|
80
|
+
const hierarchy = container.resolve('organizationHierarchyService') as OrganizationHierarchyService
|
|
81
|
+
const ancestors = await hierarchy.resolveAncestorIds({ tenantId: input.tenantId, organizationId: input.organizationId })
|
|
82
|
+
if (ancestors === null) throw new Error('[internal] Calendar organization not found')
|
|
83
|
+
const em = container.resolve('em') as EntityManager
|
|
84
|
+
const catalog = await resolveScopedCalendarEventTypes({
|
|
85
|
+
em,
|
|
86
|
+
tenantId: input.tenantId,
|
|
87
|
+
organizationId: input.organizationId,
|
|
88
|
+
readableOrganizationIds: [input.organizationId, ...ancestors.slice().reverse()],
|
|
89
|
+
})
|
|
90
|
+
return resolveCatalogEventType(catalog, input.key)?.behavior ?? null
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
72
93
|
})
|
|
73
94
|
// `crudMutationGuardService` is registered platform-wide in the shared
|
|
74
95
|
// DI bootstrap (`packages/shared/src/lib/di/container.ts`). It already
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
componentExtensionHost,
|
|
2
3
|
crudFormExtensionHost,
|
|
3
4
|
dataTableExtensionHost,
|
|
4
5
|
defineModuleExtensionPoints,
|
|
@@ -23,6 +24,18 @@ export const extensionPoints = defineModuleExtensionPoints({
|
|
|
23
24
|
companyForm: crudFormExtensionHost({ entityId: 'customers.company', spotId: 'crud-form:customers.company', source: 'backend/customers/companies-v2/[id]/page.tsx' }),
|
|
24
25
|
dealForm: crudFormExtensionHost({ entityId: 'customers.deal', spotId: 'crud-form:customers.deal', source: 'backend/customers/deals/[id]/page.tsx' }),
|
|
25
26
|
personForm: crudFormExtensionHost({ entityId: 'customers.person', spotId: 'crud-form:customers.person', source: 'backend/customers/people-v2/[id]/page.tsx' }),
|
|
27
|
+
calendarEventTypes: injectionExtensionHost({
|
|
28
|
+
family: 'generic',
|
|
29
|
+
spotId: 'calendar:customers.event-types',
|
|
30
|
+
supported: ['headless-widget', 'registry-contribution'],
|
|
31
|
+
dataContract: 'customers.calendar.event-types.v1',
|
|
32
|
+
source: 'lib/calendar/eventTypeResolver.ts',
|
|
33
|
+
}),
|
|
34
|
+
calendarEventTypePanel: componentExtensionHost({
|
|
35
|
+
componentId: 'section:customers.calendar-event-editor.type-panel',
|
|
36
|
+
propsContract: 'customers.calendar.event-type-panel.v1',
|
|
37
|
+
source: 'components/calendar/editor/EventTypePanel.tsx',
|
|
38
|
+
}),
|
|
26
39
|
companyHeader: detailHost('detail:customers.company:header', 'backend/customers/companies-v2/[id]/page.tsx'),
|
|
27
40
|
companyStatusBadges: detailHost('detail:customers.company:status-badges', 'backend/customers/companies-v2/[id]/page.tsx'),
|
|
28
41
|
companyFooter: detailHost('detail:customers.company:footer', 'backend/customers/companies-v2/[id]/page.tsx'),
|
|
@@ -193,6 +193,11 @@
|
|
|
193
193
|
"customers.audit.todos.link": "To-do verknüpfen",
|
|
194
194
|
"customers.audit.todos.unlink": "To-do-Verknüpfung lösen",
|
|
195
195
|
"customers.calendar.actions.newEvent": "Neuer Termin",
|
|
196
|
+
"customers.calendar.activityTypes.errors.changeConfirmationRequired": "Beim Ändern des Ereignistyps werden vorhandene Werte gelöscht.",
|
|
197
|
+
"customers.calendar.activityTypes.errors.fieldNotApplicable": "Dieses Feld gilt nicht für den ausgewählten Aktivitätstyp.",
|
|
198
|
+
"customers.calendar.activityTypes.errors.forbidden": "Sie haben keine Berechtigung, Aktivitätstypen anzuzeigen.",
|
|
199
|
+
"customers.calendar.activityTypes.errors.loadFailed": "Aktivitätstypen konnten nicht geladen werden.",
|
|
200
|
+
"customers.calendar.activityTypes.errors.unavailable": "Dieser Aktivitätstyp ist nicht verfügbar.",
|
|
196
201
|
"customers.calendar.agenda.eventsCount.few": "{count} Termine",
|
|
197
202
|
"customers.calendar.agenda.eventsCount.many": "{count} Termine",
|
|
198
203
|
"customers.calendar.agenda.eventsCount.one": "{count} Termin",
|
|
@@ -232,6 +237,8 @@
|
|
|
232
237
|
"customers.calendar.editor.assigneePlaceholder": "Einem Teammitglied zuweisen…",
|
|
233
238
|
"customers.calendar.editor.attendees": "Teilnehmer",
|
|
234
239
|
"customers.calendar.editor.cancel": "Abbrechen",
|
|
240
|
+
"customers.calendar.editor.catalogLoadFailed": "Aktivitätstypen konnten nicht geladen werden. Versuchen Sie es erneut, um dieses Ereignis zu speichern.",
|
|
241
|
+
"customers.calendar.editor.catalogLoading": "Aktivitätstypen werden geladen…",
|
|
235
242
|
"customers.calendar.editor.category": "Kategorie",
|
|
236
243
|
"customers.calendar.editor.close": "Schließen",
|
|
237
244
|
"customers.calendar.editor.conflictTitle": "Kalenderkonflikt",
|
|
@@ -249,8 +256,14 @@
|
|
|
249
256
|
"customers.calendar.editor.dealsSection": "Geschäfte",
|
|
250
257
|
"customers.calendar.editor.description": "Beschreibung",
|
|
251
258
|
"customers.calendar.editor.descriptionPlaceholder": "Details hinzufügen…",
|
|
259
|
+
"customers.calendar.editor.discardConfirm": "Typ ändern und Werte löschen",
|
|
260
|
+
"customers.calendar.editor.discardDescription": "Beim Ändern des Ereignistyps werden Werte gelöscht, die für den neuen Typ nicht gelten.",
|
|
261
|
+
"customers.calendar.editor.discardFields": "Zu löschende Werte:",
|
|
262
|
+
"customers.calendar.editor.discardTitle": "Ereignistyp ändern?",
|
|
263
|
+
"customers.calendar.editor.discardUnknownField": "Benutzerdefiniertes Feld",
|
|
252
264
|
"customers.calendar.editor.error": "Termin konnte nicht gespeichert werden",
|
|
253
265
|
"customers.calendar.editor.guestBadge": "Gast",
|
|
266
|
+
"customers.calendar.editor.historicalType": "Dieser Ereignistyp ist für neue Ereignisse nicht verfügbar. Sie können dieses Ereignis weiter bearbeiten oder einen anderen Typ wählen.",
|
|
254
267
|
"customers.calendar.editor.location": "Ort",
|
|
255
268
|
"customers.calendar.editor.locationPlaceholder": "Ort oder Link hinzufügen…",
|
|
256
269
|
"customers.calendar.editor.multiDayHint": "Mehrtägiger Termin · {count} Tage",
|
|
@@ -295,6 +308,7 @@
|
|
|
295
308
|
"customers.calendar.editor.saved": "Termin gespeichert",
|
|
296
309
|
"customers.calendar.editor.saving": "Speichern…",
|
|
297
310
|
"customers.calendar.editor.searching": "Suche…",
|
|
311
|
+
"customers.calendar.editor.timezone": "Zeitzone",
|
|
298
312
|
"customers.calendar.editor.title.create": "Neuer Termin",
|
|
299
313
|
"customers.calendar.editor.title.edit": "Termin bearbeiten",
|
|
300
314
|
"customers.calendar.editor.titleLabel.email": "Betreff",
|
|
@@ -303,6 +317,7 @@
|
|
|
303
317
|
"customers.calendar.editor.titlePlaceholder": "Titel hinzufügen…",
|
|
304
318
|
"customers.calendar.editor.to": "An",
|
|
305
319
|
"customers.calendar.editor.typeSwitcher": "Termintyp",
|
|
320
|
+
"customers.calendar.editor.typeUnavailable": "Wählen Sie vor dem Speichern einen verfügbaren Ereignistyp.",
|
|
306
321
|
"customers.calendar.editor.types.call": "Anruf",
|
|
307
322
|
"customers.calendar.editor.types.email": "E-Mail",
|
|
308
323
|
"customers.calendar.editor.types.event": "Event",
|
|
@@ -312,6 +327,8 @@
|
|
|
312
327
|
"customers.calendar.editor.validation.assigneeRequired": "Weise diese Aufgabe einem Teammitglied zu",
|
|
313
328
|
"customers.calendar.editor.validation.endsBeforeStarts": "Das Ende muss nach dem Beginn liegen",
|
|
314
329
|
"customers.calendar.editor.validation.relatedToRequired": "Wähle eine Person oder ein Unternehmen aus, um diesen Termin zu verknüpfen",
|
|
330
|
+
"customers.calendar.editor.validation.timezoneGap": "Diese Ortszeit existiert in der gewählten Zeitzone nicht",
|
|
331
|
+
"customers.calendar.editor.validation.timezoneInvalid": "Wählen Sie eine gültige Zeitzone",
|
|
315
332
|
"customers.calendar.editor.validation.titleRequired": "Titel ist erforderlich",
|
|
316
333
|
"customers.calendar.empty.action": "Neuer Termin",
|
|
317
334
|
"customers.calendar.empty.agenda": "In diesem Zeitraum ist nichts geplant",
|
|
@@ -368,6 +385,7 @@
|
|
|
368
385
|
"customers.calendar.settings.conflictWarnings": "Konfliktwarnungen",
|
|
369
386
|
"customers.calendar.settings.eventCategories": "Ereigniskategorien",
|
|
370
387
|
"customers.calendar.settings.eventCategoriesHint": "Eigene Gruppierungslabels (z. B. Teammeeting, Verkaufsanruf). Werden beim Erstellen eines Ereignisses angeboten.",
|
|
388
|
+
"customers.calendar.settings.manageActivityTypes": "Aktivitätstypen verwalten",
|
|
371
389
|
"customers.calendar.settings.max": "(max. {count})",
|
|
372
390
|
"customers.calendar.settings.removeTag": "{tag} entfernen",
|
|
373
391
|
"customers.calendar.settings.save": "Änderungen speichern",
|
|
@@ -642,7 +660,6 @@
|
|
|
642
660
|
"customers.companies.detail.notes.placeholder": "Schreibe eine Notiz zu diesem Unternehmen…",
|
|
643
661
|
"customers.companies.detail.people.add": "Person hinzufügen",
|
|
644
662
|
"customers.companies.detail.people.empty": "Noch keine Personen mit diesem Unternehmen verknüpft.",
|
|
645
|
-
"customers.companies.detail.people.filter": "Filters",
|
|
646
663
|
"customers.companies.detail.people.helper": "Mit diesem Unternehmen verknüpfte Personen erscheinen hier und können erstellt, verknüpft, geöffnet oder getrennt werden, ohne die Seite zu verlassen.",
|
|
647
664
|
"customers.companies.detail.people.linkAction": "Vorhandene Person verknüpfen",
|
|
648
665
|
"customers.companies.detail.people.linkCancel": "Abbrechen",
|
|
@@ -671,20 +688,13 @@
|
|
|
671
688
|
"customers.companies.detail.people.linkedOn": "Verknüpft am {{date}}",
|
|
672
689
|
"customers.companies.detail.people.loadError": "Failed to load people.",
|
|
673
690
|
"customers.companies.detail.people.loading": "Personen werden geladen…",
|
|
674
|
-
"customers.companies.detail.people.next": "Next",
|
|
675
|
-
"customers.companies.detail.people.noSearchResults": "No people match your search.",
|
|
676
691
|
"customers.companies.detail.people.open": "Person öffnen",
|
|
677
|
-
"customers.companies.detail.people.pageSummary": "Page {{page}} of {{total}}",
|
|
678
|
-
"customers.companies.detail.people.previous": "Previous",
|
|
679
692
|
"customers.companies.detail.people.remove": "Trennen",
|
|
680
693
|
"customers.companies.detail.people.removeError": "Person konnte nicht vom Unternehmen getrennt werden.",
|
|
681
694
|
"customers.companies.detail.people.removeSuccess": "Person vom Unternehmen getrennt.",
|
|
682
695
|
"customers.companies.detail.people.searchPlaceholder": "Search by name, role, email...",
|
|
683
696
|
"customers.companies.detail.people.sectionSubtitle": "Employees and decision makers on the client side",
|
|
684
697
|
"customers.companies.detail.people.sectionTitle": "People",
|
|
685
|
-
"customers.companies.detail.people.sortNameAsc": "Sort: Name A-Z",
|
|
686
|
-
"customers.companies.detail.people.sortNameDesc": "Sort: Name Z-A",
|
|
687
|
-
"customers.companies.detail.people.sortRecent": "Sort: Recently linked",
|
|
688
698
|
"customers.companies.detail.relativeTime.daysAgo": "vor {{days}} Tagen",
|
|
689
699
|
"customers.companies.detail.relativeTime.monthsAgo": "vor {{months}} Mon.",
|
|
690
700
|
"customers.companies.detail.relativeTime.oneDayAgo": "vor 1 Tag",
|
|
@@ -806,6 +816,71 @@
|
|
|
806
816
|
"customers.companies.presets.inactive60": "Inaktiv > 60 Tage",
|
|
807
817
|
"customers.companies.presets.myAccounts": "Meine Konten",
|
|
808
818
|
"customers.companies.presets.recentlyCreated": "Kürzlich erstellt",
|
|
819
|
+
"customers.config.activityTypes.appearance": "Darstellung",
|
|
820
|
+
"customers.config.activityTypes.behavior": "Formularverhalten",
|
|
821
|
+
"customers.config.activityTypes.columns.active": "Auswählbar",
|
|
822
|
+
"customers.config.activityTypes.columns.behavior": "Verhalten",
|
|
823
|
+
"customers.config.activityTypes.columns.fields": "Felder",
|
|
824
|
+
"customers.config.activityTypes.columns.fieldsets": "Feldgruppen",
|
|
825
|
+
"customers.config.activityTypes.columns.key": "Stabiler Schlüssel",
|
|
826
|
+
"customers.config.activityTypes.columns.order": "Reihenfolge",
|
|
827
|
+
"customers.config.activityTypes.columns.source": "Quelle",
|
|
828
|
+
"customers.config.activityTypes.columns.type": "Aktivitätstyp",
|
|
829
|
+
"customers.config.activityTypes.configure": "Konfigurieren",
|
|
830
|
+
"customers.config.activityTypes.delete": "Löschen",
|
|
831
|
+
"customers.config.activityTypes.empty": "Keine Aktivitätstypen verfügbar.",
|
|
832
|
+
"customers.config.activityTypes.fields.allDay": "Ganztägig",
|
|
833
|
+
"customers.config.activityTypes.fields.baseKind": "Basisverhalten",
|
|
834
|
+
"customers.config.activityTypes.fields.color": "Farbe (#RRGGBB)",
|
|
835
|
+
"customers.config.activityTypes.fields.customFieldsetIds": "Feldgruppen benutzerdefinierter Felder",
|
|
836
|
+
"customers.config.activityTypes.fields.endTime": "Endzeit",
|
|
837
|
+
"customers.config.activityTypes.fields.icon": "Symbol",
|
|
838
|
+
"customers.config.activityTypes.fields.label": "Bezeichnung",
|
|
839
|
+
"customers.config.activityTypes.fields.location": "Ortsfeld",
|
|
840
|
+
"customers.config.activityTypes.fields.order": "Anzeigereihenfolge",
|
|
841
|
+
"customers.config.activityTypes.fields.people": "Personenfeld",
|
|
842
|
+
"customers.config.activityTypes.fields.priority": "Priorität",
|
|
843
|
+
"customers.config.activityTypes.fields.recurrence": "Wiederholung",
|
|
844
|
+
"customers.config.activityTypes.fields.resources": "Ressourcen",
|
|
845
|
+
"customers.config.activityTypes.fields.selectable": "Für neue Ereignisse verfügbar",
|
|
846
|
+
"customers.config.activityTypes.fields.value": "Stabiler Schlüssel",
|
|
847
|
+
"customers.config.activityTypes.fieldsetsUnavailable": "Feldgruppen sind nicht verfügbar. Laden Sie sie erneut, bevor Sie speichern.",
|
|
848
|
+
"customers.config.activityTypes.inactiveHint": "Ein Modul verhindert derzeit, dass diese Überschreibung wirksam wird.",
|
|
849
|
+
"customers.config.activityTypes.inherited": "Geerbt",
|
|
850
|
+
"customers.config.activityTypes.inheritedHint": "Beim Speichern wird eine lokale Überschreibung für diese Organisation erstellt.",
|
|
851
|
+
"customers.config.activityTypes.invalidBehavior": "Prüfen Sie die Werte für das Formularverhalten.",
|
|
852
|
+
"customers.config.activityTypes.invalidKey": "Verwenden Sie einen kleingeschriebenen Schlüssel mit Buchstaben, Zahlen, Bindestrichen oder Unterstrichen.",
|
|
853
|
+
"customers.config.activityTypes.loadFailed": "Aktivitätstypen konnten nicht geladen werden.",
|
|
854
|
+
"customers.config.activityTypes.loadingFieldsets": "Feldgruppen werden geladen…",
|
|
855
|
+
"customers.config.activityTypes.local": "Lokale Überschreibung",
|
|
856
|
+
"customers.config.activityTypes.missing": "fehlt",
|
|
857
|
+
"customers.config.activityTypes.missingHint": "Einige konfigurierte Feldgruppen existieren nicht mehr.",
|
|
858
|
+
"customers.config.activityTypes.new": "Neuer Aktivitätstyp",
|
|
859
|
+
"customers.config.activityTypes.no": "Nein",
|
|
860
|
+
"customers.config.activityTypes.noFieldsets": "Es sind noch keine Feldgruppen für benutzerdefinierte Felder definiert.",
|
|
861
|
+
"customers.config.activityTypes.options.assignee": "Zuständige Person",
|
|
862
|
+
"customers.config.activityTypes.options.attendees": "Teilnehmende",
|
|
863
|
+
"customers.config.activityTypes.options.call": "Anruf",
|
|
864
|
+
"customers.config.activityTypes.options.email": "E-Mail",
|
|
865
|
+
"customers.config.activityTypes.options.event": "Ereignis",
|
|
866
|
+
"customers.config.activityTypes.options.location": "Ort",
|
|
867
|
+
"customers.config.activityTypes.options.meeting": "Besprechung",
|
|
868
|
+
"customers.config.activityTypes.options.none": "Keine",
|
|
869
|
+
"customers.config.activityTypes.options.note": "Notiz",
|
|
870
|
+
"customers.config.activityTypes.options.participants": "Beteiligte",
|
|
871
|
+
"customers.config.activityTypes.options.phoneLink": "Telefonlink",
|
|
872
|
+
"customers.config.activityTypes.options.recipients": "Empfänger",
|
|
873
|
+
"customers.config.activityTypes.options.task": "Aufgabe",
|
|
874
|
+
"customers.config.activityTypes.refresh": "Aktualisieren",
|
|
875
|
+
"customers.config.activityTypes.removed": "Konfiguration des Aktivitätstyps entfernt.",
|
|
876
|
+
"customers.config.activityTypes.reset": "Überschreibung zurücksetzen",
|
|
877
|
+
"customers.config.activityTypes.resetConfirm": "Lokale Konfiguration des Aktivitätstyps entfernen?",
|
|
878
|
+
"customers.config.activityTypes.retry": "Erneut versuchen",
|
|
879
|
+
"customers.config.activityTypes.save": "Speichern",
|
|
880
|
+
"customers.config.activityTypes.saveFailed": "Aktivitätstyp konnte nicht gespeichert werden.",
|
|
881
|
+
"customers.config.activityTypes.saved": "Aktivitätstyp gespeichert.",
|
|
882
|
+
"customers.config.activityTypes.view": "Anzeigen",
|
|
883
|
+
"customers.config.activityTypes.yes": "Ja",
|
|
809
884
|
"customers.config.addressFormat.description": "Legen Sie fest, wie Formulare und Ansichten im Kundenmodul strukturiert werden.",
|
|
810
885
|
"customers.config.addressFormat.error": "Adresseinstellungen konnten nicht geladen werden",
|
|
811
886
|
"customers.config.addressFormat.errorSave": "Adresseinstellungen konnten nicht aktualisiert werden",
|
|
@@ -1073,7 +1148,18 @@
|
|
|
1073
1148
|
"customers.deals.detail.notesEmptyAction": "Notiz hinzufügen",
|
|
1074
1149
|
"customers.deals.detail.notesEmptyTitle": "Teile die wichtigsten Informationen",
|
|
1075
1150
|
"customers.deals.detail.notesLoading": "Notizen werden geladen…",
|
|
1151
|
+
"customers.deals.detail.people.addNewSubtitle": "The new contact is linked to this deal automatically",
|
|
1152
|
+
"customers.deals.detail.people.dialogSubtitle": "Link an existing contact to this deal",
|
|
1153
|
+
"customers.deals.detail.people.linkAction": "Link existing person",
|
|
1154
|
+
"customers.deals.detail.people.loadError": "Failed to load people.",
|
|
1155
|
+
"customers.deals.detail.people.searchPlaceholder": "Search by name, role, email...",
|
|
1156
|
+
"customers.deals.detail.people.sectionSubtitle": "Contacts involved in this deal",
|
|
1157
|
+
"customers.deals.detail.people.sectionTitle": "People",
|
|
1158
|
+
"customers.deals.detail.peopleAdd": "Add person",
|
|
1076
1159
|
"customers.deals.detail.peopleEditorTitle": "Manage linked people",
|
|
1160
|
+
"customers.deals.detail.peopleEmpty": "No people linked to this deal yet.",
|
|
1161
|
+
"customers.deals.detail.peopleEmptyAction": "Add person",
|
|
1162
|
+
"customers.deals.detail.peopleEmptyTitle": "Link the people involved",
|
|
1077
1163
|
"customers.deals.detail.peopleNoDetails": "Keine weiteren Details",
|
|
1078
1164
|
"customers.deals.detail.peopleSearch": "Search linked people…",
|
|
1079
1165
|
"customers.deals.detail.peopleSection": "Personen",
|
|
@@ -1702,6 +1788,15 @@
|
|
|
1702
1788
|
"customers.interactions.status.waiting": "Waiting / blocked",
|
|
1703
1789
|
"customers.interactions.update.error": "Failed to update interaction.",
|
|
1704
1790
|
"customers.interactions.update.success": "Interaction updated.",
|
|
1791
|
+
"customers.linkedPeople.filter": "Filters",
|
|
1792
|
+
"customers.linkedPeople.loading": "Personen werden geladen…",
|
|
1793
|
+
"customers.linkedPeople.next": "Next",
|
|
1794
|
+
"customers.linkedPeople.noSearchResults": "No people match your search.",
|
|
1795
|
+
"customers.linkedPeople.pageSummary": "Page {{page}} of {{total}}",
|
|
1796
|
+
"customers.linkedPeople.previous": "Previous",
|
|
1797
|
+
"customers.linkedPeople.sortNameAsc": "Sort: Name A-Z",
|
|
1798
|
+
"customers.linkedPeople.sortNameDesc": "Sort: Name Z-A",
|
|
1799
|
+
"customers.linkedPeople.sortRecent": "Sort: Recently linked",
|
|
1705
1800
|
"customers.linking.actions.cancel": "Abbrechen",
|
|
1706
1801
|
"customers.linking.actions.save": "Verknüpfungen speichern",
|
|
1707
1802
|
"customers.linking.actions.saving": "Speichern…",
|
|
@@ -1812,6 +1907,7 @@
|
|
|
1812
1907
|
"customers.people.createDialog.required": "Fields marked * are required",
|
|
1813
1908
|
"customers.people.createDialog.submit": "Create person",
|
|
1814
1909
|
"customers.people.createDialog.success": "Person created and linked to company",
|
|
1910
|
+
"customers.people.createDialog.successPlain": "Person created",
|
|
1815
1911
|
"customers.people.createDialog.title": "Add new person",
|
|
1816
1912
|
"customers.people.decisionMakers.count": "{{count}} key people",
|
|
1817
1913
|
"customers.people.decisionMakers.label": "Decision Makers",
|
|
@@ -193,6 +193,11 @@
|
|
|
193
193
|
"customers.audit.todos.link": "Link todo",
|
|
194
194
|
"customers.audit.todos.unlink": "Unlink todo",
|
|
195
195
|
"customers.calendar.actions.newEvent": "New event",
|
|
196
|
+
"customers.calendar.activityTypes.errors.changeConfirmationRequired": "Changing the event type will clear existing values.",
|
|
197
|
+
"customers.calendar.activityTypes.errors.fieldNotApplicable": "This field is not applicable to the selected activity type.",
|
|
198
|
+
"customers.calendar.activityTypes.errors.forbidden": "You do not have permission to view activity types.",
|
|
199
|
+
"customers.calendar.activityTypes.errors.loadFailed": "Failed to load activity types.",
|
|
200
|
+
"customers.calendar.activityTypes.errors.unavailable": "This activity type is unavailable.",
|
|
196
201
|
"customers.calendar.agenda.eventsCount.few": "{count} events",
|
|
197
202
|
"customers.calendar.agenda.eventsCount.many": "{count} events",
|
|
198
203
|
"customers.calendar.agenda.eventsCount.one": "{count} event",
|
|
@@ -232,6 +237,8 @@
|
|
|
232
237
|
"customers.calendar.editor.assigneePlaceholder": "Assign to a team member…",
|
|
233
238
|
"customers.calendar.editor.attendees": "Attendees",
|
|
234
239
|
"customers.calendar.editor.cancel": "Cancel",
|
|
240
|
+
"customers.calendar.editor.catalogLoadFailed": "Activity types could not be loaded. Retry to save this event.",
|
|
241
|
+
"customers.calendar.editor.catalogLoading": "Loading activity types…",
|
|
235
242
|
"customers.calendar.editor.category": "Category",
|
|
236
243
|
"customers.calendar.editor.close": "Close",
|
|
237
244
|
"customers.calendar.editor.conflictTitle": "Calendar conflict",
|
|
@@ -249,8 +256,14 @@
|
|
|
249
256
|
"customers.calendar.editor.dealsSection": "Deals",
|
|
250
257
|
"customers.calendar.editor.description": "Description",
|
|
251
258
|
"customers.calendar.editor.descriptionPlaceholder": "Add details…",
|
|
259
|
+
"customers.calendar.editor.discardConfirm": "Change type and clear values",
|
|
260
|
+
"customers.calendar.editor.discardDescription": "Changing the event type will clear values that do not apply to the new type.",
|
|
261
|
+
"customers.calendar.editor.discardFields": "Values to clear:",
|
|
262
|
+
"customers.calendar.editor.discardTitle": "Change event type?",
|
|
263
|
+
"customers.calendar.editor.discardUnknownField": "Custom field",
|
|
252
264
|
"customers.calendar.editor.error": "Failed to save event",
|
|
253
265
|
"customers.calendar.editor.guestBadge": "Guest",
|
|
266
|
+
"customers.calendar.editor.historicalType": "This event type is unavailable for new events. You can keep editing this event or choose another type.",
|
|
254
267
|
"customers.calendar.editor.location": "Location",
|
|
255
268
|
"customers.calendar.editor.locationPlaceholder": "Add a location or link…",
|
|
256
269
|
"customers.calendar.editor.multiDayHint": "Multi-day event · {count} days",
|
|
@@ -295,6 +308,7 @@
|
|
|
295
308
|
"customers.calendar.editor.saved": "Event saved",
|
|
296
309
|
"customers.calendar.editor.saving": "Saving…",
|
|
297
310
|
"customers.calendar.editor.searching": "Searching…",
|
|
311
|
+
"customers.calendar.editor.timezone": "Time zone",
|
|
298
312
|
"customers.calendar.editor.title.create": "New event",
|
|
299
313
|
"customers.calendar.editor.title.edit": "Edit event",
|
|
300
314
|
"customers.calendar.editor.titleLabel.email": "Subject",
|
|
@@ -303,6 +317,7 @@
|
|
|
303
317
|
"customers.calendar.editor.titlePlaceholder": "Add a title…",
|
|
304
318
|
"customers.calendar.editor.to": "To",
|
|
305
319
|
"customers.calendar.editor.typeSwitcher": "Event type",
|
|
320
|
+
"customers.calendar.editor.typeUnavailable": "Choose an available event type before saving.",
|
|
306
321
|
"customers.calendar.editor.types.call": "Call",
|
|
307
322
|
"customers.calendar.editor.types.email": "Email",
|
|
308
323
|
"customers.calendar.editor.types.event": "Event",
|
|
@@ -312,6 +327,8 @@
|
|
|
312
327
|
"customers.calendar.editor.validation.assigneeRequired": "Assign this task to a team member",
|
|
313
328
|
"customers.calendar.editor.validation.endsBeforeStarts": "End must be after start",
|
|
314
329
|
"customers.calendar.editor.validation.relatedToRequired": "Select a person or company to link this event",
|
|
330
|
+
"customers.calendar.editor.validation.timezoneGap": "This local time does not exist in the selected time zone",
|
|
331
|
+
"customers.calendar.editor.validation.timezoneInvalid": "Choose a valid time zone",
|
|
315
332
|
"customers.calendar.editor.validation.titleRequired": "Title is required",
|
|
316
333
|
"customers.calendar.empty.action": "New event",
|
|
317
334
|
"customers.calendar.empty.agenda": "Nothing scheduled in this period",
|
|
@@ -368,6 +385,7 @@
|
|
|
368
385
|
"customers.calendar.settings.conflictWarnings": "Conflict warnings",
|
|
369
386
|
"customers.calendar.settings.eventCategories": "Event Categories",
|
|
370
387
|
"customers.calendar.settings.eventCategoriesHint": "Your own grouping labels (e.g. Team Meeting, Sales Call). Offered when creating an event.",
|
|
388
|
+
"customers.calendar.settings.manageActivityTypes": "Manage activity types",
|
|
371
389
|
"customers.calendar.settings.max": "(max. {count})",
|
|
372
390
|
"customers.calendar.settings.removeTag": "Remove {tag}",
|
|
373
391
|
"customers.calendar.settings.save": "Save Changes",
|
|
@@ -642,7 +660,6 @@
|
|
|
642
660
|
"customers.companies.detail.notes.placeholder": "Write a note about this company…",
|
|
643
661
|
"customers.companies.detail.people.add": "Add person",
|
|
644
662
|
"customers.companies.detail.people.empty": "No people linked to this company yet.",
|
|
645
|
-
"customers.companies.detail.people.filter": "Filters",
|
|
646
663
|
"customers.companies.detail.people.helper": "People linked to this company appear here and can be created, linked, opened, or unlinked without leaving the page.",
|
|
647
664
|
"customers.companies.detail.people.linkAction": "Link existing person",
|
|
648
665
|
"customers.companies.detail.people.linkCancel": "Cancel",
|
|
@@ -671,20 +688,13 @@
|
|
|
671
688
|
"customers.companies.detail.people.linkedOn": "Linked on {{date}}",
|
|
672
689
|
"customers.companies.detail.people.loadError": "Failed to load people.",
|
|
673
690
|
"customers.companies.detail.people.loading": "Loading people…",
|
|
674
|
-
"customers.companies.detail.people.next": "Next",
|
|
675
|
-
"customers.companies.detail.people.noSearchResults": "No people match your search.",
|
|
676
691
|
"customers.companies.detail.people.open": "Open person",
|
|
677
|
-
"customers.companies.detail.people.pageSummary": "Page {{page}} of {{total}}",
|
|
678
|
-
"customers.companies.detail.people.previous": "Previous",
|
|
679
692
|
"customers.companies.detail.people.remove": "Unlink",
|
|
680
693
|
"customers.companies.detail.people.removeError": "Failed to unlink person from company.",
|
|
681
694
|
"customers.companies.detail.people.removeSuccess": "Person unlinked from company.",
|
|
682
695
|
"customers.companies.detail.people.searchPlaceholder": "Search by name, role, email...",
|
|
683
696
|
"customers.companies.detail.people.sectionSubtitle": "Employees and decision makers on the client side",
|
|
684
697
|
"customers.companies.detail.people.sectionTitle": "People",
|
|
685
|
-
"customers.companies.detail.people.sortNameAsc": "Sort: Name A-Z",
|
|
686
|
-
"customers.companies.detail.people.sortNameDesc": "Sort: Name Z-A",
|
|
687
|
-
"customers.companies.detail.people.sortRecent": "Sort: Recently linked",
|
|
688
698
|
"customers.companies.detail.relativeTime.daysAgo": "{{days}} days ago",
|
|
689
699
|
"customers.companies.detail.relativeTime.monthsAgo": "{{months}} mo. ago",
|
|
690
700
|
"customers.companies.detail.relativeTime.oneDayAgo": "1 day ago",
|
|
@@ -806,6 +816,71 @@
|
|
|
806
816
|
"customers.companies.presets.inactive60": "Inactive > 60 days",
|
|
807
817
|
"customers.companies.presets.myAccounts": "My accounts",
|
|
808
818
|
"customers.companies.presets.recentlyCreated": "Recently created",
|
|
819
|
+
"customers.config.activityTypes.appearance": "Appearance",
|
|
820
|
+
"customers.config.activityTypes.behavior": "Form behavior",
|
|
821
|
+
"customers.config.activityTypes.columns.active": "Selectable",
|
|
822
|
+
"customers.config.activityTypes.columns.behavior": "Behavior",
|
|
823
|
+
"customers.config.activityTypes.columns.fields": "Fields",
|
|
824
|
+
"customers.config.activityTypes.columns.fieldsets": "Fieldsets",
|
|
825
|
+
"customers.config.activityTypes.columns.key": "Stable key",
|
|
826
|
+
"customers.config.activityTypes.columns.order": "Order",
|
|
827
|
+
"customers.config.activityTypes.columns.source": "Source",
|
|
828
|
+
"customers.config.activityTypes.columns.type": "Activity type",
|
|
829
|
+
"customers.config.activityTypes.configure": "Configure",
|
|
830
|
+
"customers.config.activityTypes.delete": "Delete",
|
|
831
|
+
"customers.config.activityTypes.empty": "No activity types available.",
|
|
832
|
+
"customers.config.activityTypes.fields.allDay": "All day",
|
|
833
|
+
"customers.config.activityTypes.fields.baseKind": "Base behavior",
|
|
834
|
+
"customers.config.activityTypes.fields.color": "Color (#RRGGBB)",
|
|
835
|
+
"customers.config.activityTypes.fields.customFieldsetIds": "Custom-field fieldsets",
|
|
836
|
+
"customers.config.activityTypes.fields.endTime": "End time",
|
|
837
|
+
"customers.config.activityTypes.fields.icon": "Icon",
|
|
838
|
+
"customers.config.activityTypes.fields.label": "Label",
|
|
839
|
+
"customers.config.activityTypes.fields.location": "Location field",
|
|
840
|
+
"customers.config.activityTypes.fields.order": "Display order",
|
|
841
|
+
"customers.config.activityTypes.fields.people": "People field",
|
|
842
|
+
"customers.config.activityTypes.fields.priority": "Priority",
|
|
843
|
+
"customers.config.activityTypes.fields.recurrence": "Recurrence",
|
|
844
|
+
"customers.config.activityTypes.fields.resources": "Resources",
|
|
845
|
+
"customers.config.activityTypes.fields.selectable": "Available for new events",
|
|
846
|
+
"customers.config.activityTypes.fields.value": "Stable key",
|
|
847
|
+
"customers.config.activityTypes.fieldsetsUnavailable": "Fieldsets are unavailable. Retry loading before saving.",
|
|
848
|
+
"customers.config.activityTypes.inactiveHint": "A module currently prevents this override from taking effect.",
|
|
849
|
+
"customers.config.activityTypes.inherited": "Inherited",
|
|
850
|
+
"customers.config.activityTypes.inheritedHint": "Saving creates a local override for this organization.",
|
|
851
|
+
"customers.config.activityTypes.invalidBehavior": "Check the form behavior values.",
|
|
852
|
+
"customers.config.activityTypes.invalidKey": "Use a lowercase key with letters, numbers, hyphens, or underscores.",
|
|
853
|
+
"customers.config.activityTypes.loadFailed": "Failed to load activity types.",
|
|
854
|
+
"customers.config.activityTypes.loadingFieldsets": "Loading fieldsets…",
|
|
855
|
+
"customers.config.activityTypes.local": "Local override",
|
|
856
|
+
"customers.config.activityTypes.missing": "missing",
|
|
857
|
+
"customers.config.activityTypes.missingHint": "Some configured fieldsets no longer exist.",
|
|
858
|
+
"customers.config.activityTypes.new": "New activity type",
|
|
859
|
+
"customers.config.activityTypes.no": "No",
|
|
860
|
+
"customers.config.activityTypes.noFieldsets": "No custom-field fieldsets are defined yet.",
|
|
861
|
+
"customers.config.activityTypes.options.assignee": "Assignee",
|
|
862
|
+
"customers.config.activityTypes.options.attendees": "Attendees",
|
|
863
|
+
"customers.config.activityTypes.options.call": "Call",
|
|
864
|
+
"customers.config.activityTypes.options.email": "Email",
|
|
865
|
+
"customers.config.activityTypes.options.event": "Event",
|
|
866
|
+
"customers.config.activityTypes.options.location": "Location",
|
|
867
|
+
"customers.config.activityTypes.options.meeting": "Meeting",
|
|
868
|
+
"customers.config.activityTypes.options.none": "None",
|
|
869
|
+
"customers.config.activityTypes.options.note": "Note",
|
|
870
|
+
"customers.config.activityTypes.options.participants": "Participants",
|
|
871
|
+
"customers.config.activityTypes.options.phoneLink": "Phone link",
|
|
872
|
+
"customers.config.activityTypes.options.recipients": "Recipients",
|
|
873
|
+
"customers.config.activityTypes.options.task": "Task",
|
|
874
|
+
"customers.config.activityTypes.refresh": "Refresh",
|
|
875
|
+
"customers.config.activityTypes.removed": "Activity type configuration removed.",
|
|
876
|
+
"customers.config.activityTypes.reset": "Reset override",
|
|
877
|
+
"customers.config.activityTypes.resetConfirm": "Remove the local activity type configuration?",
|
|
878
|
+
"customers.config.activityTypes.retry": "Retry",
|
|
879
|
+
"customers.config.activityTypes.save": "Save",
|
|
880
|
+
"customers.config.activityTypes.saveFailed": "Failed to save activity type.",
|
|
881
|
+
"customers.config.activityTypes.saved": "Activity type saved.",
|
|
882
|
+
"customers.config.activityTypes.view": "View",
|
|
883
|
+
"customers.config.activityTypes.yes": "Yes",
|
|
809
884
|
"customers.config.addressFormat.description": "Choose how address forms and displays should be structured across the customer module.",
|
|
810
885
|
"customers.config.addressFormat.error": "Failed to load address settings",
|
|
811
886
|
"customers.config.addressFormat.errorSave": "Failed to update address settings",
|
|
@@ -1073,7 +1148,18 @@
|
|
|
1073
1148
|
"customers.deals.detail.notesEmptyAction": "Add a note",
|
|
1074
1149
|
"customers.deals.detail.notesEmptyTitle": "Keep everyone in the loop",
|
|
1075
1150
|
"customers.deals.detail.notesLoading": "Loading notes…",
|
|
1151
|
+
"customers.deals.detail.people.addNewSubtitle": "The new contact is linked to this deal automatically",
|
|
1152
|
+
"customers.deals.detail.people.dialogSubtitle": "Link an existing contact to this deal",
|
|
1153
|
+
"customers.deals.detail.people.linkAction": "Link existing person",
|
|
1154
|
+
"customers.deals.detail.people.loadError": "Failed to load people.",
|
|
1155
|
+
"customers.deals.detail.people.searchPlaceholder": "Search by name, role, email...",
|
|
1156
|
+
"customers.deals.detail.people.sectionSubtitle": "Contacts involved in this deal",
|
|
1157
|
+
"customers.deals.detail.people.sectionTitle": "People",
|
|
1158
|
+
"customers.deals.detail.peopleAdd": "Add person",
|
|
1076
1159
|
"customers.deals.detail.peopleEditorTitle": "Manage linked people",
|
|
1160
|
+
"customers.deals.detail.peopleEmpty": "No people linked to this deal yet.",
|
|
1161
|
+
"customers.deals.detail.peopleEmptyAction": "Add person",
|
|
1162
|
+
"customers.deals.detail.peopleEmptyTitle": "Link the people involved",
|
|
1077
1163
|
"customers.deals.detail.peopleNoDetails": "No additional details",
|
|
1078
1164
|
"customers.deals.detail.peopleSearch": "Search linked people…",
|
|
1079
1165
|
"customers.deals.detail.peopleSection": "People",
|
|
@@ -1702,6 +1788,15 @@
|
|
|
1702
1788
|
"customers.interactions.status.waiting": "Waiting / blocked",
|
|
1703
1789
|
"customers.interactions.update.error": "Failed to update interaction.",
|
|
1704
1790
|
"customers.interactions.update.success": "Interaction updated.",
|
|
1791
|
+
"customers.linkedPeople.filter": "Filters",
|
|
1792
|
+
"customers.linkedPeople.loading": "Loading people…",
|
|
1793
|
+
"customers.linkedPeople.next": "Next",
|
|
1794
|
+
"customers.linkedPeople.noSearchResults": "No people match your search.",
|
|
1795
|
+
"customers.linkedPeople.pageSummary": "Page {{page}} of {{total}}",
|
|
1796
|
+
"customers.linkedPeople.previous": "Previous",
|
|
1797
|
+
"customers.linkedPeople.sortNameAsc": "Sort: Name A-Z",
|
|
1798
|
+
"customers.linkedPeople.sortNameDesc": "Sort: Name Z-A",
|
|
1799
|
+
"customers.linkedPeople.sortRecent": "Sort: Recently linked",
|
|
1705
1800
|
"customers.linking.actions.cancel": "Cancel",
|
|
1706
1801
|
"customers.linking.actions.save": "Save links",
|
|
1707
1802
|
"customers.linking.actions.saving": "Saving…",
|
|
@@ -1812,6 +1907,7 @@
|
|
|
1812
1907
|
"customers.people.createDialog.required": "Fields marked * are required",
|
|
1813
1908
|
"customers.people.createDialog.submit": "Create person",
|
|
1814
1909
|
"customers.people.createDialog.success": "Person created and linked to company",
|
|
1910
|
+
"customers.people.createDialog.successPlain": "Person created",
|
|
1815
1911
|
"customers.people.createDialog.title": "Add new person",
|
|
1816
1912
|
"customers.people.decisionMakers.count": "{{count}} key people",
|
|
1817
1913
|
"customers.people.decisionMakers.label": "Decision Makers",
|