package models import ( "errors" "fmt" "github.com/gin-gonic/gin" "github.com/xuri/excelize/v2" orm "go-admin/common/global" "go-admin/logger" "go-admin/tools" "go-admin/tools/config" "strconv" "time" ) // InventoryReportByProductReq 产品库存汇总(按门店)入参 type InventoryReportByProductReq struct { StoreId []uint32 `json:"store_id"` // 门店id CommoditySerialNumber []string `json:"commodity_serial_number"` // 商品编号 CommodityName []string `json:"commodity_name"` // 商品名称 CategoryID []uint32 `json:"category_id"` // 商品分类id IsExport uint32 `json:"is_export"` // 1-导出 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // InventoryReportByProductResp 产品库存汇总(按门店)出参 type InventoryReportByProductResp struct { Total uint32 `json:"total"` // 总条数/记录数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 TotalEffectiveCount uint32 `json:"total_effective_count"` // 有效库存数 TotalTransferCount uint32 `json:"total_transfer_count"` // 调入中数量 TotalCount uint32 `json:"total_count"` // 总数量 TotalEffectiveAmount float64 `json:"total_effective_amount"` // 有效库存金额 TotalTransferAmount float64 `json:"total_transfer_amount"` // 调入中金额 ExportUrl string `json:"export_url"` // 导出excel路径 List []ReportByProductData `json:"list"` // } // ReportByProductData 产品库存汇总(按门店)数据 type ReportByProductData struct { StoreId uint32 `json:"store_id"` // 门店id StoreName string `json:"store_name"` // 门店名称 CommoditySerialNumber string `json:"commodity_serial_number"` // 商品编号 CommodityId uint32 `json:"commodity_id"` // 商品id CommodityName string `json:"commodity_name"` // 商品名称 CategoryID uint32 `json:"category_id"` // 商品分类id CategoryName string `json:"category_name"` // 商品分类名称 EffectiveCount uint32 `json:"effective_count"` // 有效库存数 TransferCount uint32 `json:"transfer_count"` // 调入中数量 Count uint32 `json:"count"` // 总数量 EffectiveAmount float64 `json:"effective_amount"` // 有效库存金额 TransferAmount float64 `json:"transfer_amount"` // 调入中金额 } // InventoryReportByAllotReq 库存调拨入参 type InventoryReportByAllotReq struct { DeliverStoreId []uint32 `json:"deliver_store_id"` // 调出门店id ReceiveStoreId []uint32 `json:"receive_store_id"` // 调入门店id CommodityName []string `json:"commodity_name"` // 商品名称 CategoryID []uint32 `json:"category_id"` // 商品分类id State uint32 `json:"state"` // 调拨状态:1-调拨中 2-已完成 AuditTimeStart string `json:"audit_time_start"` // 审核/发起开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核/发起结束时间 ReceiveTimeStart string `json:"receive_time_start"` // 调入开始时间 ReceiveTimeEnd string `json:"receive_time_end"` // 调入结束时间 IsExport uint32 `json:"is_export"` // 1-导出 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // InventoryReportByAllotResp 库存调拨出参 type InventoryReportByAllotResp struct { Total int `json:"total"` // 总条数/记录数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 TotalAllotCount uint32 `json:"total_allot_count"` // 调拨数量 TotalAllotAmount float64 `json:"total_allot_amount"` // 调拨金额 ExportUrl string `json:"export_url"` // 导出excel路径 List []ReportByAllotData `json:"list"` // } // ReportByAllotData 库存调拨数据 type ReportByAllotData struct { DeliverStoreId uint32 `json:"deliver_store_id"` // 调出门店id DeliverStoreName string `json:"deliver_store_name"` // 调出门店名称 ReceiveStoreId uint32 `json:"receive_store_id"` // 调入门店id ReceiveStoreName string `json:"receive_store_name"` // 调入门店名称 CommodityId uint32 `json:"commodity_id"` // 商品id CommodityName string `json:"commodity_name"` // 商品名称 CategoryID uint32 `json:"category_id"` // 商品分类id CategoryName string `json:"category_name"` // 商品分类名称 State uint32 `json:"state"` // 调拨状态:1-调拨中 2-已完成 AllotCount uint32 `json:"allot_count"` // 调拨数量 AllotAmount float64 `json:"allot_amount"` // 调拨金额 } // InventoryReportAllotDetailReq 库存调拨明细入参 type InventoryReportAllotDetailReq struct { SerialNumber string `json:"serial_number"` // 单据编号 DeliverStoreId uint32 `json:"deliver_store_id"` // 调出门店id ReceiveStoreId uint32 `json:"receive_store_id"` // 调入门店id CommodityName []string `json:"commodity_name"` // 商品名称 CategoryID []uint32 `json:"category_id"` // 商品分类id State uint32 `json:"state"` // 调拨状态:1-调拨中 2-已完成 AuditTimeStart string `json:"audit_time_start"` // 审核/发起开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核/发起结束时间 ReceiveTimeStart string `json:"receive_time_start"` // 调入开始时间 ReceiveTimeEnd string `json:"receive_time_end"` // 调入结束时间 IsExport uint32 `json:"is_export"` // 1-导出 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // InventoryReportAllotDetailResp 库存调拨明细出参 type InventoryReportAllotDetailResp struct { Total int `json:"total"` // 总条数/记录数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 ExportUrl string `json:"export_url"` // 导出excel路径 List []ReportAllotDetailData `json:"list"` // } // ReportAllotDetailData 库存调拨明细数据 type ReportAllotDetailData struct { SerialNumber string `json:"serial_number"` // 单据编号 DeliverStoreId uint32 `json:"deliver_store_id"` // 调出门店id DeliverStoreName string `json:"deliver_store_name"` // 调出门店名称 ReceiveStoreId uint32 `json:"receive_store_id"` // 调入门店id ReceiveStoreName string `json:"receive_store_name"` // 调入门店名称 MakerTime *time.Time `json:"maker_time"` // 制单时间/发起时间 AuditTime *time.Time `json:"audit_time"` // 审核时间 State uint32 `json:"state"` // 调拨状态:1-调拨中 2-已完成 CommodityId uint32 `json:"commodity_id"` // 商品id CommodityName string `json:"commodity_name"` // 商品名称 CategoryID uint32 `json:"category_id"` // 商品分类id CategoryName string `json:"category_name"` // 商品分类名称 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei"` // 商品串码 } // InventoryReportByOtherReq 其他出入库汇总入参 type InventoryReportByOtherReq struct { StoreId []uint32 `json:"store_id"` // 门店id CommodityName []string `json:"commodity_name"` // 商品名称 CategoryID []uint32 `json:"category_id"` // 商品分类id State uint32 `json:"state"` // 调拨状态:1-产品入库 2-盘点入库 3-系统出库 4-盘点出库 StartTime string `json:"start_time"` // 开始时间/入库时间 EndTime string `json:"end_time"` // 结束时间/出库时间 IsExport uint32 `json:"is_export"` // 1-导出 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // InventoryReportByOtherResp 其他出入库汇总出参 type InventoryReportByOtherResp struct { Total int `json:"total"` // 总条数/记录数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 TotalCount int32 `json:"total_count"` // 总数量 TotalAmount float64 `json:"total_amount"` // 总金额 ExportUrl string `json:"export_url"` // 导出excel路径 List []ReportByOtherData `json:"list"` // } // ReportByOtherData 其他出入库汇总数据 type ReportByOtherData struct { StoreId uint32 `json:"store_id"` // 门店id StoreName string `json:"store_name"` // 门店名称 CommodityId uint32 `json:"commodity_id"` // 商品id CommodityName string `json:"commodity_name"` // 商品名称 CategoryID uint32 `json:"category_id"` // 商品分类id CategoryName string `json:"category_name"` // 商品分类名称 State uint32 `json:"state"` // 调拨状态:1-产品入库 2-盘点入库 3-系统出库 4-盘点出库 Count int32 `json:"count"` // 数量 Amount float64 `json:"amount"` // 金额 } // InventoryReportOtherDetailReq 其他出入库明细入参 type InventoryReportOtherDetailReq struct { SerialNumber string `json:"serial_number"` // 单据编号 StoreId []uint32 `json:"store_id"` // 门店id CommodityName []string `json:"commodity_name"` // 商品名称 CategoryID []uint32 `json:"category_id"` // 商品分类id State uint32 `json:"state"` // 调拨状态:1-产品入库 2-盘点入库 3-系统出库 4-盘点出库 StartTime string `json:"start_time"` // 开始时间/入库时间 EndTime string `json:"end_time"` // 结束时间/出库时间 IsExport uint32 `json:"is_export"` // 1-导出 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // InventoryReportOtherDetailResp 其他出入库明细出参 type InventoryReportOtherDetailResp struct { Total int `json:"total"` // 总条数/记录数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 TotalPurchasePrice float64 `json:"total_purchase_price"` // 总入库采购价 TotalEmployeePrice float64 `json:"total_employee_price"` // 总入库员工成本价 ExportUrl string `json:"export_url"` // 导出excel路径 List []ReportOtherDetailData `json:"list"` // } // ReportOtherDetailData 其他出入库明细数据 type ReportOtherDetailData struct { CommodityId uint32 `json:"commodity_id"` // 商品id CommodityName string `json:"commodity_name"` // 商品名称 CategoryID uint32 `json:"category_id"` // 商品分类id CategoryName string `json:"category_name"` // 商品分类名称 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei"` // 商品串码 StoreId uint32 `json:"store_id"` // 门店id StoreName string `json:"store_name"` // 门店名称 SupplierId uint32 `json:"supplier_id"` // 供应商id SupplierName string `json:"supplier_name"` // 供应商名称 StockTime *time.Time `json:"stock_time"` // 出入库时间 State uint32 `json:"state"` // 调拨状态:1-产品入库 2-盘点入库 3-系统出库 4-盘点出库 SerialNumber string `json:"serial_number"` // 单据编号 PurchasePrice float64 `json:"purchase_price"` // 入库采购价 EmployeePrice float64 `json:"employee_price"` // 入库员工成本价 } // ReportByProductList 产品库存汇总(按门店) func (m *InventoryReportByProductReq) ReportByProductList(c *gin.Context) (*InventoryReportByProductResp, error) { // 非管理员才判断所属门店 if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { sysUser, err := GetSysUserByCtx(c) if err != nil { return nil, errors.New("操作失败:" + err.Error()) } // 返回sysUser未过期的门店id列表 storeList := GetValidStoreIDs(sysUser.StoreData) if len(storeList) > 0 { m.StoreId = CompareLists(storeList, m.StoreId) if len(m.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店 return &InventoryReportByProductResp{}, nil } } else { return nil, errors.New("用户未绑定门店") } } resp := &InventoryReportByProductResp{ PageIndex: m.PageIndex, PageSize: m.PageSize, } page := m.PageIndex - 1 if page < 0 { page = 0 } if m.PageSize == 0 { m.PageSize = 10 } qs := orm.Eloquent.Debug().Table("erp_stock") if len(m.StoreId) > 0 { // 门店复选 var storeIDs []uint32 for _, store := range m.StoreId { storeIDs = append(storeIDs, store) } qs = qs.Where("store_id IN (?)", storeIDs) } if len(m.CategoryID) > 0 { // 商品分类id var categoryIDs []uint32 for _, category := range m.CategoryID { categoryIDs = append(categoryIDs, category) } qs = qs.Where("category_id IN (?)", categoryIDs) } if len(m.CommoditySerialNumber) > 0 { // 商品编号 var serialNumbers []string for _, serialNumber := range m.CommoditySerialNumber { serialNumbers = append(serialNumbers, serialNumber) } qs = qs.Where("commodity_serial_number IN (?)", serialNumbers) } if len(m.CommodityName) > 0 { // 商品名称 var commodityNames []string for _, commodityName := range m.CommodityName { commodityNames = append(commodityNames, commodityName) } qs = qs.Where("commodity_name IN (?)", commodityNames) } var count int64 err := qs.Count(&count).Error if err != nil { logger.Error("查询无库存列表数量失败", logger.Field("err", err)) return nil, err } var commodities []ErpStock if m.IsExport == 1 { // 导出excel err = qs.Find(&commodities).Error } else { err = qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error } if err != nil && err != RecordNotFound { logger.Error("查询无库存列表失败", logger.Field("err", err)) return nil, err } var reportList []ReportByProductData var nTotalEffectiveCount, nTotalTransferCount uint32 var nTotalEffectiveAmount, nTotalTransferAmount float64 // 遍历库存列表,计算有效库存金额,调入中金额 for _, item := range commodities { var reportData ReportByProductData reportData.StoreId = item.StoreId reportData.StoreName = item.StoreName reportData.CommoditySerialNumber = item.CommoditySerialNumber reportData.CommodityId = item.ErpCommodityId reportData.CommodityName = item.ErpCommodityName reportData.CategoryID = item.ErpCategoryId reportData.CategoryName = item.ErpCategoryName reportData.EffectiveCount = item.Count reportData.TransferCount = item.DispatchCount reportData.Count = item.Count + item.DispatchCount // 查询有效库存金额 if item.Count != 0 { reportData.EffectiveAmount, err = getStockCommodityAmount(item.StoreId, item.ErpCommodityId) if err != nil { return nil, err } } // 查询调入中金额 if item.DispatchCount != 0 { reportData.TransferAmount, err = getDispatchCommodityAmount(item.StoreId, item.ErpCommodityId) if err != nil { return nil, err } } nTotalEffectiveCount += reportData.EffectiveCount nTotalTransferCount += reportData.TransferCount nTotalEffectiveAmount += reportData.EffectiveAmount nTotalTransferAmount += reportData.TransferAmount reportList = append(reportList, reportData) } resp.TotalEffectiveCount = nTotalEffectiveCount resp.TotalTransferCount = nTotalTransferCount resp.TotalCount = resp.TotalTransferCount + resp.TotalEffectiveCount resp.TotalEffectiveAmount = nTotalEffectiveAmount resp.TotalTransferAmount = nTotalTransferAmount resp.Total = resp.TotalCount resp.List = reportList if m.IsExport == 1 { // 导出excel resp.ExportUrl, err = reportByProductExport(resp) if err != nil { return nil, err } resp.List = []ReportByProductData{} } return resp, nil } // 查询有效库存金额 func getStockCommodityAmount(storeId, commodityId uint32) (float64, error) { var nCount int64 err := orm.Eloquent.Debug().Table("erp_stock_commodity"). Where("store_id = ? and erp_commodity_id = ? and state = ?", storeId, commodityId, InStock).Count(&nCount).Error if err != nil { return 0, err } if nCount == 0 { return 0, nil } var nStockCommodityAmount float64 err = orm.Eloquent.Debug().Table("erp_stock_commodity").Select("SUM(wholesale_price) AS "+ "nStockCommodityAmount").Where("store_id = ? and erp_commodity_id = ? and state = ?", storeId, commodityId, InStock).Find(&nStockCommodityAmount).Error if err != nil { return 0, err } return nStockCommodityAmount, nil } // 查询调入中金额 func getDispatchCommodityAmount(storeId, commodityId uint32) (float64, error) { var nCount int64 err := orm.Eloquent.Debug().Table("erp_stock_commodity"). Where("store_id = ? and erp_commodity_id = ? and state = ?", storeId, commodityId, InAllot).Count(&nCount).Error if err != nil { return 0, err } if nCount == 0 { return 0, nil } var nDispatchCommodityAmount float64 err = orm.Eloquent.Debug().Table("erp_stock_commodity").Select("SUM(wholesale_price) AS "+ "nStockCommodityAmount").Where("store_id = ? and erp_commodity_id = ? and state = ?", storeId, commodityId, InAllot).Find(&nDispatchCommodityAmount).Error if err != nil { return 0, err } return nDispatchCommodityAmount, nil } // reportByProductExport 产品库存汇总(按门店)导出excel func reportByProductExport(req *InventoryReportByProductResp) (string, error) { file := excelize.NewFile() fSheet := "Sheet1" url := ExportUrl fileName := time.Now().Format(TimeFormat) + "产品库存汇总(按门店)" + ".xlsx" fmt.Println("url fileName:", url+fileName) // 组合标题栏数据 title := []interface{}{"门店", "商品编号", "商品名称", "商品分类", "有效库存数", "调入中数量", "总数量", "有效库存金额", "调入中金额"} for i, _ := range title { cell, _ := excelize.CoordinatesToCellName(1+i, 1) err := file.SetCellValue(fSheet, cell, title[i]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } var row1 []interface{} nExcelStartRow := 0 for _, reportData := range req.List { row1 = []interface{}{ reportData.StoreName, // 门店 reportData.CommoditySerialNumber, // 商品编号 reportData.CommodityName, // 商品名称 reportData.CategoryName, // 商品分类 reportData.EffectiveCount, // 有效库存数 reportData.TransferCount, // 调入中数量 reportData.Count, // 总数量 reportData.EffectiveAmount, // 有效库存金额 reportData.TransferAmount, // 调入中金额 } for j, _ := range row1 { cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2) err := file.SetCellValue(fSheet, cell, row1[j]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } nExcelStartRow++ } totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10) end := []interface{}{totalData, "", "", "", req.TotalEffectiveCount, req.TotalTransferCount, req.TotalCount, req.TotalEffectiveAmount, req.TotalTransferAmount} for i, _ := range end { cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2) err := file.SetCellValue(fSheet, cell, end[i]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } // 设置所有单元格的样式: 居中、加边框 style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}, "border":[{"type":"left","color":"000000","style":1}, {"type":"top","color":"000000","style":1}, {"type":"right","color":"000000","style":1}, {"type":"bottom","color":"000000","style":1}]}`) //设置单元格高度 file.SetRowHeight("Sheet1", 1, 20) // 设置单元格大小 file.SetColWidth("Sheet1", "A", "A", 30) file.SetColWidth("Sheet1", "C", "C", 25) file.SetColWidth("Sheet1", "D", "D", 15) file.SetColWidth("Sheet1", "E", "E", 15) file.SetColWidth("Sheet1", "F", "F", 15) file.SetColWidth("Sheet1", "H", "H", 15) file.SetColWidth("Sheet1", "I", "I", 15) endRow := fmt.Sprintf("I"+"%d", nExcelStartRow+2) // 应用样式到整个表格 _ = file.SetCellStyle("Sheet1", "A1", endRow, style) fmt.Println("save fileName:", config.ExportConfig.Path+fileName) if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil { fmt.Println(err) } return url + fileName, nil }