Přeskočit na hlavní obsah

Výsledky platby

Výsledek platby je reprezentován výčtem PaymentResult. Asynchronní metody processPayment(...)processApplePayPayment(...) vrací PaymentResult přímo, callback onResultSecurePayButtonSecureApplePayButton je vždy volán na hlavním vlákně.

PaymentResult

V praxi rozlišujte tyto typy výsledku:

Případ PaymentResultAsociované hodnotyPopis
.paid(transId:)StringPlatba byla dokončena a potvrzena.
.authorized(transId:)StringPlatba byla autorizována bankou (předautorizace).
.pending(transId:)StringPlatba se stále zpracovává (mezistav).
.cancelled(errorReason:transId:)String?, StringPlatba byla zrušena nebo zamítnuta serverem.
.failed(ComgateError)ComgateErrorChyba na straně knihovny během platebního procesu.

Platba je úspěšně dokončená.

case .paid(let transId):
// Platba dokončena
print("Paid: \(transId)")

Authorized

Platba byla autorizována (předautorizována) bankou. Jde o finální stav. Zachycení (settlement) platby provede obchodník samostatně pomocí standardních endpointů /capturePreauth nebo /cancelPreauth.

case .authorized(let transId):
// Platba autorizována, čeká na zachycení
print("Authorized: \(transId)")

Pending

Platba ještě není finální, backend ji stále zpracovává. Finálním stavem bude .paid, .authorized nebo .cancelled.

case .pending(let transId):
// Čekáme na finální stav
print("Pending: \(transId)")

Cancelled

Platba byla zrušena nebo zamítnuta serverem. Obsahuje identifikátor transakce a volitelný důvod.

case .cancelled(let errorReason, let transId):
// Platba byla ukončena bez úhrady
print("Cancelled: \(errorReason ?? "-") (\(transId))")

Možné hodnoty errorReason

errorReason je raw value výčtu ErrorReason (může být nil, pokud server hodnotu nedodá):

errorReasonVýznam
CUSTOMER_CLICKZrušeno plátcem.
FRAUD_SUSPECTEDPodezření na podvod.
ESHOP_CANCELLEDZrušeno obchodníkem.
PROVIDER_REPORTZrušeno providerem.
PROVIDER_TIMEOUTVypršel časový limit poskytovatele.
CUSTOMER_TIMEOUTVypršel časový limit platby.
ACS_TIMEOUTVypršel časový limit pro ověření.
INVALID_CARDNO_EXPIRYChybně zadané číslo karty nebo datum platnosti karty.
INVALID_CVCChybně zadaný CVC / CVV kód.
LIMIT_EXCEEDEDLimit karty byl překročen.
NO_FUNDSNa účtu není dostatečný zůstatek.
REJECTED_BY_BANKPlatba byla zamítnuta bankou.
3DS_AUTH_FAILOvěření platby nebylo úspěšné.
NOT_SPECIFIEDNespecifikováno.
Testování chybových scénářů

dev režimu (devMode = true) můžete tyto hodnoty simulovat pomocí parametru errorReasonPaymentParams. Viz sekci Simulace chybového důvodu.

Failed

Chyba na straně knihovny, která nastala během platebního procesu. Na rozdíl od .cancelled (kde server aktivně zamítl platbu) .failed značí, že k dokončení platby vůbec nedošlo — např. síťová chyba, neinicializovaná session apod.

Asociovanou hodnotou je objekt ComgateError s machine-readable kódem (code) a lidsky čitelnou zprávou (message).

case .failed(let error):
let errorCode = error.code // např. "PAYMENT_NETWORK_ERROR"
let errorMessage = error.message // např. "Network error during payment."
// Zobrazení chyby uživateli

ComgateError

Všechny chyby jsou definovány jako case výčtu ComgateError. Každý case vystavuje:

  • code: String — strojově čitelný identifikátor chyby
  • message: String — lidsky čitelný popis v angličtině
Inicializace
PřípadKódPopis
.deviceRootedDEVICE_ROOTEDZařízení je pravděpodobně jailbreaknuté nebo jinak pozměněné. Inicializace je zablokovaná za účelem ochrany karetních dat. V devMode se tato kontrola přeskočí.
.initNetworkErrorINIT_NETWORK_ERRORInicializace session selhala kvůli síťové chybě.
.initUnauthorizedINIT_UNAUTHORIZEDServer vrátil HTTP 401 při inicializaci — neplatná nebo expirovaná autorizace.
.initFailedINIT_FAILEDInicializace session selhala (jiný než síťový důvod).
.applicationNotAllowedAPPLICATION_NOT_ALLOWEDAplikace není povolena pro použití SDK (Bundle ID není na allow-listu).
Zpracování platby
PřípadKódPopis
.sessionNotInitializedSESSION_NOT_INITIALIZEDSession nebyla inicializována. Zavolejte nejprve initialize().
.invalidCardDataINVALID_CARD_DATAKaretní data nejsou validní.
.missingCardholderNameMISSING_CARDHOLDER_NAMEJméno držitele karty nebylo poskytnuto.
.paymentFailedPAYMENT_FAILEDPlatba selhala (jiný než síťový důvod).
.paymentNetworkErrorPAYMENT_NETWORK_ERRORPlatební požadavek selhal kvůli síťové chybě.
.paymentCreateFailedPAYMENT_CREATE_FAILEDVytvoření platby selhalo.
.pollingTimeoutPOLLING_TIMEOUTKontrola stavu platby vypršela.
.pollingNetworkErrorPOLLING_NETWORK_ERRORKontrola stavu platby selhala kvůli síťové chybě.
.threeDSChallengeCancelledTHREE_DS_CHALLENGE_CANCELLED3D Secure challenge byla zrušena.
.threeDSChallengeTimeoutTHREE_DS_CHALLENGE_TIMEOUT3D Secure challenge vypršela časem.
.threeDSFailedTHREE_DS_FAILED3D Secure autentizace selhala.
Apple Pay
PřípadKódPopis
.applePayNotConfiguredAPPLE_PAY_NOT_CONFIGUREDApple Pay není nakonfigurován.
.applePayCancelledAPPLE_PAY_CANCELLEDApple Pay byl zrušen uživatelem.
.applePayFailedAPPLE_PAY_FAILEDApple Pay platba selhala.
Validace polí
PřípadKódPopis
.invalidPanINVALID_PANNeplatné číslo karty.
.invalidExpiryMonthINVALID_EXPIRY_MONTHNeplatný měsíc expirace.
.cardExpiredCARD_EXPIREDKarta je expirovaná.
.invalidCvvINVALID_CVVNeplatný CVV kód.
.conflictingPaymentOptionsCONFLICTING_PAYMENT_OPTIONSinitRecurring a preauth nemohou být oba true.
.invalidPriceINVALID_PRICEprice musí být kladné celé číslo v nejmenší jednotce měny.

SecurePaymentStatusView

Komponenta SecurePaymentStatusView slouží k zobrazování stavových hlášek platby (úspěch, zpracování, chyba). Pracuje s objektem PaymentStatusState, který drží aktuální zobrazenou zprávu.

PaymentStatusState

Vlastnost / MetodaTypPopis
visibleBooltrue pokud má být view zobrazené (read-only, @Published).
textStringAktuální text (read-only, @Published).
translationTranslationPřeklady použité pro automatické zprávy. Nastavte na session.translation.
show(result:)func show(result: PaymentResult)Automaticky vybere a zobrazí lokalizovanou zprávu pro daný výsledek.
showError(_:)func showError(_ message: String)Zobrazí vlastní chybovou zprávu.
hide()func hide()Skryje view (text zůstává).
clear()func clear()Skryje view a vyčistí text.

Zobrazení stavu z PaymentResult

@StateObject private var statusState = PaymentStatusState()

statusState.translation = session.translation
statusState.show(result: paymentResult)

// V SwiftUI:
SecurePaymentStatusView(state: statusState)
PaymentResultChování
.paidZobrazí lokalizovanou zprávu z Translation.statusPaid se zeleným stylem (úspěch).
.authorizedZobrazí lokalizovanou zprávu z Translation.statusAuthorized se zeleným stylem (úspěch).
.pendingZobrazí lokalizovanou zprávu z Translation.statusPending s oranžovým stylem (zpracování).
.cancelledZobrazí errorReason s červeným stylem (chyba).
.failedZobrazí error.message s červeným stylem (chyba).

Skrytí view

statusState.clear()  // skryje view a vyčistí text
statusState.hide() // pouze skryje view, text zůstává

Stylizace

Podrobnosti o stylizaci SecurePaymentStatusView prostřednictvím struktury PaymentStatusStyle naleznete v sekci Stylizace komponent.

Kompletní příklad zpracování výsledků

struct PaymentResultHandler: View {
@ObservedObject var session: ComgateSecureSession
@StateObject private var statusState = PaymentStatusState()
@State private var resultText = ""
@State private var resultVisible = false

func handle(_ result: PaymentResult) {
statusState.translation = session.translation

switch result {
case .paid(let t):
statusState.show(result: result)
resultVisible = true
resultText = "Platba dokončena\nTransId: \(t)"
case .authorized(let t):
statusState.show(result: result)
resultVisible = true
resultText = "Platba autorizována\nTransId: \(t)"
case .pending(let t):
statusState.show(result: result)
resultVisible = true
resultText = "Platba se zpracovává\nTransId: \(t)"
case .cancelled:
statusState.show(result: result)
resultVisible = false
case .failed(let err):
statusState.show(result: result)
resultVisible = false
print("Failed: \(err.code)\(err.message)")
}
}

var body: some View {
VStack {
// ... (karetní pole, tlačítko — viz sekce Karetní data)

SecurePaymentStatusView(state: statusState)

if resultVisible {
Text(resultText)
.padding(.top, 8)
}
}
}
}