github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/bradescoShopFacil/bradescoShopFacil.go (about) 1 package bradescoShopFacil 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/mundipagg/boleto-api/metrics" 11 12 "github.com/PMoneda/flow" 13 "github.com/mundipagg/boleto-api/config" 14 "github.com/mundipagg/boleto-api/log" 15 "github.com/mundipagg/boleto-api/models" 16 "github.com/mundipagg/boleto-api/tmpl" 17 "github.com/mundipagg/boleto-api/util" 18 "github.com/mundipagg/boleto-api/validations" 19 ) 20 21 var o = &sync.Once{} 22 var m map[string]string 23 24 type bankBradescoShopFacil struct { 25 validate *models.Validator 26 log *log.Log 27 } 28 29 //barcode struct for bradescoShopFacil 30 type barcode struct { 31 bankCode string 32 currencyCode string 33 dateDueFactor string 34 value string 35 agency string 36 wallet string 37 ourNumber string 38 account string 39 zero string 40 } 41 42 //New creates a new BradescoShopFacil instance 43 func New() bankBradescoShopFacil { 44 b := bankBradescoShopFacil{ 45 validate: models.NewValidator(), 46 log: log.CreateLog(), 47 } 48 b.validate.Push(validations.ValidateAmount) 49 b.validate.Push(validations.ValidateExpireDate) 50 b.validate.Push(validations.ValidateMaxExpirationDate) 51 b.validate.Push(validations.ValidateBuyerDocumentNumber) 52 b.validate.Push(validations.ValidateRecipientDocumentNumber) 53 54 b.validate.Push(bradescoShopFacilValidateAgency) 55 b.validate.Push(bradescoShopFacilValidateAccount) 56 b.validate.Push(bradescoShopFacilValidateWallet) 57 b.validate.Push(bradescoShopFacilValidateAuth) 58 b.validate.Push(bradescoShopFacilValidateAgreement) 59 b.validate.Push(bradescoShopFacilBoletoTypeValidate) 60 61 return b 62 } 63 64 //Log retorna a referencia do log 65 func (b bankBradescoShopFacil) Log() *log.Log { 66 return b.log 67 } 68 69 func (b bankBradescoShopFacil) RegisterBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 70 boleto.Title.BoletoType, boleto.Title.BoletoTypeCode = getBoletoType(boleto) 71 r := flow.NewFlow() 72 serviceURL := config.Get().URLBradescoShopFacil 73 from := getResponseBradescoShopFacil() 74 to := getAPIResponseBradescoShopFacil() 75 bod := r.From("message://?source=inline", boleto, getRequestBradescoShopFacil(), tmpl.GetFuncMaps()) 76 bod.To("log://?type=request&url="+serviceURL, b.log) 77 duration := util.Duration(func() { 78 bod.To(serviceURL, map[string]string{"method": "POST", "insecureSkipVerify": "true", "timeout": config.Get().TimeoutDefault}) 79 }) 80 metrics.PushTimingMetric("bradesco-shopfacil-register-boleto-online", duration.Seconds()) 81 bod.To("log://?type=response&url="+serviceURL, b.log) 82 ch := bod.Choice() 83 ch.When(flow.Header("status").IsEqualTo("201")) 84 ch.To("transform://?format=json", from, to, tmpl.GetFuncMaps()) 85 ch.To("unmarshall://?format=json", new(models.BoletoResponse)) 86 ch.When(flow.Header("status").IsEqualTo("200")) 87 ch.To("transform://?format=json", from, to, tmpl.GetFuncMaps()) 88 ch.To("unmarshall://?format=json", new(models.BoletoResponse)) 89 ch.Otherwise() 90 ch.To("log://?type=response&url="+serviceURL, b.log).To("apierro://") 91 switch t := bod.GetBody().(type) { 92 case *models.BoletoResponse: 93 if !t.HasErrors() { 94 t.BarCodeNumber = getBarcode(*boleto).toString() 95 } 96 return *t, nil 97 case error: 98 return models.BoletoResponse{}, t 99 } 100 return models.BoletoResponse{}, models.NewInternalServerError("MP500", "Internal error") 101 } 102 103 func (b bankBradescoShopFacil) ProcessBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) { 104 errs := b.ValidateBoleto(boleto) 105 if len(errs) > 0 { 106 return models.BoletoResponse{Errors: errs}, nil 107 } 108 return b.RegisterBoleto(boleto) 109 } 110 111 func (b bankBradescoShopFacil) ValidateBoleto(boleto *models.BoletoRequest) models.Errors { 112 return models.Errors(b.validate.Assert(boleto)) 113 } 114 115 func (b bankBradescoShopFacil) GetBankNumber() models.BankNumber { 116 return models.Bradesco 117 } 118 119 func (b bankBradescoShopFacil) GetErrorsMap() map[string]int { 120 return nil 121 } 122 123 func getBarcode(boleto models.BoletoRequest) (bc barcode) { 124 bc.bankCode = fmt.Sprintf("%d", models.Bradesco) 125 bc.currencyCode = fmt.Sprintf("%d", models.Real) 126 bc.account = fmt.Sprintf("%07s", boleto.Agreement.Account) 127 bc.agency = fmt.Sprintf("%04s", boleto.Agreement.Agency) 128 bc.dateDueFactor, _ = dateDueFactor(boleto.Title.ExpireDateTime) 129 bc.ourNumber = fmt.Sprintf("%011d", boleto.Title.OurNumber) 130 bc.value = fmt.Sprintf("%010d", boleto.Title.AmountInCents) 131 bc.wallet = fmt.Sprintf("%02d", boleto.Agreement.Wallet) 132 bc.zero = "0" 133 return 134 } 135 136 func (bc barcode) toString() string { 137 return fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s", bc.bankCode, bc.currencyCode, bc.calcCheckDigit(), bc.dateDueFactor, bc.value, bc.agency, bc.wallet, bc.ourNumber, bc.account, bc.zero) 138 } 139 140 func (bc barcode) calcCheckDigit() string { 141 prevCode := fmt.Sprintf("%s%s%s%s%s%s%s%s%s", bc.bankCode, bc.currencyCode, bc.dateDueFactor, bc.value, bc.agency, bc.wallet, bc.ourNumber, bc.account, bc.zero) 142 return util.BarcodeDv(prevCode) 143 } 144 145 func dateDueFactor(dateDue time.Time) (string, error) { 146 var dateDueFixed = time.Date(1997, 10, 7, 0, 0, 0, 0, time.UTC) 147 dif := dateDue.Sub(dateDueFixed) 148 factor := int(dif.Hours() / 24) 149 if factor <= 0 { 150 return "", errors.New("DateDue must be in the future") 151 } 152 return fmt.Sprintf("%04d", factor), nil 153 } 154 155 func (b bankBradescoShopFacil) GetBankNameIntegration() string { 156 return "BradescoShopFacil" 157 } 158 159 func bradescoShopFacilBoletoTypes() map[string]string { 160 161 o.Do(func() { 162 m = make(map[string]string) 163 164 m["DM"] = "01" //Duplicata Mercantil 165 m["NP"] = "02" //Nota promissória 166 m["RC"] = "05" //Recibo 167 m["DS"] = "12" //Duplicata de serviço 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 := bradescoShopFacilBoletoTypes() 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 185 }