github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/stone/stone.go (about) 1 package stone 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "github.com/PMoneda/flow" 8 "github.com/mundipagg/boleto-api/config" 9 "github.com/mundipagg/boleto-api/log" 10 "github.com/mundipagg/boleto-api/metrics" 11 "github.com/mundipagg/boleto-api/models" 12 "github.com/mundipagg/boleto-api/tmpl" 13 "github.com/mundipagg/boleto-api/util" 14 "github.com/mundipagg/boleto-api/validations" 15 ) 16 17 type bankStone struct { 18 validate *models.Validator 19 log *log.Log 20 } 21 22 //New Create a new Stone Integration Instance 23 func New() bankStone { 24 b := bankStone{ 25 validate: models.NewValidator(), 26 log: log.CreateLog(), 27 } 28 29 b.validate.Push(validations.ValidateAmount) 30 b.validate.Push(validations.ValidateExpireDate) 31 b.validate.Push(validations.ValidateBuyerDocumentNumber) 32 b.validate.Push(validations.ValidateRecipientDocumentNumber) 33 34 b.validate.Push(stoneValidateAccessKeyNotEmpty) 35 b.validate.Push(validations.ValidateInterest) 36 b.validate.Push(validations.ValidateFine) 37 38 return b 39 } 40 41 func (b bankStone) ProcessBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 42 errs := b.ValidateBoleto(boleto) 43 if len(errs) > 0 { 44 return models.BoletoResponse{Errors: errs}, nil 45 } 46 47 if accToken, err := authenticate(boleto.Authentication.AccessKey, b.log); err != nil { 48 return models.GetBoletoResponseError("MP500", err.Error()), nil 49 } else { 50 boleto.Authentication.AuthorizationToken = accToken 51 } 52 return b.RegisterBoleto(boleto) 53 } 54 55 func (b bankStone) RegisterBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 56 var response string 57 var header string 58 var status int 59 var err error 60 61 stoneURL := config.Get().URLStoneRegister 62 boleto.Title.BoletoType, boleto.Title.BoletoTypeCode = getBoletoType(boleto) 63 64 body := flow.NewFlow().From("message://?source=inline", boleto, templateRequest, tmpl.GetFuncMaps()).GetBody().(string) 65 head := hearders(boleto.Authentication.AuthorizationToken) 66 b.log.Request(body, stoneURL, head) 67 68 duration := util.Duration(func() { 69 response, header, status, err = util.PostReponseWithHeader(stoneURL, util.SanitizeBody(body), config.Get().TimeoutRegister, head) 70 }) 71 metrics.PushTimingMetric("stone-register-boleto-time", duration.Seconds()) 72 73 headers := getLogResponseProperties(header) 74 75 b.log.Response(response, stoneURL, headers) 76 77 return mapStoneResponse(boleto, response, status, err), nil 78 } 79 80 func getLogResponseProperties(header string) map[string]string { 81 m := make(map[string]string) 82 m["Headers"] = header 83 return m 84 } 85 86 func mapStoneResponse(request *models.BoletoRequest, response string, status int, httpErr error) models.BoletoResponse { 87 f := flow.NewFlow().To("set://?prop=body", response) 88 switch status { 89 case 0, 504: 90 var msg string 91 if httpErr != nil { 92 msg = fmt.Sprintf("%v", httpErr) 93 } else { 94 msg = "GatewayTimeout" 95 } 96 return models.GetBoletoResponseError("MPTimeout", msg) 97 case 201: 98 f.To("transform://?format=json", templateResponse, templateAPI, tmpl.GetFuncMaps()) 99 f.To("unmarshall://?format=json", new(models.BoletoResponse)) 100 default: 101 f.To("transform://?format=json", templateError, templateAPI, tmpl.GetFuncMaps()) 102 f.To("unmarshall://?format=json", new(models.BoletoResponse)) 103 } 104 105 switch t := f.GetBody().(type) { 106 case *models.BoletoResponse: 107 if hasOurNumberFail(t) { 108 return models.GetBoletoResponseError("MPOurNumberFail", "our number was not returned by the bank") 109 } else { 110 return *t 111 } 112 case error: 113 return models.GetBoletoResponseError("MP500", t.Error()) 114 case string: 115 return models.GetBoletoResponseError("MP500", t) 116 } 117 118 return models.GetBoletoResponseError("MP500", "Internal Error") 119 } 120 121 func (b bankStone) ValidateBoleto(request *models.BoletoRequest) models.Errors { 122 return models.Errors(b.validate.Assert(request)) 123 } 124 125 func (b bankStone) GetBankNumber() models.BankNumber { 126 return models.Stone 127 } 128 129 func (b bankStone) GetBankNameIntegration() string { 130 return "Stone" 131 } 132 133 func (b bankStone) GetErrorsMap() map[string]int { 134 var erros = map[string]int{ 135 "srn:error:validation": http.StatusBadRequest, 136 "srn:error:unauthenticated": http.StatusInternalServerError, 137 "srn:error:unauthorized": http.StatusBadGateway, 138 "srn:error:not_found": http.StatusBadGateway, 139 "srn:error:conflict": http.StatusBadGateway, 140 "srn:error:product_not_enabled": http.StatusBadRequest, 141 } 142 return erros 143 } 144 145 func (b bankStone) Log() *log.Log { 146 return b.log 147 } 148 149 func getBoletoType(boleto *models.BoletoRequest) (bt string, btc string) { 150 return "DM", "bill_of_exchange" 151 } 152 153 func hearders(token string) map[string]string { 154 return map[string]string{"Authorization": "Bearer " + token, "Content-Type": "application/json"} 155 } 156 157 func hasOurNumberFail(response *models.BoletoResponse) bool { 158 return !response.HasErrors() && response.OurNumber == "" 159 }