feat(payments): payment-event dispatcher + the provider-return UX
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m45s
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m45s
Deliver payment_events to connected clients as an in-app wallet-refresh push: a background dispatcher drains undispatched events and publishes a KindNotification "payment" signal, marking each delivered; the client bumps a wallet-refresh counter the open Wallet screen watches, re-fetching in place. A return-focus refetch is the fallback. The Robokassa Success/Fail return now serves a self-closing page (the payment opens in a separate window) so the customer drops back into the live app instead of a cold start. Integration test for the event drain/mark queue.
This commit is contained in:
@@ -199,8 +199,8 @@ func (s *Server) HTTPHandler() http.Handler {
|
||||
// Direct-rail (Robokassa) return + callback routes: the server Result callback (the single
|
||||
// crediting signal, proxied to the backend intake) and the browser Success/Fail redirects.
|
||||
mux.Handle("/pay/robokassa/result", s.robokassaResultHandler())
|
||||
mux.Handle("/pay/robokassa/success", s.robokassaRedirectHandler())
|
||||
mux.Handle("/pay/robokassa/fail", s.robokassaRedirectHandler())
|
||||
mux.Handle("/pay/robokassa/success", s.robokassaReturnHandler("Оплата принята."))
|
||||
mux.Handle("/pay/robokassa/fail", s.robokassaReturnHandler("Оплата не завершена."))
|
||||
// The client posts its local-move-preview adoption telemetry here (session-gated).
|
||||
mux.Handle("/metrics/local-eval", s.localEvalMetricsHandler())
|
||||
// The index.html boot guard beacons here when it turns a client away on the unsupported-engine
|
||||
@@ -522,12 +522,24 @@ func (s *Server) robokassaResultHandler() http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// robokassaRedirectHandler redirects the customer's browser back into the app after Robokassa's
|
||||
// Success/Fail return. The credit rides the server Result callback, never these redirects, so this
|
||||
// only navigates home; the wallet reflects the credit once the callback lands.
|
||||
func (s *Server) robokassaRedirectHandler() http.Handler {
|
||||
// robokassaReturnHandler serves a minimal self-closing page for Robokassa's Success/Fail browser
|
||||
// return. The payment opens in a separate window, so on return this closes that window and drops the
|
||||
// customer back into the live app (never a cold app start); a link is the fallback if the window
|
||||
// cannot self-close. The credit rides the server Result callback, never this redirect — the wallet
|
||||
// updates in place from the payment push, with a return-focus refetch as the fallback.
|
||||
func (s *Server) robokassaReturnHandler(message string) http.Handler {
|
||||
page := []byte(`<!doctype html>
|
||||
<html lang="ru"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Оплата</title></head>
|
||||
<body style="font-family: system-ui, sans-serif; text-align: center; padding: 48px 20px; color: #1a1c20">
|
||||
<p style="font-size: 1.1rem">` + message + `</p>
|
||||
<p style="color: #5b6472">Можно закрыть это окно и вернуться в приложение.</p>
|
||||
<p><a href="/app/">Открыть приложение</a></p>
|
||||
<script>setTimeout(function () { try { window.close(); } catch (e) {} }, 1200);</script>
|
||||
</body></html>`)
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/app/", http.StatusSeeOther)
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
_, _ = w.Write(page)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user