145 lines
4.1 KiB
Swift
145 lines
4.1 KiB
Swift
import Foundation
|
|
import CoreData
|
|
|
|
@objc(InvestmentSource)
|
|
public class InvestmentSource: NSManagedObject, Identifiable {
|
|
@nonobjc public class func fetchRequest() -> NSFetchRequest<InvestmentSource> {
|
|
return NSFetchRequest<InvestmentSource>(entityName: "InvestmentSource")
|
|
}
|
|
|
|
@NSManaged public var id: UUID
|
|
@NSManaged public var name: String
|
|
@NSManaged public var notificationFrequency: String
|
|
@NSManaged public var customFrequencyMonths: Int16
|
|
@NSManaged public var isActive: Bool
|
|
@NSManaged public var createdAt: Date
|
|
@NSManaged public var category: Category?
|
|
@NSManaged public var snapshots: NSSet?
|
|
|
|
public override func awakeFromInsert() {
|
|
super.awakeFromInsert()
|
|
id = UUID()
|
|
createdAt = Date()
|
|
isActive = true
|
|
notificationFrequency = NotificationFrequency.monthly.rawValue
|
|
customFrequencyMonths = 1
|
|
name = ""
|
|
}
|
|
}
|
|
|
|
// MARK: - Notification Frequency
|
|
|
|
enum NotificationFrequency: String, CaseIterable, Identifiable {
|
|
case monthly = "monthly"
|
|
case quarterly = "quarterly"
|
|
case semiannual = "semiannual"
|
|
case annual = "annual"
|
|
case custom = "custom"
|
|
case never = "never"
|
|
|
|
var id: String { rawValue }
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .monthly: return "Monthly"
|
|
case .quarterly: return "Quarterly"
|
|
case .semiannual: return "Semi-Annual"
|
|
case .annual: return "Annual"
|
|
case .custom: return "Custom"
|
|
case .never: return "Never"
|
|
}
|
|
}
|
|
|
|
var months: Int {
|
|
switch self {
|
|
case .monthly: return 1
|
|
case .quarterly: return 3
|
|
case .semiannual: return 6
|
|
case .annual: return 12
|
|
case .custom, .never: return 0
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Computed Properties
|
|
|
|
extension InvestmentSource {
|
|
var snapshotsArray: [Snapshot] {
|
|
let set = snapshots as? Set<Snapshot> ?? []
|
|
return set.sorted { $0.date > $1.date }
|
|
}
|
|
|
|
var sortedSnapshotsByDateAscending: [Snapshot] {
|
|
let set = snapshots as? Set<Snapshot> ?? []
|
|
return set.sorted { $0.date < $1.date }
|
|
}
|
|
|
|
var latestSnapshot: Snapshot? {
|
|
snapshotsArray.first
|
|
}
|
|
|
|
var latestValue: Decimal {
|
|
latestSnapshot?.value?.decimalValue ?? Decimal.zero
|
|
}
|
|
|
|
var snapshotCount: Int {
|
|
snapshots?.count ?? 0
|
|
}
|
|
|
|
var frequency: NotificationFrequency {
|
|
NotificationFrequency(rawValue: notificationFrequency) ?? .monthly
|
|
}
|
|
|
|
var nextReminderDate: Date? {
|
|
guard frequency != .never else { return nil }
|
|
|
|
let months = frequency == .custom ? Int(customFrequencyMonths) : frequency.months
|
|
guard let lastSnapshot = latestSnapshot else {
|
|
return Date() // Remind now if no snapshots
|
|
}
|
|
|
|
return Calendar.current.date(byAdding: .month, value: months, to: lastSnapshot.date)
|
|
}
|
|
|
|
var needsUpdate: Bool {
|
|
guard let nextDate = nextReminderDate else { return false }
|
|
return Date() >= nextDate
|
|
}
|
|
|
|
// MARK: - Performance Metrics
|
|
|
|
var totalReturn: Decimal {
|
|
guard let first = sortedSnapshotsByDateAscending.first,
|
|
let last = snapshotsArray.first,
|
|
let firstValue = first.value?.decimalValue,
|
|
firstValue != Decimal.zero else {
|
|
return Decimal.zero
|
|
}
|
|
|
|
let lastValue = last.value?.decimalValue ?? Decimal.zero
|
|
return ((lastValue - firstValue) / firstValue) * 100
|
|
}
|
|
|
|
var totalContributions: Decimal {
|
|
snapshotsArray.reduce(Decimal.zero) { result, snapshot in
|
|
result + (snapshot.contribution?.decimalValue ?? Decimal.zero)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Generated accessors for snapshots
|
|
|
|
extension InvestmentSource {
|
|
@objc(addSnapshotsObject:)
|
|
@NSManaged public func addToSnapshots(_ value: Snapshot)
|
|
|
|
@objc(removeSnapshotsObject:)
|
|
@NSManaged public func removeFromSnapshots(_ value: Snapshot)
|
|
|
|
@objc(addSnapshots:)
|
|
@NSManaged public func addToSnapshots(_ values: NSSet)
|
|
|
|
@objc(removeSnapshots:)
|
|
@NSManaged public func removeFromSnapshots(_ values: NSSet)
|
|
}
|