您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

207 行
4.3KB

  1. package main
  2. import (
  3. "biukop.com/sfm/loan"
  4. "encoding/json"
  5. "errors"
  6. log "github.com/sirupsen/logrus"
  7. "io/ioutil"
  8. "os"
  9. "os/exec"
  10. "strings"
  11. )
  12. type AiDecodeIncome struct {
  13. Id int64
  14. Input loan.Uploads
  15. ul uploadsOnDisk // internal data
  16. Mime string // mime actually detected.
  17. PayIn []loan.PayIn // generated PayIn Info
  18. DecodeIncomeDetails
  19. }
  20. type DecodeIncomeDetails struct {
  21. Lender loan.LenderType
  22. AAA []PayInAAARow
  23. Connective []ConnectiveRow
  24. ResimacXls []ResimacRow
  25. ResimacPdf []ResimacPdf
  26. Pepper []PepperRow
  27. }
  28. type AiDecodeJson struct {
  29. Version string
  30. V1 DecodeIncomeDetails
  31. }
  32. func (m *AiDecodeIncome) decodeUploadToPayIn(ulMeta loan.Uploads, allowCachedResult bool) (e error) {
  33. m.Id = ulMeta.Id
  34. m.Input = ulMeta
  35. m.ul.Upload = ulMeta
  36. m.PayIn = make([]loan.PayIn, 0, 100) // finalized payIns, generated
  37. if allowCachedResult {
  38. e = m.ReadJson()
  39. if e == nil {
  40. return // already decoded
  41. } else {
  42. log.Warn("trying to read existing json failed ", e.Error())
  43. e = nil
  44. }
  45. }
  46. m.PayIn = make([]loan.PayIn, 0, 10)
  47. switch m.getFileType() {
  48. case "pdf":
  49. e = m.decodePdf()
  50. break
  51. case "excel", "opensheet":
  52. e = m.decodeXls()
  53. break
  54. default:
  55. e = errors.New("unknown format")
  56. }
  57. if e == nil {
  58. eJson := m.WriteJson()
  59. if eJson != nil {
  60. log.Error("failed to write analysis to json", eJson.Error())
  61. }
  62. }
  63. return
  64. }
  65. func (m *AiDecodeIncome) ReadJson() (e error) {
  66. if !fileExists(m.ul.jsonPath()) {
  67. return errors.New(m.ul.jsonPath() + " not found")
  68. }
  69. f, e := os.Open(m.ul.jsonPath())
  70. if e != nil {
  71. return
  72. }
  73. decoder := json.NewDecoder(f)
  74. data := AiDecodeJson{}
  75. e = decoder.Decode(&data)
  76. if e != nil {
  77. log.Error("failed load existing decode json", e.Error())
  78. return
  79. }
  80. return
  81. }
  82. func (m *AiDecodeIncome) WriteJson() (e error) {
  83. b, e := json.Marshal(m.DecodeIncomeDetails)
  84. if e != nil {
  85. return
  86. }
  87. ioutil.WriteFile(m.ul.jsonPath(), b, 0644)
  88. return
  89. }
  90. func (m *AiDecodeIncome) getFileType() (ret string) {
  91. strMime, e := GetFileContentType(m.ul.filePath())
  92. if e != nil {
  93. return
  94. }
  95. m.Mime = strMime
  96. ret, e = m.ul.GetFileType()
  97. if e != nil {
  98. ret = ""
  99. }
  100. return
  101. }
  102. func (m *AiDecodeIncome) decodePdf() (e error) {
  103. cmd := exec.Command("pdftotext", "-layout", m.ul.filePath(), "-")
  104. out, e := cmd.Output()
  105. if e != nil {
  106. log.Error("cannot convert pdf to text ", e)
  107. }
  108. raw := string(out)
  109. switch m.detectFunder(raw) {
  110. case loan.Lender_AAA:
  111. m.Lender = loan.Lender_AAA
  112. e = m.decodeAAAPdf(raw)
  113. // regardless of error, we pump in all available row successed so far
  114. for _, row := range m.AAA {
  115. pi := loan.PayIn{}
  116. pi.Id = 0
  117. pi.Ts = row.Period
  118. pi.Amount = row.LoanFacility
  119. pi.Lender = loan.Lender_AAA
  120. pi.Settlement = row.Settlement
  121. pi.Balance = row.Balance
  122. pi.OffsetBalance = -1
  123. pi.IncomeAmount = row.InTrail
  124. pi.IncomeType = "Trail"
  125. m.PayIn = append(m.PayIn, pi)
  126. }
  127. // log.Println("AAA final result", m.AAA)
  128. break
  129. case loan.Lender_Connective:
  130. m.Lender = loan.Lender_Connective
  131. e = m.decodeConnectivePdf(out)
  132. break
  133. case loan.Lender_Resimac:
  134. m.Lender = loan.Lender_Resimac
  135. e = m.decodeResimacPdf(out)
  136. break
  137. case loan.Lender_Unknown:
  138. e = errors.New(loan.Lender_Unknown)
  139. break // not able to detect Funder
  140. }
  141. return
  142. }
  143. func (m *AiDecodeIncome) decodeXls() (e error) {
  144. e = m.ul.convertExcelTo("csv")
  145. if e != nil {
  146. log.Error("cannot convert xls to csv ", e.Error())
  147. }
  148. raw := string(m.ul.tmp)
  149. switch m.detectFunder(raw) {
  150. case loan.Lender_Resimac:
  151. m.Lender = loan.Lender_Resimac
  152. e = m.decodeResimacXls(m.ul.tmp)
  153. break
  154. case loan.Lender_Pepper:
  155. m.Lender = loan.Lender_Pepper
  156. e = m.decodePepperXls(m.ul.tmp)
  157. break
  158. case loan.Lender_Unknown:
  159. e = errors.New(loan.Lender_Unknown)
  160. break // not able to detect Funder
  161. }
  162. return
  163. }
  164. func (m *AiDecodeIncome) detectFunder(raw string) loan.LenderType {
  165. if m.isAAA(raw) {
  166. return loan.Lender_AAA
  167. }
  168. if m.isConnective(raw) {
  169. return loan.Lender_Connective
  170. }
  171. if m.isResimacXls(raw) {
  172. return loan.Lender_Resimac
  173. }
  174. if m.isResimacPdf(raw) {
  175. return loan.Lender_Resimac
  176. }
  177. if m.isPepperXls(raw) {
  178. return loan.Lender_Pepper
  179. }
  180. return loan.Lender_Unknown
  181. }
  182. func (m *AiDecodeIncome) isKeywordExist(keyword string, lines []string) bool {
  183. for _, line := range lines {
  184. if strings.Contains(line, keyword) {
  185. return true
  186. }
  187. }
  188. return false
  189. }