// // P2POrder.swift // Wallet // // Created by Saveliy Stavitsky on 7/30/21. // Copyright © 2021 AM. All rights reserved. // import Foundation import Resolver import RealmSwift enum P2POrderStatus: String, PersistableEnum, Codable { case active = "available" case inactive = "unavailable" case closed = "closed" } // swiftlint:disable identifier_name class P2PRating: EmbeddedObject, Codable { @Persisted private var completed_deals: Int? @Persisted private var failed_deals: Int? var requests: Int { (completed_deals ?? 0) + (failed_deals ?? 0) } var rating: Decimal? { requests > 0 ? Decimal(completed_deals ?? 0) / Decimal(requests) : nil } } class P2POrder: Object, Decodable { @Persisted var id: Int @Persisted(indexed: true) var idText: String @Persisted var uuid: String @Persisted(primaryKey: true) var uniqueId: String @Persisted(indexed: true) var owner: String @Persisted var contentType: P2P.Model.ContentType @Persisted(indexed: true) var status: P2POrderStatus @Persisted(indexed: true) var symbol: String @Persisted var precision: Int @Persisted var volume: Decimal128 @Persisted var needClose: Bool @Persisted var insurance: Decimal128 @Persisted var min: Decimal128 @Persisted var max: Decimal128 var hasEqualAmount: Bool { min == max && (min == volume || volume == 0) } @Persisted(indexed: true) var kind: P2P.Model.Kind @Persisted var createdAt: Date @Persisted var rating: P2PRating? @Persisted var ratingValue: Decimal128? @Persisted var currencyId: Int @Persisted var rate: Decimal128 @Persisted var rateIsReversed: Bool @Persisted var cardNumber: String? @Persisted var paymentUrl: String? @Persisted var walletNumber: String? @Persisted var walletAddress: String? @Persisted var blockchainId: Int? @Persisted var paymentSystemId: Int? @Persisted var countryId: Int? @Persisted var cityId: Int? @Persisted var bankIds: List @Persisted var cardName: String? @Persisted var cardDate: String? @Persisted var cvv: String? @Persisted var memo: String? // swiftlint:disable identifier_name enum CodingKeys: String, CodingKey { case id = "order_id" case uuid case owner case data_type case status case volume case insurance case volume_balance case insurance_balance case min_package case max_package case order_type case created_at case rating case currency_id case rate case rateIsReversed = "is_cash_rate" case card_number case payment_url case wallet_number case wallet_address case blockchain_id case payment_system_id case country_id case city_id case bank_ids case card_name case card_expiry case cvv case memo } override required init() { } required init(from decoder: Decoder) throws { super.init() let values = try decoder.container(keyedBy: CodingKeys.self) if let orderId = Int(try values.decode(String.self, forKey: .id)) { id = orderId idText = "\(orderId)" } else { throw "P2POrder decoding error order id: \(try values.decode(String.self, forKey: .id)) is not Integer" } uuid = try values.decode(String.self, forKey: .uuid) owner = try values.decode(String.self, forKey: .owner) contentType = try values.decode(P2P.Model.ContentType.self, forKey: .data_type) status = try values.decode(P2POrderStatus.self, forKey: .status) symbol = try values.decode(String.self, forKey: .volume).symbol precision = try values.decode(String.self, forKey: .volume).amount.precision uniqueId = "\(symbol)#\(id)" volume = try Decimal128(string: try values.decode(String.self, forKey: .volume_balance).amount) insurance = try Decimal128(string: try values.decode(String.self, forKey: .insurance_balance).amount) min = try Decimal128(string: try values.decode(String.self, forKey: .min_package).amount) max = try Decimal128(string: try values.decode(String.self, forKey: .max_package).amount) needClose = volume < min // orderType = (try? values.decode(String.self, forKey: .order_type)) == "BUY" ? .buy : .sell kind = (try? values.decode(String.self, forKey: .order_type))?.uppercased() ?? "BUY" == "BUY" ? .buy : .sell createdAt = try values.decode(String.self, forKey: .created_at).serverDate() ?? Date() rating = try? values.decode(P2PRating.self, forKey: .rating) ratingValue = rating?.rating.map({ Decimal128(value: $0) }) currencyId = try values.decode(Int.self, forKey: .currency_id) rate = try Decimal128(string: try values.decode(String.self, forKey: .rate)) rateIsReversed = !((try? values.decode(Bool.self, forKey: .rateIsReversed)) ?? true) cardNumber = try? values.decode(String.self, forKey: .card_number) paymentUrl = try? values.decode(String.self, forKey: .payment_url) walletNumber = try? values.decode(String.self, forKey: .wallet_number) walletAddress = try? values.decode(String.self, forKey: .wallet_address) blockchainId = try? values.decode(Int.self, forKey: .blockchain_id) paymentSystemId = try? values.decode(Int.self, forKey: .payment_system_id) countryId = try? values.decode(Int.self, forKey: .country_id) cityId = try? values.decode(Int.self, forKey: .city_id) bankIds = List() bankIds.append(objectsIn: (try? values.decode([Int].self, forKey: .bank_ids)) ?? []) cardName = try? values.decode(String.self, forKey: .card_name) cardDate = try? values.decode(String.self, forKey: .card_expiry) cvv = try? values.decode(String.self, forKey: .cvv) memo = try? values.decode(String.self, forKey: .memo) } } extension P2POrder { var currency: P2PCurrency? { Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PCurrency.self, forPrimaryKey: currencyId) } var blockchain: P2PBlockchain? { Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PBlockchain.self, forPrimaryKey: blockchainId ?? -1) } var paymentSystem: P2PPaymentSystem? { Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PPaymentSystem.self, forPrimaryKey: paymentSystemId ?? -1) } var country: P2PCountry? { Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PCountry.self, forPrimaryKey: countryId ?? -1) } var city: P2PCity? { Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PCity.self, forPrimaryKey: cityId ?? -1) } var bank: P2PBank? { Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PBank.self, forPrimaryKey: bankIds.first ?? -1) } var banks: [P2PBank] { bankIds.compactMap({ Resolver.resolve(Realm.self, name: .realmP2PLists) .object(ofType: P2PBank.self, forPrimaryKey: $0) }) } } extension P2POrder { #warning(""" Fix this use @InjectedOptional(name: .realmOrders) var realm: Realm try? realm.write { realm.delete(self) } where needed after swift compiler bug fixed in swift 5.5 https://forums.swift.org/t/segmentation-fault-11-with-local-property-wrappers/47905/3 """) func delete() throws { if let realm = self.realm?.thaw(), let order = self.thaw() { try realm.write { realm.delete(order) } } } #warning(""" Fix this use @InjectedOptional(name: .realmOrders) var realm: Realm try? realm.write { self.status = .active } where needed after swift compiler bug fixed in swift 5.5 https://forums.swift.org/t/segmentation-fault-11-with-local-property-wrappers/47905/3 """) func modify(_ action: (P2POrder) -> Void) throws { if let realm = self.realm?.thaw(), let order = self.thaw() { try realm.write { action(order) } } else if self.realm == nil { @OptionalInjected(name: .realmOrders) var realm: Realm? try realm?.write { if let order = realm?.object(ofType: P2POrder.self, forPrimaryKey: self.uniqueId) { action(order) } } } } }