You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 satır
3.9KB

  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. LoanNumber string
  23. Settlement time.Time
  24. LoanAmount float64
  25. Balance float64
  26. InTrail float64
  27. }
  28. type PayInAAAPeriod struct {
  29. Period time.Time
  30. Rows []PayInAAARow
  31. }
  32. func (m *AiDecodeIncome) decodeAAAPdf(raw string) (e error) {
  33. m.AAA = make([]PayInAAAPeriod, 0, 10)
  34. lines := strings.Split(raw, "\n")
  35. var currentDecoder *PayInAAAPeriod = nil
  36. state := "start"
  37. for _, l := range lines { // DFA, wow, finally it's used. after years of learning
  38. switch state {
  39. case "start":
  40. state = currentDecoder.processStart(l)
  41. if state == "LookingForPeriod" {
  42. // determine column index, if their column is changing
  43. }
  44. break
  45. case "LookingForPeriod":
  46. state = currentDecoder.processPeriod(l)
  47. if state == "LookingForRows" {
  48. Period, e := currentDecoder.getPeriod(l)
  49. if e != nil {
  50. log.Warn("cannot find period", l, e)
  51. state = "LookingForPeriod"
  52. } else {
  53. m.AAA = append(m.AAA, PayInAAAPeriod{})
  54. idx := len(m.AAA) - 1
  55. currentDecoder = &(m.AAA[idx])
  56. currentDecoder.Rows = make([]PayInAAARow, 0, 10)
  57. currentDecoder.Period = Period
  58. }
  59. }
  60. break
  61. case "LookingForRows", "LookingForRowsSkipCurrent":
  62. nextState, row, valid := currentDecoder.processRow(l)
  63. if valid && currentDecoder != nil {
  64. currentDecoder.Rows = append(currentDecoder.Rows, row)
  65. }
  66. state = nextState
  67. if nextState == "start" {
  68. currentDecoder = nil //renew to a empty state
  69. }
  70. break
  71. }
  72. }
  73. return
  74. }
  75. func (m *PayInAAAPeriod) processStart(line string) (nextState string) {
  76. nextState = "start"
  77. if strings.Contains(line, "Loan Number") &&
  78. strings.Contains(line, "SettDate") &&
  79. strings.Contains(line, "Balance") &&
  80. strings.Contains(line, "IntTrail$") {
  81. nextState = "LookingForPeriod"
  82. }
  83. return
  84. }
  85. func (m *PayInAAAPeriod) processPeriod(line string) (nextState string) {
  86. nextState = "LookingForPeriod"
  87. if strings.Contains(line, "Period Servicing:") {
  88. nextState = "LookingForRows"
  89. }
  90. return
  91. }
  92. // Period Servicing: Feb 2020
  93. func (m *PayInAAAPeriod) getPeriod(line string) (p time.Time, e error) {
  94. idx := strings.Index(line, ":")
  95. subStr := strings.TrimSpace(line[idx+1:])
  96. p, e = time.Parse("Jan 2006", subStr)
  97. return
  98. }
  99. func (m *PayInAAAPeriod) processRow(line string) (nextState string, row PayInAAARow, valid bool) {
  100. nextState = "LookingForRows"
  101. valid = false
  102. allParts := strings.Split(line, " ")
  103. el := make([]string, 0, 10)
  104. for _, item := range allParts {
  105. if len(item) > 0 {
  106. el = append(el, item)
  107. }
  108. }
  109. if len(el) >= 5 {
  110. row.LoanNumber = el[0]
  111. row.Settlement, _ = time.Parse("02-Jan-06", el[1])
  112. row.LoanAmount = m.currencyToFloat64(el[2])
  113. row.Balance = m.currencyToFloat64(el[3])
  114. row.InTrail = m.currencyToFloat64(el[len(el)-1]) //last element
  115. valid = true
  116. } else {
  117. if strings.Contains(line, "Total:") {
  118. nextState = "start"
  119. } else {
  120. nextState = "LookingForRowsSkipCurrent"
  121. }
  122. }
  123. return
  124. }
  125. func (m *PayInAAAPeriod) currencyToFloat64(cur string) (ret float64) {
  126. cur = strings.ReplaceAll(cur, " ", "") //remove space
  127. cur = strings.ReplaceAll(cur, "$", "") //remove $
  128. cur = strings.ReplaceAll(cur, ",", "") //remove ,
  129. ret, _ = strconv.ParseFloat(cur, 64)
  130. return ret
  131. }