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/")
+}