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  }