Finding transactions total filtered by dates in range in CoreData

113 Views Asked by At

Thank you everyone in advance. I'm new to SwiftUI. I am trying to find transactions total for dates filtered with CoreData fetch sectioned by month showing month by name sales total as section header for that month when grouping transactions by month.

Transaction entity has name, date and amount attributes. How can calculate sum for each month inside groupTransactionsByMonth function for header label of section in ViewModel. here is my codes for it

typealias TransactionGroup = OrderedDictionary<String, 
[Transaction]>

class: ViewModel: NSObject, ObservableObject {

    @Published var transactions = [Transaction]()

    func groupTransactionsByMonth()->TransactionGroup{
        guard !transactions.isEmpty else {return[]}
        let groupedTransactions = Transaction(grouping: transactions, by: {"\ ($0.date?.formatted(.dateTime.year().month(.wide)) ?? "")"})
        return groupedTransactions
    }
}

I tried this inside of groupTransactionsByMonth function:

for(_, value) in groupedTransactions{
    var total: Double = 0
    for transaction in value {
        total += transaction.amount
        return total
    }
}

But it gives an error

Cannot convert return expression 0f type "Double" to return type 'TransactionGroup (aka 'OrderedDictionary<String, Array>')

@Edit1

at moment I am showing my transactions in forEach as following
@ObservedObject private var vm = ViewModel()
ForEach(Array(vm.groupTransactionsByMonth()), id: \.key){month, 
transactions in
Section{
  ForEach(transactions){transaction in
     ReportCellView(date: transaction.date ?? Date(), name: 
transaction.name ?? "", amount: transaction.amount)
                } 
            } header { 
     HStack { Text(month)
              Spacer()
             //here I wanna show monthly total amount for 
posted month in section header not achieved yet
              //Text(" Sales")
              //Text("\(monthlyTotalSalesAmount)")
         }
1

There are 1 best solutions below

1
mani On
// assuming this is what your data structure looks like, adapt as needed
struct Transaction {
  let name: String
  let date: Date
  let amount: Double
}

// tuples for transactions & sum
typealias TransactionGroupByMonth = Dictionary<String, (transactions: [Transaction], sum: Double)>


class ViewModel: NSObject, ObservableObject {
  @Published var transactions = [Transactions]()
  
  func groupTransactionsByMonth() -> TransactionGroupByMonth {
    let groupByMonth = Dictionary(grouping: self.transactions) { transaction -> String in
      return Calendar.current.dateComponents([.month], from: transaction.date).month!.formatted()
    }

    return groupByMonth.reduce([:]) { partialResult, item in
      var result = partialResult
      result[item.key] = (transactions: item.value, sum: item.value.reduce(0.0, { $0 + $1.amount }))
      return result
    }
  }
}

Example:

let instance = ViewModel()
instance.transactions = [
  Transaction(name: "1", date: Date(), amount: 0.1),
  Transaction(name: "2", date: Date(), amount: 0.2),
  Transaction(name: "3", date: Date(), amount: 0.3),
]
let grouped = instance.groupTransactionsByMonth()
print(grouped)

/**
pseudo output structure:
{
  "11": {
    "transactions": [Transaction...],
    "sum": 0.6
  }
}
**/

I hope you don't have thousands of Transactions cause this isn't the most efficient way to do this.