From 49970e13d252f70a93d789b599651708883f8d52 Mon Sep 17 00:00:00 2001 From: chenlin Date: Tue, 23 Apr 2024 18:20:49 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E6=8E=A5=E5=8F=A3=EF=BC=9A?= =?UTF-8?q?=E5=BA=93=E5=AD=98=E8=B0=83=E6=8B=A8=E6=B1=87=E6=80=BB=E3=80=81?= =?UTF-8?q?=E5=BA=93=E5=AD=98=E8=B0=83=E6=8B=A8=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/apis/inventorymanage/report.go | 18 +- app/admin/models/inventory_allot.go | 33 +- app/admin/models/inventory_report.go | 684 ++++++++++++++++++++++- 3 files changed, 707 insertions(+), 28 deletions(-) diff --git a/app/admin/apis/inventorymanage/report.go b/app/admin/apis/inventorymanage/report.go index 373a3a2..c2f3a68 100644 --- a/app/admin/apis/inventorymanage/report.go +++ b/app/admin/apis/inventorymanage/report.go @@ -51,7 +51,14 @@ func InventoryReportByAllot(c *gin.Context) { return } - app.OK(c, "", "OK") + resp, err := req.ReportAllotList(c) + if err != nil { + //logger.Error("erp commodity list err:", err) + app.Error(c, http.StatusInternalServerError, err, "查询失败:"+err.Error()) + return + } + + app.OK(c, resp, "OK") return } @@ -70,7 +77,14 @@ func InventoryReportAllotDetail(c *gin.Context) { return } - app.OK(c, "", "OK") + resp, err := req.ReportAllotDetailList(c) + if err != nil { + //logger.Error("erp commodity list err:", err) + app.Error(c, http.StatusInternalServerError, err, "查询失败:"+err.Error()) + return + } + + app.OK(c, resp, "OK") return } diff --git a/app/admin/models/inventory_allot.go b/app/admin/models/inventory_allot.go index 8ed7cc0..28b0ca3 100644 --- a/app/admin/models/inventory_allot.go +++ b/app/admin/models/inventory_allot.go @@ -45,13 +45,14 @@ type ErpInventoryAllotOrder struct { // ErpInventoryAllotCommodity 库存调拨商品信息表 type ErpInventoryAllotCommodity struct { Model - AllotOrderId uint32 `json:"allot_order_id" gorm:"index"` // 库存调拨订单表id - CommodityId uint32 `json:"commodity_id" gorm:"index"` // 商品id - CommodityName string `json:"commodity_name"` // 商品名称 - IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 - IMEI string `json:"imei"` // 商品串码 - Count uint32 `json:"count"` // 数量 - Remark string `json:"remark"` // 备注 + AllotOrderId uint32 `json:"allot_order_id" gorm:"index"` // 库存调拨订单表id + CommodityId uint32 `json:"commodity_id" gorm:"index"` // 商品id + CommodityName string `json:"commodity_name"` // 商品名称 + IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 + IMEI string `json:"imei"` // 商品串码 + Count uint32 `json:"count"` // 数量 + Amount float64 `json:"amount"` // 金额(采购价) + Remark string `json:"remark"` // 备注 } // InventoryAllotAddReq 新增库存调拨入参 @@ -584,7 +585,7 @@ func allotAuditAndUpdateStock(gdb *gorm.DB, allotOrder ErpInventoryAllotOrder) e var stockCommodity []ErpStockCommodity err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+ "AND state = ? AND imei = ?", v.CommodityId, allotOrder.DeliverStoreId, InStock, v.IMEI). - Find(&stockCommodity).Error + Order("first_stock_time ASC").Find(&stockCommodity).Error if err != nil { return fmt.Errorf("审核失败,查询商品库存失败:[%s]", err.Error()) } @@ -599,6 +600,7 @@ func allotAuditAndUpdateStock(gdb *gorm.DB, allotOrder ErpInventoryAllotOrder) e } // 更新库存商品表商品状态为:调拨中 + var nAmount float64 for i := 0; i < int(v.Count); i++ { stockCommodity[i].StoreId = allotOrder.ReceiveStoreId stockCommodity[i].StoreName = allotOrder.ReceiveStoreName @@ -607,6 +609,17 @@ func allotAuditAndUpdateStock(gdb *gorm.DB, allotOrder ErpInventoryAllotOrder) e Updates(stockCommodity[i]).Error; err != nil { return fmt.Errorf("审核失败,更新商品库存失败:%s", err.Error()) } + nAmount += stockCommodity[i].WholesalePrice + } + + // 更新库存调拨商品信息表的调拨金额 + err = gdb.Table("erp_inventory_allot_commodity").Where("id = ?", v.ID). + Updates(map[string]interface{}{ + "amount": nAmount, + }).Error + if err != nil { + logger.Errorf("update erp_inventory_allot_commodity amount err:", err) + return err } // 更新库存商品数量 @@ -645,8 +658,8 @@ func allotAuditAndUpdateStock(gdb *gorm.DB, allotOrder ErpInventoryAllotOrder) e IMEIType: v.IMEIType, RetailPrice: stockCommodity[0].RetailPrice, MinRetailPrice: stockCommodity[0].MinRetailPrice, - Count: v.Count, - DispatchCount: 0, + Count: 0, + DispatchCount: v.Count, } err = gdb.Create(stock).Error if err != nil { diff --git a/app/admin/models/inventory_report.go b/app/admin/models/inventory_report.go index 14d4eb5..1921e8b 100644 --- a/app/admin/models/inventory_report.go +++ b/app/admin/models/inventory_report.go @@ -9,6 +9,7 @@ import ( "go-admin/logger" "go-admin/tools" "go-admin/tools/config" + "sort" "strconv" "time" ) @@ -83,24 +84,26 @@ type InventoryReportByAllotResp struct { // 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"` // 调拨金额 + 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"` // 商品分类名称 + AuditTime *time.Time `json:"audit_time"` // 审核时间 + ReceiveTime *time.Time `json:"receive_time"` // 收货时间/调入时间 + 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 + 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-已完成 @@ -115,7 +118,7 @@ type InventoryReportAllotDetailReq struct { // InventoryReportAllotDetailResp 库存调拨明细出参 type InventoryReportAllotDetailResp struct { - Total int `json:"total"` // 总条数/记录数 + Total int64 `json:"total"` // 总条数/记录数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 ExportUrl string `json:"export_url"` // 导出excel路径 @@ -131,6 +134,7 @@ type ReportAllotDetailData struct { ReceiveStoreName string `json:"receive_store_name"` // 调入门店名称 MakerTime *time.Time `json:"maker_time"` // 制单时间/发起时间 AuditTime *time.Time `json:"audit_time"` // 审核时间 + ReceiveTime *time.Time `json:"receive_time"` // 收货时间/调入时间 State uint32 `json:"state"` // 调拨状态:1-调拨中 2-已完成 CommodityId uint32 `json:"commodity_id"` // 商品id CommodityName string `json:"commodity_name"` // 商品名称 @@ -138,6 +142,7 @@ type ReportAllotDetailData struct { CategoryName string `json:"category_name"` // 商品分类名称 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei"` // 商品串码 + Remark string `json:"remark"` // 备注 } // InventoryReportByOtherReq 其他出入库汇总入参 @@ -297,9 +302,9 @@ func (m *InventoryReportByProductReq) ReportByProductList(c *gin.Context) (*Inve var commodities []ErpStock if m.IsExport == 1 { // 导出excel - err = qs.Find(&commodities).Error + err = qs.Order("erp_commodity_id, store_id desc").Find(&commodities).Error } else { - err = qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error + err = qs.Order("erp_commodity_id, store_id desc").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error } if err != nil && err != RecordNotFound { logger.Error("查询无库存列表失败", logger.Field("err", err)) @@ -498,3 +503,650 @@ func reportByProductExport(req *InventoryReportByProductResp) (string, error) { } return url + fileName, nil } + +// ReportAllotList 库存调拨汇总 +func (m *InventoryReportByAllotReq) ReportAllotList(c *gin.Context) (*InventoryReportByAllotResp, 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.DeliverStoreId = CompareLists(storeList, m.DeliverStoreId) + m.ReceiveStoreId = CompareLists(storeList, m.ReceiveStoreId) + if len(m.DeliverStoreId) == 0 && len(m.ReceiveStoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店 + return &InventoryReportByAllotResp{}, nil + } + } else { + return nil, errors.New("用户未绑定门店") + } + } + + resp := &InventoryReportByAllotResp{ + 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_inventory_allot_order"). + Select("erp_inventory_allot_order.deliver_store_id, "+ + "erp_inventory_allot_order.deliver_store_name, "+ + "erp_inventory_allot_order.receive_store_id, "+ + "erp_inventory_allot_order.receive_store_name, "+ + "erp_inventory_allot_order.audit_time, "+ + "erp_inventory_allot_order.receive_time, "+ + "CASE "+ + "WHEN erp_inventory_allot_order.state IN (2, 3) THEN 1 "+ + "WHEN erp_inventory_allot_order.state = 4 THEN 2 "+ + "ELSE erp_inventory_allot_order.state "+ + "END AS state, "+ + "erp_inventory_allot_commodity.commodity_id, "+ + "erp_inventory_allot_commodity.commodity_name, "+ + "erp_inventory_allot_commodity.count as allot_count, "+ + "erp_inventory_allot_commodity.amount as allot_amount"). + Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id"). + Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单 + + // 创建一个新的查询对象,用于 count 查询 + countQuery := orm.Eloquent.Debug().Table("erp_inventory_allot_order"). + Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id"). + Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单 + + if len(m.DeliverStoreId) > 0 { // 调出门店id复选 + var storeIDs []uint32 + for _, store := range m.DeliverStoreId { + storeIDs = append(storeIDs, store) + } + qs = qs.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs) + countQuery = countQuery.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs) + } + + if len(m.ReceiveStoreId) > 0 { // 调入门店id复选 + var storeIDs []uint32 + for _, store := range m.ReceiveStoreId { + storeIDs = append(storeIDs, store) + } + qs = qs.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs) + countQuery = countQuery.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs) + } + + if len(m.CommodityName) > 0 { // 商品名称 + var commodityNames []string + for _, commodityName := range m.CommodityName { + commodityNames = append(commodityNames, commodityName) + } + qs = qs.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames) + countQuery = countQuery.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames) + } + + if len(m.CategoryID) > 0 { // 商品分类id + var categoryIDs []uint32 + for _, category := range m.CategoryID { + categoryIDs = append(categoryIDs, category) + } + qs = qs.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs) + countQuery = countQuery.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs) + } + + if m.State != 0 { // 调拨状态 + switch m.State { + case 1: // 调拨中 + qs = qs.Where("erp_inventory_allot_order.state IN (?)", + ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive) + countQuery = countQuery.Where("erp_inventory_allot_order.state IN (?)", + ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive) + case 2: // 已完成 + qs = qs.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished) + countQuery = countQuery.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished) + } + } + + if m.AuditTimeStart != "" { // 审核开始时间 + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) + if err != nil { + logger.Errorf("ReportAllotList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.audit_time > ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.audit_time > ?", parse) + } + if m.AuditTimeEnd != "" { // 审核结束时间 + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd) + if err != nil { + logger.Errorf("ReportAllotList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.audit_time < ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.audit_time < ?", parse) + } + + if m.ReceiveTimeStart != "" { // 调入开始时间 + parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeStart) + if err != nil { + logger.Errorf("ReportAllotList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.receive_time > ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.receive_time > ?", parse) + } + if m.ReceiveTimeEnd != "" { // 调入结束时间 + parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeEnd) + if err != nil { + logger.Errorf("ReportAllotList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.receive_time < ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.receive_time < ?", parse) + } + + var count int64 + err := countQuery.Count(&count).Error + if err != nil { + logger.Error("ReportAllotList 查询失败", logger.Field("err", err)) + return nil, err + } + + var commodities []ReportByAllotData + err = qs.Find(&commodities).Error + if err != nil { + return nil, err + } + + var nTotalAllotCount uint32 + var nTotalAllotAmount float64 + // 创建 map 用于存储汇总数据 + summaryMap := make(map[string]*ReportByAllotData) + // 遍历 commodities 切片 + for _, item := range commodities { + nTotalAllotCount += item.AllotCount + nTotalAllotAmount += item.AllotAmount + + // 生成键 + key := fmt.Sprintf("%d_%d_%d", item.DeliverStoreId, item.ReceiveStoreId, item.State) + // 检查是否已经存在该键的汇总数据 + if summary, ok := summaryMap[key]; ok { + // 如果已经存在,累加调拨数量和调拨金额 + summary.AllotCount += item.AllotCount + // 假设商品金额在 item.CommodityAmount 中 + summary.AllotAmount += item.AllotAmount + } else { + // 如果不存在,创建新的汇总数据并添加到 map 中 + summaryMap[key] = &ReportByAllotData{ + DeliverStoreId: item.DeliverStoreId, + DeliverStoreName: item.DeliverStoreName, + ReceiveStoreId: item.ReceiveStoreId, + ReceiveStoreName: item.ReceiveStoreName, + CommodityId: item.CommodityId, + CommodityName: item.CommodityName, + CategoryID: item.CategoryID, + CategoryName: item.CategoryName, + AuditTime: item.AuditTime, + ReceiveTime: item.ReceiveTime, + State: item.State, // 调拨中状态为 1 + AllotCount: item.AllotCount, // 初始化为 1 + AllotAmount: item.AllotAmount, + } + } + } + + var summaryList []ReportByAllotData + for i, summary := range summaryMap { + // 添加分类信息 + commodityInfo, err := GetCommodity(summary.CommodityId) + if err != nil { + logger.Error("SetCategory err:", logger.Field("err", err)) + } + summaryMap[i].CategoryID = commodityInfo.ErpCategoryId + summaryMap[i].CategoryName = commodityInfo.ErpCategoryName + + summaryList = append(summaryList, *summary) + } + + // 排序规则:商品编号小>调出店铺编号小>调入门店编号小>状态为已完成 + sort.Slice(summaryList, func(i, j int) bool { + if summaryList[i].CommodityId != summaryList[j].CommodityId { + return summaryList[i].CommodityId < summaryList[j].CommodityId + } + if summaryList[i].DeliverStoreId != summaryList[j].DeliverStoreId { + return summaryList[i].DeliverStoreId < summaryList[j].DeliverStoreId + } + if summaryList[i].ReceiveStoreId != summaryList[j].ReceiveStoreId { + return summaryList[i].ReceiveStoreId < summaryList[j].ReceiveStoreId + } + return summaryList[i].State < summaryList[j].State + }) + + // 计算分页所需的切片索引 + startIndex := page * m.PageSize + endIndex := (page + 1) * m.PageSize + if endIndex > len(summaryList) { + endIndex = len(summaryList) + } + + resp.Total = len(summaryMap) + resp.TotalAllotCount = nTotalAllotCount + resp.TotalAllotAmount = nTotalAllotAmount + resp.List = summaryList[startIndex:endIndex] + + if m.IsExport == 1 { + resp.ExportUrl, err = reportAllotExport(resp) + if err != nil { + return nil, err + } + resp.List = []ReportByAllotData{} + } + + return resp, nil +} + +// reportAllotExport 库存调拨汇总导出excel +func reportAllotExport(req *InventoryReportByAllotResp) (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 { + var allotState string + switch reportData.State { + case 1: // 调拨中 + allotState = "调拨中" + case 2: // 已完成 + allotState = "已完成" + } + + row1 = []interface{}{ + reportData.DeliverStoreName, // 调出门店 + reportData.ReceiveStoreName, // 调入门店 + reportData.CommodityName, // 商品名称 + reportData.CategoryName, // 商品分类 + allotState, // 调拨状态 + reportData.AllotCount, // 调拨数量 + reportData.AllotAmount, // 调拨金额 + } + + 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.TotalAllotCount, req.TotalAllotAmount} + 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", 28) + file.SetColWidth("Sheet1", "B", "B", 28) + file.SetColWidth("Sheet1", "C", "C", 23) + file.SetColWidth("Sheet1", "D", "D", 15) + + endRow := fmt.Sprintf("G"+"%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 +} + +// ReportAllotDetailList 库存调拨明细 +func (m *InventoryReportAllotDetailReq) ReportAllotDetailList(c *gin.Context) (*InventoryReportAllotDetailResp, 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.DeliverStoreId = CompareLists(storeList, m.DeliverStoreId) + m.ReceiveStoreId = CompareLists(storeList, m.ReceiveStoreId) + if len(m.DeliverStoreId) == 0 && len(m.ReceiveStoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店 + return &InventoryReportAllotDetailResp{}, nil + } + } else { + return nil, errors.New("用户未绑定门店") + } + } + + resp := &InventoryReportAllotDetailResp{ + 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_inventory_allot_order"). + Select("erp_inventory_allot_order.serial_number, "+ + "erp_inventory_allot_order.deliver_store_id, "+ + "erp_inventory_allot_order.deliver_store_name, "+ + "erp_inventory_allot_order.receive_store_id, "+ + "erp_inventory_allot_order.receive_store_name, "+ + "erp_inventory_allot_order.maker_time, "+ + "erp_inventory_allot_order.audit_time, "+ + "erp_inventory_allot_order.receive_time, "+ + "CASE "+ + "WHEN erp_inventory_allot_order.state IN (2, 3) THEN 1 "+ + "WHEN erp_inventory_allot_order.state = 4 THEN 2 "+ + "ELSE erp_inventory_allot_order.state "+ + "END AS state, "+ + "erp_inventory_allot_commodity.commodity_id, "+ + "erp_inventory_allot_commodity.commodity_name, "+ + "erp_inventory_allot_commodity.imei_type, "+ + "erp_inventory_allot_commodity.imei, "+ + "erp_inventory_allot_commodity.count, "+ + "erp_inventory_allot_commodity.remark"). + Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id"). + Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单 + + // 创建一个新的查询对象,用于 count 查询 + countQuery := orm.Eloquent.Debug().Table("erp_inventory_allot_order"). + Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id"). + Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单 + + if m.SerialNumber != "" { // 单据编号 + qs = qs.Where("erp_inventory_allot_order.serial_number = ?", m.SerialNumber) + countQuery = countQuery.Where("erp_inventory_allot_order.serial_number = ?", m.SerialNumber) + } + + if len(m.DeliverStoreId) > 0 { // 调出门店id复选 + var storeIDs []uint32 + for _, store := range m.DeliverStoreId { + storeIDs = append(storeIDs, store) + } + qs = qs.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs) + countQuery = countQuery.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs) + } + + if len(m.ReceiveStoreId) > 0 { // 调入门店id复选 + var storeIDs []uint32 + for _, store := range m.ReceiveStoreId { + storeIDs = append(storeIDs, store) + } + qs = qs.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs) + countQuery = countQuery.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs) + } + + if len(m.CommodityName) > 0 { // 商品名称 + var commodityNames []string + for _, commodityName := range m.CommodityName { + commodityNames = append(commodityNames, commodityName) + } + qs = qs.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames) + countQuery = countQuery.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames) + } + + if len(m.CategoryID) > 0 { // 商品分类id + var categoryIDs []uint32 + for _, category := range m.CategoryID { + categoryIDs = append(categoryIDs, category) + } + qs = qs.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs) + countQuery = countQuery.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs) + } + + if m.State != 0 { // 调拨状态 + switch m.State { + case 1: // 调拨中 + qs = qs.Where("erp_inventory_allot_order.state IN (?)", + ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive) + countQuery = countQuery.Where("erp_inventory_allot_order.state IN (?)", + ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive) + case 2: // 已完成 + qs = qs.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished) + countQuery = countQuery.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished) + } + } + + if m.AuditTimeStart != "" { // 审核开始时间 + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) + if err != nil { + logger.Errorf("ReportAllotDetailList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.audit_time > ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.audit_time > ?", parse) + } + if m.AuditTimeEnd != "" { // 审核结束时间 + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd) + if err != nil { + logger.Errorf("ReportAllotDetailList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.audit_time < ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.audit_time < ?", parse) + } + + if m.ReceiveTimeStart != "" { // 调入开始时间 + parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeStart) + if err != nil { + logger.Errorf("ReportAllotDetailList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.receive_time > ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.receive_time > ?", parse) + } + if m.ReceiveTimeEnd != "" { // 调入结束时间 + parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeEnd) + if err != nil { + logger.Errorf("ReportAllotDetailList err:", err) + return nil, err + } + qs = qs.Where("erp_inventory_allot_order.receive_time < ?", parse) + countQuery = countQuery.Where("erp_inventory_allot_order.receive_time < ?", parse) + } + + var count int64 + err := countQuery.Count(&count).Error + if err != nil { + logger.Error("查询无库存列表数量失败", logger.Field("err", err)) + return nil, err + } + + var commodities []ReportAllotDetailData + if m.IsExport == 1 { // 导出excel + err = qs.Order("audit_time DESC").Find(&commodities).Error + } else { + err = qs.Order("audit_time DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error + } + if err != nil { + return nil, err + } + + // 添加分类信息 + reportAllotDetailSetCategory(commodities) + + resp.Total = count + resp.List = commodities + + if m.IsExport == 1 { + resp.ExportUrl, err = reportAllotDetailExport(resp) + if err != nil { + return nil, err + } + resp.List = []ReportAllotDetailData{} + } + + return resp, nil +} + +// 添加订单的添加分类信息 +func reportAllotDetailSetCategory(list []ReportAllotDetailData) { + for i, _ := range list { + list[i].SetCategory() + } +} + +func (m *ReportAllotDetailData) SetCategory() { + commodityInfo, err := GetCommodity(m.CommodityId) + if err != nil { + logger.Error("SetCategory err:", logger.Field("err", err)) + } + m.CategoryID = commodityInfo.ErpCategoryId + m.CategoryName = commodityInfo.ErpCategoryName +} + +// reportAllotDetailExport 库存调拨明细导出excel +func reportAllotDetailExport(req *InventoryReportAllotDetailResp) (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 { + var allotState string + switch reportData.State { + case 1: // 调拨中 + allotState = "调拨中" + case 2: // 已完成 + allotState = "已完成" + } + + var IMEIType string + switch reportData.IMEIType { + case 1: + IMEIType = "非串码" + case 2, 3: + IMEIType = "串码类" + } + + var receiveTime, auditTime string + if reportData.ReceiveTime != nil { + receiveTime = reportData.ReceiveTime.Format(TimeFormat) + } + if reportData.AuditTime != nil { + auditTime = reportData.AuditTime.Format(TimeFormat) + } + + row1 = []interface{}{ + reportData.SerialNumber, // 单据编号 + reportData.DeliverStoreName, // 调出门店 + reportData.ReceiveStoreName, // 调入门店 + auditTime, // 订单审核时间 + receiveTime, // 调入时间 + allotState, // 调拨状态 + reportData.CommodityName, // 商品名称 + reportData.CategoryName, // 商品分类 + IMEIType, // 是否串码 + reportData.IMEI, // 串码 + } + + 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, "", "", "", "", "", "", "", "", ""} + 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", 13) + file.SetColWidth("Sheet1", "B", "B", 28) + file.SetColWidth("Sheet1", "C", "C", 28) + file.SetColWidth("Sheet1", "D", "D", 18) + file.SetColWidth("Sheet1", "E", "E", 18) + file.SetColWidth("Sheet1", "G", "G", 23) + file.SetColWidth("Sheet1", "H", "H", 15) + file.SetColWidth("Sheet1", "J", "J", 15) + + endRow := fmt.Sprintf("J"+"%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 +}