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  }