/
validate_payment.go
108 lines (101 loc) · 4.14 KB
/
validate_payment.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package placeorder
import (
"context"
"fmt"
"flamingo.me/flamingo-commerce/v3/checkout/domain/placeorder/process"
"flamingo.me/flamingo-commerce/v3/checkout/domain/placeorder/states"
"flamingo.me/flamingo-commerce/v3/payment/application"
paymentDomain "flamingo.me/flamingo-commerce/v3/payment/domain"
)
const (
// ValidatePaymentErrorNoActionURL used for errors when the needed URL is missing from the ActionData struct
ValidatePaymentErrorNoActionURL = "no url set for action"
// ValidatePaymentErrorNoActionDisplayData used for errors when the needed DisplayData/HTML is missing from the ActionData struct
ValidatePaymentErrorNoActionDisplayData = "no display data / html set for action"
)
// PaymentValidator to decide over the next state
func PaymentValidator(ctx context.Context, p *process.Process, paymentService *application.PaymentService) process.RunResult {
cart := p.Context().Cart
gateway, err := paymentService.PaymentGatewayByCart(p.Context().Cart)
if err != nil {
return process.RunResult{
Failed: process.ErrorOccurredReason{Error: err.Error()},
}
}
flowStatus, err := gateway.FlowStatus(ctx, &cart, p.Context().UUID)
if err != nil {
return process.RunResult{
Failed: process.ErrorOccurredReason{Error: err.Error()},
}
}
switch flowStatus.Status {
case paymentDomain.PaymentFlowStatusUnapproved:
switch flowStatus.Action {
case paymentDomain.PaymentFlowActionPostRedirect:
formFields := make(map[string]states.FormField, len(flowStatus.ActionData.FormParameter))
for k, v := range flowStatus.ActionData.FormParameter {
formFields[k] = states.FormField{
Value: v.Value,
}
}
if flowStatus.ActionData.URL == nil {
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: ValidatePaymentErrorNoActionURL},
}
}
p.UpdateState(states.PostRedirect{}.Name(), states.NewPostRedirectStateData(flowStatus.ActionData.URL, formFields))
case paymentDomain.PaymentFlowActionRedirect:
if flowStatus.ActionData.URL == nil {
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: ValidatePaymentErrorNoActionURL},
}
}
p.UpdateState(states.Redirect{}.Name(), states.NewRedirectStateData(flowStatus.ActionData.URL))
case paymentDomain.PaymentFlowActionShowHTML:
if flowStatus.ActionData.DisplayData == "" {
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: ValidatePaymentErrorNoActionDisplayData},
}
}
p.UpdateState(states.ShowHTML{}.Name(), states.NewShowHTMLStateData(flowStatus.ActionData.DisplayData))
case paymentDomain.PaymentFlowActionShowIframe:
if flowStatus.ActionData.URL == nil {
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: ValidatePaymentErrorNoActionURL},
}
}
p.UpdateState(states.ShowIframe{}.Name(), states.NewShowIframeStateData(flowStatus.ActionData.URL))
default:
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: fmt.Sprintf("Payment action not supported: %q", flowStatus.Action)},
}
}
case paymentDomain.PaymentFlowStatusApproved:
// payment is done but needs confirmation
p.UpdateState(states.CompletePayment{}.Name(), nil)
case paymentDomain.PaymentFlowStatusCompleted:
// payment is done and confirmed, place order if not already placed
p.UpdateState(states.Success{}.Name(), nil)
case paymentDomain.PaymentFlowStatusFailed, paymentDomain.PaymentFlowStatusCancelled:
err := ""
if flowStatus.Error != nil {
err = flowStatus.Error.Error()
}
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: err},
}
case paymentDomain.PaymentFlowStatusAborted:
return process.RunResult{
Failed: process.PaymentCanceledByCustomerReason{},
}
case paymentDomain.PaymentFlowWaitingForCustomer:
// payment pending, waiting for customer doing async stuff like finishing is payment in mobile app
p.UpdateState(states.WaitForCustomer{}.Name(), nil)
default:
// unknown payment flow status
return process.RunResult{
Failed: process.PaymentErrorOccurredReason{Error: fmt.Sprintf("Payment status not supported: %q", flowStatus.Status)},
}
}
return process.RunResult{}
}