taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

OrderHistoryEntry.swift (5822B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2026 Bohdan, Volodymyr Potuzhnyi
      4  *
      5  * GNU Taler is free software; you can redistribute it and/or modify it under the
      6  * terms of the GNU General Public License as published by the Free Software
      7  * Foundation; either version 3, or (at your option) any later version.
      8  *
      9  * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
     10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License along with
     14  * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
     15  */
     16 
     17 import Foundation
     18 
     19 struct Timestamp: Codable, Equatable {
     20     let seconds: UInt64
     21 
     22     var date: Date {
     23         Date(timeIntervalSince1970: Double(seconds))
     24     }
     25 
     26     init(seconds: UInt64) {
     27         self.seconds = seconds
     28     }
     29 
     30     init(from decoder: Decoder) throws {
     31         let container = try decoder.container(keyedBy: CodingKeys.self)
     32         if let value = try? container.decode(UInt64.self, forKey: .tS) {
     33             self.seconds = value
     34         } else if let str = try? container.decode(String.self, forKey: .tS), str == "never" {
     35             self.seconds = UInt64.max
     36         } else {
     37             throw DecodingError.dataCorruptedError(forKey: .tS, in: container, debugDescription: "Expected integer or \"never\" for t_s")
     38         }
     39     }
     40 
     41     func encode(to encoder: Encoder) throws {
     42         var container = encoder.container(keyedBy: CodingKeys.self)
     43         if seconds == UInt64.max {
     44             try container.encode("never", forKey: .tS)
     45         } else {
     46             try container.encode(seconds, forKey: .tS)
     47         }
     48     }
     49 
     50     enum CodingKeys: String, CodingKey {
     51         case tS = "t_s"
     52     }
     53 }
     54 
     55 struct OrderHistoryEntry: Codable, Identifiable {
     56     let orderId: String
     57     let rowId: Int64?
     58     let timestamp: Timestamp
     59     let amount: Amount
     60     let summary: String
     61     let paid: Bool
     62     let refundable: Bool
     63     var refunded: Bool
     64     var refundAmount: Amount?
     65     var pendingRefundAmount: Amount?
     66     var refundPending: Bool
     67 
     68     var id: String { orderId }
     69 
     70     var hasRefund: Bool {
     71         refunded || (refundAmount?.isZero == false)
     72     }
     73 
     74     var hasPendingRefund: Bool {
     75         refundPending || (pendingRefundAmount?.isZero == false)
     76     }
     77 
     78     enum CodingKeys: String, CodingKey {
     79         case orderId = "order_id"
     80         case rowId = "row_id"
     81         case timestamp
     82         case amount
     83         case summary
     84         case paid
     85         case refundable
     86         case refunded
     87         case refundAmount = "refund_amount"
     88         case refundedAmount = "refunded_amount"
     89         case pendingRefundAmount = "pending_refund_amount"
     90         case refundPendingAmount = "refund_pending_amount"
     91         case refundPending = "refund_pending"
     92     }
     93 
     94     init(
     95         orderId: String,
     96         rowId: Int64? = nil,
     97         timestamp: Timestamp,
     98         amount: Amount,
     99         summary: String,
    100         paid: Bool,
    101         refundable: Bool,
    102         refunded: Bool = false,
    103         refundAmount: Amount? = nil,
    104         pendingRefundAmount: Amount? = nil,
    105         refundPending: Bool = false
    106     ) {
    107         self.orderId = orderId
    108         self.rowId = rowId
    109         self.timestamp = timestamp
    110         self.amount = amount
    111         self.summary = summary
    112         self.paid = paid
    113         self.refundable = refundable
    114         self.refunded = refunded
    115         self.refundAmount = refundAmount
    116         self.pendingRefundAmount = pendingRefundAmount
    117         self.refundPending = refundPending
    118     }
    119 
    120     init(from decoder: Decoder) throws {
    121         let container = try decoder.container(keyedBy: CodingKeys.self)
    122         orderId = try container.decode(String.self, forKey: .orderId)
    123         rowId = try container.decodeIfPresent(Int64.self, forKey: .rowId)
    124         timestamp = try container.decode(Timestamp.self, forKey: .timestamp)
    125         amount = try container.decode(Amount.self, forKey: .amount)
    126         summary = try container.decode(String.self, forKey: .summary)
    127         paid = try container.decode(Bool.self, forKey: .paid)
    128         refundable = try container.decode(Bool.self, forKey: .refundable)
    129         refunded = try container.decodeIfPresent(Bool.self, forKey: .refunded) ?? false
    130         if let ra = try container.decodeIfPresent(Amount.self, forKey: .refundAmount) {
    131             refundAmount = ra
    132         } else {
    133             refundAmount = try container.decodeIfPresent(Amount.self, forKey: .refundedAmount)
    134         }
    135         if let pra = try container.decodeIfPresent(Amount.self, forKey: .pendingRefundAmount) {
    136             pendingRefundAmount = pra
    137         } else {
    138             pendingRefundAmount = try container.decodeIfPresent(Amount.self, forKey: .refundPendingAmount)
    139         }
    140         refundPending = try container.decodeIfPresent(Bool.self, forKey: .refundPending) ?? false
    141     }
    142 
    143     func encode(to encoder: Encoder) throws {
    144         var container = encoder.container(keyedBy: CodingKeys.self)
    145         try container.encode(orderId, forKey: .orderId)
    146         try container.encodeIfPresent(rowId, forKey: .rowId)
    147         try container.encode(timestamp, forKey: .timestamp)
    148         try container.encode(amount, forKey: .amount)
    149         try container.encode(summary, forKey: .summary)
    150         try container.encode(paid, forKey: .paid)
    151         try container.encode(refundable, forKey: .refundable)
    152         try container.encode(refunded, forKey: .refunded)
    153         try container.encodeIfPresent(refundAmount, forKey: .refundAmount)
    154         try container.encodeIfPresent(pendingRefundAmount, forKey: .pendingRefundAmount)
    155         try container.encode(refundPending, forKey: .refundPending)
    156     }
    157 }
    158 
    159 struct OrderHistory: Codable {
    160     let orders: [OrderHistoryEntry]
    161 }