Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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