@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
|
@@ -9,6 +9,24 @@ export function normalizeNumber(value: unknown, fallback = 0): number {
|
|
|
9
9
|
return fallback
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* A catalog price is only usable on a line when it carries a positive amount, because line
|
|
14
|
+
* submission rejects a unit price of zero. Returns the amount for the requested mode, falling
|
|
15
|
+
* back to the other mode only when the requested amount is missing, or `null` when the price
|
|
16
|
+
* has no positive amount to use.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveCatalogPriceAmount(
|
|
19
|
+
amountNet: number | null | undefined,
|
|
20
|
+
amountGross: number | null | undefined,
|
|
21
|
+
mode: 'net' | 'gross',
|
|
22
|
+
): number | null {
|
|
23
|
+
const isPresent = (value: number | null | undefined): value is number =>
|
|
24
|
+
typeof value === 'number' && Number.isFinite(value)
|
|
25
|
+
const [preferred, fallback] = mode === 'net' ? [amountNet, amountGross] : [amountGross, amountNet]
|
|
26
|
+
const amount = isPresent(preferred) ? preferred : isPresent(fallback) ? fallback : null
|
|
27
|
+
return amount !== null && amount > 0 ? amount : null
|
|
28
|
+
}
|
|
29
|
+
|
|
12
30
|
/**
|
|
13
31
|
* Pass `locale` to format in the application locale (`useLocale()` in client components).
|
|
14
32
|
* Omitting it keeps the runtime default, which varies per machine and is therefore not
|
|
@@ -177,7 +177,13 @@ export default function TimesheetProjectDetailPage({ params }: { params?: { id?:
|
|
|
177
177
|
const [loading, setLoading] = React.useState(true)
|
|
178
178
|
const [error, setError] = React.useState<string | null>(null)
|
|
179
179
|
const [isNotFound, setIsNotFound] = React.useState(false)
|
|
180
|
-
|
|
180
|
+
// Keyed by project id so a route change to another project never shows the
|
|
181
|
+
// previous project's guard (with a live request button) while the new one loads.
|
|
182
|
+
const [accessDeniedProjectId, setAccessDeniedProjectId] = React.useState<string | null>(null)
|
|
183
|
+
const accessDenied = accessDeniedProjectId !== null && accessDeniedProjectId === projectId
|
|
184
|
+
// The id the last finished load was for. Until it matches the route, the page
|
|
185
|
+
// is still loading — never the previous project's error or empty state.
|
|
186
|
+
const [settledProjectId, setSettledProjectId] = React.useState<string | null>(null)
|
|
181
187
|
|
|
182
188
|
const [employees, setEmployees] = React.useState<EmployeeAssignment[]>([])
|
|
183
189
|
const [employeesLoading, setEmployeesLoading] = React.useState(false)
|
|
@@ -387,7 +393,6 @@ export default function TimesheetProjectDetailPage({ params }: { params?: { id?:
|
|
|
387
393
|
setLoading(true)
|
|
388
394
|
setError(null)
|
|
389
395
|
setIsNotFound(false)
|
|
390
|
-
setAccessDenied(false)
|
|
391
396
|
try {
|
|
392
397
|
const queryParams = new URLSearchParams({ page: '1', pageSize: '1', ids: projectId! })
|
|
393
398
|
const call = await apiCall<ProjectResponse>(
|
|
@@ -396,9 +401,10 @@ export default function TimesheetProjectDetailPage({ params }: { params?: { id?:
|
|
|
396
401
|
// Screen 17: the route answers 404 with this discriminator for a project
|
|
397
402
|
// the caller is not a member of, without naming it.
|
|
398
403
|
if (call.status === 404 && readDenialReason(call.result) === NO_PROJECT_ACCESS_REASON) {
|
|
399
|
-
if (!cancelled)
|
|
404
|
+
if (!cancelled) setAccessDeniedProjectId(projectId ?? null)
|
|
400
405
|
return
|
|
401
406
|
}
|
|
407
|
+
if (!cancelled) setAccessDeniedProjectId(null)
|
|
402
408
|
if (!call.ok) {
|
|
403
409
|
throw new Error(t('staff.timesheets.projects.errors.load', 'Failed to load project.'))
|
|
404
410
|
}
|
|
@@ -414,7 +420,10 @@ export default function TimesheetProjectDetailPage({ params }: { params?: { id?:
|
|
|
414
420
|
setError(loadError instanceof Error ? loadError.message : t('staff.timesheets.projects.errors.load', 'Failed to load project.'))
|
|
415
421
|
}
|
|
416
422
|
} finally {
|
|
417
|
-
if (!cancelled)
|
|
423
|
+
if (!cancelled) {
|
|
424
|
+
setLoading(false)
|
|
425
|
+
setSettledProjectId(projectId ?? null)
|
|
426
|
+
}
|
|
418
427
|
}
|
|
419
428
|
}
|
|
420
429
|
loadProject()
|
|
@@ -649,7 +658,18 @@ export default function TimesheetProjectDetailPage({ params }: { params?: { id?:
|
|
|
649
658
|
}, [handleAddEmployee])
|
|
650
659
|
|
|
651
660
|
// --- Render ---
|
|
652
|
-
|
|
661
|
+
// Screen 17 — the caller may not open this project. The guard state names
|
|
662
|
+
// neither the customer nor the project (note 1), and the surrounding shell
|
|
663
|
+
// (sidebar, topbar) is untouched because the caller still has other projects
|
|
664
|
+
// (note 3). It is checked before `loading` and only cleared by a response that
|
|
665
|
+
// grants access, so a background reload (e.g. the organization scope
|
|
666
|
+
// resolving late) keeps the guard mounted instead of resetting a request the
|
|
667
|
+
// user has just sent.
|
|
668
|
+
if (accessDenied) {
|
|
669
|
+
return <NoProjectAccess timeProjectId={projectId} />
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (loading || settledProjectId !== (projectId ?? null)) {
|
|
653
673
|
return (
|
|
654
674
|
<Page>
|
|
655
675
|
<PageBody>
|
|
@@ -659,14 +679,6 @@ export default function TimesheetProjectDetailPage({ params }: { params?: { id?:
|
|
|
659
679
|
)
|
|
660
680
|
}
|
|
661
681
|
|
|
662
|
-
// Screen 17 — the caller may not open this project. The guard state names
|
|
663
|
-
// neither the customer nor the project (note 1), and the surrounding shell
|
|
664
|
-
// (sidebar, topbar) is untouched because the caller still has other projects
|
|
665
|
-
// (note 3).
|
|
666
|
-
if (accessDenied) {
|
|
667
|
-
return <NoProjectAccess timeProjectId={projectId} />
|
|
668
|
-
}
|
|
669
|
-
|
|
670
682
|
if (isNotFound) {
|
|
671
683
|
return (
|
|
672
684
|
<Page>
|
|
@@ -764,7 +764,19 @@ async function resolveUpload(em: EntityManager, runId: string | undefined, curso
|
|
|
764
764
|
return null
|
|
765
765
|
}
|
|
766
766
|
|
|
767
|
+
async function personExists(em: EntityManager, personId: string, scope: TenantScope): Promise<boolean> {
|
|
768
|
+
const matches = await em.count(CustomerEntity, {
|
|
769
|
+
id: personId,
|
|
770
|
+
kind: 'person',
|
|
771
|
+
organizationId: scope.organizationId,
|
|
772
|
+
tenantId: scope.tenantId,
|
|
773
|
+
deletedAt: null,
|
|
774
|
+
})
|
|
775
|
+
return matches > 0
|
|
776
|
+
}
|
|
777
|
+
|
|
767
778
|
async function resolveExistingPersonId(params: {
|
|
779
|
+
em: EntityManager
|
|
768
780
|
externalIdMappingService: ExternalIdMappingService
|
|
769
781
|
externalId: string | null | undefined
|
|
770
782
|
email: string | null | undefined
|
|
@@ -778,7 +790,7 @@ async function resolveExistingPersonId(params: {
|
|
|
778
790
|
params.externalId,
|
|
779
791
|
params.scope,
|
|
780
792
|
)
|
|
781
|
-
if (mappedLocalId) return mappedLocalId
|
|
793
|
+
if (mappedLocalId && await personExists(params.em, mappedLocalId, params.scope)) return mappedLocalId
|
|
782
794
|
}
|
|
783
795
|
|
|
784
796
|
if (!params.email) return null
|
|
@@ -866,6 +878,7 @@ async function processRow(params: {
|
|
|
866
878
|
}
|
|
867
879
|
}
|
|
868
880
|
const existingId = await resolveExistingPersonId({
|
|
881
|
+
em: params.em,
|
|
869
882
|
externalIdMappingService: params.externalIdMappingService,
|
|
870
883
|
externalId,
|
|
871
884
|
email: payload.values.primaryEmail,
|
|
@@ -885,6 +898,21 @@ async function processRow(params: {
|
|
|
885
898
|
}
|
|
886
899
|
}
|
|
887
900
|
|
|
901
|
+
const rememberPersonIdentity = async (personId: string): Promise<void> => {
|
|
902
|
+
if (externalId) {
|
|
903
|
+
await params.externalIdMappingService.storeExternalIdMapping(
|
|
904
|
+
'sync_excel',
|
|
905
|
+
'customers.person',
|
|
906
|
+
personId,
|
|
907
|
+
externalId,
|
|
908
|
+
params.scope,
|
|
909
|
+
)
|
|
910
|
+
}
|
|
911
|
+
if (payload.values.primaryEmail && !params.emailDedupeIndex.has(payload.values.primaryEmail)) {
|
|
912
|
+
params.emailDedupeIndex.set(payload.values.primaryEmail, personId)
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
888
916
|
try {
|
|
889
917
|
if (existingId) {
|
|
890
918
|
const updateInput = {
|
|
@@ -897,6 +925,8 @@ async function processRow(params: {
|
|
|
897
925
|
ctx: params.commandContext,
|
|
898
926
|
})
|
|
899
927
|
|
|
928
|
+
await rememberPersonIdentity(existingId)
|
|
929
|
+
|
|
900
930
|
await upsertPrimaryAddress({
|
|
901
931
|
entityId: existingId,
|
|
902
932
|
addressValues: payload.addressValues,
|
|
@@ -906,19 +936,6 @@ async function processRow(params: {
|
|
|
906
936
|
em: params.em,
|
|
907
937
|
})
|
|
908
938
|
|
|
909
|
-
if (externalId) {
|
|
910
|
-
await params.externalIdMappingService.storeExternalIdMapping(
|
|
911
|
-
'sync_excel',
|
|
912
|
-
'customers.person',
|
|
913
|
-
existingId,
|
|
914
|
-
externalId,
|
|
915
|
-
params.scope,
|
|
916
|
-
)
|
|
917
|
-
}
|
|
918
|
-
if (payload.values.primaryEmail && !params.emailDedupeIndex.has(payload.values.primaryEmail)) {
|
|
919
|
-
params.emailDedupeIndex.set(payload.values.primaryEmail, existingId)
|
|
920
|
-
}
|
|
921
|
-
|
|
922
939
|
return {
|
|
923
940
|
externalId: externalId ?? sourceIdentifier,
|
|
924
941
|
action: 'update',
|
|
@@ -941,6 +958,8 @@ async function processRow(params: {
|
|
|
941
958
|
ctx: params.commandContext,
|
|
942
959
|
})
|
|
943
960
|
|
|
961
|
+
await rememberPersonIdentity(commandResult.result.entityId)
|
|
962
|
+
|
|
944
963
|
await upsertPrimaryAddress({
|
|
945
964
|
entityId: commandResult.result.entityId,
|
|
946
965
|
addressValues: payload.addressValues,
|
|
@@ -950,19 +969,6 @@ async function processRow(params: {
|
|
|
950
969
|
em: params.em,
|
|
951
970
|
})
|
|
952
971
|
|
|
953
|
-
if (externalId) {
|
|
954
|
-
await params.externalIdMappingService.storeExternalIdMapping(
|
|
955
|
-
'sync_excel',
|
|
956
|
-
'customers.person',
|
|
957
|
-
commandResult.result.entityId,
|
|
958
|
-
externalId,
|
|
959
|
-
params.scope,
|
|
960
|
-
)
|
|
961
|
-
}
|
|
962
|
-
if (payload.values.primaryEmail && !params.emailDedupeIndex.has(payload.values.primaryEmail)) {
|
|
963
|
-
params.emailDedupeIndex.set(payload.values.primaryEmail, commandResult.result.entityId)
|
|
964
|
-
}
|
|
965
|
-
|
|
966
972
|
return {
|
|
967
973
|
externalId: externalId ?? sourceIdentifier,
|
|
968
974
|
action: 'create',
|