github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/santander/santander.go (about) 1 package santander 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 "sync" 9 10 "net/http" 11 12 . "github.com/PMoneda/flow" 13 "github.com/mundipagg/boleto-api/certificate" 14 "github.com/mundipagg/boleto-api/config" 15 "github.com/mundipagg/boleto-api/log" 16 "github.com/mundipagg/boleto-api/metrics" 17 "github.com/mundipagg/boleto-api/models" 18 "github.com/mundipagg/boleto-api/tmpl" 19 "github.com/mundipagg/boleto-api/util" 20 "github.com/mundipagg/boleto-api/validations" 21 ) 22 23 var ( 24 onceMap = &sync.Once{} 25 onceTransport = &sync.Once{} 26 transportTLS *http.Transport 27 m map[string]string 28 ) 29 30 type bankSantander struct { 31 validate *models.Validator 32 log *log.Log 33 transport *http.Transport 34 } 35 36 //New Create a new Santander Integration Instance 37 func New() (bankSantander, error) { 38 var err error 39 b := bankSantander{ 40 validate: models.NewValidator(), 41 log: log.CreateLog(), 42 } 43 44 certificates := certificate.TLSCertificate{ 45 Crt: config.Get().SantanderCertificateSSLName, 46 Key: config.Get().SantanderCertificateSSLName, 47 } 48 49 onceTransport.Do(func() { 50 transportTLS, err = util.BuildTLSTransport(certificates) 51 }) 52 b.transport = transportTLS 53 54 if err != nil || (b.transport == nil && !config.Get().MockMode) { 55 return bankSantander{}, fmt.Errorf("fail on load TLSTransport: %v", err) 56 } 57 58 b.validate.Push(validations.ValidateAmount) 59 b.validate.Push(validations.ValidateExpireDate) 60 b.validate.Push(validations.ValidateBuyerDocumentNumber) 61 b.validate.Push(validations.ValidateRecipientDocumentNumber) 62 b.validate.Push(santanderValidateAgreementNumber) 63 b.validate.Push(satanderBoletoTypeValidate) 64 65 return b, nil 66 } 67 68 //Log retorna a referencia do log 69 func (b bankSantander) Log() *log.Log { 70 return b.log 71 } 72 73 func (b bankSantander) GetTicket(boleto *models.BoletoRequest) (string, error) { 74 boleto.Title.OurNumber = calculateOurNumber(boleto) 75 boleto.Title.BoletoType, boleto.Title.BoletoTypeCode = getBoletoType(boleto) 76 pipe := NewFlow() 77 url := config.Get().URLTicketSantander 78 tlsURL := strings.Replace(config.Get().URLTicketSantander, "https", "tls", 1) 79 pipe.From("message://?source=inline", boleto, getRequestTicket(), tmpl.GetFuncMaps()) 80 pipe.To("log://?type=request&format=xml&url="+url, b.log) 81 duration := util.Duration(func() { 82 pipe.To(tlsURL, b.transport, map[string]string{"timeout": config.Get().TimeoutToken}) 83 }) 84 metrics.PushTimingMetric("santander-get-ticket-boleto-time", duration.Seconds()) 85 pipe.To("log://?type=response&format=xml&url="+url, b.log) 86 ch := pipe.Choice() 87 ch.When(Header("status").IsEqualTo("200")) 88 ch.To("transform://?format=xml", getTicketResponse(), `{{.returnCode}}:::{{.ticket}}`, tmpl.GetFuncMaps()) 89 ch.When(Header("status").IsEqualTo("403")) 90 ch.To("set://?prop=body", errors.New("403 Forbidden")) 91 ch.Otherwise() 92 ch.To("log://?type=request&url="+url, b.log).To("set://?prop=body", errors.New("integration error")) 93 switch t := pipe.GetBody().(type) { 94 case string: 95 items := pipe.GetBody().(string) 96 parts := strings.Split(items, ":::") 97 returnCode, ticket := parts[0], parts[1] 98 return ticket, checkError(returnCode) 99 case error: 100 return "", t 101 } 102 return "", nil 103 } 104 105 func (b bankSantander) RegisterBoleto(input *models.BoletoRequest) (models.BoletoResponse, error) { 106 serviceURL := config.Get().URLRegisterBoletoSantander 107 fromResponse := getResponseSantander() 108 toAPI := getAPIResponseSantander() 109 inputTemplate := getRequestSantander() 110 santanderURL := strings.Replace(serviceURL, "https", "tls", 1) 111 112 exec := NewFlow().From("message://?source=inline", input, inputTemplate, tmpl.GetFuncMaps()) 113 exec.To("log://?type=request&format=xml&url="+serviceURL, b.log) 114 duration := util.Duration(func() { 115 exec.To(santanderURL, b.transport, map[string]string{"method": "POST", "insecureSkipVerify": "true", "timeout": config.Get().TimeoutRegister}) 116 }) 117 metrics.PushTimingMetric("santander-register-boleto-time", duration.Seconds()) 118 exec.To("log://?type=response&format=xml&url="+serviceURL, b.log) 119 ch := exec.Choice() 120 ch.When(Header("status").IsEqualTo("200")) 121 ch.To("transform://?format=xml", fromResponse, toAPI, tmpl.GetFuncMaps()) 122 ch.To("unmarshall://?format=json", new(models.BoletoResponse)) 123 ch.Otherwise() 124 ch.To("log://?type=response&url="+serviceURL, b.log).To("apierro://") 125 switch t := exec.GetBody().(type) { 126 case *models.BoletoResponse: 127 return *t, nil 128 case error: 129 return models.BoletoResponse{}, t 130 } 131 return models.BoletoResponse{}, models.NewInternalServerError("MP500", "Internal error") 132 } 133 func (b bankSantander) ProcessBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 134 errs := b.ValidateBoleto(boleto) 135 if len(errs) > 0 { 136 return models.BoletoResponse{Errors: errs}, nil 137 } 138 if ticket, err := b.GetTicket(boleto); err != nil { 139 return models.BoletoResponse{Errors: errs}, err 140 } else { 141 boleto.Authentication.AuthorizationToken = ticket 142 } 143 return b.RegisterBoleto(boleto) 144 } 145 146 func (b bankSantander) ValidateBoleto(boleto *models.BoletoRequest) models.Errors { 147 return models.Errors(b.validate.Assert(boleto)) 148 } 149 150 //GetBankNumber retorna o codigo do banco 151 func (b bankSantander) GetBankNumber() models.BankNumber { 152 return models.Santander 153 } 154 155 func (b bankSantander) GetErrorsMap() map[string]int { 156 return nil 157 } 158 159 func calculateOurNumber(boleto *models.BoletoRequest) uint { 160 ourNumberWithDigit := strconv.Itoa(int(boleto.Title.OurNumber)) + util.OurNumberDv(strconv.Itoa(int(boleto.Title.OurNumber)), util.MOD11) 161 value, _ := strconv.Atoi(ourNumberWithDigit) 162 return uint(value) 163 } 164 165 func (b bankSantander) GetBankNameIntegration() string { 166 return "Santander" 167 } 168 169 func santanderBoletoTypes() map[string]string { 170 onceMap.Do(func() { 171 m = make(map[string]string) 172 173 m["DM"] = "02" //Duplicata Mercantil 174 m["DS"] = "04" //Duplicata de serviço 175 m["NP"] = "12" //Nota promissória 176 m["RC"] = "17" //Recibo 177 m["BDP"] = "32" //Boleto de proposta 178 m["CH"] = "97" //Cheque 179 m["OUT"] = "99" //Outros 180 }) 181 182 return m 183 } 184 185 func getBoletoType(boleto *models.BoletoRequest) (bt string, btc string) { 186 if len(boleto.Title.BoletoType) < 1 { 187 return "DM", "02" 188 } 189 190 btm := santanderBoletoTypes() 191 192 if btm[strings.ToUpper(boleto.Title.BoletoType)] == "" { 193 return "DM", "02" 194 } 195 196 return boleto.Title.BoletoType, btm[strings.ToUpper(boleto.Title.BoletoType)] 197 }