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

     1  package tmpl
     2  
     3  import (
     4  	"bytes"
     5  	"html"
     6  	"html/template"
     7  	"math"
     8  	"regexp"
     9  	"strings"
    10  	"time"
    11  
    12  	"strconv"
    13  
    14  	"fmt"
    15  
    16  	"github.com/kennygrant/sanitize"
    17  	"github.com/mundipagg/boleto-api/config"
    18  	"github.com/mundipagg/boleto-api/models"
    19  	"github.com/mundipagg/boleto-api/util"
    20  
    21  	"go.mongodb.org/mongo-driver/bson/primitive"
    22  )
    23  
    24  var funcMap = template.FuncMap{
    25  	"today":                               today,
    26  	"todayCiti":                           todayCiti,
    27  	"brdate":                              brDate,
    28  	"replace":                             replace,
    29  	"docType":                             docType,
    30  	"trim":                                trim,
    31  	"padLeft":                             padLeft,
    32  	"clearString":                         clearString,
    33  	"toString":                            toString,
    34  	"toString64":                          toString64,
    35  	"fmtDigitableLine":                    fmtDigitableLine,
    36  	"fmtCNPJ":                             fmtCNPJ,
    37  	"fmtCPF":                              fmtCPF,
    38  	"fmtDoc":                              fmtDoc,
    39  	"truncate":                            truncateString,
    40  	"fmtNumber":                           fmtNumber,
    41  	"joinSpace":                           joinSpace,
    42  	"brDateWithoutDelimiter":              brDateWithoutDelimiter,
    43  	"enDateWithoutDelimiter":              enDateWithoutDelimiter,
    44  	"fullDate":                            fulldate,
    45  	"enDate":                              enDate,
    46  	"hasErrorTags":                        hasErrorTags,
    47  	"toFloatStr":                          toFloatStr,
    48  	"concat":                              concat,
    49  	"base64":                              base64,
    50  	"unscape":                             unscape,
    51  	"unescapeHtmlString":                  unescapeHtmlString,
    52  	"trimLeft":                            trimLeft,
    53  	"santanderNSUPrefix":                  santanderNSUPrefix,
    54  	"santanderEnv":                        santanderEnv,
    55  	"formatSingleLine":                    formatSingleLine,
    56  	"diff":                                diff,
    57  	"mod11dv":                             calculateOurNumberMod11,
    58  	"mod10ItauDv":                         mod10Itau,
    59  	"printIfNotProduction":                printIfNotProduction,
    60  	"itauEnv":                             itauEnv,
    61  	"caixaEnv":                            caixaEnv,
    62  	"extractNumbers":                      extractNumbers,
    63  	"splitValues":                         splitValues,
    64  	"brDateDelimiter":                     brDateDelimiter,
    65  	"brDateDelimiterTime":                 brDateDelimiterTime,
    66  	"toString16":                          toString16,
    67  	"mod11BradescoShopFacilDv":            mod11BradescoShopFacilDv,
    68  	"bsonMongoToString":                   bsonMongoToString,
    69  	"escapeStringOnJson":                  escapeStringOnJson,
    70  	"removeSpecialCharacter":              removeSpecialCharacter,
    71  	"sanitizeCitibankSpecialCharacteres":  sanitizeCitibankSpecialCharacteres,
    72  	"clearStringCaixa":                    clearStringCaixa,
    73  	"truncateOnly":                        truncateOnly,
    74  	"toUint":                              toUint,
    75  	"strToFloat":                          strToFloat,
    76  	"float64ToString":                     float64ToString,
    77  	"datePlusDays":                        datePlusDays,
    78  	"datePlusDaysConsideringZeroAsStart":  datePlusDaysConsideringZeroAsStart,
    79  	"getInterestInstruction":              getInterestInstruction,
    80  	"getFineInstruction":                  getFineInstruction,
    81  	"datePlusDaysLocalTime":               datePlusDaysLocalTime,
    82  	"calculateFees":                       calculateFees,
    83  	"calculateInterestByDay":              calculateInterestByDay,
    84  	"onlyAlphabetics":                     onlyAlphabetics,
    85  	"onlyAlphanumerics":                   onlyAlphanumerics,
    86  	"onlyOneSpace":                        onlyOneSpace,
    87  	"removeAllSpaces":                     removeAllSpaces,
    88  	"convertAmountInCentsToPercent":       convertAmountInCentsToPercent,
    89  	"convertAmountInCentsToPercentPerDay": convertAmountInCentsToPercentPerDay,
    90  	"float64ToStringTruncate":             float64ToStringTruncate,
    91  }
    92  
    93  func GetFuncMaps() template.FuncMap {
    94  	return funcMap
    95  }
    96  
    97  func santanderNSUPrefix(number string) string {
    98  	if config.Get().SantanderEnv == "T" {
    99  		return "TST" + number
   100  	}
   101  	return number
   102  }
   103  
   104  func santanderEnv() string {
   105  	return config.Get().SantanderEnv
   106  }
   107  
   108  func diff(a string, b string) bool {
   109  	return a != b
   110  }
   111  
   112  func formatSingleLine(s string) string {
   113  	s1 := strings.Replace(s, "\r", "", -1)
   114  	return strings.Replace(s1, "\n", "; ", -1)
   115  }
   116  
   117  func padLeft(value, char string, total uint) string {
   118  	s := util.PadLeft(value, char, total)
   119  	return s
   120  }
   121  func unscape(s string) template.HTML {
   122  	return template.HTML(s)
   123  }
   124  
   125  func sanitizeHtmlString(s string) string {
   126  	str := html.UnescapeString(s)
   127  	return sanitize.HTML(str)
   128  }
   129  
   130  func unescapeHtmlString(s string) template.HTML {
   131  	c := sanitizeHtmlString(s)
   132  	return template.HTML(html.UnescapeString(c))
   133  }
   134  
   135  func trimLeft(s string, caract string) string {
   136  	return strings.TrimLeft(s, caract)
   137  }
   138  
   139  func truncateString(str string, num int) string {
   140  	bnoden := removeSpecialCharacter(str)
   141  
   142  	if len(bnoden) > num {
   143  		bnoden = str[0:num]
   144  	}
   145  	//Support extended ASCII
   146  	return string([]rune(bnoden))
   147  }
   148  
   149  func clearString(str string) string {
   150  	s := sanitize.Accents(str)
   151  	var buffer bytes.Buffer
   152  	for _, ch := range s {
   153  		if ch <= 122 && ch >= 32 {
   154  			buffer.WriteString(string(ch))
   155  		}
   156  	}
   157  	return buffer.String()
   158  }
   159  
   160  func joinSpace(str ...string) string {
   161  	return strings.Join(str, " ")
   162  }
   163  
   164  func hasErrorTags(mapValues map[string]string, errorTags ...string) bool {
   165  	hasError := false
   166  	for _, v := range errorTags {
   167  		if value, exist := mapValues[v]; exist && strings.Trim(value, " ") != "" {
   168  			hasError = true
   169  			break
   170  		}
   171  	}
   172  	return hasError
   173  }
   174  
   175  func fmtNumber(n uint64) string {
   176  	real := n / 100
   177  	cents := n % 100
   178  	return fmt.Sprintf("%d,%02d", real, cents)
   179  }
   180  
   181  func printIfNotProduction(obj string) string {
   182  	if config.IsNotProduction() {
   183  		return fmt.Sprintf("%s", obj)
   184  	}
   185  	return ""
   186  }
   187  
   188  func toFloatStr(n uint64) string {
   189  	real := n / 100
   190  	cents := n % 100
   191  	return fmt.Sprintf("%d.%02d", real, cents)
   192  }
   193  
   194  func strToFloat(n string) float64 {
   195  	s, _ := strconv.ParseFloat(n, 64)
   196  	return s
   197  }
   198  
   199  func float64ToString(format string, value float64) string {
   200  	return fmt.Sprintf(format, value)
   201  }
   202  
   203  // Truncamento se precision for 2 Ex: 12.3496 -> 12.34
   204  // precision: Quantidade de casas decimais depois da vírgula
   205  func roundDown(val float64, precision int) float64 {
   206  	return math.Floor(float64(float32(val)*float32(math.Pow10(precision)))) / math.Pow10(precision)
   207  }
   208  
   209  // Converte um número float para string
   210  // precision: Quantidade de casas decimais depois da vírgula
   211  func float64ToStringTruncate(format string, precision int, value float64) string {
   212  	b := fmt.Sprintf(format, roundDown(value, precision))
   213  	return b
   214  }
   215  
   216  func fmtDoc(doc models.Document) string {
   217  	if e := doc.ValidateCPF(); e == nil {
   218  		return fmtCPF(doc.Number)
   219  	}
   220  	return fmtCNPJ(doc.Number)
   221  }
   222  
   223  func toString(number uint) string {
   224  	return strconv.FormatInt(int64(number), 10)
   225  }
   226  
   227  func toUint(number string) uint {
   228  	value, _ := strconv.Atoi(number)
   229  	return uint(value)
   230  }
   231  
   232  func toString16(number uint16) string {
   233  	return strconv.FormatInt(int64(number), 10)
   234  }
   235  
   236  func toString64(number uint64) string {
   237  	return strconv.FormatInt(int64(number), 10)
   238  }
   239  
   240  func today() time.Time {
   241  	return util.BrNow()
   242  }
   243  
   244  func todayCiti() time.Time {
   245  	return util.NycNow()
   246  }
   247  
   248  func fulldate(t time.Time) string {
   249  	return t.Format("20060102150405")
   250  }
   251  
   252  func brDate(d time.Time) string {
   253  	return d.Format("02/01/2006")
   254  }
   255  
   256  func enDate(d time.Time, del string) string {
   257  	return d.Format("2006" + del + "01" + del + "02")
   258  }
   259  
   260  func datePlusDays(date time.Time, days uint) time.Time {
   261  	timeToPlus := time.Hour * 24 * time.Duration(days)
   262  	return date.UTC().Add(timeToPlus)
   263  }
   264  
   265  func datePlusDaysConsideringZeroAsStart(date time.Time, days uint) time.Time {
   266  	daysConsideringZeroAsStart := days - 1
   267  	return datePlusDays(date, daysConsideringZeroAsStart)
   268  }
   269  
   270  func brDateWithoutDelimiter(d time.Time) string {
   271  	return d.Format("02012006")
   272  }
   273  
   274  func enDateWithoutDelimiter(d time.Time) string {
   275  	return d.Format("20060102")
   276  }
   277  
   278  func replace(str, old, new string) string {
   279  	return strings.Replace(str, old, new, -1)
   280  }
   281  
   282  func docType(s models.Document) int {
   283  	if s.IsCPF() {
   284  		return 1
   285  	}
   286  	return 2
   287  }
   288  
   289  func trim(s string) string {
   290  	return strings.TrimSpace(s)
   291  }
   292  
   293  func fmtDigitableLine(s string) string {
   294  	buf := bytes.Buffer{}
   295  	for idx, c := range s {
   296  		if idx == 5 || idx == 15 || idx == 26 {
   297  			buf.WriteString(".")
   298  		}
   299  		if idx == 10 || idx == 21 || idx == 32 || idx == 33 {
   300  			buf.WriteString(" ")
   301  		}
   302  		buf.WriteByte(byte(c))
   303  	}
   304  	return buf.String()
   305  }
   306  
   307  func fmtCNPJ(s string) string {
   308  	buf := bytes.Buffer{}
   309  	for idx, c := range s {
   310  		if idx == 2 || idx == 5 {
   311  			buf.WriteString(".")
   312  		}
   313  		if idx == 8 {
   314  			buf.WriteString("/")
   315  		}
   316  		if idx == 12 {
   317  			buf.WriteString("-")
   318  		}
   319  		buf.WriteRune(c)
   320  	}
   321  	return buf.String()
   322  }
   323  
   324  func fmtCPF(s string) string {
   325  	buf := bytes.Buffer{}
   326  	for idx, c := range s {
   327  		if idx == 3 || idx == 6 {
   328  			buf.WriteString(".")
   329  		}
   330  		if idx == 9 {
   331  			buf.WriteString("-")
   332  		}
   333  		buf.WriteRune(c)
   334  	}
   335  	return buf.String()
   336  }
   337  
   338  func concat(s ...string) string {
   339  	buf := bytes.Buffer{}
   340  	for _, item := range s {
   341  		buf.WriteString(item)
   342  	}
   343  	return buf.String()
   344  }
   345  
   346  func base64(s string) string {
   347  	return util.Base64(s)
   348  }
   349  
   350  func calculateOurNumberMod11(number uint, onlyDigit bool) uint {
   351  
   352  	ourNumberDigit := util.OurNumberDv(strconv.Itoa(int(number)), util.MOD11)
   353  
   354  	if onlyDigit {
   355  		value, _ := strconv.Atoi(ourNumberDigit)
   356  		return uint(value)
   357  	}
   358  
   359  	ourNumberWithDigit := strconv.Itoa(int(number)) + ourNumberDigit
   360  	value, _ := strconv.Atoi(ourNumberWithDigit)
   361  	return uint(value)
   362  }
   363  
   364  func mod10Itau(number string, agency string, account string, wallet uint16) string {
   365  
   366  	var buffer bytes.Buffer
   367  
   368  	if wallet == 126 || wallet == 131 || wallet == 146 || wallet == 168 {
   369  
   370  		buffer.WriteString(strconv.FormatUint(uint64(wallet), 10))
   371  		buffer.WriteString(number)
   372  
   373  		return util.OurNumberDv(buffer.String(), util.MOD10)
   374  	} else {
   375  		buffer.WriteString(agency)
   376  		buffer.WriteString(account)
   377  		buffer.WriteString(strconv.FormatUint(uint64(wallet), 10))
   378  		buffer.WriteString(number)
   379  		return util.OurNumberDv(buffer.String(), util.MOD10)
   380  	}
   381  }
   382  
   383  func itauEnv() string {
   384  	return config.Get().ItauEnv
   385  }
   386  
   387  func caixaEnv() string {
   388  	return config.Get().CaixaEnv
   389  }
   390  
   391  func extractNumbers(value string) string {
   392  	re := regexp.MustCompile("(\\D+)")
   393  	sanitizeValue := re.ReplaceAllString(string(value), "")
   394  	return sanitizeValue
   395  }
   396  
   397  func splitValues(value string, init int, end int) string {
   398  	return value[init:end]
   399  }
   400  
   401  func brDateDelimiter(date string, del string) string {
   402  	layout := "2006-01-02"
   403  	d, err := time.Parse(layout, date)
   404  	if err != nil {
   405  		return date
   406  	}
   407  
   408  	return d.Format("02" + del + "01" + del + "2006")
   409  }
   410  
   411  func brDateDelimiterTime(date time.Time, del string) string {
   412  	layout := "2006-01-02 00:00:00 +0000 UTC"
   413  
   414  	d, err := time.Parse(layout, date.String())
   415  
   416  	if err != nil {
   417  		return date.String()
   418  	}
   419  
   420  	return d.Format("02" + del + "01" + del + "2006")
   421  }
   422  
   423  func mod11BradescoShopFacilDv(number string, wallet string) string {
   424  	var buffer bytes.Buffer
   425  	buffer.WriteString(wallet)
   426  	buffer.WriteString(number)
   427  	return util.OurNumberDv(buffer.String(), util.MOD11, 7)
   428  }
   429  
   430  func bsonMongoToString(bsonId primitive.ObjectID) string {
   431  	return bsonId.Hex()
   432  }
   433  
   434  func escapeStringOnJson(field string) string {
   435  	field = strings.Replace(field, "\b", "", -1)
   436  	return regexp.MustCompile(`[\t\f\r\\]`).ReplaceAllString(field, "")
   437  }
   438  
   439  func removeSpecialCharacter(str string) string {
   440  	return regexp.MustCompile("[^a-zA-Z0-9ÁÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕáéíóúàèìòùâêîôûãõç,.\\-\\s]+").ReplaceAllString(str, "")
   441  }
   442  
   443  func sanitizeCitibankSpecialCharacteres(str string) string {
   444  	str = regexp.MustCompile("[^a-zA-Z0-9.;@\\-\\/\\s]+").ReplaceAllString(clearString(str), "")
   445  	return str
   446  }
   447  
   448  //clearStringCaixa Define os caracteres aceitos de acordo com a documentação da caixa.
   449  func clearStringCaixa(str string) string {
   450  	s := sanitize.Accents(str)
   451  	var buffer bytes.Buffer
   452  	for _, ch := range s {
   453  		if util.IsDigit(ch) || util.IsBasicCharacter(ch) || util.IsCaixaSpecialCharacter(ch) {
   454  			buffer.WriteString(string(ch))
   455  		} else {
   456  			buffer.WriteString(" ")
   457  		}
   458  	}
   459  	return buffer.String()
   460  }
   461  
   462  //truncateOnly Realiza o truncate da string
   463  func truncateOnly(str string, num int) string {
   464  	if len([]rune(str)) > num {
   465  		str = string([]rune(str)[0:num])
   466  	}
   467  	return str
   468  }
   469  
   470  //calculateFees Calcula o fees em reais por dia, sobre o valor do titulo
   471  func calculateFees(amountFee uint64, percentageFee float64, titleAmount uint64) float64 {
   472  	const conversionFactor = 0.01
   473  	const defaultValueRate = 0
   474  
   475  	if amountFee <= defaultValueRate && percentageFee <= defaultValueRate {
   476  		return defaultValueRate
   477  	}
   478  
   479  	if amountFee > defaultValueRate {
   480  		return float64(amountFee) * conversionFactor
   481  	}
   482  
   483  	originalAmountToReal := float64(titleAmount) * conversionFactor
   484  	return (percentageFee * conversionFactor) * originalAmountToReal
   485  }
   486  
   487  //calculateInterestByDay Calcula a taxa de juros em reais por dia, sobre o valor do titulo
   488  func calculateInterestByDay(amountFee uint64, percentageFee float64, titleAmount uint64) float64 {
   489  	interestAmount := calculateFees(amountFee, percentageFee, titleAmount)
   490  
   491  	if percentageFee > 0 {
   492  		interestAmount /= 30
   493  	}
   494  
   495  	return interestAmount
   496  }
   497  
   498  func datePlusDaysLocalTime(date time.Time, days uint) time.Time {
   499  	timeToPlus := time.Hour * 24 * time.Duration(days)
   500  	return date.Add(timeToPlus)
   501  }
   502  
   503  //getFineInstruction Obtém a instrução de multa
   504  func getFineInstruction(title models.Title) string {
   505  	dateFine := datePlusDaysLocalTime(title.ExpireDateTime, title.Fees.Fine.DaysAfterExpirationDate)
   506  	dateFineFormatted := brDate(dateFine)
   507  
   508  	fineAmountInReal := calculateFees(title.Fees.Fine.AmountInCents, title.Fees.Fine.PercentageOnTotal, title.AmountInCents)
   509  
   510  	return fmt.Sprintf("A PARTIR DE %s: MULTA..........R$ %.2f", dateFineFormatted, roundDown(fineAmountInReal, 2))
   511  }
   512  
   513  //getInterestInstruction Obtém a instrução de juros
   514  func getInterestInstruction(title models.Title) string {
   515  	dateInterest := datePlusDaysLocalTime(title.ExpireDateTime, title.Fees.Interest.DaysAfterExpirationDate)
   516  	dateInterestFormatted := brDate(dateInterest)
   517  
   518  	interestAmountByDayInReal := calculateInterestByDay(title.Fees.Interest.AmountPerDayInCents, title.Fees.Interest.PercentagePerMonth, title.AmountInCents)
   519  
   520  	return fmt.Sprintf("A PARTIR DE %s: JUROS POR DIA DE ATRASO.........R$ %.3f", dateInterestFormatted, roundDown(interestAmountByDayInReal, 3))
   521  }
   522  
   523  func onlyAlphanumerics(str string) string {
   524  	return regexp.MustCompile(`[^a-zA-zÁÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕáéíóúàèìòùâêîôûãõç0-9\s]+`).ReplaceAllString(str, "")
   525  }
   526  
   527  func onlyAlphabetics(str string) string {
   528  	return regexp.MustCompile(`[^a-zA-zÁÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕáéíóúàèìòùâêîôûãõç\s]+`).ReplaceAllString(str, "")
   529  }
   530  
   531  func onlyOneSpace(str string) string {
   532  	return regexp.MustCompile(`\s+`).ReplaceAllString(str, " ")
   533  }
   534  
   535  func removeAllSpaces(str string) string {
   536  	return regexp.MustCompile(`\s+`).ReplaceAllString(str, "")
   537  }
   538  
   539  func convertAmountInCentsToPercent(totalAmount, amount uint64) float64 {
   540  	a := float64(amount) * 100 / float64(totalAmount)
   541  	return a
   542  }
   543  
   544  func convertAmountInCentsToPercentPerDay(totalAmount, amount uint64) float64 {
   545  	return float64(amount) * 30 * 100 / float64(totalAmount)
   546  }