github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/bb/bb.go (about) 1 package bb 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/log" 11 "github.com/mundipagg/boleto-api/metrics" 12 "github.com/mundipagg/boleto-api/models" 13 "github.com/mundipagg/boleto-api/tmpl" 14 "github.com/mundipagg/boleto-api/util" 15 16 "github.com/mundipagg/boleto-api/validations" 17 ) 18 19 var o = &sync.Once{} 20 var m map[string]string 21 22 type bankBB struct { 23 validate *models.Validator 24 log *log.Log 25 } 26 27 //New Cria uma nova instância do objeto que implementa os serviços do Banco do Brasil e configura os validadores que serão utilizados 28 func New() bankBB { 29 b := bankBB{ 30 validate: models.NewValidator(), 31 log: log.CreateLog(), 32 } 33 b.validate.Push(bbValidateAccountAndDigit) 34 b.validate.Push(bbValidateAgencyAndDigit) 35 b.validate.Push(bbValidateOurNumber) 36 b.validate.Push(bbValidateWalletVariation) 37 b.validate.Push(validations.ValidateAmount) 38 b.validate.Push(validations.ValidateExpireDate) 39 b.validate.Push(validations.ValidateBuyerDocumentNumber) 40 b.validate.Push(validations.ValidateRecipientDocumentNumber) 41 b.validate.Push(bbValidateTitleInstructions) 42 b.validate.Push(bbValidateTitleDocumentNumber) 43 b.validate.Push(bbValidateBoletoType) 44 return b 45 } 46 47 //Log retorna a referencia do log 48 func (b bankBB) Log() *log.Log { 49 return b.log 50 } 51 52 func (b *bankBB) login(boleto *models.BoletoRequest) (string, error) { 53 type errorAuth struct { 54 Error string `json:"error"` 55 ErrorDescription string `json:"error_description"` 56 } 57 58 r := flow.NewFlow() 59 url := config.Get().URLBBToken 60 from, resp := GetBBAuthLetters() 61 bod := r.From("message://?source=inline", boleto, from, tmpl.GetFuncMaps()) 62 bod = bod.To("log://?type=request&url="+url, b.log) 63 duration := util.Duration(func() { 64 bod = bod.To(url, map[string]string{"method": "POST", "insecureSkipVerify": "true", "timeout": config.Get().TimeoutToken}) 65 }) 66 metrics.PushTimingMetric("bb-login-time", duration.Seconds()) 67 bod = bod.To("log://?type=response&format=json&url="+url, b.log) 68 ch := bod.Choice().When(flow.Header("status").IsEqualTo("200")).To("transform://?format=json", resp, `{{.authToken}}`) 69 ch = ch.Otherwise().To("unmarshall://?format=json", new(errorAuth)) 70 result := bod.GetBody() 71 switch t := result.(type) { 72 case string: 73 return t, nil 74 case error: 75 return "", t 76 case *errorAuth: 77 return "", errors.New(t.ErrorDescription) 78 } 79 return "", errors.New("Saída inválida") 80 } 81 82 //ProcessBoleto faz o processamento de registro de boleto 83 func (b bankBB) ProcessBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 84 errs := b.ValidateBoleto(boleto) 85 if len(errs) > 0 { 86 return models.BoletoResponse{Errors: errs}, nil 87 } 88 tok, err := b.login(boleto) 89 if err != nil { 90 return models.BoletoResponse{}, err 91 } 92 boleto.Authentication.AuthorizationToken = tok 93 return b.RegisterBoleto(boleto) 94 } 95 96 func (b bankBB) RegisterBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 97 r := flow.NewFlow() 98 url := config.Get().URLBBRegisterBoleto 99 from := getRequest() 100 101 boleto.Title.BoletoType, boleto.Title.BoletoTypeCode = getBoletoType(boleto) 102 103 r = r.From("message://?source=inline", boleto, from, tmpl.GetFuncMaps()) 104 r.To("log://?type=request&url="+url, b.log) 105 duration := util.Duration(func() { 106 r.To(url, map[string]string{"method": "POST", "insecureSkipVerify": "true", "timeout": config.Get().TimeoutRegister}) 107 }) 108 metrics.PushTimingMetric("bb-register-boleto-time", duration.Seconds()) 109 r.To("log://?type=response&url="+url, b.log) 110 ch := r.Choice() 111 ch.When(flow.Header("status").IsEqualTo("200")) 112 ch.To("transform://?format=xml", getResponseBB(), getAPIResponse(), tmpl.GetFuncMaps()) 113 ch.To("unmarshall://?format=json", new(models.BoletoResponse)) 114 ch.Otherwise() 115 ch.To("log://?type=response&url="+url, b.log).To("apierro://") 116 switch t := r.GetBody().(type) { 117 case *models.BoletoResponse: 118 return *t, nil 119 case models.BoletoResponse: 120 return t, nil 121 case error: 122 return models.BoletoResponse{}, t 123 default: 124 return models.BoletoResponse{}, errors.New("Unexpected Type") 125 } 126 127 } 128 129 func (b bankBB) ValidateBoleto(boleto *models.BoletoRequest) models.Errors { 130 return models.Errors(b.validate.Assert(boleto)) 131 } 132 133 //GetBankNumber retorna o codigo do banco 134 func (b bankBB) GetBankNumber() models.BankNumber { 135 return models.BancoDoBrasil 136 } 137 138 func (b bankBB) GetBankNameIntegration() string { 139 return "BancoDoBrasil" 140 } 141 142 func (b bankBB) GetErrorsMap() map[string]int { 143 return nil 144 } 145 146 func bbBoletoTypes() map[string]string { 147 148 o.Do(func() { 149 m = make(map[string]string) 150 151 m["CH"] = "01" //Cheque 152 m["DM"] = "02" //Duplicata Mercantil 153 m["DS"] = "04" //Duplicata de serviços 154 m["NP"] = "12" //Nota promissória 155 m["RC"] = "17" //Recibo 156 m["ND"] = "19" //Nota de Débito 157 }) 158 159 return m 160 } 161 162 func getBoletoType(boleto *models.BoletoRequest) (bt string, btc string) { 163 if len(boleto.Title.BoletoType) < 1 { 164 return "ND", "19" 165 } 166 btm := bbBoletoTypes() 167 168 if btm[strings.ToUpper(boleto.Title.BoletoType)] == "" { 169 return "ND", "19" 170 } 171 172 return boleto.Title.BoletoType, btm[strings.ToUpper(boleto.Title.BoletoType)] 173 }