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  }