12

In my application I support only EUR and USD currency. So when user tries to send payment with Siri to GBP, for example, I ask him to choose between EUR and USD.

After that on the screen I see:

  • 100 $
  • 100 EUR

If I choose 100$ in intent.currencyAmount!.currencyCode I always have GBP (but user chose dollars). It's very strange.

Here is my code:

func resolveCurrencyAmount(forSendPayment intent: INSendPaymentIntent, with completion: @escaping (INCurrencyAmountResolutionResult) -> Void) {
        if let currencyAmount = intent.currencyAmount { // need to check if we have proper value
            if let amount = currencyAmount.amount {

                if amount.doubleValue == 0 { // wrong amount
                    completion(INCurrencyAmountResolutionResult.unsupported())
                    return
                }

                if let currencyCode = currencyAmount.currencyCode {
                    if let _ = EnumCurrency(rawValue: currencyCode) { // we found currency code that we know
                        completion(INCurrencyAmountResolutionResult.success(with: INCurrencyAmount(amount: NSDecimalNumber(value: abs(amount.doubleValue)), currencyCode: currencyCode)))
                        return
                    }
                }


                // if we are here so we don't have proper currency, try to offer user to choose the same amount but with all possible currencies
                let disambiguationArray: [INCurrencyAmount] = EnumCurrency.allValues.map({ (currency) -> INCurrencyAmount in
                    return INCurrencyAmount(amount: NSDecimalNumber(value: abs(amount.doubleValue)), currencyCode: currency.rawValue)
                })
                completion(INCurrencyAmountResolutionResult.disambiguation(with: disambiguationArray))
            }
        }
        else { // we don't have value
            completion(INCurrencyAmountResolutionResult.needsValue())
        }
    }

enum EnumCurrency : String {
    case EUR = "EUR"
    case USD = "USD"

    static let allValues = [EUR, USD]
}

Update: how to reproduce (according to David question):

1) create a new intent extantion

2) in plist file leave only one type of intent: http://take.ms/pt16N

3) Your IntentHandler class (will be created by xCode) must confirm to INSendPaymentIntentHandling protocol

4) In IntentHandler class add this:

func resolveCurrencyAmount(forSendPayment intent: INSendPaymentIntent, with completion: @escaping (INCurrencyAmountResolutionResult) -> Void) {
            if let currencyAmount = intent.currencyAmount { // need to check if we have proper value
                if let amount = currencyAmount.amount {

                    if amount.doubleValue == 0 { // wrong amount


                 completion(INCurrencyAmountResolutionResult.unsupported())
                    return
                }

                if let currencyCode = currencyAmount.currencyCode {
                    if let _ = EnumCurrency(rawValue: currencyCode) { // we found currency code that we know
                        completion(INCurrencyAmountResolutionResult.success(with: INCurrencyAmount(amount: NSDecimalNumber(value: abs(amount.doubleValue)), currencyCode: currencyCode)))
                        return
                    }
                }


                // if we are here so we don't have proper currency, try to offer user to choose the same amount but with all possible currencies
                let disambiguationArray: [INCurrencyAmount] = EnumCurrency.allValues.map({ (currency) -> INCurrencyAmount in
                    return INCurrencyAmount(amount: NSDecimalNumber(value: abs(amount.doubleValue)), currencyCode: currency.rawValue)
                })
                completion(INCurrencyAmountResolutionResult.disambiguation(with: disambiguationArray))
            }
        }
        else { // we don't have value
            completion(INCurrencyAmountResolutionResult.needsValue())
        }
    }

enum EnumCurrency : String {
    case EUR = "EUR"
    case USD = "USD"

    static let allValues = [EUR, USD]
}

// MARK: - Confirm

    func confirm(sendPayment intent: INSendPaymentIntent, completion: @escaping (INSendPaymentIntentResponse) -> Void) {
// success
        completion(INSendPaymentIntentResponse(code: INSendPaymentIntentResponseCode.success, userActivity: nil))

}

// MARK: - Handle

    func handle(sendPayment intent: INSendPaymentIntent, completion: @escaping (INSendPaymentIntentResponse) -> Void) {

// just for test
completion(INSendPaymentIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity))
}

5) And you can launch with Siri: you will see that if you choose Chinese currency or any other not regular currency and then I in code make you to choose between EUR and USD, but after that in RESOLVE function (called when siri want to resolve currency on more time) you will get Chinese currency (so you don't need to add any code for buttons like David asked, because all the button interface will be provided by Siri)

Paul T.
  • 4,938
  • 7
  • 45
  • 93
  • 1
    I don't see a mistake in that short code snipped. Maybe you want to post the code of the `Button` or whatever element takes the user interaction. – David Seek Nov 02 '16 at 06:41
  • 1
    there is no mistake. I think that may be it Apple's mistake, because it's very strange that if I choose USD , I immidiatly get GBP currency from Siri – Paul T. Nov 02 '16 at 12:53
  • 1
    okay but if you don't want to post code, assume that you are right and furthermore assume, that there is a bug within the apple framework, what do you expect out of this thread? – David Seek Nov 02 '16 at 13:19
  • 1
    I updated the instruction for you. As you see you don't need any code for buttons, because all the button interface will be provided by Siri. So you can try to reproduce the same issue, but before you need to create Intents Extention. And if there is a bug in Apple framework, I think that may be there is any workaround, that will let the code work – Paul T. Nov 03 '16 at 03:43

2 Answers2

3

i created this issue: Siri and wrong currency

All you need to do is confirm currency picked by user. Your confirm method is wrongly implemented, you should confirm currency with something like this:

let response = INSendPaymentIntentResponse(code: .ready, userActivity: nil)
response.paymentRecord = INPaymentRecord(
    payee: intent.payee, 
    payer: nil, 
    currencyAmount: intent.currencyAmount, 
    paymentMethod: nil, 
    note: nil, 
    status: .pending, 
    feeAmount: nil)
completion(response)
Community
  • 1
  • 1
user3292998
  • 209
  • 1
  • 8
  • Could you add full code with resolve (if you have), confirm, handle methods? (so I can try your code, because my issue happens before confirm method, it happens in Resolve method, so if my resolve method stays the same, Confirm method will never be called). And in your Issue, @Reem user says that this solution didn't help him, so I just want to try the whole code – Paul T. Nov 04 '16 at 06:35
  • 1
    I thought about this, I don't understand: if I don't have resolve method for currencyAmount, I can't just confirm his currency, because he could choose GBP currency, but application doesn't support it. But if I have resolveCurrencyAmount method, I don't understand how determine in this method, when I need to return completion(INCurrencyAmountResolutionResult.success), because the only case when I have problem is when currency is GBP, but in this case I will always ask user to choose between possible currencies,and it will be endless.So it will be very good,if you can give your almost full code – Paul T. Nov 04 '16 at 07:18
  • 1
    added comment in code, where you should create INpaymentRecord – user3292998 Nov 04 '16 at 13:03
  • 1
    1) in this case that doesn't work, because as I said before , confirm function will be never called, because user will endlessly see the window in Siri to choose between EUR and USD (because in resolve method after user choose USD, I will get GPB and that's why I endlessly make user to choose between currencies 2) please post your full code for sendMoneyIntentHandlingProtocol (you can remove very personal and not very important parts of code)) 3) please don't make edits in my code (because editors of stackoverflow don't allow this and it difficult to see your edits – Paul T. Nov 05 '16 at 05:42
0

In confirmSendPayment method, create INSendPaymentIntentResponse instance and assign a INPaymentRecord instance to paymentRecord property. I made a helper method to do this thing.

func confirm(sendPayment intent: INSendPaymentIntent, completion: (INSendPaymentIntentResponse) -> Void) {
    let response = INSendPaymentIntentResponse(code: .Ready, userActivity: nil)
    response.paymentRecord = getPaymentRecord(fromIntent: intent)
    completion(response)
}

private func getPaymentRecord(fromIntent intent: INSendPaymentIntent) -> INPaymentRecord? {
    let currencyAmount = INCurrencyAmount(amount: intent.currencyAmount?.amount ?? 0.0, currencyCode: "INR")
    return INPaymentRecord(payee: intent.payee, payer: nil, currencyAmount: currencyAmount, paymentMethod: nil, note: nil, status: .Pending)
}

Hope this helps.

sudhanshu-shishodia
  • 1,100
  • 1
  • 11
  • 25
  • if user didn't provide amount you assign 0 with INR currency, but I need to user to enter amount and currency, so I need resolveAmount functions, but if I have this function, confirm function will never be executed if currency is wrong (but it offten wrong) – Paul T. Feb 07 '17 at 07:23
  • I didn't get what you meant by "confirm function will not be executed if currency is wrong" ?? – sudhanshu-shishodia Feb 07 '17 at 11:20
  • because if currency is wrong, I will ask to choose between EUR and USD , user will choose EUR for example, but iOS will think he chose GBP and that's why user will see endless choose method to choose between currencies – Paul T. Feb 07 '17 at 11:31