convert.go (3290B)
1 package convert 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "regexp" 7 "strings" 8 ) 9 10 type Converter interface { 11 Type() string 12 CanConvert(fname string) bool 13 Convert(fname string) (string, error) 14 } 15 16 // RbcDirectInvesting is a Converter for RBC Direct Investing statements. 17 type RbcDirectInvesting struct{} 18 19 // AppleCard is a Converter for Apple Card (MasterCard) statements. 20 type AppleCard struct{} 21 22 // ShinseiBank is a Converter for Shinsei Bank statements. 23 type ShinseiBank struct{} 24 25 func ConverterForFile(fname string) (Converter, error) { 26 converters := []Converter{ 27 &AppleCard{}, 28 &RbcDirectInvesting{}, 29 &ShinseiBank{}, 30 } 31 for _, c := range converters { 32 if c.CanConvert(fname) { 33 return c, nil 34 } 35 } 36 return nil, fmt.Errorf("Unknown statement type: %s", fname) 37 } 38 39 func (c *RbcDirectInvesting) Type() string { 40 return "RBC Direct Investing" 41 } 42 43 func (c *RbcDirectInvesting) CanConvert(fname string) bool { 44 r := regexp.MustCompile(`^\d+-\d{4}[A-Za-z]{3}\d\d-\d{4}[A-Za-z]{3}\d\d\.pdf$`) 45 return r.MatchString(fname) 46 } 47 48 // Format: ACCTNO-2020Jan15-2020Feb14.pdf 49 func (c *RbcDirectInvesting) Convert(fname string) (string, error) { 50 date := strings.Split(fname, "-")[2][0:9] 51 y := date[0:4] 52 m, err := getMonthNumber(strings.ToLower(date[4:7])) 53 if err != nil { 54 return "", err 55 } 56 d := date[7:9] 57 newFname := fmt.Sprintf("%s-%s-%s.pdf", y, m, d) 58 return newFname, nil 59 } 60 61 func (c *AppleCard) Type() string { 62 return "Apple Card" 63 } 64 65 func (c *AppleCard) CanConvert(fname string) bool { 66 return strings.HasPrefix(strings.ToLower(fname), "apple card statement ") 67 } 68 69 // Format: Apple Card Statement - January 2020.pdf 70 func (c *AppleCard) Convert(fname string) (string, error) { 71 ext := filepath.Ext(fname) 72 basename := fname[0 : len(fname)-len(ext)] 73 date := strings.Split(basename, " ")[4:6] 74 y := date[1] 75 m, err := getMonthNumber(strings.ToLower(date[0])) 76 if err != nil { 77 return "", err 78 } 79 newFname := fmt.Sprintf("%s-%s.pdf", y, m) 80 return newFname, nil 81 } 82 83 func (c *ShinseiBank) Type() string { 84 return "Shinsei Bank" 85 } 86 87 func (c *ShinseiBank) CanConvert(fname string) bool { 88 // TODO: this will break in the year 3000. 89 // Even more terrifying if we're still using PDFs. 90 r := regexp.MustCompile(`^2\d{15}\.pdf$`) 91 return r.MatchString(strings.ToLower(fname)) 92 } 93 94 // Format: YYYYmmBBBAAAAAAA.pdf where BBB is the branch number and AAAAAAA is 95 // the 7-digit account number. 96 func (c *ShinseiBank) Convert(fname string) (string, error) { 97 y := fname[0:4] 98 m := fname[4:6] 99 newFname := fmt.Sprintf("%s-%s.pdf", y, m) 100 return newFname, nil 101 } 102 103 func getMonthNumber(m string) (string, error) { 104 switch { 105 case m == "jan" || m == "january": 106 return "01", nil 107 case m == "feb" || m == "february": 108 return "02", nil 109 case m == "mar" || m == "march": 110 return "03", nil 111 case m == "apr" || m == "april": 112 return "04", nil 113 case m == "may": 114 return "05", nil 115 case m == "jun" || m == "june": 116 return "06", nil 117 case m == "jul" || m == "july": 118 return "07", nil 119 case m == "aug" || m == "august": 120 return "08", nil 121 case m == "sep" || m == "september": 122 return "09", nil 123 case m == "oct" || m == "october": 124 return "10", nil 125 case m == "nov" || m == "november": 126 return "11", nil 127 case m == "dec" || m == "december": 128 return "12", nil 129 } 130 return "", fmt.Errorf("Bad month name: %s", m) 131 }