SwiftUI使用Core Data实现发票应用金额税额计算与汇总
问题根因
现有代码计算逻辑错误核心有三点:
- 计算函数内部每次执行都会新建一个空的
FacturationCoreData实例,没有接收列表遍历到的当前商品条目作为入参,读取的全是空属性的默认值,计算结果完全不符合预期 - 缺少全单维度的汇总逻辑,计算和当前遍历行、全量商品数据完全脱钩
- 保存新商品后没有清空输入框,重复点击保存会生成大量带空值的无效条目
正确实现方案
核心思路是把无参的计算函数改成接收单条FacturationCoreData实例作为入参,所有单条计算都基于传入的真实条目数据取值,同时新增全单汇总计算逻辑,直接遍历@FetchRequest拉取的全量商品做累加。
1. 替换原有错误的计算函数
删掉原来的prixQuantite()、calculeTvaC()两个错误函数,换成和单条条目绑定的计算方法,以及两个全单汇总的计算属性:
// 计算单条商品不含税小计:单价*数量 func calculateExTaxTotal(for item: FacturationCoreData) -> Double { let price = Double(item.prix ?? "") ?? 0 let quantity = Double(item.quantite ?? "") ?? 0 return price * quantity } // 计算单条商品税额 func calculateTaxAmount(for item: FacturationCoreData) -> Double { let exTaxTotal = calculateExTaxTotal(for: item) let taxRate = Double(item.tva ?? "") ?? 0 return exTaxTotal * taxRate / 100 } // 计算单条商品含税总价 func calculateInTaxTotal(for item: FacturationCoreData) -> Double { let exTaxTotal = calculateExTaxTotal(for: item) let taxAmount = calculateTaxAmount(for: item) return exTaxTotal + taxAmount } // 全单总税额汇总 var totalOrderTax: Double { factures.reduce(0) { $0 + calculateTaxAmount(for: $1) } } // 全单含税总金额汇总 var totalOrderInTax: Double { factures.reduce(0) { $0 + calculateInTaxTotal(for: $1) } }
2. 修复列表行的计算调用
原来列表里调用计算函数时没有传入当前遍历到的facture参数,改成传入对应条目,同时补上要求展示的单条税额字段,金额做两位小数格式化避免显示异常:
List{ ForEach(factures) { facture in VStack(alignment: .leading, spacing: 4){ Text("商品名: \(facture.article ?? "")") Text("数量: \(facture.quantite ?? "")x") Text("单价: \(facture.prix ?? "")€") Text("税率: \(facture.tva ?? "")%") Text("单条不含税小计: \(String(format: "%.2f", calculateExTaxTotal(for: facture)))€") Text("单条税额: \(String(format: "%.2f", calculateTaxAmount(for: facture)))€") Text("单条含税总价: \(String(format: "%.2f", calculateInTaxTotal(for: facture)))€") }.onTapGesture { textChange = facture.article ?? "" } }.onDelete { indexSet in indexSet.forEach { index in let deletfacture = factures[index] viewContext.delete(deletfacture) do{ try viewContext.save() }catch{ print(error) } } } }
3. 补全全单汇总展示、修复保存逻辑
修改原有保存按钮逻辑,保存成功后清空输入框避免重复提交无效数据,在页面底部新增全单汇总的独立文本展示:
// 修复后的保存按钮逻辑 Button { let facture = FacturationCoreData(context: viewContext) facture.article = article facture.quantite = quantite facture.prix = prix facture.tva = tvac do{ try viewContext.save() // 保存成功清空输入框 article = "" quantite = "" prix = "" tvac = "" }catch{ print(error) } } label: { Image(systemName: "square.and.arrow.down.fill") .font(.title) } // 在表单底部新增全单汇总区块 Section("全单汇总") { Text("全单总税额: \(String(format: "%.2f", totalOrderTax))€") .font(.headline) Text("全单含税总金额: \(String(format: "%.2f", totalOrderInTax))€") .font(.headline) }
可选优化建议
- 目前Core Data里把价格、数量、税率都存为String类型,计算时频繁转Double容易出现转换异常,建议直接在Core Data模型编辑器里把这三个属性改成
Double类型,在输入环节做格式校验,能减少大量空值转换的冗余代码 - 税率输入可以直接复用你已经定义好的
tva税率数组做Picker选择,不用用户手动输入,能大幅降低填错税率的概率 - 可以加输入校验,商品名、单价、数量、税率为空时禁用保存按钮,避免生成无效数据
内容的提问来源于stack exchange,提问作者Erfan Alipour
相关产品推荐
相关产品推荐

