github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/citibank/citi.go (about)

     1  package citibank
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"strconv"
     7  	"sync"
     8  
     9  	"github.com/PMoneda/flow"
    10  	"github.com/mundipagg/boleto-api/certificate"
    11  	"github.com/mundipagg/boleto-api/config"
    12  	"github.com/mundipagg/boleto-api/issuer"
    13  	"github.com/mundipagg/boleto-api/log"
    14  	"github.com/mundipagg/boleto-api/metrics"
    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 (
    22  	onceTransport = &sync.Once{}
    23  	transportTLS  *http.Transport
    24  )
    25  
    26  type bankCiti struct {
    27  	validate  *models.Validator
    28  	log       *log.Log
    29  	transport *http.Transport
    30  }
    31  
    32  func New() (bankCiti, error) {
    33  	var err error
    34  	b := bankCiti{
    35  		validate: models.NewValidator(),
    36  		log:      log.CreateLog(),
    37  	}
    38  
    39  	certificates := certificate.TLSCertificate{
    40  		Crt: config.Get().CitibankCertificateSSLName,
    41  		Key: config.Get().CitibankCertificateSSLName,
    42  	}
    43  
    44  	onceTransport.Do(func() {
    45  		transportTLS, err = util.BuildTLSTransport(certificates)
    46  	})
    47  	b.transport = transportTLS
    48  
    49  	if err != nil || (b.transport == nil && !config.Get().MockMode) {
    50  		return bankCiti{}, fmt.Errorf("fail on load TLSTransport: %v", err)
    51  	}
    52  
    53  	b.validate.Push(validations.ValidateAmount)
    54  	b.validate.Push(validations.ValidateExpireDate)
    55  	b.validate.Push(validations.ValidateBuyerDocumentNumber)
    56  	b.validate.Push(validations.ValidateRecipientDocumentNumber)
    57  	b.validate.Push(validations.ValidatePayeeGuarantorDocumentNumber)
    58  	b.validate.Push(validations.ValidatePayeeGuarantorName)
    59  	b.validate.Push(citiValidateAgency)
    60  	b.validate.Push(citiValidateAccount)
    61  	b.validate.Push(citiValidateWallet)
    62  
    63  	return b, nil
    64  }
    65  
    66  //Log retorna a referencia do log
    67  func (b bankCiti) Log() *log.Log {
    68  	return b.log
    69  }
    70  
    71  func (b bankCiti) RegisterBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) {
    72  
    73  	boleto.Title.BoletoType, boleto.Title.BoletoTypeCode = getBoletoType()
    74  
    75  	boleto.Title.OurNumber = calculateOurNumber(boleto)
    76  	r := flow.NewFlow()
    77  	serviceURL := config.Get().URLCiti
    78  	from := getResponseCiti()
    79  	to := getAPIResponseCiti()
    80  	bod := r.From("message://?source=inline", boleto, getRequestCiti(), tmpl.GetFuncMaps())
    81  	bod.To("log://?type=request&format=xml&url="+serviceURL, b.log)
    82  	var responseCiti string
    83  	var status int
    84  	var err error
    85  	duration := util.Duration(func() {
    86  		responseCiti, status, err = b.sendRequest(bod.GetBody().(string))
    87  	})
    88  	if err != nil {
    89  		return models.BoletoResponse{}, err
    90  	}
    91  	metrics.PushTimingMetric("citibank-register-boleto-online", duration.Seconds())
    92  	bod.To("set://?prop=header", map[string]string{"status": strconv.Itoa(status)})
    93  	bod.To("set://?prop=body", responseCiti)
    94  	bod.To("log://?type=response&format=xml&url="+serviceURL, b.log)
    95  	ch := bod.Choice()
    96  	ch.When(flow.Header("status").IsEqualTo("200"))
    97  	ch.To("transform://?format=xml", from, to, tmpl.GetFuncMaps())
    98  	ch.Otherwise()
    99  	ch.To("log://?type=response&url="+serviceURL, b.log).To("apierro://")
   100  
   101  	switch t := bod.GetBody().(type) {
   102  	case string:
   103  		response := util.ParseJSON(t, new(models.BoletoResponse)).(*models.BoletoResponse)
   104  		issuer := issuer.NewIssuer(response.BarCodeNumber, response.DigitableLine)
   105  		if !((issuer.IsValidBarCode() && issuer.IsValidDigitableLine()) || response.HasErrors()) {
   106  			return models.BoletoResponse{}, models.NewBadGatewayError("BadGateway")
   107  		}
   108  		return *response, nil
   109  	case models.BoletoResponse:
   110  		return t, nil
   111  	}
   112  	return models.BoletoResponse{}, models.NewInternalServerError("MP500", "Internal error")
   113  }
   114  
   115  func (b bankCiti) ProcessBoleto(boleto *models.BoletoRequest) (models.BoletoResponse, error) {
   116  	errs := b.ValidateBoleto(boleto)
   117  	if len(errs) > 0 {
   118  		return models.BoletoResponse{Errors: errs}, nil
   119  	}
   120  	return b.RegisterBoleto(boleto)
   121  }
   122  
   123  func (b bankCiti) ValidateBoleto(boleto *models.BoletoRequest) models.Errors {
   124  	return models.Errors(b.validate.Assert(boleto))
   125  }
   126  
   127  func (b bankCiti) sendRequest(body string) (string, int, error) {
   128  	serviceURL := config.Get().URLCiti
   129  	if config.Get().MockMode {
   130  		return util.Post(serviceURL, body, config.Get().TimeoutDefault, map[string]string{"Soapaction": "RegisterBoleto"})
   131  	} else {
   132  		return util.PostTLS(serviceURL, body, config.Get().TimeoutDefault, map[string]string{"Soapaction": "RegisterBoleto"}, b.transport)
   133  	}
   134  }
   135  
   136  //GetBankNumber retorna o codigo do banco
   137  func (b bankCiti) GetBankNumber() models.BankNumber {
   138  	return models.Citibank
   139  }
   140  
   141  func calculateOurNumber(boleto *models.BoletoRequest) uint {
   142  	ourNumberWithDigit := strconv.Itoa(int(boleto.Title.OurNumber)) + util.OurNumberDv(strconv.Itoa(int(boleto.Title.OurNumber)), util.MOD11)
   143  	value, _ := strconv.Atoi(ourNumberWithDigit)
   144  	return uint(value)
   145  }
   146  
   147  func (b bankCiti) GetBankNameIntegration() string {
   148  	return "Citibank"
   149  }
   150  
   151  func (b bankCiti) GetErrorsMap() map[string]int {
   152  	return nil
   153  }
   154  
   155  func getBoletoType() (bt string, btc string) {
   156  	return "DMI", "03"
   157  }