fix(dates): une date corrigee a la main perd la precision importee

Sinon « vers 1879 » restait colle a la date saisie ensuite, et l'export l'aurait ecrite.
Personne, union, et voie contribution.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
IliesAllaliandClaude Opus 5.5 committed 2026-10-16 22:29:21 +02:00
1 parent f6affa81d6
commit f47ef8ecac
4 files changed
+82 -4

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
// Une date corrigée à la main perd la précision lue dans le GEDCOM (« vers 1879 », « entre 1914 et 1918 ») :
// elle décrivait l'ancienne date, pas celle qu'on vient de saisir. Une date renvoyée telle quelle la garde.
const sameDay = (a: Date | null | undefined, b: Date | null | undefined) =>
(a ? a.toISOString().slice(0, 10) : null) === (b ? b.toISOString().slice(0, 10) : null)
type PersonDates = { birthDate: Date | null; deathDate: Date | null }
export function personPrecisionResets(current: PersonDates | null, next: Partial<PersonDates>) {
const out: { birthDatePrecision?: null; birthDateEnd?: null; deathDatePrecision?: null; deathDateEnd?: null } = {}
if (!current) return out
if (next.birthDate !== undefined && !sameDay(current.birthDate, next.birthDate)) {
out.birthDatePrecision = null
out.birthDateEnd = null
}
if (next.deathDate !== undefined && !sameDay(current.deathDate, next.deathDate)) {
out.deathDatePrecision = null
out.deathDateEnd = null
}
return out
}
export function unionPrecisionResets(current: { startDate: Date | null } | null, next: { startDate?: Date | null }) {
if (!current || next.startDate === undefined || sameDay(current.startDate, next.startDate)) return {}
return { startDatePrecision: null }
}
+19 -2
View File
@@ -12,6 +12,7 @@ import { syncPersonMediaOrder } from '../lib/media-order.js'
import type { Actor, MembershipRole } from '../types/auth.js'
import { findParentChildValidationError, findUnionValidationError } from '../utils/relationship-guards.js'
import { nextSiblingOrder } from '../lib/sibling-order.js'
import { personPrecisionResets, unionPrecisionResets } from '../lib/date-precision.js'
const isoDateRegex = /^\d{4}-\d{2}-\d{2}$/
@@ -391,6 +392,17 @@ async function applyContributionChange(
throw new ContributionRouteError(400, 'invalid_change_after')
}
const nextDates = {
birthDate: parsed.data.birthDate !== undefined ? toDateOrNull(parsed.data.birthDate) : undefined,
deathDate: parsed.data.deathDate !== undefined ? toDateOrNull(parsed.data.deathDate) : undefined,
}
const currentDates = nextDates.birthDate !== undefined || nextDates.deathDate !== undefined
? await tx.person.findFirst({
where: { id: change.entityId, treeId, deletedAt: null },
select: { birthDate: true, deathDate: true },
})
: null
const result = await tx.person.updateMany({
where: {
id: change.entityId,
@@ -398,11 +410,12 @@ async function applyContributionChange(
deletedAt: null,
},
data: {
...personPrecisionResets(currentDates, nextDates),
firstName: parsed.data.firstName !== undefined ? parsed.data.firstName.trim() : undefined,
lastName: parsed.data.lastName !== undefined ? parsed.data.lastName.trim() : undefined,
birthName: parsed.data.birthName !== undefined ? toTrimmedStringOrNull(parsed.data.birthName) : undefined,
birthDate: parsed.data.birthDate !== undefined ? toDateOrNull(parsed.data.birthDate) : undefined,
deathDate: parsed.data.deathDate !== undefined ? toDateOrNull(parsed.data.deathDate) : undefined,
birthDate: nextDates.birthDate,
deathDate: nextDates.deathDate,
birthPlace: parsed.data.birthPlace !== undefined ? toTrimmedStringOrNull(parsed.data.birthPlace) : undefined,
profession: parsed.data.profession !== undefined ? toTrimmedStringOrNull(parsed.data.profession) : undefined,
region: parsed.data.region !== undefined ? toTrimmedStringOrNull(parsed.data.region) : undefined,
@@ -511,6 +524,7 @@ async function applyContributionChange(
select: {
partner1PersonId: true,
partner2PersonId: true,
startDate: true,
},
})
if (!existingUnion) {
@@ -537,6 +551,9 @@ async function applyContributionChange(
deletedAt: null,
},
data: {
...unionPrecisionResets(existingUnion, {
startDate: parsed.data.startDate !== undefined ? toDateOrNull(parsed.data.startDate) : undefined,
}),
partner1PersonId: parsed.data.partner1PersonId,
partner2PersonId: parsed.data.partner2PersonId,
unionType: parsed.data.unionType,
+14 -2
View File
@@ -15,6 +15,7 @@ import { nextSiblingOrder } from '../lib/sibling-order.js'
import { reserveTreeUnlockAttempt, serializePasswordCheck } from '../lib/unlock-guard.js'
import type { MembershipRole } from '../types/auth.js'
import { findParentChildValidationError, findUnionValidationError } from '../utils/relationship-guards.js'
import { personPrecisionResets, unionPrecisionResets } from '../lib/date-precision.js'
const MAX_TREES_PER_ACCOUNT = 10
@@ -1371,13 +1372,21 @@ export const treeRoutes: FastifyPluginAsync = async (app) => {
data.updatedBy = user.userId
const datesChanged = data.birthDate !== undefined || data.deathDate !== undefined
const current = datesChanged
? await app.prisma.person.findFirst({
where: { id: params.data.personId, treeId: params.data.id, deletedAt: null },
select: { birthDate: true, deathDate: true },
})
: null
const updated = await app.prisma.person.updateMany({
where: {
id: params.data.personId,
treeId: params.data.id,
deletedAt: null,
},
data,
data: { ...data, ...personPrecisionResets(current, data) },
})
if (updated.count === 0) {
@@ -1586,6 +1595,7 @@ export const treeRoutes: FastifyPluginAsync = async (app) => {
select: {
partner1PersonId: true,
partner2PersonId: true,
startDate: true,
},
})
@@ -1636,6 +1646,7 @@ export const treeRoutes: FastifyPluginAsync = async (app) => {
return reply.code(400).send({ error: unionValidationError })
}
const startDate = payload.data.startDate !== undefined ? toDateOrNull(payload.data.startDate) : undefined
const updated = await app.prisma.union.updateMany({
where: {
id: params.data.unionId,
@@ -1643,10 +1654,11 @@ export const treeRoutes: FastifyPluginAsync = async (app) => {
deletedAt: null,
},
data: {
...unionPrecisionResets(existingUnion, { startDate }),
partner1PersonId: payload.data.partner1PersonId,
partner2PersonId: payload.data.partner2PersonId,
unionType: payload.data.unionType,
startDate: payload.data.startDate !== undefined ? toDateOrNull(payload.data.startDate) : undefined,
startDate,
endDate: payload.data.endDate !== undefined ? toDateOrNull(payload.data.endDate) : undefined,
displayOrder: payload.data.displayOrder,
},
+23
View File
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest'
import { personPrecisionResets, unionPrecisionResets } from '../src/lib/date-precision'
const d = (iso: string) => new Date(`${iso}T00:00:00.000Z`)
describe('précision d’une date corrigée à la main', () => {
const current = { birthDate: d('1879-01-01'), deathDate: d('1950-05-02') }
it('une date changée perd sa précision, une date renvoyée telle quelle la garde', () => {
expect(personPrecisionResets(current, { birthDate: d('1880-03-12'), deathDate: d('1950-05-02') }))
.toEqual({ birthDatePrecision: null, birthDateEnd: null })
expect(personPrecisionResets(current, { birthDate: d('1879-01-01') })).toEqual({})
expect(personPrecisionResets(current, { deathDate: null })).toEqual({ deathDatePrecision: null, deathDateEnd: null })
expect(personPrecisionResets(current, {})).toEqual({})
})
it('mariage', () => {
expect(unionPrecisionResets({ startDate: d('1905-01-01') }, { startDate: d('1906-01-01') })).toEqual({ startDatePrecision: null })
expect(unionPrecisionResets({ startDate: d('1905-01-01') }, { startDate: d('1905-01-01') })).toEqual({})
expect(unionPrecisionResets({ startDate: d('1905-01-01') }, {})).toEqual({})
})
})