commit 0353dcaea3e0aea4e1aeaca2158e2c4701b5cbf8
parent bdcb5d615442507d066b0036983abc8205ce3923
Author: Marc Stibane <marc@taler.net>
Date: Thu, 6 Jul 2023 18:01:01 +0200
Payment model uses transactionID
Diffstat:
2 files changed, 107 insertions(+), 66 deletions(-)
diff --git a/TalerWallet1/Model/Model+Payment.swift b/TalerWallet1/Model/Model+Payment.swift
@@ -9,48 +9,72 @@ import AnyCodable
fileprivate let ASYNCDELAY: UInt = 0 //set e.g to 6 or 9 seconds for debugging
// MARK: - ContractTerms
-struct ContractTerms: Codable {
- let amount: Amount
- let maxFee: Amount
- let maxWireFee: Amount
+
+// export interface TalerProtocolDuration {
+// readonly d_us: number | "forever";
+// }
+
+struct MerchantContractTerms: Codable {
+ let hWire: String // Hash of the merchant's wire details
+// let autoRefund: String? // TODO: TalerProtocolDuration
+ let wireMethod: String // merchant wants to use
+ let summary: String // Human-readable short summary of the contract
+ let summaryI18n: String? // " localized "
+ let nonce: String // used to ensure freshness
+ let amount: Amount // Total amount payable
+ let payDeadline: Timestamp // Deadline to pay for the contract
+ let maxFee: Amount // Maximum deposit fee covered by the merchant
let merchant: Merchant
- let extra: Extra
- let summary: String
- let timestamp: Timestamp
- let payDeadline: Timestamp
- let refundDeadline: Timestamp
- let wireTransferDeadline: Timestamp
- let merchantBaseURL: String
- let fulfillmentURL: String
- let publicReorderURL: String
- let auditors: [Auditor]
+ let merchantPub: String // Public key of the merchant
+ let deliveryDate: Timestamp? // indicating when the order should be delivered
+ let deliveryLocation: Location? // Delivery location for (all!) products
let exchanges: [ExchangeForPay]
- let orderID, nonce, merchantPub: String
- let products: [Product]
- let hWire: String
- let wireMethod: String
- let wireFeeAmortization: Int
+ let products: [Product]? // Products that are sold in this contract
+ let refundDeadline: Timestamp // Deadline for refunds
+ let wireTransferDeadline: Timestamp // Deadline for the wire transfer
+ let timestamp: Timestamp // Time when the contract was generated by the merchant
+ let orderID: String // uniquely identify the purchase within one merchant instance
+ let merchantBaseURL: String // Base URL of the merchant's backend
+ let fulfillmentURL: String? // Fulfillment URL to view the product or delivery status
+ let publicReorderURL: String? // URL meant to share the shopping cart
+ let fulfillmentMessage: String? // Plain text fulfillment message in the merchant's default language
+ let fulfillmentMessageI18n: String? // Plain text fulfillment message in the merchant's default language
+ let wireFeeAmortization: Int? // Share of the wire fee that must be settled with one payment
+ let maxWireFee: Amount? // Maximum wire fee that the merchant agrees to pay for
+ let minimumAge: Int?
+ let extra: Extra // Extra data, interpreted by the mechant only
+// let auditors: [Auditor]?
enum CodingKeys: String, CodingKey {
+ case hWire = "h_wire"
+// case autoRefund = "auto_refund"
+ case wireMethod = "wire_method"
+ case summary
+ case summaryI18n = "summary_i18n"
+ case nonce
case amount
- case maxFee = "max_fee"
- case maxWireFee = "max_wire_fee"
- case merchant, extra, summary
- case timestamp
case payDeadline = "pay_deadline"
+ case maxFee = "max_fee"
+ case merchant
+ case merchantPub = "merchant_pub"
+ case deliveryDate = "delivery_date"
+ case deliveryLocation = "delivery_location"
+ case exchanges
+ case products
case refundDeadline = "refund_deadline"
case wireTransferDeadline = "wire_transfer_deadline"
+ case timestamp
+ case orderID = "order_id"
case merchantBaseURL = "merchant_base_url"
case fulfillmentURL = "fulfillment_url"
case publicReorderURL = "public_reorder_url"
- case auditors, exchanges
- case orderID = "order_id"
- case nonce
- case merchantPub = "merchant_pub"
- case products
- case hWire = "h_wire"
- case wireMethod = "wire_method"
+ case fulfillmentMessage = "fulfillment_message"
+ case fulfillmentMessageI18n = "fulfillment_message_i18n"
case wireFeeAmortization = "wire_fee_amortization"
+ case maxWireFee = "max_wire_fee"
+ case minimumAge = "minimum_age"
+ case extra
+// case auditors
}
}
// MARK: - Auditor
@@ -77,20 +101,28 @@ struct ExchangeForPay: Codable {
}
// MARK: - Extra
struct Extra: Codable {
- let articleName: String
+ let articleName: String?
enum CodingKeys: String, CodingKey {
case articleName = "article_name"
}
}
// MARK: -
+enum PreparePayResultType: String, Codable {
+ case paymentPossible = "payment-possible"
+ case alreadyConfirmed = "already-confirmed"
+ case insufficientBalance = "insufficient-balance"
+}
+
/// The result from PreparePayForUri
struct PaymentDetailsForUri: Codable {
+ let status: PreparePayResultType
+ let transactionId: String
+ let contractTerms: MerchantContractTerms
+ let contractTermsHash: String
let amountRaw: Amount
let amountEffective: Amount
- let proposalId: String
- let contractTerms: ContractTerms
- let contractTermsHash: String
+ let talerUri: String
}
/// A request to get an exchange's payment contract terms.
fileprivate struct PreparePayForUri: WalletBackendFormattedRequest {
@@ -107,18 +139,18 @@ fileprivate struct PreparePayForUri: WalletBackendFormattedRequest {
/// The result from confirmPayForUri
struct ConfirmPayResult: Decodable {
var type: String
- var contractTerms: ContractTerms
+ var contractTerms: MerchantContractTerms
var transactionId: String
}
/// A request to get an exchange's payment details.
fileprivate struct confirmPayForUri: WalletBackendFormattedRequest {
typealias Response = ConfirmPayResult
func operation() -> String { return "confirmPay" }
- func args() -> Args { return Args(proposalId: proposalId) }
+ func args() -> Args { return Args(transactionId: transactionId) }
- var proposalId: String
+ var transactionId: String
struct Args: Encodable {
- var proposalId: String
+ var transactionId: String
}
}
// MARK: -
@@ -132,9 +164,9 @@ extension WalletModel {
return response
}
@MainActor
- func confirmPayM(_ proposalId: String) // M for MainActor
+ func confirmPayM(_ transactionId: String) // M for MainActor
async throws -> ConfirmPayResult {
- let request = confirmPayForUri(proposalId: proposalId)
+ let request = confirmPayForUri(transactionId: transactionId)
let response = try await sendRequest(request, ASYNCDELAY)
return response
}
diff --git a/TalerWallet1/Views/Payment/PaymentURIView.swift b/TalerWallet1/Views/Payment/PaymentURIView.swift
@@ -22,7 +22,7 @@ struct PaymentURIView: View {
func acceptAction(detailsForUri: PaymentDetailsForUri) {
Task {
do {
- let confirmPayResult = try await model.confirmPayM(detailsForUri.proposalId)
+ let confirmPayResult = try await model.confirmPayM(detailsForUri.transactionId)
symLog.log(confirmPayResult as Any)
if confirmPayResult.type != "done" {
controller.playSound(0)
@@ -85,34 +85,43 @@ struct PaymentURIView_Previews: PreviewProvider {
let merchant = Merchant(name: "Merchant")
let extra = Extra(articleName: "articleName")
let product = Product(description: "description")
- let terms = ContractTerms(amount: try! Amount(fromString: LONGCURRENCY + ":2.2"),
- maxFee: try! Amount(fromString: LONGCURRENCY + ":0.2"),
- maxWireFee: try! Amount(fromString: LONGCURRENCY + ":0.2"),
- merchant: merchant,
- extra: extra,
- summary: "summary",
- timestamp: Timestamp.now(),
- payDeadline: Timestamp.tomorrow(),
- refundDeadline: Timestamp.tomorrow(),
- wireTransferDeadline: Timestamp.tomorrow(),
- merchantBaseURL: "merchantBaseURL",
- fulfillmentURL: "fulfillmentURL",
- publicReorderURL: "publicReorderURL",
- auditors: [],
- exchanges: [],
- orderID: "orderID",
- nonce: "nonce",
- merchantPub: "merchantPub",
- products: [product],
- hWire: "hWire",
- wireMethod: "wireMethod",
- wireFeeAmortization: 0)
+ let terms = MerchantContractTerms(hWire: "hWire",
+ wireMethod: "wireMethod",
+ summary: "summary",
+ summaryI18n: nil,
+ nonce: "nonce",
+ amount: try! Amount(fromString: LONGCURRENCY + ":2.2"),
+ payDeadline: Timestamp.tomorrow(),
+ maxFee: try! Amount(fromString: LONGCURRENCY + ":0.2"),
+ merchant: merchant,
+ merchantPub: "merchantPub",
+ deliveryDate: nil,
+ deliveryLocation: nil,
+ exchanges: [],
+ products: [product],
+ refundDeadline: Timestamp.tomorrow(),
+ wireTransferDeadline: Timestamp.tomorrow(),
+ timestamp: Timestamp.now(),
+ orderID: "orderID",
+ merchantBaseURL: "merchantBaseURL",
+ fulfillmentURL: "fulfillmentURL",
+ publicReorderURL: "publicReorderURL",
+ fulfillmentMessage: nil,
+ fulfillmentMessageI18n: nil,
+ wireFeeAmortization: 0,
+ maxWireFee: try! Amount(fromString: LONGCURRENCY + ":0.2"),
+ minimumAge: nil,
+ extra: extra
+// auditors: [],
+ )
let details = PaymentDetailsForUri(
+ status: PreparePayResultType.paymentPossible,
+ transactionId: "txn:payment:012345",
+ contractTerms: terms,
+ contractTermsHash: "termsHash",
amountRaw: try! Amount(fromString: LONGCURRENCY + ":2.2"),
amountEffective: try! Amount(fromString: LONGCURRENCY + ":2.4"),
- proposalId: "proposalId",
- contractTerms: terms,
- contractTermsHash: "termsHash"
+ talerUri: "talerURI"
)
let url = URL(string: "taler://pay/some_amount")!