From 485e8cc94408a0cc1fd5ac3b6f6ab0c69df8d998 Mon Sep 17 00:00:00 2001 From: "Mr.Li" Date: Tue, 31 Jan 2023 18:29:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor(export):=20=E8=B0=83=E6=95=B4=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=95=B0=E6=8D=AE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- biz/BaseExportBiz.go | 32 +++++++++ biz/batch.go | 153 +++++++++++++++++++++++++++++++++++++++ biz/batch_test.go | 36 ++++++++++ biz/card.go | 90 +++++++++++++++++++++++ biz/card_test.go | 35 +++++++++ biz/common.go | 41 +++++++++++ biz/direct.go | 159 +++++++++++++++++++++++++++++++++++++++++ biz/direct_test.go | 36 ++++++++++ biz/order.go | 150 ++++++++++++++++++++++++++++++++++++++ biz/order_test.go | 35 +++++++++ cmd/cmd/order.go | 35 +++++++++ cmd/cmd/root.go | 28 ++++++++ cmd/cmd/uitls.go | 49 +++++++++++++ cmd/main.go | 4 +- data/batch.go | 17 +++++ data/card.go | 77 +++++++++++++++----- data/card_test.go | 24 +++++++ data/common.go | 40 +++++++++++ data/conn.go | 2 +- data/direct.go | 72 ++++++++++++++++--- data/direct_test.go | 33 +++++++++ data/history_direct.go | 87 ++++++++++++++++++++++ data/history_order.go | 77 ++++++++++++++++++++ data/order.go | 11 +-- export/batch.go | 57 +++++++++++++++ export/card.go | 43 +++++++++++ export/direct.go | 57 +++++++++++++++ export/excel.go | 12 ++-- export/excel_test.go | 15 ++-- go.mod | 9 +++ 30 files changed, 1466 insertions(+), 50 deletions(-) create mode 100644 biz/BaseExportBiz.go create mode 100644 biz/batch.go create mode 100644 biz/batch_test.go create mode 100644 biz/card.go create mode 100644 biz/card_test.go create mode 100644 biz/common.go create mode 100644 biz/direct.go create mode 100644 biz/direct_test.go create mode 100644 biz/order.go create mode 100644 biz/order_test.go create mode 100644 cmd/cmd/order.go create mode 100644 cmd/cmd/root.go create mode 100644 cmd/cmd/uitls.go create mode 100644 data/batch.go create mode 100644 data/card_test.go create mode 100644 data/common.go create mode 100644 data/direct_test.go create mode 100644 data/history_direct.go create mode 100644 data/history_order.go create mode 100644 export/batch.go create mode 100644 export/card.go create mode 100644 export/direct.go diff --git a/biz/BaseExportBiz.go b/biz/BaseExportBiz.go new file mode 100644 index 0000000..536d090 --- /dev/null +++ b/biz/BaseExportBiz.go @@ -0,0 +1,32 @@ +package biz + +import ( + "fmt" + "time" +) + +type baseExportBiz struct { + fileSize int + opts *ExportOpts + fileName string +} + +func (e *baseExportBiz) FileSize() int { + return e.fileSize +} + +func (e *baseExportBiz) FileName() string { + return e.fileName +} + +func (e *baseExportBiz) FileNames() []string { + name := make([]string, e.fileSize+1) + for i := 0; i <= e.fileSize; i++ { + name[i] = fmt.Sprintf(e.fileName, i) + } + return name +} + +func (e *baseExportBiz) setFileArg(begin time.Time) { + e.fileName = getFielName(e.opts.Path, e.opts.Tag, begin) +} diff --git a/biz/batch.go b/biz/batch.go new file mode 100644 index 0000000..ee3b4d5 --- /dev/null +++ b/biz/batch.go @@ -0,0 +1,153 @@ +package biz + +import ( + "context" + "excel_export/data" + "excel_export/export" + "fmt" + "time" +) + +func NewBatchBiz(repo *data.DirectRepo, historyRepo *data.HistoryDirectRepo, opts *ExportOpts) *BatchBiz { + biz := &BatchBiz{ + repo: repo, + historyRepo: historyRepo, + } + biz.opts = DefaultOpts + if opts != nil { + biz.opts = opts + } + biz.opts.Tag = "batch" + return biz +} + +type BatchBiz struct { + repo *data.DirectRepo + historyRepo *data.HistoryDirectRepo + baseExportBiz +} + +func (e *BatchBiz) Export(begin, end time.Time) error { + e.setFileArg(begin) + file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) + + if err := file.Open(); err != nil { + return err + } + if err := file.Title(export.Batchs{}.Title()); err != nil { + return err + } + + //导出历史订单数据 + if err := e.exportHistoryData(file, begin, end); err != nil { + return err + } + + //导出最近7天数据 + if err := e.exportData(file, begin, end); err != nil { + return err + } + + e.fileSize = file.Index() + return nil +} + +func (e *BatchBiz) exportHistoryData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.historyRepo.BatchList(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.HistoryTransforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].SerialNumber + } + + return nil +} + +func (e *BatchBiz) exportData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.repo.BatchList(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.Transforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].SerialNumber + } + + return nil +} + +func (e BatchBiz) Transforms(data []data.Direct) export.Batchs { + result := make(export.Batchs, len(data)) + for i, val := range data { + result[i] = e.Transform(val) + } + return result +} + +func (e BatchBiz) Transform(data data.Direct) *export.Batch { + return &export.Batch{ + ResellerId: data.Batch.ResellerId, + ResellerName: data.Batch.Reseller.Name, + OursProductId: data.OursProductId, + OursProductTitle: data.OrderItem.OursProductTitle, + PlatformName: data.PlatformProduct.Platform.Name, + PlatformProductCode: data.PlatformProduct.Code, + PlatformProductName: data.PlatformProduct.Name, + Status: data.Status, + OrderOrderNumber: data.OrderOrderNumber, + SerialNumber: data.SerialNumber, + TerminalAccount: data.TerminalAccount, + TradePrice: data.TradePrice, + PlatformPrice: data.PlatformPrice, + CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), + ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), + Remark: data.Batch.Remark, + } +} + +func (e BatchBiz) HistoryTransforms(data []data.HistoryDirect) export.Batchs { + result := make(export.Batchs, len(data)) + for i, val := range data { + result[i] = e.HistoryTransform(val) + } + return result +} + +func (e BatchBiz) HistoryTransform(data data.HistoryDirect) *export.Batch { + return &export.Batch{ + ResellerId: data.Batch.ResellerId, + ResellerName: data.Batch.Reseller.Name, + OursProductId: data.OursProductId, + OursProductTitle: data.OrderItem.OursProductTitle, + PlatformName: data.PlatformProduct.Platform.Name, + PlatformProductCode: data.PlatformProduct.Code, + PlatformProductName: data.PlatformProduct.Name, + Status: data.Status, + OrderOrderNumber: data.OrderOrderNumber, + SerialNumber: data.SerialNumber, + TerminalAccount: data.TerminalAccount, + TradePrice: data.TradePrice, + PlatformPrice: data.PlatformPrice, + CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), + ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), + Remark: data.Batch.Remark, + } +} diff --git a/biz/batch_test.go b/biz/batch_test.go new file mode 100644 index 0000000..832b703 --- /dev/null +++ b/biz/batch_test.go @@ -0,0 +1,36 @@ +package biz + +import ( + "excel_export/data" + "fmt" + "github.com/stretchr/testify/assert" + "os" + "testing" + "time" +) + +func batchBiz() *BatchBiz { + db := data.Conn() + repo := data.NewDirectRepo(db) + historyRepo := data.NewHistoryDirectRepo(db) + + return NewBatchBiz(repo, historyRepo, nil) +} + +func TestBatchBiz_Export(t *testing.T) { + biz := batchBiz() + begin := time.Date(2021, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) + + err := biz.Export(begin, end) + assert.Nil(t, err) + + for i := 0; i <= biz.FileSize(); i++ { + fileName := fmt.Sprintf(biz.FileName(), i) + assert.FileExists(t, fileName) + + //清理文件 + os.Remove(fileName) + } + +} diff --git a/biz/card.go b/biz/card.go new file mode 100644 index 0000000..9eac35a --- /dev/null +++ b/biz/card.go @@ -0,0 +1,90 @@ +package biz + +import ( + "context" + "excel_export/data" + "excel_export/export" + "fmt" + "time" +) + +func NewCardBiz(repo *data.CardRepo, opts *ExportOpts) *CardBiz { + biz := &CardBiz{ + repo: repo, + } + + if opts == nil { + opts = DefaultOpts + } + opts.Tag = "card" + biz.opts = opts + return biz +} + +type CardBiz struct { + repo *data.CardRepo + baseExportBiz +} + +func (e *CardBiz) Export(begin, end time.Time) error { + e.setFileArg(begin) + file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) + + if err := file.Open(); err != nil { + return err + } + if err := file.Title(export.Cards{}.Title()); err != nil { + return err + } + + if err := e.exportData(file, begin, end); err != nil { + return err + } + + e.fileSize = file.Index() + return nil +} + +func (e *CardBiz) exportData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.repo.List(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.Transforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].OrderNumber + } + + return nil +} + +func (e CardBiz) Transforms(data []data.Card) export.Cards { + result := make(export.Cards, len(data)) + for i, val := range data { + result[i] = e.Transform(val) + } + return result +} + +func (e CardBiz) Transform(data data.Card) *export.Card { + return &export.Card{ + OrderNumber: data.OrderNumber, + ResellerOrderNumber: data.ResellerOrderNumber, + Amount: data.Amount, + Quantity: data.Quantity, + Status: data.Status, + ResellerId: data.ResellerId, + ResellerName: data.Reseller.Name, + OursProductId: data.OursProductId, + OursProductTitle: data.OurProduct.Name, + CreateTime: time.Unix(data.CreateTime, 0).Format("2006-01-02 15:04:05"), + } +} diff --git a/biz/card_test.go b/biz/card_test.go new file mode 100644 index 0000000..5d04e0b --- /dev/null +++ b/biz/card_test.go @@ -0,0 +1,35 @@ +package biz + +import ( + "excel_export/data" + "fmt" + "github.com/stretchr/testify/assert" + "os" + "testing" + "time" +) + +func cardBiz() *CardBiz { + db := data.Conn() + repo := data.NewCardRepo(db) + + return NewCardBiz(repo, nil) +} + +func TestCardBiz_Export(t *testing.T) { + biz := cardBiz() + begin := time.Date(2012, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) + + err := biz.Export(begin, end) + assert.Nil(t, err) + + for i := 0; i <= biz.FileSize(); i++ { + fileName := fmt.Sprintf(biz.FileName(), i) + assert.FileExists(t, fileName) + + //清理文件 + os.Remove(fileName) + } + +} diff --git a/biz/common.go b/biz/common.go new file mode 100644 index 0000000..a2a4c71 --- /dev/null +++ b/biz/common.go @@ -0,0 +1,41 @@ +package biz + +import ( + "fmt" + "os" + "time" +) + +const ( + QueryLImit = 10 + ExcelMaxRow = 10 +) + +func getFielName(path, filename string, time time.Time) string { + if path == "" { + path, _ = os.Getwd() + } + date := time.Format("20060102") + return fmt.Sprintf("%s/%s_%s_%%d.xlsx", path, filename, date) +} + +type ExportOpts struct { + QueryLimit int + ExcelMaxRow int + Path string + Tag string +} + +var DefaultOpts *ExportOpts = &ExportOpts{ + QueryLimit: QueryLImit, + ExcelMaxRow: ExcelMaxRow, + Tag: "export", +} + +func NewExportOpts(query, limit int, path string) *ExportOpts { + return &ExportOpts{ + QueryLimit: query, + ExcelMaxRow: limit, + Path: path, + } +} diff --git a/biz/direct.go b/biz/direct.go new file mode 100644 index 0000000..aaad4a1 --- /dev/null +++ b/biz/direct.go @@ -0,0 +1,159 @@ +package biz + +import ( + "context" + "excel_export/data" + "excel_export/export" + "fmt" + "time" +) + +func NewDirectBiz(repo *data.DirectRepo, historyRepo *data.HistoryDirectRepo, opts *ExportOpts) *DirectBiz { + biz := &DirectBiz{ + repo: repo, + historyRepo: historyRepo, + } + if opts == nil { + opts = DefaultOpts + } + opts.Tag = "direct" + biz.opts = opts + return biz +} + +type DirectBiz struct { + repo *data.DirectRepo + historyRepo *data.HistoryDirectRepo + baseExportBiz +} + +func (e *DirectBiz) FileSize() int { + return e.fileSize +} + +func (e *DirectBiz) Export(begin, end time.Time) error { + e.setFileArg(begin) + file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) + + if err := file.Open(); err != nil { + return err + } + if err := file.Title(export.Directs{}.Title()); err != nil { + return err + } + + //导出历史订单数据 + if err := e.exportHistoryData(file, begin, end); err != nil { + return err + } + + //导出最近7天数据 + if err := e.exportData(file, begin, end); err != nil { + return err + } + + e.fileSize = file.Index() + return nil +} + +func (e *DirectBiz) exportHistoryData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.historyRepo.List(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.HistoryTransforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].SerialNumber + } + + return nil +} + +func (e *DirectBiz) exportData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.repo.List(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.Transforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].SerialNumber + } + + return nil +} + +func (e DirectBiz) Transforms(data []data.Direct) export.Directs { + result := make(export.Directs, len(data)) + for i, val := range data { + result[i] = e.Transform(val) + } + return result +} + +func (e DirectBiz) Transform(data data.Direct) *export.Direct { + return &export.Direct{ + ResellerId: data.Order.ResellerId, + ResellerName: data.Order.Reseller.Name, + ResellerOrderNumber: data.Order.ResellerOrderNumber, + OursProductId: data.OursProductId, + OursProductTitle: data.OrderItem.OursProductTitle, + PlatformName: data.PlatformProduct.Platform.Name, + PlatformProductCode: data.PlatformProduct.Code, + PlatformProductName: data.PlatformProduct.Name, + Status: data.Status, + OrderOrderNumber: data.OrderOrderNumber, + SerialNumber: data.SerialNumber, + TerminalAccount: data.TerminalAccount, + TradePrice: data.TradePrice, + PlatformPrice: data.PlatformPrice, + CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), + ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), + Remark: data.Order.Remark.Remark, + } +} + +func (e DirectBiz) HistoryTransforms(data []data.HistoryDirect) export.Directs { + result := make(export.Directs, len(data)) + for i, val := range data { + result[i] = e.HistoryTransform(val) + } + return result +} + +func (e DirectBiz) HistoryTransform(data data.HistoryDirect) *export.Direct { + return &export.Direct{ + ResellerId: data.Order.ResellerId, + ResellerName: data.Order.Reseller.Name, + ResellerOrderNumber: data.Order.ResellerOrderNumber, + OursProductId: data.OursProductId, + OursProductTitle: data.OrderItem.OursProductTitle, + PlatformName: data.PlatformProduct.Platform.Name, + PlatformProductCode: data.PlatformProduct.Code, + PlatformProductName: data.PlatformProduct.Name, + Status: data.Status, + OrderOrderNumber: data.OrderOrderNumber, + SerialNumber: data.SerialNumber, + TerminalAccount: data.TerminalAccount, + TradePrice: data.TradePrice, + PlatformPrice: data.PlatformPrice, + CreateTime: data.CreateTime.Format("2006-01-02 15:04:05"), + ExecuteTime: data.ExecuteTime.Format("2006-01-02 15:04:05"), + Remark: data.Order.Remark.Remark, + } +} diff --git a/biz/direct_test.go b/biz/direct_test.go new file mode 100644 index 0000000..58a4ec0 --- /dev/null +++ b/biz/direct_test.go @@ -0,0 +1,36 @@ +package biz + +import ( + "excel_export/data" + "fmt" + "github.com/stretchr/testify/assert" + "os" + "testing" + "time" +) + +func directBiz() *DirectBiz { + db := data.Conn() + repo := data.NewDirectRepo(db) + historyRepo := data.NewHistoryDirectRepo(db) + + return NewDirectBiz(repo, historyRepo, nil) +} + +func TestDirectBiz_Export(t *testing.T) { + biz := directBiz() + begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) + + err := biz.Export(begin, end) + assert.Nil(t, err) + + for i := 0; i <= biz.FileSize(); i++ { + fileName := fmt.Sprintf(biz.FileName(), i) + assert.FileExists(t, fileName) + + //清理文件 + os.Remove(fileName) + } + +} diff --git a/biz/order.go b/biz/order.go new file mode 100644 index 0000000..d06ad13 --- /dev/null +++ b/biz/order.go @@ -0,0 +1,150 @@ +package biz + +import ( + "context" + "excel_export/data" + "excel_export/export" + "fmt" + "time" +) + +func NewOrderBiz(repo *data.OrderRepo, historyRepo *data.HistoryOrderRepo, opts *ExportOpts) *OrderBiz { + biz := &OrderBiz{ + repo: repo, + historyRepo: historyRepo, + } + + biz.opts = DefaultOpts + if opts != nil { + biz.opts = opts + } + return biz +} + +type OrderBiz struct { + repo *data.OrderRepo + historyRepo *data.HistoryOrderRepo + baseExportBiz +} + +func (e *OrderBiz) Export(begin, end time.Time) error { + e.setFileArg(begin) + file := export.NewExport(e.fileName, e.opts.ExcelMaxRow) + + if err := file.Open(); err != nil { + return err + } + + if err := file.Title(export.Orders{}.Title()); err != nil { + return err + } + + //导出历史订单数据 + if err := e.exportHistoryData(file, begin, end); err != nil { + return err + } + + //导出最近7天数据 + if err := e.exportData(file, begin, end); err != nil { + return err + } + + e.fileSize = file.Index() + return nil +} + +func (e *OrderBiz) exportHistoryData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.historyRepo.List(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.HistoryTransforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].OrderNumber + } + + return nil +} + +func (e *OrderBiz) exportData(export *export.Export, begin, end time.Time) error { + var last string + for true { + //导出最近7天数据 + data, err := e.repo.List(context.Background(), begin, end, e.opts.QueryLimit, last) + if err != nil { + return fmt.Errorf("获取导出数据错误:%w", err) + } + + if err := export.Export(e.Transforms(data)); err != nil { + return err + } + if len(data) < e.opts.QueryLimit { + return nil + } + last = data[len(data)-1].OrderNumber + } + + return nil +} + +func (e OrderBiz) Transforms(data []data.Order) export.Orders { + result := make(export.Orders, len(data)) + for i, val := range data { + result[i] = e.Transform(val) + } + return result +} + +func (e OrderBiz) Transform(order data.Order) *export.Order { + return &export.Order{ + OrderNumber: order.OrderNumber, + ResellerId: order.ResellerId, + ResellerName: order.Reseller.Name, + ResellerOrderNumber: order.ResellerOrderNumber, + Amount: order.Amount, + Account: order.Account, + Quantity: order.Quantity, + Status: order.Status, + PayStatus: order.PayStatus, + CreateTime: time.Unix(order.CreateTime, 0).Format("2006-01-02 15:04:05"), + FinishTime: time.Unix(order.FinishTime, 0).Format("2006-01-02 15:04:05"), + OursProductId: order.Item.OursProductId, + OursProductTitle: order.Item.OursProductTitle, + Remark: order.Remark.Remark, + } +} + +func (e OrderBiz) HistoryTransforms(data []data.HistoryOrder) export.Orders { + result := make(export.Orders, len(data)) + for i, val := range data { + result[i] = e.HistoryTransform(val) + } + return result +} + +func (e OrderBiz) HistoryTransform(order data.HistoryOrder) *export.Order { + return &export.Order{ + OrderNumber: order.OrderNumber, + ResellerId: order.ResellerId, + ResellerName: order.Reseller.Name, + ResellerOrderNumber: order.ResellerOrderNumber, + Amount: order.Amount, + Account: order.Account, + Quantity: order.Quantity, + Status: order.Status, + PayStatus: order.PayStatus, + CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"), + FinishTime: order.FinishTime.Format("2006-01-02 15:04:05"), + OursProductId: order.Item.OursProductId, + OursProductTitle: order.Item.OursProductTitle, + Remark: order.Remark.Remark, + } +} diff --git a/biz/order_test.go b/biz/order_test.go new file mode 100644 index 0000000..33b437e --- /dev/null +++ b/biz/order_test.go @@ -0,0 +1,35 @@ +package biz + +import ( + "excel_export/data" + "fmt" + "github.com/stretchr/testify/assert" + "os" + "testing" + "time" +) + +func orderBiz() *OrderBiz { + db := data.Conn() + repo := data.NewOrderRepo(db) + historyRepo := data.NewHistoryOrderRepo(db) + + return NewOrderBiz(repo, historyRepo, nil) +} + +func TestOrderBiz_Export(t *testing.T) { + biz := orderBiz() + begin := time.Date(2022, 8, 1, 0, 0, 0, 0, time.UTC) + end := time.Date(2022, 8, 2, 10, 0, 0, 0, time.UTC) + + err := biz.Export(begin, end) + assert.Nil(t, err) + + for i := 0; i <= biz.FileSize(); i++ { + fileName := fmt.Sprintf(biz.FileName(), i) + assert.FileExists(t, fileName) + + //清理文件 + os.Remove(fileName) + } +} diff --git a/cmd/cmd/order.go b/cmd/cmd/order.go new file mode 100644 index 0000000..ab2f3e2 --- /dev/null +++ b/cmd/cmd/order.go @@ -0,0 +1,35 @@ +package cmd + +import ( + "excel_export/biz" + "excel_export/data" + "github.com/spf13/cobra" +) + +var OrderCmd = &cobra.Command{ + Use: "order", + Short: "导出订单记录", + Run: orderRun, +} + +func orderRun(cmd *cobra.Command, args []string) { + begin := MustFlagsDateTime(cmd, "begin") + end := MustFlagsDateTime(cmd, "end") + + query, limit, path := GetGlobalFlags(cmd) + + db := data.Conn() + repo := data.NewOrderRepo(db) + historyRepo := data.NewHistoryOrderRepo(db) + + orderBiz := biz.NewOrderBiz(repo, historyRepo, biz.NewExportOpts(query, limit, path)) + + cmd.Println("开始导出文件...") + cobra.CheckErr(orderBiz.Export(begin, end)) + + cmd.Println("导出文件完成") + for _, name := range orderBiz.FileNames() { + cmd.Println(name) + } + +} diff --git a/cmd/cmd/root.go b/cmd/cmd/root.go new file mode 100644 index 0000000..7afec75 --- /dev/null +++ b/cmd/cmd/root.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "os" +) + +var rootCmd = &cobra.Command{ + Use: "export", + Short: "导出直充系统订单数据", + SilenceUsage: true, + SilenceErrors: true, +} + +func Execute() { + path, _ := os.Getwd() + + rootCmd.PersistentFlags().StringP("path", "p", path, "文件路径") + rootCmd.PersistentFlags().IntP("query", "q", 10000, "单次查询数") + rootCmd.PersistentFlags().IntP("limit", "l", 1000000, "单个文档最大记录数") + + OrderCmd.Flags().StringP("begin", "b", "", "开始时间,如:2006-01-02 15:04:05") + OrderCmd.Flags().StringP("end", "e", "", "结束时间,如:2006-01-02 15:04:05") + + rootCmd.AddCommand(OrderCmd) + cobra.CheckErr(rootCmd.Execute()) + +} diff --git a/cmd/cmd/uitls.go b/cmd/cmd/uitls.go new file mode 100644 index 0000000..db1c44e --- /dev/null +++ b/cmd/cmd/uitls.go @@ -0,0 +1,49 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "os" + "time" +) + +func MustFlagsDateTime(cmd *cobra.Command, key string) time.Time { + t, err := ParseFlagsDateTime(cmd.Flags(), key) + cobra.CheckErr(err) + return *t +} + +func ParseFlagsDateTime(set *flag.FlagSet, key string) (*time.Time, error) { + val, err := set.GetString(key) + + if err != nil { + return nil, fmt.Errorf("获取参数异常:%w", err) + } + beginTime, err := time.Parse("2006-01-02 15:04:05", val) + if err != nil { + return nil, fmt.Errorf("不是有效的时间格式:%w", err) + } + return &beginTime, nil +} + +func CmdOutput(cmd *cobra.Command, format string, opts ...interface{}) { + fmt.Fprintf(cmd.OutOrStdout(), format, opts...) +} + +func CmdError(cmd *cobra.Command, format string, opts ...interface{}) { + fmt.Fprintf(cmd.OutOrStderr(), format, opts...) + os.Exit(1) +} + +func GetGlobalFlags(cmd *cobra.Command) (int, int, string) { + path, err := cmd.Flags().GetString("path") + cobra.CheckErr(err) + + query, err := cmd.Flags().GetInt("query") + cobra.CheckErr(err) + + limit, err := cmd.Flags().GetInt("limit") + cobra.CheckErr(err) + return query, limit, path +} diff --git a/cmd/main.go b/cmd/main.go index c9b0d72..a80b1a0 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,7 +1,9 @@ package main -func main() { +import "excel_export/cmd/cmd" +func main() { + cmd.Execute() } //分块获取数据 diff --git a/data/batch.go b/data/batch.go new file mode 100644 index 0000000..effabcc --- /dev/null +++ b/data/batch.go @@ -0,0 +1,17 @@ +package data + +type Batch struct { + BatchId string `gorm:"primaryKey;column:batch_id"` + Customer string + Price float32 + DingTalkSn string + Remark string + Success int + Fail int + ResellerId int + Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"` +} + +func (b Batch) TableName() string { + return "batch_direct" +} diff --git a/data/card.go b/data/card.go index e7ed8f2..2a72c33 100644 --- a/data/card.go +++ b/data/card.go @@ -1,24 +1,63 @@ package data -import "time" +import ( + "context" + "gorm.io/gorm" + "time" +) type Card struct { - OrderNumber string - ResellerId int - ResellerOrderNumber string - OursProductId int - Price float32 - Quantity int - Amount float32 - PayStatus int - Status int - Profit float32 - NotifyUrl string - NotifyTime time.Time - CreateIp int - CreateTime time.Time - CardCode string - FinishTime time.Time - Message string - Mobile string + OrderNumber string `gorm:"primaryKey;column:order_number"` + ResellerId int `gorm:"column:reseller_id"` + ResellerOrderNumber string `gorm:"column:reseller_order_number"` + OursProductId int `gorm:"column:ours_product_id"` + Price float32 `gorm:"column:price"` + Quantity int `gorm:"column:quantity"` + Amount float32 `gorm:"column:amount"` + PayStatus int `gorm:"column:pay_status"` + Status int `gorm:"column:status"` + Profit float32 `gorm:"column:profit"` + NotifyTime int64 `gorm:"column:notify_time"` + CreateIp int64 `gorm:"column:create_ip"` + CreateTime int64 `gorm:"column:create_time"` + CardCode string `gorm:"column:card_code"` + FinishTime time.Time `gorm:"column:finish_time"` + Message string `gorm:"column:message"` + Mobile string `gorm:"column:mobile"` + OurProduct OurProduct `gorm:"foreignkey:id;references:ours_product_id"` + Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"` +} + +func (o Card) TableName() string { + return "order_card" +} + +type CardRepo struct { + db *gorm.DB +} + +func NewCardRepo(db *gorm.DB) *CardRepo { + return &CardRepo{ + db: db, + } +} + +func (repo CardRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]Card, error) { + var orders []Card + db := repo.db.WithContext(ctx). + Preload("OurProduct"). + Preload("Reseller"). + Where("create_time BETWEEN ? AND ?", begin.Unix(), end.Unix()) + if last != "" { + db.Where("order_number > ?", last) + } + result := db.Order("create_time,order_number"). + Limit(limit). + Find(&orders) + + if result.Error != nil { + return nil, result.Error + } + + return orders, nil } diff --git a/data/card_test.go b/data/card_test.go new file mode 100644 index 0000000..8bb2be2 --- /dev/null +++ b/data/card_test.go @@ -0,0 +1,24 @@ +package data + +import ( + "context" + "fmt" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func cardRepo() *CardRepo { + db := Conn() + return NewCardRepo(db) +} + +func TestCardRepo_List(t *testing.T) { + repo := cardRepo() + begin := time.Date(2018, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2023, 12, 1, 0, 0, 0, 0, time.Local) + cards, err := repo.List(context.Background(), begin, end, 10, "123") + assert.Nil(t, err) + fmt.Printf("%+v\n", cards) + +} diff --git a/data/common.go b/data/common.go new file mode 100644 index 0000000..642b1cd --- /dev/null +++ b/data/common.go @@ -0,0 +1,40 @@ +package data + +type OurProduct struct { + Id int64 `gorm:"column:id"` + Name string `gorm:"column:name"` +} + +func (o OurProduct) TableName() string { + return "ours_product" +} + +type Platform struct { + Id int64 + Name string +} + +func (p Platform) TableName() string { + return "platform" +} + +type PlatformProduct struct { + Id int64 + PlatformId int64 + Name string + Code string + Platform Platform `gorm:"foreignkey:id;references:platform_id"` +} + +func (p PlatformProduct) TableName() string { + return "platform_product" +} + +type Reseller struct { + Id int64 `gorm:"primaryKey;column:id"` + Name string +} + +func (o Reseller) TableName() string { + return "reseller" +} diff --git a/data/conn.go b/data/conn.go index 574568f..5d21486 100644 --- a/data/conn.go +++ b/data/conn.go @@ -10,5 +10,5 @@ func Conn() *gorm.DB { if err != nil { panic("数据库连接失败") } - return conn + return conn //.Debug() } diff --git a/data/direct.go b/data/direct.go index 95415c6..6033c55 100644 --- a/data/direct.go +++ b/data/direct.go @@ -1,15 +1,10 @@ package data -import "time" - -type PlatformProduct struct { - Id int64 - Name string -} - -func (p PlatformProduct) TableName() string { - return "platform_product" -} +import ( + "context" + "gorm.io/gorm" + "time" +) type Direct struct { SerialNumber string `gorm:"primaryKey;column:serial_number"` @@ -26,10 +21,67 @@ type Direct struct { Version int `gorm:"column:version"` Type int `gorm:"column:type"` Position int `gorm:"column:position"` + Order Order `gorm:"foreignkey:order_number;references:order_order_number"` OrderItem OrderItem `gorm:"foreignkey:order_order_number;references:order_order_number"` PlatformProduct PlatformProduct `gorm:"foreignkey:id;references:platform_product_id"` + Batch Batch `gorm:"foreignkey:batch_id;references:order_order_number"` } func (d Direct) TableName() string { return "order_direct" } + +type DirectRepo struct { + db *gorm.DB +} + +func NewDirectRepo(db *gorm.DB) *DirectRepo { + return &DirectRepo{ + db: db, + } +} + +func (repo DirectRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]Direct, error) { + var directs []Direct + db := repo.db.WithContext(ctx). + Preload("Order.Remark"). + Preload("Order.Reseller"). + Preload("OrderItem"). + Preload("PlatformProduct"). + Preload("PlatformProduct.Platform"). + Where("create_time BETWEEN ? AND ?", begin, end) + if last != "" { + db.Where("serial_number > ?", last) + } + result := db.Order("create_time,serial_number"). + Limit(limit). + Find(&directs) + + if result.Error != nil { + return nil, result.Error + } + + return directs, nil +} + +func (repo DirectRepo) BatchList(ctx context.Context, begin, end time.Time, limit int, last string) ([]Direct, error) { + var directs []Direct + db := repo.db.WithContext(ctx). + InnerJoins("Batch"). + Preload("Batch.Reseller"). + Preload("PlatformProduct"). + Preload("PlatformProduct.Platform"). + Where("order_direct.create_time BETWEEN ? AND ?", begin, end) + if last != "" { + db.Where("order_direct.serial_number > ?", last) + } + result := db.Order("order_direct.create_time,order_direct.serial_number"). + Limit(limit). + Find(&directs) + + if result.Error != nil { + return nil, result.Error + } + + return directs, nil +} diff --git a/data/direct_test.go b/data/direct_test.go new file mode 100644 index 0000000..00f3626 --- /dev/null +++ b/data/direct_test.go @@ -0,0 +1,33 @@ +package data + +import ( + "context" + "fmt" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func directRepo() *DirectRepo { + db := Conn() + return NewDirectRepo(db) +} + +func TestDirectRepo_List(t *testing.T) { + repo := directRepo() + begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) + directs, err := repo.List(context.Background(), begin, end, 10, "123") + assert.Nil(t, err) + fmt.Printf("%+v\n", directs) + +} + +func TestDirectRepo_BatchList(t *testing.T) { + repo := directRepo() + begin := time.Date(2022, 10, 1, 0, 0, 0, 0, time.Local) + end := time.Date(2022, 12, 1, 0, 0, 0, 0, time.Local) + directs, err := repo.BatchList(context.Background(), begin, end, 10, "123") + assert.Nil(t, err) + fmt.Printf("%+v\n", directs) +} diff --git a/data/history_direct.go b/data/history_direct.go new file mode 100644 index 0000000..9a83e1e --- /dev/null +++ b/data/history_direct.go @@ -0,0 +1,87 @@ +package data + +import ( + "context" + "gorm.io/gorm" + "time" +) + +type HistoryDirect struct { + SerialNumber string `gorm:"primaryKey;column:serial_number"` + OrderOrderNumber string `gorm:"column:order_order_number"` + TerminalAccount string `gorm:"column:terminal_account"` + OursProductId int `gorm:"column:ours_product_id"` + Status int `gorm:"column:status"` + TradePrice float32 `gorm:"column:trade_price"` + PlatformProductId int `gorm:"column:platform_product_id"` + PlatformPrice float32 `gorm:"column:platform_price"` + CreateTime time.Time `gorm:"column:create_time"` + ExecuteTime time.Time `gorm:"column:execute_time"` + Identifier int `gorm:"column:identifier"` + Version int `gorm:"column:version"` + Type int `gorm:"column:type"` + Position int `gorm:"column:position"` + Order HistoryOrder `gorm:"foreignkey:order_number;references:order_order_number"` + OrderItem HistoryOrderItem `gorm:"foreignkey:order_order_number;references:order_order_number"` + PlatformProduct PlatformProduct `gorm:"foreignkey:id;references:platform_product_id"` + Batch Batch `gorm:"foreignkey:batch_id;references:order_order_number"` +} + +func (d HistoryDirect) TableName() string { + return "history_order_direct" +} + +type HistoryDirectRepo struct { + db *gorm.DB +} + +func NewHistoryDirectRepo(db *gorm.DB) *HistoryDirectRepo { + return &HistoryDirectRepo{ + db: db, + } +} + +func (repo HistoryDirectRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]HistoryDirect, error) { + var directs []HistoryDirect + db := repo.db.WithContext(ctx). + Preload("Order.Remark"). + Preload("Order.Reseller"). + Preload("OrderItem"). + Preload("PlatformProduct"). + Preload("PlatformProduct.Platform"). + Where("create_time BETWEEN ? AND ?", begin, end) + if last != "" { + db.Where("serial_number > ?", last) + } + result := db.Order("create_time,serial_number"). + Limit(limit). + Find(&directs) + + if result.Error != nil { + return nil, result.Error + } + + return directs, nil +} + +func (repo HistoryDirectRepo) BatchList(ctx context.Context, begin, end time.Time, limit int, last string) ([]HistoryDirect, error) { + var directs []HistoryDirect + db := repo.db.WithContext(ctx). + InnerJoins("Batch"). + Preload("Batch.Reseller"). + Preload("PlatformProduct"). + Preload("PlatformProduct.Platform"). + Where("history_order_direct.create_time BETWEEN ? AND ?", begin, end) + if last != "" { + db.Where("history_order_direct.serial_number > ?", last) + } + result := db.Order("history_order_direct.create_time,history_order_direct.serial_number"). + Limit(limit). + Find(&directs) + + if result.Error != nil { + return nil, result.Error + } + + return directs, nil +} diff --git a/data/history_order.go b/data/history_order.go new file mode 100644 index 0000000..7180462 --- /dev/null +++ b/data/history_order.go @@ -0,0 +1,77 @@ +package data + +import ( + "context" + "gorm.io/gorm" + "time" +) + +type HistoryOrderItem struct { + OrderNumber string `gorm:"primaryKey;column:order_order_number"` + OursProductId int + OursProductTitle string +} + +func (o HistoryOrderItem) TableName() string { + return "history_order_item" +} + +type HistoryOrderRemark struct { + OrderNumber string `gorm:"primaryKey;column:order_number"` + Remark string +} + +func (o HistoryOrderRemark) TableName() string { + return "history_order_remark" +} + +type HistoryOrder struct { + OrderNumber string `gorm:"primaryKey;column:order_number"` + ResellerId int64 + ResellerOrderNumber string + Amount float32 + Account string + Quantity int + Status int + PayStatus int + CreateTime time.Time + FinishTime time.Time + Item HistoryOrderItem `gorm:"foreignkey:order_order_number;references:order_number"` + Remark HistoryOrderRemark `gorm:"foreignkey:order_number;references:order_number"` + Reseller Reseller `gorm:"foreignkey:id;references:reseller_id"` +} + +func (o HistoryOrder) TableName() string { + return "history_order" +} + +type HistoryOrderRepo struct { + db *gorm.DB +} + +func NewHistoryOrderRepo(db *gorm.DB) *HistoryOrderRepo { + return &HistoryOrderRepo{ + db: db, + } +} + +func (repo HistoryOrderRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]HistoryOrder, error) { + var orders []HistoryOrder + db := repo.db.WithContext(ctx). + Preload("Reseller"). + Preload("Item"). + Preload("Remark"). + Where("create_time BETWEEN ? AND ?", begin, end) + if last != "" { + db.Where("order_number > ?", last) + } + result := db.Order("create_time,order_number"). + Limit(limit). + Find(&orders) + + if result.Error != nil { + return nil, result.Error + } + + return orders, nil +} diff --git a/data/order.go b/data/order.go index 8e1d8ba..38f7a33 100644 --- a/data/order.go +++ b/data/order.go @@ -6,15 +6,6 @@ import ( "time" ) -type Reseller struct { - Id int64 `gorm:"primaryKey;column:id"` - Name string -} - -func (o Reseller) TableName() string { - return "reseller" -} - type OrderItem struct { OrderNumber string `gorm:"primaryKey;column:order_order_number"` OursProductId int @@ -66,7 +57,7 @@ func NewOrderRepo(db *gorm.DB) *OrderRepo { func (repo OrderRepo) List(ctx context.Context, begin, end time.Time, limit int, last string) ([]Order, error) { var orders []Order - db := repo.db.WithContext(ctx).Debug(). + db := repo.db.WithContext(ctx). Preload("Reseller"). Preload("Item"). Preload("Remark"). diff --git a/export/batch.go b/export/batch.go new file mode 100644 index 0000000..05759a1 --- /dev/null +++ b/export/batch.go @@ -0,0 +1,57 @@ +package export + +type Batch struct { + ResellerId int + ResellerName string + OursProductId int + OursProductTitle string + PlatformName string + PlatformProductCode string + PlatformProductName string + Status int + OrderOrderNumber string + SerialNumber string + TerminalAccount string + TradePrice float32 + PlatformPrice float32 + CreateTime string + ExecuteTime string + DingTalkSn string + Remark string +} + +type Batchs []*Batch + +func (o Batchs) Title() []string { + return []string{ + "分销商id", + "分销商名称", + "我们的商品id", + "订单商品名称", + "接口平台", + "接口平台产品编码", + "接口平台产品名称", + "充值状态", + "系统订单号", + "流水号", + "充值账号", + "成交价格", + "接口平台价格", + "创建时间", + "执行时间", + "钉钉审批序号", + "批量备注", + } +} + +func (o Batchs) Size() int { + return len(o) +} + +func (o Batchs) Data() []interface{} { + d := make([]interface{}, o.Size()) + for i, v := range o { + d[i] = v + } + return d +} diff --git a/export/card.go b/export/card.go new file mode 100644 index 0000000..cce0e95 --- /dev/null +++ b/export/card.go @@ -0,0 +1,43 @@ +package export + +type Card struct { + OrderNumber string + ResellerOrderNumber string + Amount float32 + Quantity int + Status int + ResellerId int + ResellerName string + OursProductId int + OursProductTitle string + CreateTime string +} + +type Cards []*Card + +func (o Cards) Title() []string { + return []string{ + "订单号", + "分销商订单号", + "扣款价格", + "数量", + "充值状态", + "分销商编号", + "分销商名称", + "订单商品编号", + "订单商品名称", + "创建时间", + } +} + +func (o Cards) Size() int { + return len(o) +} + +func (o Cards) Data() []interface{} { + d := make([]interface{}, o.Size()) + for i, v := range o { + d[i] = v + } + return d +} diff --git a/export/direct.go b/export/direct.go new file mode 100644 index 0000000..4b3cf88 --- /dev/null +++ b/export/direct.go @@ -0,0 +1,57 @@ +package export + +type Direct struct { + ResellerId int64 + ResellerName string + ResellerOrderNumber string + OursProductId int + OursProductTitle string + PlatformName string + PlatformProductCode string + PlatformProductName string + Status int + OrderOrderNumber string + SerialNumber string + TerminalAccount string + TradePrice float32 + PlatformPrice float32 + CreateTime string + ExecuteTime string + Remark string +} + +type Directs []*Direct + +func (o Directs) Title() []string { + return []string{ + "分销商id", + "分销商名称", + "商户订单号", + "我们的商品id", + "订单商品名称", + "接口平台", + "接口平台产品编码", + "接口平台产品名称", + "充值状态", + "系统订单号", + "流水号", + "充值账号", + "成交价格", + "接口平台价格", + "创建时间", + "执行时间", + "备注", + } +} + +func (o Directs) Size() int { + return len(o) +} + +func (o Directs) Data() []interface{} { + d := make([]interface{}, o.Size()) + for i, v := range o { + d[i] = v + } + return d +} diff --git a/export/excel.go b/export/excel.go index c8ae787..507497f 100644 --- a/export/excel.go +++ b/export/excel.go @@ -58,25 +58,29 @@ func (e *Export) slice() { } func (e *Export) reset() { - e.Save() + e.save() e.index++ e.Open() e.Title(nil) e.slice() } +func (e Export) Index() int { + return e.index +} + func (e *Export) Export(data Entity) error { if e.file == nil || e.sheet == nil { return errors.New("没有执行open方法") } - e.count = data.Size() + e.count = e.count + data.Size() for _, order := range data.Data() { e.slice() row := e.sheet.AddRow() row.WriteStruct(order, -1) } - return nil + return e.save() } func (e *Export) Open() error { @@ -124,6 +128,6 @@ func (e *Export) isFielExist(file string) (bool, error) { return false, err } -func (e *Export) Save() error { +func (e *Export) save() error { return e.file.Save(e.fileName()) } diff --git a/export/excel_test.go b/export/excel_test.go index 687d9f4..182a27e 100644 --- a/export/excel_test.go +++ b/export/excel_test.go @@ -3,6 +3,7 @@ package export import ( "excel_export/data" "fmt" + "github.com/stretchr/testify/assert" "os" "testing" ) @@ -12,7 +13,7 @@ func TestExport_Export(t *testing.T) { path := dir + "/aa_%d.xlsx" e := NewExport(path, 4) err := e.Open() - fmt.Println(err) + assert.Nil(t, err) data := NewOrder([]data.Order{ { @@ -216,11 +217,15 @@ func TestExport_Export(t *testing.T) { }) err = e.Title(data.Title()) - fmt.Println(err) + assert.Nil(t, err) err = e.Export(data) - fmt.Println(err) + assert.Nil(t, err) + + for i := 0; i <= e.Index(); i++ { + file := fmt.Sprintf(path, i) + assert.FileExists(t, file) + os.Remove(file) + } - err = e.Save() - fmt.Println(err) } diff --git a/go.mod b/go.mod index d5bdd67..a238f79 100644 --- a/go.mod +++ b/go.mod @@ -6,20 +6,29 @@ require ( github.com/tealeg/xlsx/v3 v3.2.4 // direct gorm.io/driver/mysql v1.4.5 // direct gorm.io/gorm v1.24.3 // direct + github.com/spf13/cobra v1.6.1 // direct ) +require github.com/stretchr/testify v1.8.1 + require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/frankban/quicktest v1.11.2 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/go-cmp v0.5.2 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/kr/text v0.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect + + github.com/spf13/pflag v1.0.5 // indirect golang.org/x/text v0.3.3 // indirect golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect )