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 }