github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/itau/itau.go (about) 1 package itau 2 3 import ( 4 "errors" 5 "strings" 6 "sync" 7 8 . "github.com/PMoneda/flow" 9 "github.com/mundipagg/boleto-api/config" 10 "github.com/mundipagg/boleto-api/issuer" 11 "github.com/mundipagg/boleto-api/log" 12 "github.com/mundipagg/boleto-api/metrics" 13 "github.com/mundipagg/boleto-api/models" 14 "github.com/mundipagg/boleto-api/tmpl" 15 "github.com/mundipagg/boleto-api/util" 16 "github.com/mundipagg/boleto-api/validations" 17 ) 18 19 var o = &sync.Once{} 20 var m map[string]string 21 22 type bankItau struct { 23 validate *models.Validator 24 log *log.Log 25 } 26 27 func New() bankItau { 28 b := bankItau{ 29 validate: models.NewValidator(), 30 log: log.CreateLog(), 31 } 32 b.validate.Push(validations.ValidateAmount) 33 b.validate.Push(validations.ValidateExpireDate) 34 b.validate.Push(validations.ValidateBuyerDocumentNumber) 35 b.validate.Push(validations.ValidateRecipientDocumentNumber) 36 b.validate.Push(itauValidateAccount) 37 b.validate.Push(itauValidateAgency) 38 b.validate.Push(itauBoletoTypeValidate) 39 return b 40 } 41 42 //Log retorna a referencia do log 43 func (b bankItau) Log() *log.Log { 44 return b.log 45 } 46 47 func (b bankItau) GetTicket(boleto *models.BoletoRequest) (string, error) { 48 pipe := NewFlow() 49 url := config.Get().URLTicketItau 50 pipe.From("message://?source=inline", boleto, getRequestTicket(), tmpl.GetFuncMaps()) 51 pipe.To("log://?type=request&format=params&url="+url, b.log) 52 duration := util.Duration(func() { 53 pipe.To(url, map[string]string{"method": "POST", "insecureSkipVerify": "true", "timeout": config.Get().TimeoutToken}) 54 }) 55 metrics.PushTimingMetric("itau-get-ticket-boleto-time", duration.Seconds()) 56 pipe.To("log://?type=response&format=json&url="+url, b.log) 57 ch := pipe.Choice() 58 ch.When(Header("status").IsEqualTo("200")) 59 ch.To("transform://?format=json", getTicketResponse(), `{{.access_token}}`, tmpl.GetFuncMaps()) 60 ch.When(Header("status").IsEqualTo("400")) 61 ch.To("transform://?format=json", getTicketResponse(), `{{.errorMessage}}`, tmpl.GetFuncMaps()) 62 ch.To("set://?prop=body", errors.New(pipe.GetBody().(string))) 63 ch.When(Header("status").IsEqualTo("403")) 64 ch.To("set://?prop=body", errors.New("403 Forbidden")) 65 ch.When(Header("status").IsEqualTo("500")) 66 ch.To("transform://?format=json", getTicketErrorResponse(), `{{.errorMessage}}`, tmpl.GetFuncMaps()) 67 ch.To("set://?prop=body", errors.New(pipe.GetBody().(string))) 68 ch.Otherwise() 69 ch.To("log://?type=request&url="+url, b.log).To("print://?msg=${body}").To("set://?prop=body", errors.New("integration error")) 70 switch t := pipe.GetBody().(type) { 71 case string: 72 return t, nil 73 case error: 74 return "", t 75 } 76 return "", nil 77 } 78 79 func (b bankItau) RegisterBoleto(input *models.BoletoRequest) (models.BoletoResponse, error) { 80 itauURL := config.Get().URLRegisterBoletoItau 81 fromResponse := getResponseItau() 82 fromResponseError := getResponseErrorItau() 83 toAPI := getAPIResponseItau() 84 inputTemplate := getRequestItau() 85 86 input.Title.BoletoType, input.Title.BoletoTypeCode = getBoletoType(input) 87 exec := NewFlow().From("message://?source=inline", input, inputTemplate, tmpl.GetFuncMaps()) 88 exec.To("log://?type=request&url="+itauURL, b.log) 89 duration := util.Duration(func() { 90 exec.To(itauURL, map[string]string{"method": "POST", "insecureSkipVerify": "true", "timeout": config.Get().TimeoutRegister}) 91 }) 92 metrics.PushTimingMetric("itau-register-boleto-time", duration.Seconds()) 93 b.log.Response(exec.GetBody().(string), itauURL, exec.GetHeader()) 94 95 ch := exec.Choice() 96 ch.When(Header("status").IsEqualTo("200")) 97 98 ch.To("transform://?format=json", fromResponse, toAPI, tmpl.GetFuncMaps()) 99 ch.To("unmarshall://?format=json", new(models.BoletoResponse)) 100 101 headerMap := exec.GetHeader() 102 103 if status, exist := headerMap["Content-Type"]; exist && strings.Contains(status, "text/html") { 104 exec.To("set://?prop=body", `{"codigo":"501","mensagem":"Error"}`) 105 ch.When(Header("Content-Type").IsEqualTo(status)) 106 ch.To("transform://?format=json", fromResponseError, toAPI, tmpl.GetFuncMaps()) 107 } else if status, exist = headerMap["status"]; exist && status != "200" { 108 ch.When(Header("status").IsEqualTo(status)) 109 ch.To("transform://?format=json", fromResponseError, toAPI, tmpl.GetFuncMaps()) 110 ch.To("unmarshall://?format=json", new(models.BoletoResponse)) 111 } 112 113 ch.Otherwise() 114 ch.To("log://?type=response&url="+itauURL, b.log).To("apierro://") 115 116 switch t := exec.GetBody().(type) { 117 case *models.BoletoResponse: 118 issuer := issuer.NewIssuer(t.BarCodeNumber, t.DigitableLine) 119 if !((issuer.IsValidBarCode() && issuer.IsValidDigitableLine()) || t.HasErrors()) { 120 return models.BoletoResponse{}, models.NewBadGatewayError("BadGateway") 121 } 122 return *t, nil 123 case error: 124 return models.BoletoResponse{}, t 125 } 126 return models.BoletoResponse{}, models.NewInternalServerError("MP500", "Internal error") 127 } 128 129 func (b bankItau) ProcessBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 130 errs := b.ValidateBoleto(boleto) 131 if len(errs) > 0 { 132 return models.BoletoResponse{Errors: errs}, nil 133 } 134 if ticket, err := b.GetTicket(boleto); err != nil { 135 return models.BoletoResponse{Errors: errs}, err 136 } else { 137 boleto.Authentication.AuthorizationToken = ticket 138 } 139 return b.RegisterBoleto(boleto) 140 } 141 142 func (b bankItau) ValidateBoleto(boleto *models.BoletoRequest) models.Errors { 143 return models.Errors(b.validate.Assert(boleto)) 144 } 145 146 //GetBankNumber retorna o codigo do banco 147 func (b bankItau) GetBankNumber() models.BankNumber { 148 return models.Itau 149 } 150 151 func (b bankItau) GetBankNameIntegration() string { 152 return "Itau" 153 } 154 155 func (b bankItau) GetErrorsMap() map[string]int { 156 return nil 157 } 158 159 func itauBoletoTypes() map[string]string { 160 o.Do(func() { 161 m = make(map[string]string) 162 163 m["DM"] = "01" //Duplicata Mercantil 164 m["NP"] = "02" //Nota Promissória 165 m["RC"] = "05" //Recibo 166 m["DS"] = "08" //Duplicata de serviços 167 m["BDP"] = "18" //Boleto de proposta 168 m["OUT"] = "99" //Outros 169 }) 170 return m 171 } 172 173 func getBoletoType(boleto *models.BoletoRequest) (bt string, btc string) { 174 if len(boleto.Title.BoletoType) < 1 { 175 return "DM", "01" 176 } 177 btm := itauBoletoTypes() 178 179 if btm[strings.ToUpper(boleto.Title.BoletoType)] == "" { 180 return "DM", "01" 181 } 182 183 return boleto.Title.BoletoType, btm[strings.ToUpper(boleto.Title.BoletoType)] 184 }