Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 14 additions & 5 deletions Sources/ProcessOut/Sources/Api/ProcessOut.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Andrii Vysotskyi on 14.10.2024.
//

// swiftlint:disable force_unwrapping type_body_length
// swiftlint:disable force_unwrapping type_body_length file_length

import Foundation
import UIKit
Expand Down Expand Up @@ -143,7 +143,10 @@ public final class ProcessOut: @unchecked Sendable {
)
gatewayConfigurations = HttpGatewayConfigurationsRepository(connector: httpConnector)
invoices = Self.createInvoicesService(
httpConnector: httpConnector, customerActionsService: customerActionsService, logger: serviceLogger
httpConnector: httpConnector,
customerActionsService: customerActionsService,
eventEmitter: eventEmitter,
logger: serviceLogger
)
_alternativePayments = Self.createAlternativePaymentsService(
configuration: configuration, webAuthenticationSession: webAuthenticationSession, logger: serviceLogger
Expand All @@ -170,11 +173,17 @@ public final class ProcessOut: @unchecked Sendable {
// MARK: - Services

private static func createInvoicesService(
httpConnector: HttpConnector, customerActionsService: CustomerActionsService, logger: POLogger
httpConnector: HttpConnector,
customerActionsService: CustomerActionsService,
eventEmitter: POEventEmitter,
logger: POLogger
) -> POInvoicesService {
let repository = HttpInvoicesRepository(connector: httpConnector)
return DefaultInvoicesService(
repository: repository, customerActionsService: customerActionsService, logger: logger
repository: repository,
customerActionsService: customerActionsService,
eventEmitter: eventEmitter,
logger: logger
)
}

Expand Down Expand Up @@ -393,4 +402,4 @@ extension ProcessOut {
}
}

// swiftlint:enable force_unwrapping type_body_length
// swiftlint:enable force_unwrapping type_body_length file_length
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ final class LocalEventEmitter: POEventEmitter, @unchecked Sendable {
return cancellable
}

func hasListeners<Event: POEventEmitterEvent>(of eventType: Event.Type) -> Bool {
lock.lock()
defer {
lock.unlock()
}
return subscriptions.keys.contains(Event.name) ?? false
}

// MARK: - Private Nested Types

private struct Subscription {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ public protocol POEventEmitter: Sendable {
func on<Event: POEventEmitterEvent>(
_ eventType: Event.Type, listener: @escaping @Sendable (Event) -> Bool
) -> AnyObject

/// Returns boolean value indicating whether there are currently any listeners
/// of event with given type.
func hasListeners<Event: POEventEmitterEvent>(of eventType: Event.Type) -> Bool
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ public struct PONativeAlternativePaymentTokenizationRequestV2: Sendable, Encodab
/// Gateway configuration identifier.
public let gatewayConfigurationId: String

/// Alternative payment configuration.
///
/// - WARNING: Configuration is respected only with the **FIRST** request for the payment, ignored for
/// subsequent ones.
public let configuration: PONativeAlternativePaymentConfigurationV2

/// Payment request parameters.
public let submitData: PONativeAlternativePaymentSubmitDataV2?

Expand All @@ -30,13 +36,15 @@ public struct PONativeAlternativePaymentTokenizationRequestV2: Sendable, Encodab
customerId: String,
customerTokenId: String,
gatewayConfigurationId: String,
configuration: PONativeAlternativePaymentConfigurationV2 = .init(),
submitData: PONativeAlternativePaymentSubmitDataV2? = nil,
redirect: PONativeAlternativePaymentRedirectResultV2? = nil,
localeIdentifier: String? = nil
) {
self.customerId = customerId
self.customerTokenId = customerTokenId
self.gatewayConfigurationId = gatewayConfigurationId
self.configuration = configuration
self.submitData = submitData
self.redirect = redirect
self.localeIdentifier = localeIdentifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

/// Customer tokens (usually just called tokens for short) are objects that associate a payment source such as a
/// card or APM token with a customer.
public struct POCustomerToken: Codable, Sendable {
public struct POCustomerToken: Identifiable, Codable, Sendable {

/// Customer token verification status.
public enum VerificationStatus: String, Codable, Sendable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ final class HttpInvoicesRepository: InvoicesRepository {
return try await connector.execute(request: httpRequest)
}

func resolveUrl(
request: PONativeAlternativePaymentUrlResolutionRequestV2
) async throws -> PONativeAlternativePaymentUrlResolutionResponseV2 {
let httpRequest = HttpConnectorRequest<PONativeAlternativePaymentUrlResolutionResponseV2>.post(
path: "/apm-payments", body: request
)
return try await connector.execute(request: httpRequest)
}

// MARK: - Deprecated

func nativeAlternativePaymentMethodTransactionDetails(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// Created by Andrii Vysotskyi on 17.10.2022.
//

import Foundation

protocol InvoicesRepository: PORepository {

/// Creates invoice with given parameters.
Expand All @@ -23,6 +25,11 @@ protocol InvoicesRepository: PORepository {
request: PONativeAlternativePaymentAuthorizationRequestV2
) async throws -> PONativeAlternativePaymentAuthorizationResponseV2

/// Resolves native alternative payment return URL.
func resolveUrl(
request: PONativeAlternativePaymentUrlResolutionRequestV2
) async throws -> PONativeAlternativePaymentUrlResolutionResponseV2

// MARK: - Alternative Payment (Deprecated)

/// Requests information needed to continue existing payment or start new one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ public struct PONativeAlternativePaymentAuthorizationRequestV2: Sendable, Encoda
/// Gateway configuration identifier.
public let gatewayConfigurationId: String

/// Alternative payment configuration.
///
/// - WARNING: Configuration is respected only with the **FIRST** request for the payment, ignored for
/// subsequent ones.
public let configuration: PONativeAlternativePaymentConfigurationV2

/// Payment source.
public let source: String?

Expand All @@ -29,13 +35,15 @@ public struct PONativeAlternativePaymentAuthorizationRequestV2: Sendable, Encoda
public init(
invoiceId: String,
gatewayConfigurationId: String,
configuration: PONativeAlternativePaymentConfigurationV2 = .init(),
source: String? = nil,
submitData: PONativeAlternativePaymentSubmitDataV2? = nil,
redirect: PONativeAlternativePaymentRedirectResultV2? = nil,
localeIdentifier: String? = nil
) {
self.invoiceId = invoiceId
self.gatewayConfigurationId = gatewayConfigurationId
self.configuration = configuration
self.source = source
self.submitData = submitData
self.redirect = redirect
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// PONativeAlternativePaymentUrlResolutionRequestV2.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 27.03.2026.
//

import Foundation

@_spi(PO)
public struct PONativeAlternativePaymentUrlResolutionRequestV2: Sendable, Encodable {

public struct Redirect: Sendable, Encodable {

public struct Result: Sendable, Encodable { // swiftlint:disable:this nesting

/// Result URL.
public let url: URL
}

/// Redirect result.
public let result: Result
}

/// Redirect information.
public let redirect: Redirect

public init(redirect: Redirect) {
self.redirect = redirect
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// PONativeAlternativePaymentUrlResolutionResponseV2.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 27.03.2026.
//

import Foundation

@_spi(PO)
public struct PONativeAlternativePaymentUrlResolutionResponseV2: Sendable, Decodable {

public struct CustomerToken: Sendable, Decodable {

/// Customer token ID.
public let id: POCustomerToken.ID
}

/// Payment state.
public let state: PONativeAlternativePaymentStateV2

/// Payment method information.
public let paymentMethod: PONativeAlternativePaymentMethodV2

/// Invoice information if available.
public let invoice: PONativeAlternativePaymentInvoiceV2?

/// Customer token information if any.
public let customerToken: CustomerToken?

/// UI elements to display to user.
public let elements: [PONativeAlternativePaymentElementV2]?

/// Redirect details.
public let redirect: PONativeAlternativePaymentRedirectV2?
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

/// Invoice details.
public struct POInvoice: Codable, Sendable {
public struct POInvoice: Identifiable, Codable, Sendable {

/// String value that uniquely identifies this invoice.
public let id: String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// PONativeAlternativePaymentConfigurationV2.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 27.03.2026.
//

/// Payment configuration.
public struct PONativeAlternativePaymentConfigurationV2: Sendable, Encodable {

public struct ReturnRedirectType: Sendable {

/// Redirect type raw value.
let rawValue: String
}

/// Return redirect type.
public let returnRedirectType: ReturnRedirectType

public init(returnRedirectType: ReturnRedirectType = .automatic) {
self.returnRedirectType = returnRedirectType
}
}

extension PONativeAlternativePaymentConfigurationV2.ReturnRedirectType {

/// Redirect result is handled automatically.
public static let automatic = Self(rawValue: "automatic")

/// Redirect result is not processed automatically and should be resolved explicitly.
@_spi(PO)
public static let manual = Self(rawValue: "manual")
}

extension PONativeAlternativePaymentConfigurationV2.ReturnRedirectType: Encodable {

public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public struct PONativeAlternativePaymentRedirectResultV2: Sendable, Encodable {
self.success = success
}

/// indicates whether customer was redirected successfully.
/// Indicates whether customer was redirected successfully.
public let success: Bool
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import Foundation
/// Native alternative payment invoice information.
public struct PONativeAlternativePaymentInvoiceV2: Sendable, Decodable {

/// String value that uniquely identifies this invoice.
public let id: POInvoice.ID

/// Invoice amount.
@POImmutableStringCodableDecimal
public var amount: Decimal
Expand Down
Loading
Loading