Desactiva auto-dedup (pérdida de datos cross-device) + forward-fill en gráficas de evolution
CRÍTICO: el auto-dedup de build 68 borraba entidades padre con regla Cascade (Account/Category). Al propagarse el delete por CloudKit, otros dispositivos aplicaban la cascada al importar ANTES de la reasignación de hijos → wipe de sources/snapshots. Vació iPhone y iPad. Quitadas las llamadas automáticas a cleanupLogicalDuplicates() en processRemoteChanges y en la carga; el UUID-dedup seguro se mantiene. Métodos quedan definidos para un rediseño CloudKit-safe. Gráficas: forward-fill por source en evolution/allocation/period para que el total de cada mes refleje el último valor de CADA source (no solo las actualizadas ese mes) y el último punto coincida con el total del portfolio. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L2p3gUZRNWW388rWFRjiU7
This commit is contained in:
@@ -283,21 +283,33 @@ class DashboardViewModel: ObservableObject {
|
||||
return EvolutionSummary(evolutionData: [], categorySeries: [], categoryTotals: [:])
|
||||
}
|
||||
|
||||
let sortedSnapshots = snapshots.sorted { $0.date < $1.date }
|
||||
let groupedByMonth = Dictionary(grouping: sortedSnapshots) { snapshot -> DateComponents in
|
||||
let components = Calendar.current.dateComponents([.year, .month], from: snapshot.date)
|
||||
let calendar = Calendar.current
|
||||
let groupedByMonth = Dictionary(grouping: snapshots) { snapshot -> DateComponents in
|
||||
let components = calendar.dateComponents([.year, .month], from: snapshot.date)
|
||||
return DateComponents(year: components.year, month: components.month)
|
||||
}
|
||||
|
||||
let sortedMonthKeys = groupedByMonth.keys.sorted {
|
||||
(calendar.date(from: $0) ?? .distantPast) < (calendar.date(from: $1) ?? .distantPast)
|
||||
}
|
||||
|
||||
var evolution: [(date: Date, value: Decimal)] = []
|
||||
evolution.reserveCapacity(groupedByMonth.count)
|
||||
evolution.reserveCapacity(sortedMonthKeys.count)
|
||||
var series: [(date: Date, valuesByCategory: [UUID: Decimal])] = []
|
||||
series.reserveCapacity(groupedByMonth.count)
|
||||
series.reserveCapacity(sortedMonthKeys.count)
|
||||
var categoryTotals: [UUID: Decimal] = [:]
|
||||
|
||||
for (key, monthSnapshots) in groupedByMonth {
|
||||
// Forward-fill per source: carry each source's last known value into later
|
||||
// months where it has no new snapshot, so a month's total reflects EVERY
|
||||
// source's latest value (not only the ones updated that month). This keeps
|
||||
// the most-recent point equal to the dashboard total, which sums each
|
||||
// source's latest snapshot regardless of month.
|
||||
var currentValueBySource: [UUID: Decimal] = [:]
|
||||
var categoryBySource: [UUID: UUID] = [:]
|
||||
|
||||
for key in sortedMonthKeys {
|
||||
var latestBySource: [UUID: Snapshot] = [:]
|
||||
for snapshot in monthSnapshots {
|
||||
for snapshot in groupedByMonth[key] ?? [] {
|
||||
guard let sourceId = snapshot.source?.id else { continue }
|
||||
if let existing = latestBySource[sourceId] {
|
||||
if snapshot.date > existing.date {
|
||||
@@ -307,27 +319,29 @@ class DashboardViewModel: ObservableObject {
|
||||
latestBySource[sourceId] = snapshot
|
||||
}
|
||||
}
|
||||
// Apply this month's updates on top of the carried-forward state.
|
||||
for (sourceId, snapshot) in latestBySource {
|
||||
currentValueBySource[sourceId] = snapshot.decimalValue
|
||||
if let categoryId = snapshot.source?.category?.id {
|
||||
categoryBySource[sourceId] = categoryId
|
||||
}
|
||||
}
|
||||
|
||||
var total: Decimal = 0
|
||||
var valuesByCategory: [UUID: Decimal] = [:]
|
||||
|
||||
for snapshot in latestBySource.values {
|
||||
let value = snapshot.decimalValue
|
||||
for (sourceId, value) in currentValueBySource {
|
||||
total += value
|
||||
if let categoryId = snapshot.source?.category?.id {
|
||||
if let categoryId = categoryBySource[sourceId] {
|
||||
valuesByCategory[categoryId, default: 0] += value
|
||||
categoryTotals[categoryId, default: 0] += value
|
||||
}
|
||||
}
|
||||
|
||||
let date = Calendar.current.date(from: key) ?? Date()
|
||||
let date = calendar.date(from: key) ?? Date()
|
||||
evolution.append((date: date, value: total))
|
||||
series.append((date: date, valuesByCategory: valuesByCategory))
|
||||
}
|
||||
|
||||
evolution.sort { $0.date < $1.date }
|
||||
series.sort { $0.date < $1.date }
|
||||
|
||||
return EvolutionSummary(
|
||||
evolutionData: evolution,
|
||||
categorySeries: series,
|
||||
|
||||
Reference in New Issue
Block a user