diff --git a/src/db/database-primitives.go b/src/db/database-primitives.go index e70a27d..55da0d2 100644 --- a/src/db/database-primitives.go +++ b/src/db/database-primitives.go @@ -3,6 +3,7 @@ package db import ( "database/sql" "fmt" + _ "github.com/go-sql-driver/mysql" "io/ioutil" "log" "os" @@ -87,6 +88,7 @@ func (c *ConnectorGeneric) CreateTables() { NewRunner("create-insight-user-table.sql", InsightDatabaseName), NewRunner("create-insight-timeEntry-table.sql", InsightDatabaseName), NewRunner("create-mercury-picturePatterns-table.sql", MercuryDatabaseName), + NewRunner("create-mercury-arReports-table.sql", MercuryDatabaseName), } for _, runner := range tableCreationRunners { @@ -142,11 +144,11 @@ func QueryForObjects[K any](db *ConnectorGeneric, dbName string, queryScript str return &rs } -func BulkUpdate[K any](db *ConnectorGeneric, dbName string, updateScript string, items *[]*K, mapping func(s *sql.Stmt, item *K)) { - db.startConnection(dbName) - defer db.returnConnection() +func BulkUpdate[K any](connector *ConnectorGeneric, dbName string, updateScript string, items *[]*K, mapping func(s *sql.Stmt, item *K)) { + connector.startConnection(dbName) + defer connector.returnConnection() statement := loadSqlFile(updateScript) - s, err := db.cachedConnection.Prepare(*statement) + s, err := connector.cachedConnection.Prepare(*statement) if err != nil { log.Panic(err) } diff --git a/src/drive/drive.go b/src/drive/drive.go new file mode 100644 index 0000000..fb8e13f --- /dev/null +++ b/src/drive/drive.go @@ -0,0 +1,5 @@ +package drive + +func Test() { + +} diff --git a/src/finance/ar.go b/src/finance/ar.go new file mode 100644 index 0000000..dcf7759 --- /dev/null +++ b/src/finance/ar.go @@ -0,0 +1,134 @@ +package finance + +import ( + "database/sql" + "fmt" + "log" + "mercury/src/db" + "os" + "path" + "strconv" + "strings" +) + +var ( + ArInputHeaders = []string{"Acct Name", "Current", "30", "60", "90", ">90"} + + arReportInputLineMappingFunction = func(s *sql.Stmt, item *arReportInputLine) { + _, err := s.Exec( + item.AccountName, + item.Current, + item.Thirty, + item.Sixty, + item.Ninety, + item.OverNinety, + item.TotalForPeriod, + item.ReportNameInfo.DateString, + item.ReportNameInfo.Region) + if err != nil { + log.Printf("%#v\n", s) + log.Panic(err) + } + } +) + +type ( + arReportInputLine struct { + AccountName string + Current float64 + Thirty float64 + Sixty float64 + Ninety float64 + OverNinety float64 + TotalForPeriod float64 + ReportNameInfo *arReportNameInfo + } + + arReportNameInfo struct { + DateString string + Region string + } +) + +func GenerateArAgingReport(pathlike string) { + connector := &db.ConnectorGeneric{} + res := make([]*arReportInputLine, 0, 5000) + listing, err := os.ReadDir(pathlike) + if err != nil { + log.Panic(err) + } + for _, listing := range listing { + subPath := path.Join(pathlike, listing.Name()) + parts := processArReport(subPath) + + for _, part := range *parts { + res = append(res, part) + } + } + + db.BulkUpdate[arReportInputLine](connector, "mercury", "update-mercury-arReport.sql", &res, arReportInputLineMappingFunction) + +} + +func processArReport(pathlike string) *[]*arReportInputLine { + res := make([]*arReportInputLine, 0, 500) + contents := readCsv(pathlike) + for _, row := range *contents { + if row[0] == "" || row[0] == "TOTAL" { + continue + } + reportNameInfo := parseReportNameToInfo(pathlike) + inputLine := rawRowToArReportInputLine(row, reportNameInfo) + res = append(res, inputLine) + } + return &res +} + +func parseReportNameToInfo(pathlike string) *arReportNameInfo { + base := path.Base(pathlike) + parts := strings.Split(base, "_") + date := reformatSolidDateString(parts[0]) + region := parts[2] + return &arReportNameInfo{date, region} +} + +func reformatSolidDateString(dateString string) string { + year := dateString[:4] + month := dateString[4:6] + day := dateString[6:8] + return fmt.Sprintf("%s-%s-%s", year, month, day) +} + +func rawRowToArReportInputLine(row []string, fileNameInfo *arReportNameInfo) *arReportInputLine { + res := arReportInputLine{} + res.AccountName = row[0] + current, err := strconv.ParseFloat(row[1], 64) + if err != nil { + log.Panicln(err) + } + thirty, err := strconv.ParseFloat(row[2], 64) + if err != nil { + log.Panicln(err) + } + sixty, err := strconv.ParseFloat(row[3], 64) + if err != nil { + log.Panicln(err) + } + ninety, err := strconv.ParseFloat(row[4], 64) + if err != nil { + log.Panicln(err) + } + overninety, err := strconv.ParseFloat(row[5], 64) + if err != nil { + log.Panicln(err) + } + + res.Current = current + res.Thirty = thirty + res.Sixty = sixty + res.Ninety = ninety + res.OverNinety = overninety + res.TotalForPeriod = current + thirty + sixty + ninety + overninety + res.ReportNameInfo = fileNameInfo + return &res +} diff --git a/src/mercury/csv.go b/src/finance/csv.go similarity index 92% rename from src/mercury/csv.go rename to src/finance/csv.go index ef14d02..4d41afd 100644 --- a/src/mercury/csv.go +++ b/src/finance/csv.go @@ -1,4 +1,4 @@ -package mercury +package finance import ( "encoding/csv" @@ -202,25 +202,6 @@ func ProcessCSVsFromPath(pathlikeIn string, pathlikeOut string) { } -func createCsvWriter(pathlike string) *csv.Writer { - _, err := os.Stat(pathlike) - var file *os.File - if os.IsNotExist(err) { - file, err = os.Create(pathlike) - if err != nil { - log.Panic(err) - } - } else { - os.Remove(pathlike) - file, err = os.Create(pathlike) - if err != nil { - log.Panic(err) - } - } - writer := csv.NewWriter(file) - return writer -} - func processFile(pathlike *string) *[]*BillingLine { ret := make([]*BillingLine, 0, 500000) content, err := os.OpenFile(*pathlike, os.O_RDONLY, 0755) @@ -265,11 +246,6 @@ func processFile(pathlike *string) *[]*BillingLine { return &ret } -func convertDateToSqlDate(datelike string) string { - parts := strings.Split(datelike, "/") - return fmt.Sprintf("%s-%s-%s", parts[2], parts[0], parts[1]) -} - func enumFiles(pathlikebase string) *[]*string { files, err := os.ReadDir(pathlikebase) ret := make([]*string, 0, 100) @@ -290,3 +266,49 @@ func (b *BillingLine) toRow() []string { func (t *TrialBalanceLine) toRow() []string { return []string{t.AccountName, strconv.FormatFloat(t.Amount, 'f', 2, 64), t.Period, t.AccountType} } + +// +/*====================================================================================== + util +======================================================================================*/ + +func convertDateToSqlDate(datelike string) string { + parts := strings.Split(datelike, "/") + return fmt.Sprintf("%s-%s-%s", parts[2], parts[0], parts[1]) +} + +func readCsv(pathlike string) *[][]string { + file, err := os.OpenFile(pathlike, os.O_RDONLY, 0755) + if err != nil { + log.Panic(err) + } + defer file.Close() + + reader := csv.NewReader(file) + contents, err := reader.ReadAll() + if err != nil { + log.Panic(err) + } + return &contents +} + +func createCsvWriter(pathlike string) *csv.Writer { + _, err := os.Stat(pathlike) + var file *os.File + if os.IsNotExist(err) { + file, err = os.Create(pathlike) + if err != nil { + log.Panic(err) + } + } else { + os.Remove(pathlike) + file, err = os.Create(pathlike) + if err != nil { + log.Panic(err) + } + } + writer := csv.NewWriter(file) + return writer +} + +// diff --git a/src/mercury.go b/src/mercury.go index ed5da81..18bf0ef 100644 --- a/src/mercury.go +++ b/src/mercury.go @@ -2,6 +2,7 @@ package main import ( "log" + "mercury/src/finance" "mercury/src/mercury" "mercury/src/projectClarity" "os" @@ -42,5 +43,5 @@ func processQbBilling() { log.Fatalln("please set the mercury_qb_path env var. we don't know where to look otherwise") } - mercury.ProcessTrialBalances(reportBase, "./updateInsightData.csv") + finance.ProcessTrialBalances(reportBase, "./updateInsightData.csv") } diff --git a/src/projectClarity/snitch.go b/src/projectClarity/snitch.go index cd019b1..9ab1a93 100644 --- a/src/projectClarity/snitch.go +++ b/src/projectClarity/snitch.go @@ -1,8 +1,10 @@ package projectClarity import ( + "database/sql" "log" - "mercury/src/projectInsight" + "mercury/src/db" + "regexp" ) // @@ -11,11 +13,11 @@ import ( ======================================================================================*/ type Snitch struct { - DB projectInsight.InsightDBConnector + DB *db.ConnectorGeneric } func NewSnitch() *Snitch { - return &Snitch{} + return &Snitch{&db.ConnectorGeneric{}} } func (s *Snitch) Test() { @@ -30,6 +32,10 @@ func (s *Snitch) getProjectNumbersForTesting() *[]*string { return nil } +func (s *Snitch) getPatterns() *[]*picturePattern { + return db.QueryForObjects[picturePattern](s.DB, db.MercuryDatabaseName, "read-mercury-picturePatterns.sql", mercuryPicturePatternMappingFunction) +} + // // @@ -38,3 +44,26 @@ func (s *Snitch) getProjectNumbersForTesting() *[]*string { ======================================================================================*/ // + +// +/*====================================================================================== + scratch +======================================================================================*/ + +type picturePattern struct { + id int + rawPattern string + pattern regexp.Regexp + verified bool +} + +var mercuryPicturePatternMappingFunction = func(rows *sql.Rows) *picturePattern { + pattern := picturePattern{} + err := rows.Scan(&pattern.id, &pattern.rawPattern, &pattern.verified) + if err != nil { + log.Panic(err) + } + return &pattern +} + +// diff --git a/src/projectInsight/insight-database.go b/src/projectInsight/insight-database.go index 81f4386..670380e 100644 --- a/src/projectInsight/insight-database.go +++ b/src/projectInsight/insight-database.go @@ -2,7 +2,7 @@ package projectInsight import ( "database/sql" - _ "github.com/go-sql-driver/mysql" + "log" "mercury/src/db" ) diff --git a/src/sql/create-mercury-arReports-table.sql b/src/sql/create-mercury-arReports-table.sql new file mode 100644 index 0000000..129a658 --- /dev/null +++ b/src/sql/create-mercury-arReports-table.sql @@ -0,0 +1,14 @@ +DROP TABLE IF EXISTS mercury.ar_aging_report; + +CREATE TABLE mercury.ar_aging_report +( + AccountName VARCHAR(150), + Current REAL, + Thirty REAL, + Sixty REAL, + Ninety REAL, + OverNinety REAL, + Total_for_Period REAL, + DateExported Date, + Region VARCHAR(25) +); \ No newline at end of file diff --git a/src/sql/read-mercury-picturePatterns.sql b/src/sql/read-mercury-picturePatterns.sql new file mode 100644 index 0000000..8dfaf73 --- /dev/null +++ b/src/sql/read-mercury-picturePatterns.sql @@ -0,0 +1 @@ +select * from picture_patterns; \ No newline at end of file diff --git a/src/sql/update-mercury-arReport.sql b/src/sql/update-mercury-arReport.sql new file mode 100644 index 0000000..5da41e3 --- /dev/null +++ b/src/sql/update-mercury-arReport.sql @@ -0,0 +1,2 @@ +INSERT INTO mercury.ar_aging_report (AccountName, Current, Thirty, Sixty, Ninety, OverNinety, Total_for_Period, DateExported, Region) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); \ No newline at end of file diff --git a/src/test.go b/src/test.go new file mode 100644 index 0000000..7fccb73 --- /dev/null +++ b/src/test.go @@ -0,0 +1,12 @@ +package main + +import ( + "mercury/src/finance" + "mercury/src/mercury" +) + +func main() { + ic := mercury.NewInterconnect() + ic.ResetTables() + finance.GenerateArAgingReport("/home/dtookey/work/clarity-reporting/qb/ar/") +}