No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

142 líneas
3.7KB

  1. package main
  2. import (
  3. log "github.com/sirupsen/logrus"
  4. "strconv"
  5. "strings"
  6. "time"
  7. )
  8. /* Sample Text
  9. AAA Financial Trail Report
  10. Super Finance Markets Pty Ltd
  11. Loan Number SettDate Loan Balance Arrears DisDate IntTrail$ Comments
  12. Facility
  13. Columbus
  14. Period Servicing: Feb 2020
  15. 400053440 02-Sep-19 $552,463 552,579.52 $32.19
  16. 400063271 19-Feb-20 $832,000 832,000.00 $0.00
  17. Columbus Total: $32.19
  18. Grand Total: $32.19
  19. Super Finance Markets Pty Ltd
  20. */
  21. type PayInAAARow struct {
  22. Period time.Time
  23. LoanNumber string
  24. Settlement time.Time
  25. LoanAmount float64
  26. Balance float64
  27. InTrail float64
  28. }
  29. func (m *AiDecodeIncome) decodeAAAPdf(raw string) (e error) {
  30. m.AAA = make([]PayInAAARow, 0, 10)
  31. lines := strings.Split(raw, "\n")
  32. var currentRow = PayInAAARow{}
  33. var currentPeriod = time.Time{}
  34. state := "start"
  35. for _, l := range lines { // DFA, wow, finally it's used. after years of learning
  36. switch state {
  37. case "start":
  38. state = currentRow.processStart(l)
  39. if state == "LookingForPeriod" {
  40. // determine column index, if their column is changing
  41. }
  42. break
  43. case "LookingForPeriod":
  44. state = currentRow.processPeriod(l)
  45. if state == "LookingForRows" {
  46. currentPeriod, e = currentRow.getPeriod(l)
  47. if e != nil {
  48. log.Warn("cannot find period", l, e)
  49. state = "LookingForPeriod"
  50. } else {
  51. currentRow.Period = currentPeriod
  52. }
  53. }
  54. break
  55. case "LookingForRows", "LookingForRowsSkipCurrent":
  56. nextState, valid := currentRow.processRow(l)
  57. if valid {
  58. m.AAA = append(m.AAA, currentRow)
  59. }
  60. state = nextState
  61. if nextState == "start" { // reset current state
  62. currentRow = PayInAAARow{}
  63. currentRow.Period = currentPeriod
  64. }
  65. break
  66. }
  67. }
  68. return
  69. }
  70. func (m *PayInAAARow) processStart(line string) (nextState string) {
  71. nextState = "start"
  72. if strings.Contains(line, "Loan Number") &&
  73. strings.Contains(line, "SettDate") &&
  74. strings.Contains(line, "Balance") &&
  75. strings.Contains(line, "IntTrail$") {
  76. nextState = "LookingForPeriod"
  77. }
  78. return
  79. }
  80. func (m *PayInAAARow) processPeriod(line string) (nextState string) {
  81. nextState = "LookingForPeriod"
  82. if strings.Contains(line, "Period Servicing:") {
  83. nextState = "LookingForRows"
  84. }
  85. return
  86. }
  87. // Period Servicing: Feb 2020
  88. func (m *PayInAAARow) getPeriod(line string) (p time.Time, e error) {
  89. idx := strings.Index(line, ":")
  90. subStr := strings.TrimSpace(line[idx+1:])
  91. p, e = time.Parse("Jan 2006", subStr)
  92. return
  93. }
  94. func (m *PayInAAARow) processRow(line string) (nextState string, valid bool) {
  95. nextState = "LookingForRows"
  96. valid = false
  97. allParts := strings.Split(line, " ")
  98. el := make([]string, 0, 10)
  99. for _, item := range allParts {
  100. if len(item) > 0 {
  101. el = append(el, item)
  102. }
  103. }
  104. if len(el) >= 5 {
  105. m.LoanNumber = el[0]
  106. m.Settlement, _ = time.Parse("02-Jan-06", el[1])
  107. m.LoanAmount = m.currencyToFloat64(el[2])
  108. m.Balance = m.currencyToFloat64(el[3])
  109. m.InTrail = m.currencyToFloat64(el[len(el)-1]) //last element
  110. valid = true
  111. } else {
  112. if strings.Contains(line, "Total:") {
  113. nextState = "start"
  114. } else {
  115. nextState = "LookingForRowsSkipCurrent"
  116. }
  117. }
  118. return
  119. }
  120. func (m *PayInAAARow) currencyToFloat64(cur string) (ret float64) {
  121. cur = strings.ReplaceAll(cur, " ", "") //remove space
  122. cur = strings.ReplaceAll(cur, "$", "") //remove $
  123. cur = strings.ReplaceAll(cur, ",", "") //remove ,
  124. ret, _ = strconv.ParseFloat(cur, 64)
  125. return ret
  126. }