Skip to content

Commit

Permalink
feat: Add AccessToken to Full Payment Process (#13)
Browse files Browse the repository at this point in the history
Add the optional parameter `accessToken` to the `OSPMTActionDelegate`'s `set` method and the `OSPMTStripeWrapper`'s `processPaymentWithDetails` method. Apply consequent changes to it.
In case of a full payment is triggered but no access token is passed, a `tokenIssue` is returned.
  • Loading branch information
OS-ricardomoreirasilva committed Apr 11, 2024
1 parent d96dba9 commit 13fdfb1
Show file tree
Hide file tree
Showing 14 changed files with 86 additions and 29 deletions.
5 changes: 4 additions & 1 deletion OSPaymentsLib/Error/OSPMTError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum OSPMTError: Int, CustomNSError, LocalizedError {
case stripePaymentMethodCreation = 13
case paymentIssue = 14
case gatewayNotConfigured = 15
case tokenIssue = 19

/// Textual description
public var errorDescription: String? {
Expand Down Expand Up @@ -43,7 +44,9 @@ public enum OSPMTError: Int, CustomNSError, LocalizedError {
case .paymentIssue:
return "Couldn't process payment."
case .gatewayNotConfigured:
return "Couldn't trigger the payment because the requested payment service provider is not configured."
return "Couldn't trigger the payment. The requested payment service provider is not configured yet."
case .tokenIssue:
return "Couldn’t trigger the payment. The access token is not defined."
}
}
}
5 changes: 3 additions & 2 deletions OSPaymentsLib/Gateways/Stripe/OSPMTStripeWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ extension OSPMTStripeWrapper {
/// - Parameters:
/// - payment: Apple Pay's payment request result.
/// - details: Payment details to trigger processing.
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: Payment process result. If returns the process result in case of success or an error otherwise.
func process(_ payment: PKPayment, with details: OSPMTDetailsModel, _ completion: @escaping (Result<OSPMTServiceProviderInfoModel, OSPMTError>) -> Void) {
func process(_ payment: PKPayment, with details: OSPMTDetailsModel, and accessToken: String, _ completion: @escaping (Result<OSPMTServiceProviderInfoModel, OSPMTError>) -> Void) {
self.apiDelegate.getPaymentMethodId(from: payment) { result in
switch result {
case .success(let paymentMethodId):
let requestParametersModel = OSPMTStripeRequestParametersModel(
amount: details.paymentAmount.multiplying(by: 100).intValue, currency: details.currency, paymentMethodId: paymentMethodId
)
self.processURLRequest(requestParametersModel, completion)
self.processURLRequest(requestParametersModel, and: accessToken, completion)
case .failure(let error):
completion(.failure(error))
}
Expand Down
5 changes: 3 additions & 2 deletions OSPaymentsLib/OSPMTApplePayHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ extension OSPMTApplePayHandler: OSPMTHandlerDelegate {
/// Sets Payment details and triggers its processing.
/// - Parameters:
/// - detailsModel: payment details information.
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: an async closure that can return a successful Payment Scope Model or an error otherwise.
func set(_ detailsModel: OSPMTDetailsModel, completion: @escaping OSPMTCompletionHandler) {
self.requestBehaviour.trigger(with: detailsModel, completion)
func set(_ detailsModel: OSPMTDetailsModel, and accessToken: String?, _ completion: @escaping OSPMTCompletionHandler) {
self.requestBehaviour.trigger(with: detailsModel, and: accessToken, completion)
}
}
10 changes: 6 additions & 4 deletions OSPaymentsLib/OSPMTPayments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ extension OSPMTPayments: OSPMTActionDelegate {
}
}

/// Sets payment details and triggers the request proccess.
/// - Parameter details: Payment details model serialized into a text field.
public func set(_ details: String) {
/// Sets payment details and triggers the request process.
/// - Parameters:
/// - details: Payment details model serialized into a text field.
/// - accessToken: Authorisation token related with a full payment type.
public func set(_ details: String, and accessToken: String?) {
let detailsResult = self.decode(details)
switch detailsResult {
case .success(let detailsModel):
self.handler.set(detailsModel) { [weak self] result in
self.handler.set(detailsModel, and: accessToken) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let scopeModel):
Expand Down
12 changes: 11 additions & 1 deletion OSPaymentsLib/Protocols/OSPMTActionDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ public protocol OSPMTActionDelegate: AnyObject {
func checkWalletSetup()

/// Sets payment details and triggers the request proccess.
/// - Parameters:
/// - details: Payment details model serialized into a text field.
/// - accessToken: Authorisation token related with a full payment type.
func set(_ details: String, and accessToken: String?)
}

public extension OSPMTActionDelegate {
/// Sets payment details and triggers the request proccess. This uses the default method without the `accessToken` parameter.
/// - Parameter details: Payment details model serialized into a text field.
func set(_ details: String)
func set(_ details: String) {
self.set(details, and: nil)
}
}
8 changes: 6 additions & 2 deletions OSPaymentsLib/Protocols/OSPMTGatewayDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ protocol OSPMTGatewayDelegate: AnyObject {
/// - Parameters:
/// - payment: Apple Pay's payment request result.
/// - details: Payment details to trigger processing.
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: Payment process result. If returns the process result in case of success or an error otherwise.
func process(_ payment: PKPayment, with details: OSPMTDetailsModel, _ completion: @escaping (Result<OSPMTServiceProviderInfoModel, OSPMTError>) -> Void)
func process(_ payment: PKPayment, with details: OSPMTDetailsModel, and accessToken: String, _ completion: @escaping (Result<OSPMTServiceProviderInfoModel, OSPMTError>) -> Void)
}

extension OSPMTGatewayDelegate {

/// Triggers the backend url request.
/// - Parameters:
/// - requestParameters: Model containing the request body to trigger
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: Payment process result. If returns the process result in case of success or an error otherwise.
func processURLRequest(_ requestParameters: OSPMTRequestParametersModel, _ completion: @escaping (Result<OSPMTServiceProviderInfoModel, OSPMTError>) -> Void) {
func processURLRequest(_ requestParameters: OSPMTRequestParametersModel, and accessToken: String, _ completion: @escaping (Result<OSPMTServiceProviderInfoModel, OSPMTError>) -> Void) {
self.urlRequest.httpMethod = "POST"
self.urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
self.urlRequest.setValue("application/json", forHTTPHeaderField: "Accept")
self.urlRequest.setValue(accessToken, forHTTPHeaderField: "Payments-Token")

self.urlRequest.httpBody = try? JSONEncoder().encode(requestParameters)
let task = self.urlSession.dataTask(with: self.urlRequest) { data, response, error in
guard let response = response as? HTTPURLResponse,
Expand Down
13 changes: 12 additions & 1 deletion OSPaymentsLib/Protocols/OSPMTHandlerDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ protocol OSPMTHandlerDelegate: AnyObject {
/// Sets Payment details and triggers its processing.
/// - Parameters:
/// - detailsModel: payment details information.
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: an async closure that can return a successful Payment Scope Model or an error otherwise.
func set(_ detailsModel: OSPMTDetailsModel, completion: @escaping OSPMTCompletionHandler)
func set(_ detailsModel: OSPMTDetailsModel, and accessToken: String?, _ completion: @escaping OSPMTCompletionHandler)
}

extension OSPMTHandlerDelegate {
/// Sets Payment details and triggers its processing. It uses the default `set` method without the `accessToken` parameter.
/// - Parameters:
/// - detailsModel: payment details information.
/// - completion: an async closure that can return a successful Payment Scope Model or an error otherwise.
func set(_ detailsModel: OSPMTDetailsModel, _ completion: @escaping OSPMTCompletionHandler) {
self.set(detailsModel, and: nil, completion)
}
}
37 changes: 28 additions & 9 deletions OSPaymentsLib/Protocols/OSPMTRequestDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,19 @@ protocol OSPMTRequestDelegate: AnyObject {
/// Sets Payment details and triggers its processing.
/// - Parameters:
/// - detailsModel: payment details information.
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: an async closure that can return a successful Payment Scope Model or an error otherwise.
func trigger(with detailsModel: OSPMTDetailsModel, _ completion: @escaping OSPMTCompletionHandler)
func trigger(with detailsModel: OSPMTDetailsModel, and accessToken: String?, _ completion: @escaping OSPMTCompletionHandler)
}

extension OSPMTRequestDelegate {
/// Sets Payment details and triggers its processing. It uses the default method without the `accessToken` parameter.
/// - Parameters:
/// - detailsModel: payment details information.
/// - completion: an async closure that can return a successful Payment Scope Model or an error otherwise.
func trigger(with detailsModel: OSPMTDetailsModel, _ completion: @escaping OSPMTCompletionHandler) {
self.trigger(with: detailsModel, and: nil, completion)
}
}

/// Class that implements the `OSPMTRequestDelegate` for Apple Pay, providing it the required that details to work.
Expand All @@ -37,6 +48,7 @@ class OSPMTApplePayRequestBehaviour: NSObject, OSPMTRequestDelegate {
var paymentStatus: PKPaymentAuthorizationStatus = .failure
var paymentScope: OSPMTScopeModel?
var paymentDetails: OSPMTDetailsModel?
var accessToken: String?
var completionHandler: OSPMTCompletionHandler!

/// Constructor method.
Expand All @@ -48,8 +60,14 @@ class OSPMTApplePayRequestBehaviour: NSObject, OSPMTRequestDelegate {
self.requestTriggerType = requestTriggerType
}

func trigger(with detailsModel: OSPMTDetailsModel, _ completion: @escaping OSPMTCompletionHandler) {
/// Sets Payment details and triggers its processing.
/// - Parameters:
/// - detailsModel: payment details information.
/// - accessToken: Authorisation token related with a full payment type.
/// - completion: an async closure that can return a successful Payment Scope Model or an error otherwise.
func trigger(with detailsModel: OSPMTDetailsModel, and accessToken: String?, _ completion: @escaping OSPMTCompletionHandler) {
self.paymentDetails = detailsModel
self.accessToken = accessToken
self.completionHandler = completion

let result = self.requestTriggerType.createRequestTriggerBehaviour(for: detailsModel, andDelegate: self)
Expand Down Expand Up @@ -125,18 +143,19 @@ extension OSPMTApplePayRequestBehaviour: PKPaymentAuthorizationControllerDelegat
}

if let paymentDetails = paymentDetails, paymentDetails.gateway != nil {
guard let accessToken = self.accessToken, !accessToken.isEmpty else {
return completion(PKPaymentAuthorizationResult(status: self.paymentStatus, errors: [OSPMTError.tokenIssue]))
}

guard let paymentGateway = self.configuration.gatewayModel, paymentGateway.gatewayEnum == paymentDetails.gateway else {
completion(PKPaymentAuthorizationResult(status: self.paymentStatus, errors: [OSPMTError.gatewayNotConfigured]))
return
return completion(PKPaymentAuthorizationResult(status: self.paymentStatus, errors: [OSPMTError.gatewayNotConfigured]))
}

guard let gatewayWrapper = OSPMTGatewayFactory.createWrapper(for: paymentGateway)
else {
completion(PKPaymentAuthorizationResult(status: self.paymentStatus, errors: [OSPMTError.gatewaySetFailed]))
return
guard let gatewayWrapper = OSPMTGatewayFactory.createWrapper(for: paymentGateway) else {
return completion(PKPaymentAuthorizationResult(status: self.paymentStatus, errors: [OSPMTError.gatewaySetFailed]))
}

gatewayWrapper.process(payment, with: paymentDetails) { result in
gatewayWrapper.process(payment, with: paymentDetails, and: accessToken) { result in
var errorArray = [OSPMTError]()
var paymentResultModel: OSPMTServiceProviderInfoModel?

Expand Down
2 changes: 1 addition & 1 deletion OSPaymentsLibTests/OSPMTApplePayHandlerSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class OSPMTMockRequestBehaviour: OSPMTRequestDelegate {
self.scopeModel = scopeModel
}

func trigger(with detailsModel: OSPMTDetailsModel, _ completion: @escaping OSPMTCompletionHandler) {
func trigger(with detailsModel: OSPMTDetailsModel, and accessToken: String?, _ completion: @escaping OSPMTCompletionHandler) {
if let error = self.error {
completion(.failure(error))
} else {
Expand Down
2 changes: 1 addition & 1 deletion OSPaymentsLibTests/OSPMTPaymentsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class OSPMTMockHandler: OSPMTHandlerDelegate {
return self.error
}

func set(_ detailsModel: OSPMTDetailsModel, completion: @escaping OSPMTCompletionHandler) {
func set(_ detailsModel: OSPMTDetailsModel, and accessToken: String?, _ completion: @escaping OSPMTCompletionHandler) {
if let error = self.error {
completion(.failure(error))
} else if let scopeModel = self.scopeModel {
Expand Down
8 changes: 4 additions & 4 deletions OSPaymentsLibTests/OSPMTStripeWrapperSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class OSPMTStripeWrapperSpec: QuickSpec {
it("It should return a Stripe Payment Method Creation error") {
mockAPIDelegate.error = OSPMTError.stripePaymentMethodCreation

stripeWrapper.process(mockPayment, with: mockDetailsModel) { result in
stripeWrapper.process(mockPayment, with: mockDetailsModel, and: OSPMTTestConfigurations.dummyAccessToken) { result in
switch result {
case .failure(let errorResult):
expect(errorResult).to(equal(OSPMTError.stripePaymentMethodCreation))
Expand All @@ -116,7 +116,7 @@ class OSPMTStripeWrapperSpec: QuickSpec {
return (response, OSPMTTestConfigurations.dummyString.data(using: .utf8))
}

stripeWrapper.process(mockPayment, with: mockDetailsModel) { result in
stripeWrapper.process(mockPayment, with: mockDetailsModel, and: OSPMTTestConfigurations.dummyAccessToken) { result in
switch result {
case .failure(let errorResult):
expect(errorResult).to(equal(.paymentIssue))
Expand All @@ -139,7 +139,7 @@ class OSPMTStripeWrapperSpec: QuickSpec {
return (response, resultData)
}

stripeWrapper.process(mockPayment, with: mockDetailsModel) { result in
stripeWrapper.process(mockPayment, with: mockDetailsModel, and: OSPMTTestConfigurations.dummyAccessToken) { result in
switch result {
case .failure(let errorResult):
expect(errorResult).to(equal(.paymentIssue))
Expand All @@ -164,7 +164,7 @@ class OSPMTStripeWrapperSpec: QuickSpec {
return (response, resultData)
}

stripeWrapper.process(mockPayment, with: mockDetailsModel) { result in
stripeWrapper.process(mockPayment, with: mockDetailsModel, and: OSPMTTestConfigurations.dummyAccessToken) { result in
switch result {
case .success(let resultModel):
expect(resultModel).to(equal(OSPMTTestConfigurations.validPaymentProcessResultModel))
Expand Down
2 changes: 2 additions & 0 deletions OSPaymentsLibTests/OSPMTTestConfigurations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,6 @@ struct OSPMTTestConfigurations {

static let invalidPaymentProcessResultModel = OSPMTServiceProviderInfoModel(id: Self.dummyString, status: OSPMTProcessStatus.fail.rawValue)
static let validPaymentProcessResultModel = OSPMTServiceProviderInfoModel(id: Self.dummyString, status: OSPMTProcessStatus.success.rawValue)

static let dummyAccessToken = "dummy"
}
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### 2023-01-05
- Feat: Add access token to Full Payment Process (https://outsystemsrd.atlassian.net/browse/RMET-2147).

### 2022-12-12
- Feat: Add Payment Service Provider property to `OSPMTDetailsModel` struct (https://outsystemsrd.atlassian.net/browse/RMET-2095).

Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ The method's success is returned through a `OSPMTCallbackDelegate` call. Success
### Set Details and Trigger Payment

```swift
func set(_ details: String)
func set(_ details: String, and: accessToken: String?)
```

Sets payment details and triggers the request proccess. The method contains the following parameter:
- `details`: Payment details model serialized into a text field. This model can be checked in the `OSPMTDetailsModel` structure.
- `accessToken`: Authorisation token related with a full payment type. Can be empty, which should be the case for custom payments.

The method's success is returned through a `OSPMTCallbackDelegate` call. Success operations returns an object of the structure type `OSPMTScopeModel`, encoded in a UTF-8 string. An `OSPMTError` error is returned in case of error.

0 comments on commit 13fdfb1

Please sign in to comment.