Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ad-hoc): allow injecting invoice in example #351

Merged
merged 7 commits into from
Sep 16, 2024
Merged
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
10 changes: 10 additions & 0 deletions Example/Example/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,16 @@
}
}
},
"invoice.id" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "ID (optional)"
}
}
}
},
"invoice.name" : {
"localizations" : {
"en" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,14 @@ final class AlternativePaymentsInteractor {
_ = await task.result
}

func createInvoice(name: String, amount: Decimal, currencyCode: String) async throws -> POInvoice {
func invoice(id: String) async throws -> POInvoice {
let request = POInvoiceRequest(invoiceId: id)
return try await invoicesService.invoice(request: request)
}

func createInvoice(amount: Decimal, currencyCode: String) async throws -> POInvoice {
let request = POInvoiceCreationRequest(
name: name,
name: UUID().uuidString,
amount: amount,
currency: currencyCode,
returnUrl: Example.Constants.returnUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,13 @@ final class AlternativePaymentsViewModel: ObservableObject {
return
}
do {
let invoice = try await interactor.createInvoice(
name: state.invoice.name,
amount: state.invoice.amount,
currencyCode: state.invoice.currencyCode
)
let invoice = if state.invoice.id.isEmpty {
try await interactor.createInvoice(
amount: state.invoice.amount, currencyCode: state.invoice.currencyCode
)
} else {
try await interactor.invoice(id: state.invoice.id)
}
var authorizationSource = gatewayConfigurationId
if state.shouldTokenize {
let token = try await interactor.tokenize(gatewayConfigurationId: gatewayConfigurationId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,8 @@ final class ApplePayViewModel: ObservableObject {

private func createInvoiceAndAuthorize(request: PKPaymentRequest) async {
do {
var invoice: POInvoice! // swiftlint:disable:this implicitly_unwrapped_optional
let invoiceCreationRequest = POInvoiceCreationRequest(
name: state.invoice.name,
amount: state.invoice.amount,
currency: state.invoice.currencyCode
)
let invoice = try await createInvoice()
let coordinator = ApplePayTokenizationCoordinator { [invoicesService] card in
invoice = try await invoicesService.createInvoice(request: invoiceCreationRequest)
let authorizationRequest = POInvoiceAuthorizationRequest(
invoiceId: invoice.id, source: card.id
)
Expand All @@ -77,6 +71,21 @@ final class ApplePayViewModel: ObservableObject {
}
}

private func createInvoice() async throws -> POInvoice {
if state.invoice.id.isEmpty {
let request = POInvoiceCreationRequest(
name: UUID().uuidString,
amount: state.invoice.amount,
currency: state.invoice.currencyCode,
returnUrl: Constants.returnUrl
)
return try await invoicesService.createInvoice(request: request)
} else {
let request = POInvoiceRequest(invoiceId: state.invoice.id)
return try await invoicesService.invoice(request: request)
}
}

private func setSuccessMessage(invoice: POInvoice, card: POCard) {
let text = String(localized: .ApplePay.successMessage, replacements: invoice.id, card.id)
state.message = .init(text: text, severity: .success)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,27 @@ final class CardPaymentViewModel: ObservableObject {
)
state.cardTokenization = cardTokenizationItem
}

private func createInvoice() async throws -> POInvoice {
if state.invoice.id.isEmpty {
let request = POInvoiceCreationRequest(
name: UUID().uuidString,
amount: state.invoice.amount,
currency: state.invoice.currencyCode,
returnUrl: Constants.returnUrl
)
return try await invoicesService.createInvoice(request: request)
} else {
let request = POInvoiceRequest(invoiceId: state.invoice.id)
return try await invoicesService.invoice(request: request)
}
}
}

extension CardPaymentViewModel: POCardTokenizationDelegate {

func cardTokenization(didTokenizeCard card: POCard, shouldSaveCard save: Bool) async throws {
let invoiceCreationRequest = POInvoiceCreationRequest(
name: state.invoice.name,
amount: state.invoice.amount,
currency: state.invoice.currencyCode,
returnUrl: Constants.returnUrl
)
let invoice = try await invoicesService.createInvoice(request: invoiceCreationRequest)
let invoice = try await createInvoice()
let invoiceAuthorizationRequest = POInvoiceAuthorizationRequest(
invoiceId: invoice.id,
source: card.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,9 @@ struct ConfigurationView: View {
}
}
.sheet(isPresented: $isScannerPresented) {
VStack {
ConfigurationScannerView { code in
viewModel.didScanConfiguration(code)
}
Spacer()
ConfigurationScannerView { code in
viewModel.didScanConfiguration(code)
}
.presentationCornerRadius(16)
.presentationDragIndicator(.visible)
.presentationDetents([.fraction(0.5)])
}
}
.onReceive(viewModel.dismiss) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ struct ConfigurationScannerView: View {
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(8)
.fixedSize(horizontal: false, vertical: true)
Spacer()
}
.frame(maxWidth: .infinity)
.padding(32)
.presentationCornerRadius(16)
.presentationDragIndicator(.visible)
.presentationDetents([.fraction(0.5)])
}

// MARK: - Private Properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,8 @@ final class DynamicCheckoutViewModel: ObservableObject {

@MainActor
private func startDynamicCheckout() async {
let invoiceCreationRequest = POInvoiceCreationRequest(
name: state.invoice.name,
amount: state.invoice.amount,
currency: state.invoice.currencyCode,
returnUrl: Constants.returnUrl,
customerId: Constants.customerId
)
do {
let invoice = try await self.invoicesService.createInvoice(request: invoiceCreationRequest)
let invoice = try await createInvoice()
continueDynamicCheckout(invoice: invoice)
} catch {
setMessage(with: error)
Expand Down Expand Up @@ -87,6 +80,21 @@ final class DynamicCheckoutViewModel: ObservableObject {
}
state.message = .init(text: errorMessage ?? String(localized: .DynamicCheckout.errorMessage), severity: .error)
}

private func createInvoice() async throws -> POInvoice {
if state.invoice.id.isEmpty {
let request = POInvoiceCreationRequest(
name: UUID().uuidString,
amount: state.invoice.amount,
currency: state.invoice.currencyCode,
returnUrl: Constants.returnUrl
)
return try await invoicesService.createInvoice(request: request)
} else {
let request = POInvoiceRequest(invoiceId: state.invoice.id)
return try await invoicesService.invoice(request: request)
}
}
}

extension DynamicCheckoutViewModel: PODynamicCheckoutDelegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ extension LocalizedStringResource {

enum Invoice {

/// Invoice ID.
static let id = LocalizedStringResource("invoice.id")

/// Title.
static let title = LocalizedStringResource("invoice.title")

Expand Down
25 changes: 22 additions & 3 deletions Example/Example/Sources/UI/Modules/Invoice/View/InvoiceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,25 @@ struct InvoiceView: View {

var body: some View {
Section {
TextField(
String(localized: .Invoice.name), text: $viewModel.name
)
HStack {
TextField(
String(localized: .Invoice.id), text: $viewModel.id
)
.keyboardType(.asciiCapable)
Button(
action: {
isScannerPresented = true
},
label: {
Image(systemName: "qrcode.viewfinder")
}
)
}
.sheet(isPresented: $isScannerPresented) {
ConfigurationScannerView { invoiceId in
viewModel.id = invoiceId
}
}
TextField(
String(localized: .Invoice.amount), value: $viewModel.amount, format: .number
)
Expand All @@ -37,4 +53,7 @@ struct InvoiceView: View {

@Binding
private var viewModel: InvoiceViewModel

@State
private var isScannerPresented = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import Foundation

struct InvoiceViewModel {

/// Invoice name.
var name: String
/// Invoice ID.
var id: String

/// Invoice amount.
var amount: Decimal
Expand All @@ -23,8 +23,8 @@ extension InvoiceViewModel {

/// Convenience init to create default view model.
init() {
self.name = UUID().uuidString
self.amount = 100
id = ""
amount = 100
currencyCode = "USD"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,10 @@ final class DefaultHttpConnectorRequestMapper: HttpConnectorRequestMapper {
request: HttpConnectorRequest<some Decodable>, configuration: HttpConnectorRequestMapperConfiguration
) -> String {
var value = configuration.projectId + ":"
if request.requiresPrivateKey {
if let privateKey = configuration.privateKey {
value += privateKey
} else {
assertionFailure("Private key is required by '\(request)' request but not set")
}
if let privateKey = configuration.privateKey {
value += privateKey
} else if request.requiresPrivateKey {
assertionFailure("Private key is required by '\(request)' request but not set")
}
return "Basic " + Data(value.utf8).base64EncodedString()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ final class DefaultHttpConnectorRequestMapperTests: XCTestCase {

// Then
let authorization = urlRequest.value(forHTTPHeaderField: "Authorization")
XCTAssertEqual(authorization, "Basic PElEPjo=")
XCTAssertEqual(authorization, "Basic PElEPjo8S0VZPg==")
}

func test_urlRequest_whenPrivateKeyIsRequired_addsAuthorization() async throws {
Expand Down
Loading