diff --git a/.github/workflows/health-sdk.build.xcframeworks.xcode16.yml b/.github/workflows/health-sdk.build.xcframeworks.xcode16.yml new file mode 100644 index 000000000..0768815fe --- /dev/null +++ b/.github/workflows/health-sdk.build.xcframeworks.xcode16.yml @@ -0,0 +1,79 @@ +name: Build HealthSDK XCFrameworks XCode 16 +on: + push: + tags: + - 'GiniHealthSDK;[0-9]+.[0-9]+.[0-9]+;xcframeworks**' + - 'GiniHealthSDK;[0-9]+.[0-9]+.[0-9]+-beta[0-9][0-9]+;xcframeworks**' + workflow_dispatch: + workflow_call: + secrets: + BUILD_CERTIFICATE_BASE64: + required: true + P12_PASSWORD: + required: true + BUILD_PROVISION_PROFILE_BASE64: + required: true + KEYCHAIN_PASSWORD: + required: true +jobs: + prepare-frameworks: + name: Create Release + runs-on: macos-15 + steps: + - uses: maxim-lobanov/setup-xcode@v1.6.0 + with: + xcode-version: '16.2' + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Archiving project and creating XCFrameworks + run: | + ./build-healthsdk.sh + + - name: Sign the XCFrameworks + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.GINI_DISTRIBUTION_CERTIFICATE }} + P12_PASSWORD: ${{ secrets.GINI_DISTRIBUTION_CERTIFICATE_SECRET }} + BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.GINI_HEALTH_SDK_EXAMPLE_APP_ADHOC_DISTRIBUTION_PROVISION_PROFILE }} + KEYCHAIN_PASSWORD: ${{ secrets.GINI_DISTRIBUTION_CERTIFICATE_SECRET }} + run: | + # Setup distribution certificate + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH1=$RUNNER_TEMP/build_pp1.mobileprovision + + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH1 + + # create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + # apply provisioning profile + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_PATH1 ~/Library/MobileDevice/Provisioning\ Profiles + + # sign xcframeworks + codesign --timestamp -v --sign "Apple Distribution: Gini GmbH (JA825X8F7Z)" GiniHealthAPILibrary.xcframework && \ + codesign --timestamp -v --sign "Apple Distribution: Gini GmbH (JA825X8F7Z)" GiniHealthSDK.xcframework && \ + codesign --timestamp -v --sign "Apple Distribution: Gini GmbH (JA825X8F7Z)" GiniInternalPaymentSDK.xcframework && \ + codesign --timestamp -v --sign "Apple Distribution: Gini GmbH (JA825X8F7Z)" GiniUtilites.xcframework + + - name: archive frameworks GiniHealthAPILibrary + uses: actions/upload-artifact@v4 + with: + name: GiniHealthSDKFramework + path: | + GiniHealthAPILibrary.xcframework + GiniHealthSDK.xcframework + GiniInternalPaymentSDK.xcframework + GiniUtilites.xcframework + diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/ReturnAssistant/EditLineItem/EditLineItemViewModel.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/ReturnAssistant/EditLineItem/EditLineItemViewModel.swift index ca1661e65..de3a28508 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/ReturnAssistant/EditLineItem/EditLineItemViewModel.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/ReturnAssistant/EditLineItem/EditLineItemViewModel.swift @@ -15,7 +15,7 @@ protocol EditLineItemViewModelDelegate: AnyObject { final class EditLineItemViewModel { weak var delegate: EditLineItemViewModelDelegate? private var lineItem: DigitalInvoice.LineItem - private (set) var itemsChanged: [GiniLineItemAnalytics] = [] + private(set) var itemsChanged: [GiniLineItemAnalytics] = [] var name: String? { return lineItem.name diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoDocumentPagesViewModel.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoDocumentPagesViewModel.swift index 2be3b1fed..4346d0340 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoDocumentPagesViewModel.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoDocumentPagesViewModel.swift @@ -27,7 +27,7 @@ final class SkontoDocumentPagesViewModel: DocumentPagesViewModelProtocol { private var expiryDate: Date // Information to be displayed in the screen after highlighting Skonto details - private (set) var processedImages = [UIImage]() + private(set) var processedImages = [UIImage]() static var screenTitle = NSLocalizedStringPreferredGiniBankFormat("ginibank.skonto.document.pages.screen.title", comment: "Skonto discount details") var bottomInfoItems: [String] { diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoViewModel.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoViewModel.swift index c722c3332..5b0230903 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoViewModel.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/Skonto/Models/SkontoViewModel.swift @@ -26,21 +26,21 @@ class SkontoViewModel { var proceedAction: (() -> Void)? private let skontoDiscounts: SkontoDiscounts - private (set) var isWithDiscountSwitchAvailable: Bool + private(set) var isWithDiscountSwitchAvailable: Bool private var skontoPercentage: Double - private (set) var isSkontoApplied: Bool = true - private (set) var amountToPay: Price - private (set) var skontoAmountToPay: Price + private(set) var isSkontoApplied: Bool = true + private(set) var amountToPay: Price + private(set) var skontoAmountToPay: Price - private (set) var dueDate: Date - private (set) var amountDiscounted: Price - private (set) var currencyCode: String - private (set) var remainingDays: Int - private (set) var paymentMethod: SkontoDiscountDetails.PaymentMethod - private (set) var edgeCase: SkontoEdgeCase? + private(set) var dueDate: Date + private(set) var amountDiscounted: Price + private(set) var currencyCode: String + private(set) var remainingDays: Int + private(set) var paymentMethod: SkontoDiscountDetails.PaymentMethod + private(set) var edgeCase: SkontoEdgeCase? - private (set) var documentPagesViewModel: SkontoDocumentPagesViewModel? + private(set) var documentPagesViewModel: SkontoDocumentPagesViewModel? private var maximumAmountToPayValue: Decimal = 99999.99 diff --git a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/TransactionDocs/Components/TransactionDocsItemView.swift b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/TransactionDocs/Components/TransactionDocsItemView.swift index afa96132b..ff0fcc429 100644 --- a/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/TransactionDocs/Components/TransactionDocsItemView.swift +++ b/BankSDK/GiniBankSDK/Sources/GiniBankSDK/Core/TransactionDocs/Components/TransactionDocsItemView.swift @@ -52,7 +52,7 @@ class TransactionDocsItemView: UIView { private let configuration = GiniBankConfiguration.shared - private (set) var transactionDocsItem: TransactionDoc? + private(set) var transactionDocsItem: TransactionDoc? var optionsAction: (() -> Void)? diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Document picker/DocumentPickerCoordinator.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Document picker/DocumentPickerCoordinator.swift index f0ca0663b..b198731a0 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Document picker/DocumentPickerCoordinator.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Document picker/DocumentPickerCoordinator.swift @@ -198,19 +198,26 @@ public final class DocumentPickerCoordinator: NSObject { /// A UIDocumentPickerViewController that sets navigation bar buttons' tint color to a correct one, instead of using the accent color specified by app private class GiniDocumentPickerViewController: UIDocumentPickerViewController { var initialTintColor: UIColor? = navBarInstance.tintColor + var initialButtonTintColor: UIColor? = barButtonInstance.tintColor override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) Self.navBarInstance.tintColor = .GiniCapture.accent1 + Self.barButtonInstance.tintColor = .GiniCapture.accent1 } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // make sure to revert the tint color, otherwise it will affect document pickers/browsers from the host app - Self.navBarInstance.tintColor = initialTintColor + Self.navBarInstance.tintColor = initialTintColor ?? UINavigationBar.appearance().tintColor + Self.barButtonInstance.tintColor = initialButtonTintColor ?? UIBarButtonItem.appearance().tintColor } static var navBarInstance: UINavigationBar { UINavigationBar.appearance(whenContainedInInstancesOf: [UIDocumentBrowserViewController.self]) } + + static var barButtonInstance: UIBarButtonItem { + UIBarButtonItem.appearance(whenContainedInInstancesOf: [UIDocumentBrowserViewController.self]) + } } fileprivate extension DocumentPickerCoordinator { diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpFormatsViewController.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpFormatsViewController.swift index 55e06adc6..4bfacb308 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpFormatsViewController.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpFormatsViewController.swift @@ -23,7 +23,7 @@ final class HelpFormatsViewController: UIViewController, HelpBottomBarEnabledVie tableView.translatesAutoresizingMaskIntoConstraints = false return tableView }() - private (set) var dataSource: HelpFormatsDataSource + private(set) var dataSource: HelpFormatsDataSource private var giniConfiguration: GiniConfiguration private let tableRowHeight: CGFloat = 44 private let sectionHeight: CGFloat = 70 diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpMenuViewController.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpMenuViewController.swift index 8cdbccf67..d396a74ce 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpMenuViewController.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpMenuViewController.swift @@ -22,7 +22,7 @@ protocol HelpMenuViewControllerDelegate: AnyObject { final class HelpMenuViewController: UIViewController, HelpBottomBarEnabledViewController { weak var delegate: HelpMenuViewControllerDelegate? - private (set) var dataSource: HelpMenuDataSource + private(set) var dataSource: HelpMenuDataSource private let giniConfiguration: GiniConfiguration private let tableRowHeight: CGFloat = 44 var navigationBarBottomAdapter: HelpBottomNavigationBarAdapter? diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpTipsViewController.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpTipsViewController.swift index 327dce613..f5e2a4381 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpTipsViewController.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Help/ViewControllers/HelpTipsViewController.swift @@ -28,7 +28,7 @@ final class HelpTipsViewController: UIViewController, HelpBottomBarEnabledViewCo tableView.translatesAutoresizingMaskIntoConstraints = false return tableView }() - private (set) var dataSource: HelpTipsDataSource + private(set) var dataSource: HelpTipsDataSource private var giniConfiguration: GiniConfiguration private let tableRowHeight: CGFloat = 76 diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/BottomButtonsViewModel.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/BottomButtonsViewModel.swift index edcd98598..0b28e492d 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/BottomButtonsViewModel.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/BottomButtonsViewModel.swift @@ -15,7 +15,7 @@ final class BottomButtonsViewModel { init(retakeBlock: (() -> Void)? = nil, manuallyPressed: (() -> Void)? = nil, - cancelPressed: @escaping(() -> Void)) { + cancelPressed: @escaping (() -> Void)) { self.retakePressed = retakeBlock self.enterManuallyPressed = manuallyPressed self.cancelPressed = cancelPressed diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/NoResultScreenViewController.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/NoResultScreenViewController.swift index 55fe441dc..033dc1b2e 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/NoResultScreenViewController.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/NoResult/NoResultScreenViewController.swift @@ -69,7 +69,7 @@ final class NoResultScreenViewController: UIViewController { } fatalError("No result header not found") }() - private (set) var dataSource: HelpDataSource + private(set) var dataSource: HelpDataSource private var giniConfiguration: GiniConfiguration private let type: NoResultType private let viewModel: BottomButtonsViewModel diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingDataSource.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingDataSource.swift index 179108e4d..bad09b08d 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingDataSource.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingDataSource.swift @@ -21,9 +21,9 @@ class OnboardingDataSource: NSObject, BaseCollectionViewDataSource { weak var delegate: OnboardingScreen? var isProgrammaticScroll = false - + private let giniConfiguration: GiniConfiguration - private (set) var currentPageIndex = 0 + private(set) var currentPageIndex = 0 private var isInitialScroll = true lazy var pageModels: [OnboardingPageModel] = { diff --git a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingViewController.swift b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingViewController.swift index c75c72170..9b1a59632 100644 --- a/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingViewController.swift +++ b/CaptureSDK/GiniCaptureSDK/Sources/GiniCaptureSDK/Core/Screens/Onboarding/OnboardingViewController.swift @@ -10,7 +10,7 @@ class OnboardingViewController: UIViewController { @IBOutlet weak var pagesCollection: UICollectionView! @IBOutlet weak var pageControl: UIPageControl! @IBOutlet weak var nextButton: MultilineTitleButton! - private (set) var dataSource: OnboardingDataSource + private(set) var dataSource: OnboardingDataSource private let configuration = GiniConfiguration.shared private var navigationBarBottomAdapter: OnboardingNavigationBarBottomAdapter? private var bottomNavigationBar: UIView? diff --git a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewModel.swift b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewModel.swift index 9da2a556f..279473664 100644 --- a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewModel.swift +++ b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewModel.swift @@ -13,13 +13,13 @@ protocol PaymentReviewViewModelDelegate: AnyObject { func presentInstallAppBottomSheet(bottomSheet: BottomSheetViewController) func presentBankSelectionBottomSheet(bottomSheet: BottomSheetViewController) func createPaymentRequestAndOpenBankApp() - func obtainPDFFromPaymentRequest() + func obtainPDFFromPaymentRequest(paymentRequestId: String) } /// BottomSheetsProviderProtocol defines methods for providing custom bottom sheets. public protocol BottomSheetsProviderProtocol: AnyObject { func installAppBottomSheet() -> BottomSheetViewController - func shareInvoiceBottomSheet(qrCodeData: Data) -> BottomSheetViewController + func shareInvoiceBottomSheet(qrCodeData: Data, paymentRequestId: String) -> BottomSheetViewController func bankSelectionBottomSheet() -> UIViewController } @@ -33,7 +33,7 @@ public protocol PaymentReviewAPIProtocol: AnyObject { func openPaymentProviderApp(requestId: String, universalLink: String) func submitFeedback(for document: Document, updatedExtractions: [Extraction], completion: ((Result) -> Void)?) func preview(for documentId: String, pageNumber: Int, completion: @escaping (Result) -> Void) - func obtainPDFURLFromPaymentRequest(paymentInfo: PaymentInfo, viewController: UIViewController) + func obtainPDFURLFromPaymentRequest(viewController: UIViewController, paymentRequestId: String) } /// PaymentReviewTrackingProtocol defines methods for tracking user interactions during the payment review process. @@ -298,8 +298,8 @@ extension PaymentReviewModel: InstallAppBottomViewProtocol { } extension PaymentReviewModel: ShareInvoiceBottomViewProtocol { - public func didTapOnContinueToShareInvoice() { - viewModelDelegate?.obtainPDFFromPaymentRequest() + public func didTapOnContinueToShareInvoice(paymentRequestId: String) { + viewModelDelegate?.obtainPDFFromPaymentRequest(paymentRequestId: paymentRequestId) } } diff --git a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewViewController+PaymentReviewViewModelDelegate.swift b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewViewController+PaymentReviewViewModelDelegate.swift index 5ef1673f1..a9929e0d2 100644 --- a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewViewController+PaymentReviewViewModelDelegate.swift +++ b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReview/PaymentReviewViewController+PaymentReviewViewModelDelegate.swift @@ -25,8 +25,9 @@ extension PaymentReviewViewController: PaymentReviewViewModelDelegate { presentBottomSheet(viewController: bottomSheet) } - func obtainPDFFromPaymentRequest() { - model.delegate?.obtainPDFURLFromPaymentRequest(paymentInfo: paymentInfoContainerView.obtainPaymentInfo(), viewController: self) + func obtainPDFFromPaymentRequest(paymentRequestId: String) { + model.delegate?.obtainPDFURLFromPaymentRequest(viewController: self, + paymentRequestId: paymentRequestId) } func presentBankSelectionBottomSheet(bottomSheet: BottomSheetViewController) { diff --git a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReviewContainer/PaymentReviewContainerView.swift b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReviewContainer/PaymentReviewContainerView.swift index b3c4cdfa3..48296350b 100644 --- a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReviewContainer/PaymentReviewContainerView.swift +++ b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/PaymentReviewContainer/PaymentReviewContainerView.swift @@ -42,7 +42,7 @@ public final class PaymentReviewContainerView: UIView { private lazy var recipientTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.recipientFieldTag.rawValue, isEditable: !viewModel.configuration.lockedFields) private lazy var ibanTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.ibanFieldTag.rawValue, isEditable: !viewModel.configuration.lockedFields) - private lazy var amountTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.amountFieldTag.rawValue, isEditable: true) + private lazy var amountTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.amountFieldTag.rawValue, isEditable: true, keyboardType: .numberPad) private lazy var usageTextFieldView = buildTextFieldWithLabelView(tag: TextFieldType.usageFieldTag.rawValue, isEditable: !viewModel.configuration.lockedFields) private let buttonsView = EmptyView() @@ -557,10 +557,11 @@ public final class PaymentReviewContainerView: UIView { return label } - private func buildTextFieldWithLabelView(tag: Int, isEditable: Bool) -> TextFieldWithLabelView { + private func buildTextFieldWithLabelView(tag: Int, isEditable: Bool, keyboardType: UIKeyboardType = .default) -> TextFieldWithLabelView { let textFieldView = TextFieldWithLabelView() textFieldView.tag = tag textFieldView.isUserInteractionEnabled = isEditable + textFieldView.setKeyboardType(keyboardType: keyboardType) return textFieldView } } diff --git a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/ShareInvoice/ShareInvoiceBottomViewModel.swift b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/ShareInvoice/ShareInvoiceBottomViewModel.swift index fd566cb3f..e41f9a5ad 100644 --- a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/ShareInvoice/ShareInvoiceBottomViewModel.swift +++ b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/ShareInvoice/ShareInvoiceBottomViewModel.swift @@ -11,7 +11,7 @@ import GiniHealthAPILibrary /// A protocol for handling actions from the Onboarding Share Invoice bottom view public protocol ShareInvoiceBottomViewProtocol: AnyObject { - func didTapOnContinueToShareInvoice() + func didTapOnContinueToShareInvoice(paymentRequestId: String) } struct SingleApp { @@ -39,6 +39,8 @@ public final class ShareInvoiceBottomViewModel { let bankImageIcon: Data let qrCodeData: Data let continueButtonText: String + + let paymentRequestId: String /// An optional identifier for the document ID being shared in order to pass it back to the delegates public var documentId: String? @@ -64,7 +66,8 @@ public final class ShareInvoiceBottomViewModel { poweredByGiniConfiguration: PoweredByGiniConfiguration, poweredByGiniStrings: PoweredByGiniStrings, qrCodeData: Data, - paymentInfo: PaymentInfo?) { + paymentInfo: PaymentInfo?, + paymentRequestId: String) { self.selectedPaymentProvider = selectedPaymentProvider self.bankImageIcon = selectedPaymentProvider?.iconData ?? Data() self.paymentProviderColors = selectedPaymentProvider?.colors @@ -74,6 +77,7 @@ public final class ShareInvoiceBottomViewModel { self.poweredByGiniViewModel = PoweredByGiniViewModel(configuration: poweredByGiniConfiguration, strings: poweredByGiniStrings) self.qrCodeData = qrCodeData self.paymentInfo = paymentInfo + self.paymentRequestId = paymentRequestId titleText = strings.titleTextPattern.replacingOccurrences(of: bankToReplaceString, with: selectedPaymentProvider?.name ?? "") descriptionLabelText = strings.descriptionTextPattern.replacingOccurrences(of: bankToReplaceString, with: selectedPaymentProvider?.name ?? "") @@ -81,6 +85,6 @@ public final class ShareInvoiceBottomViewModel { } func didTapOnContinue() { - viewDelegate?.didTapOnContinueToShareInvoice() + viewDelegate?.didTapOnContinueToShareInvoice(paymentRequestId: paymentRequestId) } } diff --git a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/TextField/TextFieldWithLabelView.swift b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/TextField/TextFieldWithLabelView.swift index 483602a97..3d737d516 100644 --- a/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/TextField/TextFieldWithLabelView.swift +++ b/GiniComponents/GiniInternalPaymentSDK/Sources/GiniInternalPaymentSDK/TextField/TextFieldWithLabelView.swift @@ -77,6 +77,10 @@ public final class TextFieldWithLabelView: UIView { textField.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Constants.topBottomPadding) ]) } + + func setKeyboardType(keyboardType: UIKeyboardType) { + textField.keyboardType = keyboardType + } } public extension TextFieldWithLabelView { diff --git a/HealthSDK/GiniHealthSDK/Documentation/source/Integration.md b/HealthSDK/GiniHealthSDK/Documentation/source/Integration.md index 4bc117e20..0a53c8947 100644 --- a/HealthSDK/GiniHealthSDK/Documentation/source/Integration.md +++ b/HealthSDK/GiniHealthSDK/Documentation/source/Integration.md @@ -113,6 +113,19 @@ dispatchGroup.notify(queue: .main) { } ``` +## Check if the document contains multiple invoices + +GiniHealth provides a method to check whether a document contains multiple invoices: + +```swift +healthSDK.checkIfDocumentContainsMultipleInvoices(docId: String, completion: @escaping (Result) -> Void) +``` + +The method returns `true` in the success case if the `contains_multiple_docs` field was extracted and its value is `true`. + +> - Recommendation: Use this check in a specific order. First, call the `checkIfDocumentIsPayable` method, and then call `checkIfDocumentContainsMultipleInvoices` method. + + ## Integrate the Payment flow We provide a custom payment flow for the users to pay the invoice/document/digital payment . diff --git a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth+PaymentComponentsConfigurationProvider.swift b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth+PaymentComponentsConfigurationProvider.swift index b7c4a912f..830e3a884 100644 --- a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth+PaymentComponentsConfigurationProvider.swift +++ b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth+PaymentComponentsConfigurationProvider.swift @@ -23,9 +23,8 @@ extension GiniHealth: PaymentComponentsConfigurationProvider { } public var showPaymentReviewCloseButton: Bool { - false + GiniHealthConfiguration.shared.showPaymentReviewCloseButton } - public var paymentComponentButtonsHeight: CGFloat { GiniHealthConfiguration.shared.paymentComponentButtonsHeight diff --git a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth.swift b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth.swift index ce4ef797e..d9898ac8c 100644 --- a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth.swift +++ b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealth.swift @@ -150,6 +150,7 @@ public struct DataForReview { self.clientConfigurationService = giniApiLib.clientConfigurationService() super.init() self.paymentComponentsController = PaymentComponentsController(giniHealth: self) + self.paymentComponentsController.delegate = self } /** diff --git a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealthConfiguration.swift b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealthConfiguration.swift index 247ea5210..7814bcf15 100644 --- a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealthConfiguration.swift +++ b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/GiniHealthConfiguration.swift @@ -64,6 +64,16 @@ public final class GiniHealthConfiguration: NSObject { */ public var showPaymentReviewScreen = true + /** + Set to `false` to hide close button on the payment review screen + */ + public var showPaymentReviewCloseButton = true + + /** + Sets the status bar style on the payment review screen. Only if `View controller-based status bar appearance` = `YES` in info.plist. + */ + @objc public var paymentReviewStatusBarStyle: UIStatusBarStyle = .default + // MARK: - Button configuration options /** A configuration that defines the appearance of the primary button, including its background color, border color, title color, shadow color, corner radius, border width, shadow radius, and whether to apply a blur effect. It is used for buttons on different UI elements: Payment Component View, Payment Review Screen. @@ -145,11 +155,6 @@ public final class GiniHealthConfiguration: NSObject { Custom localization configuration for localizable strings. */ public var customLocalization: GiniLocalization? - - /** - Sets the status bar style on the payment review screen. Only if `View controller-based status bar appearance` = `YES` in info.plist. - */ - @objc public var paymentReviewStatusBarStyle: UIStatusBarStyle = .default /** Client's configuration provided from the server diff --git a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController+Helpers.swift b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController+Helpers.swift index 75cb8da27..160d33400 100644 --- a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController+Helpers.swift +++ b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController+Helpers.swift @@ -320,9 +320,10 @@ extension PaymentComponentsController { It also increments the onboarding count for the selected payment provider. - Parameter qrCodeData: A qrCode data information for the document associated payment request generated by the payment details. + - Parameter paymentRequestId:The payment request id from generated from the payment info extracted from the invoice - Returns: A configured `BottomSheetViewController` for sharing invoices. */ - public func shareInvoiceBottomSheet(qrCodeData: Data) -> BottomSheetViewController { + public func shareInvoiceBottomSheet(qrCodeData: Data, paymentRequestId: String) -> BottomSheetViewController { previousPresentedViews.removeAll() let shareInvoiceBottomViewModel = ShareInvoiceBottomViewModel(selectedPaymentProvider: healthSelectedPaymentProvider, configuration: configurationProvider.shareInvoiceConfiguration, @@ -331,7 +332,8 @@ extension PaymentComponentsController { poweredByGiniConfiguration: configurationProvider.poweredByGiniConfiguration, poweredByGiniStrings: stringsProvider.poweredByGiniStrings, qrCodeData: qrCodeData, - paymentInfo: paymentInfo) + paymentInfo: paymentInfo, + paymentRequestId: paymentRequestId) shareInvoiceBottomViewModel.viewDelegate = self shareInvoiceBottomViewModel.documentId = documentId let shareInvoiceBottomView = ShareInvoiceBottomView(viewModel: shareInvoiceBottomViewModel, bottomSheetConfiguration: configurationProvider.bottomSheetConfiguration) @@ -414,19 +416,12 @@ extension PaymentComponentsController { /** Creates a payment request and obtains the PDF URL using the provided payment information. - - - Parameter paymentInfo: The payment information for the request. + - Parameter viewController: The view controller used to present any necessary UI related to the request. + - Parameter paymentRequestId: The payment request id generated from the payment info extracted from the invoice */ - public func obtainPDFURLFromPaymentRequest(paymentInfo: GiniInternalPaymentSDK.PaymentInfo, viewController: UIViewController) { - createPaymentRequest(paymentInfo: paymentInfo) { [weak self] result in - switch result { - case .success(let paymentRequestId): - self?.loadPDFData(paymentRequestId: paymentRequestId, viewController: viewController) - case .failure: - break - } - } + public func obtainPDFURLFromPaymentRequest(viewController: UIViewController, paymentRequestId: String) { + loadPDFData(paymentRequestId: paymentRequestId, viewController: viewController) } private func loadPDFData(paymentRequestId: String, viewController: UIViewController) { @@ -443,13 +438,6 @@ extension PaymentComponentsController { guard let shareInvoiceBottomSheet = self?.shareInvoiceBottomSheet else { return } self?.dismissAndPresent(viewController: shareInvoiceBottomSheet, animated: false) } - - guard activity != nil else { - return - } - - // Publish the payment request id only after a user has picked an activity (app) - self?.giniSDK.delegate?.didCreatePaymentRequest(paymentRequestId: paymentRequestId) } }) } @@ -537,6 +525,7 @@ extension PaymentComponentsController { switch result { case .success(let paymentRequestId): completion(.success(paymentRequestId)) + self.giniSDK.delegate?.didCreatePaymentRequest(paymentRequestId: paymentRequestId) case .failure(let error): let healthError = GiniHealthAPILibrary.GiniError.unknown(response: error.response, data: error.data) completion(.failure(healthError)) @@ -735,7 +724,7 @@ extension PaymentComponentsController: PaymentComponentViewProtocol { switch result { case .success(let image): DispatchQueue.main.async { - let shareInvoiceBottomSheet = self?.shareInvoiceBottomSheet(qrCodeData: image) + let shareInvoiceBottomSheet = self?.shareInvoiceBottomSheet(qrCodeData: image, paymentRequestId: paymentRequestId) shareInvoiceBottomSheet?.modalPresentationStyle = .overFullScreen guard let shareInvoiceBottomSheet else { return } self?.dismissAndPresent(viewController: shareInvoiceBottomSheet, animated: false) @@ -746,18 +735,6 @@ extension PaymentComponentsController: PaymentComponentViewProtocol { } } - private func handleDismissalAndPDFURL(paymentInfo: GiniInternalPaymentSDK.PaymentInfo) { - if let presentedVC = self.navigationControllerProvided?.presentedViewController { - presentedVC.dismiss(animated: true) { [weak self] in - guard let self = self, let navController = self.navigationControllerProvided else { return } - self.obtainPDFURLFromPaymentRequest(paymentInfo: paymentInfo, viewController: navController) - } - } else { - guard let presentedVC = self.navigationControllerProvided?.presentedViewController else { return } - self.obtainPDFURLFromPaymentRequest(paymentInfo: paymentInfo, viewController: presentedVC) - } - } - private func processPaymentRequest(paymentInfo: GiniInternalPaymentSDK.PaymentInfo) { createPaymentRequest(paymentInfo: paymentInfo) { [weak self] result in switch result { @@ -832,16 +809,16 @@ extension PaymentComponentsController: PaymentComponentViewProtocol { giniSDK.paymentService.qrCodeImage(paymentRequestId: paymentRequestId) { [weak self] result in switch result { case .success(let image): - self?.presentShareInvoiceBottomSheet(with: image) + self?.presentShareInvoiceBottomSheet(with: image, paymentRequestId: paymentRequestId) case .failure(let error): self?.handleError(error) } } } - private func presentShareInvoiceBottomSheet(with qrCodeData: Data) { + private func presentShareInvoiceBottomSheet(with qrCodeData: Data, paymentRequestId: String) { DispatchQueue.main.async { [weak self] in - let shareInvoiceBottomSheet = self?.shareInvoiceBottomSheet(qrCodeData: qrCodeData) + let shareInvoiceBottomSheet = self?.shareInvoiceBottomSheet(qrCodeData: qrCodeData, paymentRequestId: paymentRequestId) shareInvoiceBottomSheet?.modalPresentationStyle = .overFullScreen guard let shareInvoiceBottomSheet else { return } self?.dismissAndPresent(viewController: shareInvoiceBottomSheet, animated: false) @@ -872,9 +849,9 @@ extension PaymentComponentsController: PaymentProvidersBottomViewProtocol { extension PaymentComponentsController: ShareInvoiceBottomViewProtocol { /// Notifies the delegate to continue sharing the invoice with the provided document ID. - public func didTapOnContinueToShareInvoice() { - guard let navigationControllerProvided, let paymentInfo else { return } - obtainPDFURLFromPaymentRequest(paymentInfo: paymentInfo, viewController: navigationControllerProvided) + public func didTapOnContinueToShareInvoice(paymentRequestId: String) { + guard let navigationControllerProvided else { return } + obtainPDFURLFromPaymentRequest(viewController: navigationControllerProvided, paymentRequestId: paymentRequestId) } } diff --git a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController.swift b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController.swift index 99b3b9ba7..779b9560b 100644 --- a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController.swift +++ b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/PaymentComponentsController.swift @@ -225,7 +225,7 @@ extension PaymentComponentsController: PaymentReviewProtocol { This method notifies the tracking delegate about the close button click event. */ public func trackOnPaymentReviewCloseButtonClicked() { - // Not anymore tracked on HealthSDK + trackingDelegate?.onPaymentReviewScreenEvent(event: TrackingEvent.init(type: .onCloseButtonClicked)) } /** diff --git a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/Tracking/GiniHealthTrackingDelegate.swift b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/Tracking/GiniHealthTrackingDelegate.swift index e56165009..6e4bf8c72 100644 --- a/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/Tracking/GiniHealthTrackingDelegate.swift +++ b/HealthSDK/GiniHealthSDK/Sources/GiniHealthSDK/Core/Tracking/GiniHealthTrackingDelegate.swift @@ -26,6 +26,8 @@ public enum PaymentReviewScreenEventType: String { case onToTheBankButtonClicked /// User tapped "close" button and keyboard will be hidden case onCloseKeyboardButtonClicked + /// User tapped "close" button and keyboard will be hidden + case onCloseButtonClicked } /** diff --git a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/AppCoordinator.swift b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/AppCoordinator.swift index 2c047d13f..15042e329 100644 --- a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/AppCoordinator.swift +++ b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/AppCoordinator.swift @@ -103,7 +103,13 @@ final class AppCoordinator: Coordinator { } func processBankUrl(url: URL) { - rootViewController.dismiss(animated: true) + if let invoicesListCoordinator = childCoordinators.last as? InvoicesListCoordinator { + invoicesListCoordinator.invoicesListNavigationController.popViewController(animated: true) + } else if let orderListCoordinator = childCoordinators.last as? OrderListCoordinator { + orderListCoordinator.orderListViewController.presentedViewController?.dismiss(animated: true, completion: { + orderListCoordinator.orderListNavigationController.popViewController(animated: true) + }) + } guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return } @@ -387,12 +393,6 @@ extension AppCoordinator: GiniHealthDelegate { func didCreatePaymentRequest(paymentRequestId: String) { GiniUtilites.Log("Created payment request with id \(paymentRequestId)", event: .success) - DispatchQueue.main.async { - guard let invoicesListCoordinator = self.childCoordinators.first as? InvoicesListCoordinator else { - return - } - invoicesListCoordinator.invoicesListViewController.presentedViewController?.dismiss(animated: true) - } } } @@ -401,7 +401,9 @@ extension AppCoordinator: GiniHealthDelegate { extension AppCoordinator: DebugMenuPresenter { func presentDebugMenu() { let debugMenuViewController = DebugMenuViewController(showReviewScreen: giniHealthConfiguration.showPaymentReviewScreen, - useBottomPaymentComponent: giniHealthConfiguration.useBottomPaymentComponentView) + useBottomPaymentComponent: giniHealthConfiguration.useBottomPaymentComponentView, + paymentComponentConfiguration: health.paymentComponentConfiguration, + showPaymentCloseButton: giniHealthConfiguration.showPaymentReviewCloseButton) debugMenuViewController.delegate = self rootViewController.present(debugMenuViewController, animated: true) } @@ -417,6 +419,8 @@ extension AppCoordinator: DebugMenuDelegate { health.paymentComponentConfiguration.isPaymentComponentBranded = isOn case .useBottomPaymentComponent: giniHealthConfiguration.useBottomPaymentComponentView = isOn + case .showPaymentCloseButton: + giniHealthConfiguration.showPaymentReviewCloseButton = isOn } } diff --git a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/DebugMenuViewController.swift b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/DebugMenuViewController.swift index f2b55c88c..61ab8a9dd 100644 --- a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/DebugMenuViewController.swift +++ b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/DebugMenuViewController.swift @@ -13,6 +13,7 @@ enum SwitchType { case showReviewScreen case showBrandedView case useBottomPaymentComponent + case showPaymentCloseButton } protocol DebugMenuDelegate: AnyObject { @@ -79,12 +80,20 @@ class DebugMenuViewController: UIViewController { private lazy var comunicationToneRow: UIStackView = stackView(axis: .horizontal, subviews: [comunicationToneTitleLabel, comunicationPicker]) + private lazy var closeButtonOptionLabel: UILabel = rowTitle("Show Payment Review Close Button") + private var closeButtonSwitch: UISwitch! + private lazy var closeButtonRow: UIStackView = stackView(axis: .horizontal, subviews: [closeButtonOptionLabel, closeButtonSwitch]) + weak var delegate: DebugMenuDelegate? - init(showReviewScreen: Bool, useBottomPaymentComponent: Bool) { + init(showReviewScreen: Bool, + useBottomPaymentComponent: Bool, + paymentComponentConfiguration: PaymentComponentConfiguration, + showPaymentCloseButton: Bool) { super.init(nibName: nil, bundle: nil) self.reviewScreenSwitch = self.switchView(isOn: showReviewScreen) self.bottomPaymentComponentSwitch = self.switchView(isOn: useBottomPaymentComponent) + self.closeButtonSwitch = self.switchView(isOn: showPaymentCloseButton) } required init?(coder: NSCoder) { @@ -117,7 +126,7 @@ class DebugMenuViewController: UIViewController { view.backgroundColor = UIColor(named: "background") let spacer = UIView() - let mainStackView = stackView(axis: .vertical, subviews: [titleLabel, localizationRow, comunicationToneRow, reviewScreenRow, brandedRow, bottomPaymentComponentEditableRow, spacer]) + let mainStackView = stackView(axis: .vertical, subviews: [titleLabel, localizationRow, comunicationToneRow, reviewScreenRow, brandedRow, bottomPaymentComponentEditableRow, closeButtonRow, spacer]) view.addSubview(mainStackView) NSLayoutConstraint.activate([ @@ -132,7 +141,8 @@ class DebugMenuViewController: UIViewController { reviewScreenRow.heightAnchor.constraint(equalToConstant: rowHeight), brandedRow.heightAnchor.constraint(equalToConstant: rowHeight), comunicationToneRow.heightAnchor.constraint(equalToConstant: rowHeight), - bottomPaymentComponentEditableRow.heightAnchor.constraint(equalToConstant: rowHeight) + bottomPaymentComponentEditableRow.heightAnchor.constraint(equalToConstant: rowHeight), + closeButtonRow.heightAnchor.constraint(equalToConstant: rowHeight) ]) } } @@ -215,6 +225,8 @@ private extension DebugMenuViewController { delegate?.didChangeSwitchValue(type: .showReviewScreen, isOn: sender.isOn) case bottomPaymentComponentSwitch: delegate?.didChangeSwitchValue(type: .useBottomPaymentComponent, isOn: sender.isOn) + case closeButtonSwitch: + delegate?.didChangeSwitchValue(type: .showPaymentCloseButton, isOn: sender.isOn) default: break } diff --git a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/InvoicesList/InvoicesListViewModel.swift b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/InvoicesList/InvoicesListViewModel.swift index 8cfc9db90..db517e875 100644 --- a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/InvoicesList/InvoicesListViewModel.swift +++ b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/InvoicesList/InvoicesListViewModel.swift @@ -251,6 +251,8 @@ extension InvoicesListViewModel: GiniHealthTrackingDelegate { GiniUtilites.Log("To the banking app button was tapped,\(String(describing: event.info))", event: .success) case .onCloseKeyboardButtonClicked: GiniUtilites.Log("Close keyboard was triggered", event: .success) + case .onCloseButtonClicked: + GiniUtilites.Log("Close button was tapped", event: .success) } } } diff --git a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/OrdersList/OrderDetailViewController.swift b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/OrdersList/OrderDetailViewController.swift index 493e5a3ad..c2b88b84b 100644 --- a/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/OrdersList/OrderDetailViewController.swift +++ b/HealthSDK/GiniHealthSDKExample/GiniHealthSDKExample/OrdersList/OrderDetailViewController.swift @@ -195,6 +195,8 @@ extension OrderDetailViewController: GiniHealthTrackingDelegate { GiniUtilites.Log("To the banking app button was tapped,\(String(describing: event.info))", event: .success) case .onCloseKeyboardButtonClicked: GiniUtilites.Log("Close keyboard was triggered", event: .success) + case .onCloseButtonClicked: + GiniUtilites.Log("Close button was tapped", event: .success) } } } diff --git a/MerchantSDK/GiniMerchantSDK/Sources/GiniMerchantSDK/Core/PaymentComponentsController.swift b/MerchantSDK/GiniMerchantSDK/Sources/GiniMerchantSDK/Core/PaymentComponentsController.swift index 5dc24f501..4b6c47854 100644 --- a/MerchantSDK/GiniMerchantSDK/Sources/GiniMerchantSDK/Core/PaymentComponentsController.swift +++ b/MerchantSDK/GiniMerchantSDK/Sources/GiniMerchantSDK/Core/PaymentComponentsController.swift @@ -25,7 +25,7 @@ public protocol PaymentProvidersBottomViewProtocol: AnyObject { func didSelectPaymentProvider(paymentProvider: PaymentProvider) func didTapOnClose() func didTapOnMoreInformation() - func didTapOnContinueOnShareBottomSheet() + func didTapOnContinueOnShareBottomSheet(paymentRequestId: String) func didTapForwardOnInstallBottomSheet() func didTapOnPayButton() } @@ -406,10 +406,11 @@ public final class PaymentComponentsController: PaymentComponentsProtocol, Botto localized strings, and returns a `ShareInvoiceBottomView` configured with the view model. It also increments the onboarding count for the selected payment provider. - - Parameter documentId: An optional identifier for the document associated id with the invoice. + - Parameter qrCodeData: QR Data shown in the Share Invoice Bottom Sheet + - Parameter paymentRequestId: Payment request id generated from the payment info extracted from the order - Returns: A configured `BottomSheetViewController` for sharing invoices. */ - public func shareInvoiceBottomSheet(qrCodeData: Data) -> BottomSheetViewController { + public func shareInvoiceBottomSheet(qrCodeData: Data, paymentRequestId: String) -> BottomSheetViewController { previousPresentedView = nil let shareInvoiceBottomViewModel = ShareInvoiceBottomViewModel(selectedPaymentProvider: healthSelectedPaymentProvider, configuration: configurationProvider.shareInvoiceConfiguration, @@ -418,7 +419,8 @@ public final class PaymentComponentsController: PaymentComponentsProtocol, Botto poweredByGiniConfiguration: configurationProvider.poweredByGiniConfiguration, poweredByGiniStrings: stringsProvider.poweredByGiniStrings, qrCodeData: qrCodeData, - paymentInfo: nil) + paymentInfo: nil, + paymentRequestId: paymentRequestId) shareInvoiceBottomViewModel.viewDelegate = self let shareInvoiceBottomView = ShareInvoiceBottomView(viewModel: shareInvoiceBottomViewModel, bottomSheetConfiguration: configurationProvider.bottomSheetConfiguration) return shareInvoiceBottomView @@ -471,15 +473,11 @@ public final class PaymentComponentsController: PaymentComponentsProtocol, Botto /** Creates a payment request and obtains the PDF URL using the provided payment information. - - Parameter paymentInfo: The payment information for the request. - Parameter viewController: The view controller used to present any necessary UI related to the request. + - Parameter paymentRequestId: The paymentRequestId generated from the payment info extracted from the order */ - public func obtainPDFURLFromPaymentRequest(paymentInfo: PaymentInfo, viewController: UIViewController) { - createPaymentRequest(paymentInfo: paymentInfo, completion: { [weak self] paymentRequestID, error in - if let paymentRequestID { - self?.loadPDFData(paymentRequestID: paymentRequestID, viewController: viewController) - } - }) + public func obtainPDFURLFromPaymentRequest(viewController: UIViewController, paymentRequestId: String) { + self.loadPDFData(paymentRequestID: paymentRequestId, viewController: viewController) } /** @@ -490,10 +488,11 @@ public final class PaymentComponentsController: PaymentComponentsProtocol, Botto - completion: A closure that is called with the payment request ID or an error. */ public func createPaymentRequest(paymentInfo: PaymentInfo, completion: @escaping (_ paymentRequestID: String?, _ error: GiniMerchantError?) -> Void) { - giniSDK.createPaymentRequest(paymentInfo: paymentInfo) { result in + giniSDK.createPaymentRequest(paymentInfo: paymentInfo) {[weak self] result in switch result { case let .success(requestId): completion(requestId, nil) + self?.didCreatePaymentRequest(paymentRequestId: requestId) case let .failure(error): completion(nil, GiniMerchantError.apiError(error)) } @@ -663,8 +662,8 @@ extension PaymentComponentsController: BanksSelectionProtocol { extension PaymentComponentsController: ShareInvoiceBottomViewProtocol { /// Notifies the delegate to continue sharing the invoice with the provided document ID. - public func didTapOnContinueToShareInvoice() { - bottomViewDelegate?.didTapOnContinueOnShareBottomSheet() + public func didTapOnContinueToShareInvoice(paymentRequestId: String) { + bottomViewDelegate?.didTapOnContinueOnShareBottomSheet(paymentRequestId: paymentRequestId) } } @@ -676,6 +675,15 @@ extension PaymentComponentsController: InstallAppBottomViewProtocol { } extension PaymentComponentsController: PaymentReviewProtocol { + /** + Called when the payment request was successfully created + + - parameter paymentRequestId: Id of created payment request. + */ + public func didCreatePaymentRequest(paymentRequestId: String) { + giniSDK.delegate?.didCreatePaymentRequest(paymentRequestID: paymentRequestId) + } + /** Submits feedback for the specified document and its updated extractions. Method used to update the information extracted from a document. diff --git a/MerchantSDK/GiniMerchantSDKExample/GiniMerchantSDKExample/Sources/InvoicesList/OrderDetailViewController.swift b/MerchantSDK/GiniMerchantSDKExample/GiniMerchantSDKExample/Sources/InvoicesList/OrderDetailViewController.swift index eb0d99b29..f5eb2624d 100644 --- a/MerchantSDK/GiniMerchantSDKExample/GiniMerchantSDKExample/Sources/InvoicesList/OrderDetailViewController.swift +++ b/MerchantSDK/GiniMerchantSDKExample/GiniMerchantSDKExample/Sources/InvoicesList/OrderDetailViewController.swift @@ -178,7 +178,7 @@ extension OrderDetailViewController: GiniInternalPaymentSDK.PaymentComponentView } else { if paymentComponentsController.supportsOpenWith() { // TODO: Fix share onboarding flow in MerchantSDK - let shareInvoiceBottomSheet = paymentComponentsController.shareInvoiceBottomSheet(qrCodeData: Data()) + let shareInvoiceBottomSheet = paymentComponentsController.shareInvoiceBottomSheet(qrCodeData: Data(), paymentRequestId: "") shareInvoiceBottomSheet.modalPresentationStyle = .overFullScreen self.dismissAndPresent(viewController: shareInvoiceBottomSheet, animated: false) } else if paymentComponentsController.supportsGPC() { @@ -294,8 +294,9 @@ extension OrderDetailViewController: PaymentProvidersBottomViewProtocol { } } - func didTapOnContinueOnShareBottomSheet() { - paymentComponentsController.obtainPDFURLFromPaymentRequest(paymentInfo: obtainPaymentInfo(), viewController: self) + func didTapOnContinueOnShareBottomSheet(paymentRequestId: String) { + paymentComponentsController.obtainPDFURLFromPaymentRequest(viewController: self, + paymentRequestId: paymentRequestId) } func didTapForwardOnInstallBottomSheet() {