From c6c500d7044c5e4785fc856a5a1253b0604a8147 Mon Sep 17 00:00:00 2001 From: zhangqian <zhangqian@123.com> Date: 星期二, 04 六月 2024 21:16:18 +0800 Subject: [PATCH] 库存报表下载 --- service/inventory_report_forms.go | 234 +++++++++++++++++++++++ controllers/report_forms_controller.go | 175 +++++------------ docs/swagger.yaml | 36 +++ docs/docs.go | 59 +++++ docs/swagger.json | 59 +++++ router/router.go | 11 6 files changed, 447 insertions(+), 127 deletions(-) diff --git a/controllers/report_forms_controller.go b/controllers/report_forms_controller.go index 7c48974..03cc2b0 100644 --- a/controllers/report_forms_controller.go +++ b/controllers/report_forms_controller.go @@ -4,10 +4,13 @@ "fmt" "github.com/gin-gonic/gin" "github.com/shopspring/decimal" + "net/url" + "os" "wms/constvar" "wms/extend/code" "wms/extend/util" "wms/models" + "wms/pkg/logx" "wms/request" "wms/response" "wms/service" @@ -28,6 +31,7 @@ // @Tags 鎶ヨ〃 // @Summary 鑾峰彇搴撳瓨鎶ヨ〃 // @Produce application/json +// @Param Authorization header string true "token" // @Param object body request.GetInventoryForms true "鏌ヨ鍙傛暟" // @Success 200 {object} util.ResponseList{data=[]response.InventoryForms} "鎴愬姛" // @Router /api-wms/v1/forms/getInventoryForms [post] @@ -38,137 +42,64 @@ util.ResponseFormat(c, code.RequestParamError, "鍙傛暟瑙f瀽澶辫触锛屾暟鎹被鍨嬮敊璇�") return } - locationIds := make([]int, 0) - productIds := make([]string, 0) - productAmounts := make([]*models.LocationProductAmount, 0) - if params.WarehouseCode != "" { - locations, err := models.NewLocationSearch().SetJointName(params.WarehouseCode).FindNotTotal() - if err != nil { - util.ResponseFormat(c, code.RequestParamError, "鏌ヨ浠撳簱浣嶇疆澶辫触") - return - } - - for _, location := range locations { - locationIds = append(locationIds, location.Id) - } - productAmounts, err = models.NewLocationProductAmountSearch().SetLocationIds(locationIds).SetQuery("amount > 0").Find() - if err != nil { - util.ResponseFormat(c, code.RequestParamError, "鏌ヨ鍦ㄥ簱鏁伴噺澶辫触") - return - } - for _, amount := range productAmounts { - productIds = append(productIds, amount.ProductId) - } - - } - //鏌ヨ浜у搧 - search := models.NewMaterialSearch() - search.Orm = search.Orm.Model(&models.Material{}). - Select(`material.id, material.name, material.cost, material.amount, material.unit, wms_product_category.name as category_name `). - Joins("left join wms_product_category on material.category_id = wms_product_category.id") - if len(params.CategoryIds) > 0 { - search.Orm.Where("material.category_id in (?)", params.CategoryIds) - } - if params.KeyWord != "" { - search.Orm.Where("material.name like ?", "%"+params.KeyWord+"%").Or("wms_product_category.name like ?", "%"+params.KeyWord+"%") - } - if len(productIds) > 0 { - search.Orm.Where("material.id in (?)", productIds) - } - var ( - materials = make([]*models.Material, 0) - total int64 - ) - if err := search.Orm.Count(&total).Error; err != nil { - util.ResponseFormat(c, code.RequestParamError, "鏌ヨtotal澶辫触") - return - } - if params.Page*params.PageSize > 0 { - search.Orm = search.Orm.Offset((params.Page - 1) * params.PageSize).Limit(params.PageSize) - } - if err := search.Orm.Find(&materials).Error; err != nil { - util.ResponseFormat(c, code.RequestParamError, fmt.Errorf("鏌ヨ浜у搧澶辫触: %v", err)) - return - } - - //鏌ヨ鍦ㄥ簱鏁伴噺 - if len(productIds) == 0 { - for _, material := range materials { - productIds = append(productIds, material.ID) - } - productAmounts, err = models.NewLocationProductAmountSearch().SetProductIds(productIds).SetLocationIds(locationIds).Find() - if err != nil { - util.ResponseFormat(c, code.RequestParamError, "鏌ヨ鍦ㄥ簱鏁伴噺澶辫触") - return - } - } - - //鏌ヨ鍑哄叆搴撳氨缁暟閲� - var inHouse []Detail - var outHouse []Detail - dbIn := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}). - Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.status as status"). - Joins("left join wms_operation ON wms_operation_details.operation_id=wms_operation.id"). - Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeIncoming, constvar.BaseOperationTypeInternal}). - Where("wms_operation.status in (?)", []constvar.OperationStatus{constvar.OperationStatus_Finish}) - dbOut := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}). - Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.status as status"). - Joins("left join wms_operation ON wms_operation_details.operation_id=wms_operation.id"). - Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}). - Where("wms_operation.status in (?)", []constvar.OperationStatus{constvar.OperationStatus_Ready, constvar.OperationStatus_Finish}) - if len(locationIds) > 0 { - dbIn.Where("wms_operation_details.to_location_id in (?)", locationIds) - dbOut.Where("wms_operation_details.from_location_id in (?)", locationIds) - } - if len(productIds) > 0 { - dbIn.Where("wms_operation_details.product_id in (?)", productIds) - dbOut.Where("wms_operation_details.product_id in (?)", productIds) - } - err = dbIn.Find(&inHouse).Error + inventoryReportFormsService := service.NewInventoryReportFormsService() + total, err := inventoryReportFormsService.Count(params) if err != nil { - util.ResponseFormat(c, code.RequestParamError, "鏌ヨ鍏ュ簱鏁伴噺澶辫触") + logx.Errorf("GetInventoryForms count err:%v", err) + util.ResponseFormat(c, code.InternalError, "鏌ヨ鎬绘暟澶辫触") return } - err = dbOut.Find(&outHouse).Error + result, err := inventoryReportFormsService.Query(params) if err != nil { - util.ResponseFormat(c, code.RequestParamError, "鏌ヨ鍑哄簱鏁伴噺澶辫触") + logx.Errorf("GetInventoryForms query err:%v", err) + util.ResponseFormat(c, code.InternalError, "鏌ヨ澶辫触") return } - var result []response.InventoryForms - for _, material := range materials { - var resp response.InventoryForms - resp.ProduceId = material.ID - resp.ProductName = material.Name - resp.Cost = material.Cost - resp.Unit = material.Unit - resp.Value = material.Amount.Mul(material.Cost) - resp.ProductType = material.CategoryName - for _, amount := range productAmounts { - if material.ID == amount.ProductId { - resp.Amount = resp.Amount.Add(amount.Amount) - } - } - for _, details := range inHouse { - if material.ID == details.ProductId { - resp.In = resp.In.Add(details.Amount) - } - } - available := decimal.NewFromInt(0) - for _, details := range outHouse { - if material.ID == details.ProductId { - if details.Status == constvar.OperationStatus_Ready { - available = available.Add(details.Amount) - } else { - resp.Out = resp.Out.Add(details.Amount) - } - } - } - resp.AvailableNumber = resp.Amount.Sub(available) - result = append(result, resp) - } + util.ResponseFormatList(c, code.Success, result, int(total)) } +// DownloadInventoryForms +// @Tags 鎶ヨ〃 +// @Summary 涓嬭浇搴撳瓨鎶ヨ〃 +// @Produce application/json +// @Param Authorization header string true "token" +// @Param object body request.GetInventoryForms true "鏌ヨ鍙傛暟" +// @Success 200 {object} util.ResponseList{data=[]response.InventoryForms} "鎴愬姛" +// @Router /api-wms/v1/forms/downloadInventoryForms [post] +func (slf ReportFormsController) DownloadInventoryForms(c *gin.Context) { + var params request.GetInventoryForms + err := c.BindJSON(¶ms) + if err != nil { + util.ResponseFormat(c, code.RequestParamError, "鍙傛暟瑙f瀽澶辫触锛屾暟鎹被鍨嬮敊璇�") + return + } + inventoryReportFormsService := service.NewInventoryReportFormsService() + list, err := inventoryReportFormsService.FetchAll(params) + if err != nil { + logx.Errorf("DownloadInventoryForms FetchAll err:%v", err) + util.ResponseFormat(c, code.InternalError, "鏌ヨ澶辫触") + return + } + filename, err := inventoryReportFormsService.Export(list) + if err != nil { + logx.Errorf("DownloadInventoryForms Export err:%v", err) + util.ResponseFormat(c, code.InternalError, "瀵煎嚭鏁版嵁鍒版枃浠跺け璐�") + return + } + + if err != nil { + util.ResponseFormat(c, code.RequestParamError, "瀵煎嚭澶辫触") + return + } + + fileContentDisposition := "attachment;filename=\"" + url.QueryEscape(filename) + "\"" + c.Header("Content-Type", "application/xlsx") + c.Header("Content-Disposition", fileContentDisposition) + c.File(filename) + defer os.Remove(filename) +} + // GetHistory // @Tags 鎶ヨ〃 // @Summary 鑾峰彇鍘嗗彶淇℃伅 diff --git a/docs/docs.go b/docs/docs.go index 16ef563..6a0b008 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -468,6 +468,58 @@ } } }, + "/api-wms/v1/forms/downloadInventoryForms": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "鎶ヨ〃" + ], + "summary": "涓嬭浇搴撳瓨鎶ヨ〃", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Authorization", + "in": "header", + "required": true + }, + { + "description": "鏌ヨ鍙傛暟", + "name": "object", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetInventoryForms" + } + } + ], + "responses": { + "200": { + "description": "鎴愬姛", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseList" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/response.InventoryForms" + } + } + } + } + ] + } + } + } + } + }, "/api-wms/v1/forms/getHistory": { "post": { "produces": [ @@ -524,6 +576,13 @@ "summary": "鑾峰彇搴撳瓨鎶ヨ〃", "parameters": [ { + "type": "string", + "description": "token", + "name": "Authorization", + "in": "header", + "required": true + }, + { "description": "鏌ヨ鍙傛暟", "name": "object", "in": "body", diff --git a/docs/swagger.json b/docs/swagger.json index bfed35b..2fe0e55 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -456,6 +456,58 @@ } } }, + "/api-wms/v1/forms/downloadInventoryForms": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "鎶ヨ〃" + ], + "summary": "涓嬭浇搴撳瓨鎶ヨ〃", + "parameters": [ + { + "type": "string", + "description": "token", + "name": "Authorization", + "in": "header", + "required": true + }, + { + "description": "鏌ヨ鍙傛暟", + "name": "object", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetInventoryForms" + } + } + ], + "responses": { + "200": { + "description": "鎴愬姛", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/util.ResponseList" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/response.InventoryForms" + } + } + } + } + ] + } + } + } + } + }, "/api-wms/v1/forms/getHistory": { "post": { "produces": [ @@ -512,6 +564,13 @@ "summary": "鑾峰彇搴撳瓨鎶ヨ〃", "parameters": [ { + "type": "string", + "description": "token", + "name": "Authorization", + "in": "header", + "required": true + }, + { "description": "鏌ヨ鍙傛暟", "name": "object", "in": "body", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4d081f3..f8b7f54 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2220,6 +2220,37 @@ summary: 鎵嬪姩璺戞湀搴︾粺璁″簱瀛樻姤琛� tags: - 鎶ヨ〃 + /api-wms/v1/forms/downloadInventoryForms: + post: + parameters: + - description: token + in: header + name: Authorization + required: true + type: string + - description: 鏌ヨ鍙傛暟 + in: body + name: object + required: true + schema: + $ref: '#/definitions/request.GetInventoryForms' + produces: + - application/json + responses: + "200": + description: 鎴愬姛 + schema: + allOf: + - $ref: '#/definitions/util.ResponseList' + - properties: + data: + items: + $ref: '#/definitions/response.InventoryForms' + type: array + type: object + summary: 涓嬭浇搴撳瓨鎶ヨ〃 + tags: + - 鎶ヨ〃 /api-wms/v1/forms/getHistory: post: parameters: @@ -2249,6 +2280,11 @@ /api-wms/v1/forms/getInventoryForms: post: parameters: + - description: token + in: header + name: Authorization + required: true + type: string - description: 鏌ヨ鍙傛暟 in: body name: object diff --git a/router/router.go b/router/router.go index 4ed0a82..83c7b8f 100644 --- a/router/router.go +++ b/router/router.go @@ -153,11 +153,12 @@ reportFormsController := new(controllers.ReportFormsController) reportFormsAPI := r.Group(urlPrefix + "/forms") { - reportFormsAPI.POST("getInventoryForms", reportFormsController.GetInventoryForms) //鑾峰彇搴撳瓨鎶ヨ〃 - reportFormsAPI.POST("getHistory", reportFormsController.GetHistory) //鑾峰彇搴撳瓨鍘嗗彶 - reportFormsAPI.POST("getLocationForms", reportFormsController.GetLocationForms) //鑾峰彇浣嶇疆鎶ヨ〃 - reportFormsAPI.POST("monthStats", reportFormsController.MonthStats) //鑾峰彇鏈堝害缁熻鎶ヨ〃 - reportFormsAPI.POST("doMonthStats", reportFormsController.DoMonthStats) //鑾峰彇鏈堝害缁熻鎶ヨ〃 + reportFormsAPI.POST("getInventoryForms", reportFormsController.GetInventoryForms) //鑾峰彇搴撳瓨鎶ヨ〃 + reportFormsAPI.POST("downloadInventoryForms", reportFormsController.DownloadInventoryForms) //涓嬭浇搴撳瓨鎶ヨ〃 + reportFormsAPI.POST("getHistory", reportFormsController.GetHistory) //鑾峰彇搴撳瓨鍘嗗彶 + reportFormsAPI.POST("getLocationForms", reportFormsController.GetLocationForms) //鑾峰彇浣嶇疆鎶ヨ〃 + reportFormsAPI.POST("monthStats", reportFormsController.MonthStats) //鑾峰彇鏈堝害缁熻鎶ヨ〃 + reportFormsAPI.POST("doMonthStats", reportFormsController.DoMonthStats) //鑾峰彇鏈堝害缁熻鎶ヨ〃 } //閲嶈璐ц鍒� diff --git a/service/inventory_report_forms.go b/service/inventory_report_forms.go new file mode 100644 index 0000000..82a5d2e --- /dev/null +++ b/service/inventory_report_forms.go @@ -0,0 +1,234 @@ +package service + +import ( + "fmt" + "github.com/shopspring/decimal" + "github.com/xuri/excelize/v2" + "strconv" + "time" + "wms/constvar" + "wms/models" + "wms/request" + "wms/response" +) + +type Detail struct { + ProductId string `json:"productId"` + Amount decimal.Decimal `json:"amount"` + Status constvar.OperationStatus `json:"status"` + //ProductName string `json:"productName"` +} + +type InventoryReportFormsService struct{} + +func NewInventoryReportFormsService() *InventoryReportFormsService { + return &InventoryReportFormsService{} +} + +func (slf *InventoryReportFormsService) Query(params request.GetInventoryForms) (result []*response.InventoryForms, err error) { + var ( + materials = make([]*models.Material, 0) + ) + search, productIds, productAmounts, locationIds, err := slf.BuildSearch(params) + if err != nil { + return nil, err + } + + if params.Page*params.PageSize > 0 { + search.Orm = search.Orm.Offset((params.Page - 1) * params.PageSize).Limit(params.PageSize) + } + if err := search.Orm.Find(&materials).Error; err != nil { + return nil, err + } + //鏌ヨ鍦ㄥ簱鏁伴噺 + if len(productIds) == 0 { + for _, material := range materials { + productIds = append(productIds, material.ID) + } + productAmounts, err = models.NewLocationProductAmountSearch().SetProductIds(productIds).SetLocationIds(locationIds).Find() + if err != nil { + return nil, err + } + } + + //鏌ヨ鍑哄叆搴撳氨缁暟閲� + var inHouse []Detail + var outHouse []Detail + dbIn := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}). + Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.status as status"). + Joins("left join wms_operation ON wms_operation_details.operation_id=wms_operation.id"). + Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeIncoming, constvar.BaseOperationTypeInternal}). + Where("wms_operation.status in (?)", []constvar.OperationStatus{constvar.OperationStatus_Finish}) + dbOut := models.NewOperationDetailsSearch().Orm.Model(&models.OperationDetails{}). + Select("wms_operation_details.product_id,wms_operation_details.amount,wms_operation.status as status"). + Joins("left join wms_operation ON wms_operation_details.operation_id=wms_operation.id"). + Where("wms_operation.base_operation_type in (?)", []constvar.BaseOperationType{constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeInternal, constvar.BaseOperationTypeDisuse}). + Where("wms_operation.status in (?)", []constvar.OperationStatus{constvar.OperationStatus_Ready, constvar.OperationStatus_Finish}) + if len(locationIds) > 0 { + dbIn.Where("wms_operation_details.to_location_id in (?)", locationIds) + dbOut.Where("wms_operation_details.from_location_id in (?)", locationIds) + } + if len(productIds) > 0 { + dbIn.Where("wms_operation_details.product_id in (?)", productIds) + dbOut.Where("wms_operation_details.product_id in (?)", productIds) + } + err = dbIn.Find(&inHouse).Error + if err != nil { + return + } + err = dbOut.Find(&outHouse).Error + if err != nil { + return + } + for _, material := range materials { + data := new(response.InventoryForms) + data.ProduceId = material.ID + data.ProductName = material.Name + data.Cost = material.Cost + data.Unit = material.Unit + data.Value = material.Amount.Mul(material.Cost) + data.ProductType = material.CategoryName + for _, amount := range productAmounts { + if material.ID == amount.ProductId { + data.Amount = data.Amount.Add(amount.Amount) + } + } + for _, details := range inHouse { + if material.ID == details.ProductId { + data.In = data.In.Add(details.Amount) + } + } + available := decimal.NewFromInt(0) + for _, details := range outHouse { + if material.ID == details.ProductId { + if details.Status == constvar.OperationStatus_Ready { + available = available.Add(details.Amount) + } else { + data.Out = data.Out.Add(details.Amount) + } + } + } + data.AvailableNumber = data.Amount.Sub(available) + result = append(result, data) + } + return +} + +func (slf *InventoryReportFormsService) BuildSearch(params request.GetInventoryForms) ( + search *models.MaterialSearch, + productIds []string, + productAmounts []*models.LocationProductAmount, + locationIds []int, + err error) { + productAmounts = make([]*models.LocationProductAmount, 0) + if params.WarehouseCode != "" { + locations, err := models.NewLocationSearch().SetJointName(params.WarehouseCode).FindNotTotal() + if err != nil { + return nil, nil, nil, nil, err + } + + for _, location := range locations { + locationIds = append(locationIds, location.Id) + } + productAmounts, err = models.NewLocationProductAmountSearch().SetLocationIds(locationIds).SetQuery("amount > 0").Find() + if err != nil { + return nil, nil, nil, nil, err + } + for _, amount := range productAmounts { + productIds = append(productIds, amount.ProductId) + } + } + + //鏌ヨ浜у搧 + search = models.NewMaterialSearch() + search.Orm = search.Orm.Model(&models.Material{}). + Select(`material.id, material.name, material.cost, material.amount, material.unit, wms_product_category.name as category_name `). + Joins("left join wms_product_category on material.category_id = wms_product_category.id") + if len(params.CategoryIds) > 0 { + search.Orm.Where("material.category_id in (?)", params.CategoryIds) + } + if params.KeyWord != "" { + search.Orm.Where("material.name like ?", "%"+params.KeyWord+"%").Or("wms_product_category.name like ?", "%"+params.KeyWord+"%") + } + if len(productIds) > 0 { + search.Orm.Where("material.id in (?)", productIds) + } + + return search, productIds, productAmounts, locationIds, nil +} + +func (slf *InventoryReportFormsService) Count(params request.GetInventoryForms) (total int64, err error) { + search, _, _, _, err := slf.BuildSearch(params) + if err != nil { + return 0, err + } + if err := search.Orm.Count(&total).Error; err != nil { + return 0, err + } + return total, nil +} + +func (slf *InventoryReportFormsService) FetchAll(params request.GetInventoryForms) (list []*response.InventoryForms, err error) { + total, err := slf.Count(params) + if err != nil { + return nil, err + } + list = make([]*response.InventoryForms, 0, total) + params.PageSize = 1000 + page := 1 + for { + params.Page = page + data, err := slf.Query(params) + if err != nil { + return nil, err + } + if len(data) == 0 { + break + } + list = append(list, data...) + page++ + } + return +} + +func (slf *InventoryReportFormsService) Export(dataList []*response.InventoryForms) (filename string, err error) { + var fileName string + f := excelize.NewFile() + + // 鑷畾涔夎〃澶� + headers := []string{"浜у搧", "浜у搧绫诲埆", "鍗曚綅鎴愭湰", "鎬讳环鍊�", "鍦ㄥ簱", "鍙敤搴撳瓨", "鍏ュ簱", "鍑哄簱", "鍗曚綅"} + + // 璁剧疆琛ㄥご + for i, header := range headers { + cell := getColumnAlphabet(i+1) + "1" + f.SetCellValue("Sheet1", cell, header) + } + + for i, v := range dataList { + f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), v.ProductName) + f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), v.ProductType) + f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), v.Cost) + f.SetCellValue("Sheet1", "D"+strconv.Itoa(i+2), v.Value) + f.SetCellValue("Sheet1", "E"+strconv.Itoa(i+2), v.Amount) + f.SetCellValue("Sheet1", "F"+strconv.Itoa(i+2), v.AvailableNumber) + f.SetCellValue("Sheet1", "G"+strconv.Itoa(i+2), v.In) + f.SetCellValue("Sheet1", "H"+strconv.Itoa(i+2), v.Out) + f.SetCellValue("Sheet1", "I"+strconv.Itoa(i+2), v.Unit) + } + + fileName = fmt.Sprintf("搴撳瓨鎶ヨ〃%s.xlsx", time.Now().Format("2006-01-02-1504")) + if err := f.SaveAs(fileName); err != nil { + return fileName, err + } + + return fileName, nil +} + +// 鏍规嵁绱㈠紩鑾峰彇 Excel 鍒楀悕锛圓銆丅銆丆...锛� +func getColumnAlphabet(index int) string { + const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + if index <= 26 { + return string(alphabet[index-1]) + } + return getColumnAlphabet((index-1)/26) + getColumnAlphabet((index-1)%26+1) +} -- Gitblit v1.8.0