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"
	"gorm.io/gorm"
	"math"
	"sort"
	"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"`  // 页面条数
	ReportByProductSumData
	ExportUrl string                `json:"export_url"` // 导出excel路径
	List      []ReportByProductData `json:"list"`       //
}

type ReportByProductSumData struct {
	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"`  // 调出中金额
	TotalAmount          float64 `json:"total_amount"`           // 总金额
}

// 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"`         // 调出中金额
	Amount                float64 `json:"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"`          // 商品名称
	CommoditySerialNumber string     `json:"commodity_serial_number"` // 商品编号
	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
	CommodityName    []string `json:"commodity_name"`     // 商品名称
	CategoryID       []uint32 `json:"category_id"`        // 商品分类id
	IMEI             string   `json:"imei"`               // 串码
	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            int64                   `json:"total"`              // 总条数/记录数
	TotalAllotAmount float64                 `json:"total_allot_amount"` // 调拨金额
	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"`         // 审核时间
	ReceiveTime      *time.Time `json:"receive_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"`               // 商品串码
	Remark           string     `json:"remark"`             // 备注
	AllotAmount      float64    `json:"allot_amount"`       // 调拨金额
}

// InventoryReportByOtherReq 其他出入库汇总入参
type InventoryReportByOtherReq struct {
	StoreId       []uint32 `json:"store_id"`       // 门店id
	CommodityName []string `json:"commodity_name"` // 商品名称
	CategoryID    []uint32 `json:"category_id"`    // 商品分类id
	Type          uint32   `json:"type"`           // 出入库方式：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  int64               `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"`          // 商品名称
	CommoditySerialNumber string     `json:"commodity_serial_number"` // 商品编号
	CategoryID            uint32     `json:"category_id"`             // 商品分类id
	CategoryName          string     `json:"category_name"`           // 商品分类名称
	StockTime             *time.Time `json:"stock_time"`              // 出入库时间
	Type                  uint32     `json:"type"`                    // 出入库方式：1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
	Count                 int64      `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
	Type          uint32   `json:"type"`           // 出入库方式：1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
	IMEI          string   `json:"imei"`           // 串码
	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"`     // 出入库时间
	Type          uint32     `json:"type"`           // 调拨状态：1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
	SerialNumber  string     `json:"serial_number"`  // 单据编号
	PurchasePrice float64    `json:"purchase_price"` // 入库采购价
	EmployeePrice float64    `json:"employee_price"` // 入库员工成本价
}

// ReportByProductList2 产品库存汇总（按门店）
func (m *InventoryReportByProductReq) ReportByProductList2(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")
	sumQs := orm.Eloquent.Debug().Table("erp_stock_commodity")

	if len(m.StoreId) > 0 { // 门店复选
		var storeIDs []uint32
		for _, store := range m.StoreId {
			storeIDs = append(storeIDs, store)
		}
		qs = qs.Where("store_id IN (?)", storeIDs)
		sumQs = sumQs.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("erp_category_id IN (?)", categoryIDs)
		sumQs = sumQs.Where("erp_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)
		sumQs = sumQs.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("erp_commodity_name IN (?)", commodityNames)
		sumQs = sumQs.Where("erp_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
	err = qs.Order("erp_commodity_id, store_id desc").Find(&commodities).Error
	//if m.IsExport == 1 { // 导出excel
	//	err = qs.Order("erp_commodity_id, store_id desc").Find(&commodities).Error
	//} else {
	//	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))
		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
			}
		}

		reportData.Amount = reportData.EffectiveAmount + reportData.TransferAmount

		nTotalEffectiveCount += reportData.EffectiveCount
		nTotalTransferCount += reportData.TransferCount

		nTotalEffectiveAmount += reportData.EffectiveAmount
		nTotalTransferAmount += reportData.TransferAmount

		if reportData.Count == 0 {
			continue
		}

		reportList = append(reportList, reportData)
	}

	sumData, err := getReportByProductSumData(sumQs)
	if err != nil {
		return nil, err
	}

	resp.TotalEffectiveCount = sumData.TotalEffectiveCount
	resp.TotalTransferCount = sumData.TotalTransferCount
	resp.TotalCount = sumData.TotalCount
	resp.TotalEffectiveAmount = sumData.TotalEffectiveAmount
	resp.TotalTransferAmount = sumData.TotalTransferAmount
	resp.TotalAmount = resp.TotalEffectiveAmount + resp.TotalTransferAmount
	resp.TotalAmount = math.Round(resp.TotalAmount*100) / 100
	resp.Total = uint32(len(reportList))
	resp.List = reportList

	if m.IsExport == 1 { // 导出excel
		resp.ExportUrl, err = reportByProductExport(resp)
		if err != nil {
			return nil, err
		}
		resp.List = []ReportByProductData{}
	} else {
		// 计算分页所需的切片索引
		startIndex := page * m.PageSize
		endIndex := (page + 1) * m.PageSize
		if endIndex > len(reportList) {
			endIndex = len(reportList)
		}
		resp.List = reportList[startIndex:endIndex]
	}

	return resp, nil
}

// 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")
	sumQs := orm.Eloquent.Debug().Table("erp_stock_commodity")

	// 应用 StoreId 和其他条件
	if len(m.StoreId) > 0 {
		qs = qs.Where("store_id IN (?)", m.StoreId)
		sumQs = sumQs.Where("store_id IN (?)", m.StoreId)
	}

	if len(m.CategoryID) > 0 {
		categoryList, err := TransformErpCategoryIds(m.CategoryID)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("erp_category_id IN ?", categoryList)
		sumQs = sumQs.Where("erp_category_id IN ?", categoryList)
	}

	if len(m.CommoditySerialNumber) > 0 { // 商品编号
		qs = qs.Where("commodity_serial_number IN (?)", m.CommoditySerialNumber)
		sumQs = sumQs.Where("commodity_serial_number IN (?)", m.CommoditySerialNumber)
	}

	if len(m.CommodityName) > 0 { // 商品名称
		qs = qs.Where("erp_commodity_name IN (?)", m.CommodityName)
		sumQs = sumQs.Where("erp_commodity_name IN (?)", m.CommodityName)
	}

	// 统计总条数并直接赋值给 resp.Total
	var count int64
	err := qs.Where("count != 0 or dispatch_count != 0 ").Count(&count).Error
	if err != nil {
		logger.Error("查询无库存列表数量失败", logger.Field("err", err))
		return nil, err
	}
	resp.Total = uint32(count)

	// 批量查询 EffectiveAmount 和 TransferAmount
	effectiveAmounts, transferAmounts, err := getBatchAmounts(m.StoreId, m.CategoryID)
	if err != nil {
		return nil, err
	}

	// 获取库存商品数据并填充金额
	var commodities []ErpStock
	if m.IsExport == 1 { // 导出excel
		err = qs.Order("erp_commodity_id, store_id desc").Find(&commodities).Error
	} else {
		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))
		return nil, err
	}

	if m.IsExport == 1 {
		SortStockCommodities(commodities)
	}

	// 构造报表数据
	var reportList []ReportByProductData
	for _, item := range commodities {
		reportData := ReportByProductData{
			StoreId:               item.StoreId,
			StoreName:             item.StoreName,
			CommoditySerialNumber: item.CommoditySerialNumber,
			CommodityId:           item.ErpCommodityId,
			CommodityName:         item.ErpCommodityName,
			CategoryID:            item.ErpCategoryId,
			CategoryName:          item.ErpCategoryName,
			EffectiveCount:        item.Count,
			TransferCount:         item.DispatchCount,
			Count:                 item.Count + item.DispatchCount,
		}

		reportData.EffectiveAmount = effectiveAmounts[item.StoreId][item.ErpCommodityId]
		reportData.TransferAmount = transferAmounts[item.StoreId][item.ErpCommodityId]
		reportData.Amount = reportData.EffectiveAmount + reportData.TransferAmount

		reportList = append(reportList, reportData)
	}

	// 获取汇总数据
	sumData, err := getReportByProductSumData(sumQs)
	if err != nil {
		return nil, err
	}

	// 填充响应数据
	resp.TotalEffectiveCount = sumData.TotalEffectiveCount
	resp.TotalTransferCount = sumData.TotalTransferCount
	resp.TotalCount = sumData.TotalCount
	resp.TotalEffectiveAmount = math.Round(sumData.TotalEffectiveAmount*100) / 100
	resp.TotalTransferAmount = math.Round(sumData.TotalTransferAmount*100) / 100
	resp.TotalAmount = math.Round((resp.TotalEffectiveAmount+resp.TotalTransferAmount)*100) / 100
	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 getBatchAmounts(storeIDs, categoryIDs []uint32) (map[uint32]map[uint32]float64, map[uint32]map[uint32]float64, error) {
	effectiveAmounts := make(map[uint32]map[uint32]float64)
	transferAmounts := make(map[uint32]map[uint32]float64)

	// 基于 storeIDs 和 categoryIDs 限制查询范围
	query := orm.Eloquent.Debug().Table("erp_stock_commodity").
		Select("store_id, erp_commodity_id, state, SUM(wholesale_price) AS amount").
		Where("state IN (?, ?)", InStock, InAllot)

	if len(storeIDs) > 0 {
		query = query.Where("store_id IN (?)", storeIDs)
	}
	if len(categoryIDs) > 0 {
		query = query.Where("erp_category_id IN (?)", categoryIDs)
	}

	rows, err := query.Group("store_id, erp_commodity_id, state").Rows()
	if err != nil {
		return nil, nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var storeID, commodityID uint32
		var state int
		var amount float64
		rows.Scan(&storeID, &commodityID, &state, &amount)

		if state == InStock {
			if _, exists := effectiveAmounts[storeID]; !exists {
				effectiveAmounts[storeID] = make(map[uint32]float64)
			}
			effectiveAmounts[storeID][commodityID] = amount
		} else if state == InAllot {
			if _, exists := transferAmounts[storeID]; !exists {
				transferAmounts[storeID] = make(map[uint32]float64)
			}
			transferAmounts[storeID][commodityID] = amount
		}
	}

	return effectiveAmounts, transferAmounts, 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
}

// 查询产品库存汇总（按门店）的汇总数据：总有效库存数、总调出中数量、总数量、总有效库存金额、总调出中金额
func getReportByProductSumData(qs *gorm.DB) (ReportByProductSumData, error) {
	var data ReportByProductSumData

	// 查询汇总数据
	//err := orm.Eloquent.Debug().Table("erp_stock_commodity").
	err := qs.
		Select(`
            SUM(CASE WHEN state = ? THEN wholesale_price ELSE 0 END) AS total_effective_amount,
            SUM(CASE WHEN state = ? THEN wholesale_price ELSE 0 END) AS total_transfer_amount,
            SUM(CASE WHEN state = ? THEN Count ELSE 0 END) AS total_effective_count,
            SUM(CASE WHEN state = ? THEN Count ELSE 0 END) AS total_transfer_count,
            SUM(CASE WHEN state IN (?, ?) THEN Count ELSE 0 END) AS total_count
        `, InStock, InAllot, InStock, InAllot, InStock, InAllot).
		Find(&data).Error
	if err != nil {
		return data, err
	}

	data.TotalEffectiveAmount = math.Round(data.TotalEffectiveAmount*100) / 100
	data.TotalTransferAmount = math.Round(data.TotalTransferAmount*100) / 100

	return data, nil
}

// reportByProductExport 产品库存汇总（按门店）导出excel
func reportByProductExport(req *InventoryReportByProductResp) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "产品库存汇总（按门店）" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	// 组合标题栏数据
	title1 := []interface{}{"门店", "商品编号", "商品名称", "商品分类", "", "", "有效库存数", "调出中数量", "总数量", "有效库存金额",
		"调出中金额", "总金额"}
	title2 := []interface{}{"门店", "商品编号", "商品名称", "一级分类", "二级分类", "三级分类", "有效库存数", "调出中数量",
		"总数量", "有效库存金额",
		"调出中金额", "总金额"}
	for i, _ := range title1 {
		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
		err := file.SetCellValue(fSheet, cell, title1[i])
		if err != nil {
			logger.Errorf("file set value err:", err)
		}
	}

	for i, _ := range title2 {
		cell, _ := excelize.CoordinatesToCellName(1+i, 2)
		err := file.SetCellValue(fSheet, cell, title2[i])
		if err != nil {
			logger.Errorf("file set value err:", err)
		}
	}

	var row1 []interface{}
	nExcelStartRow := 0
	for _, reportData := range req.List {
		categoryLevels, _ := GetCategoryLevels(reportData.CategoryID)
		row1 = []interface{}{
			reportData.StoreName,             // 门店
			reportData.CommoditySerialNumber, // 商品编号
			reportData.CommodityName,         // 商品名称
			categoryLevels.Level1.Name,       // 一级分类
			categoryLevels.Level2.Name,       // 二级分类
			categoryLevels.Level3.Name,       // 三级分类
			reportData.EffectiveCount,        // 有效库存数
			reportData.TransferCount,         // 调出中数量
			reportData.Count,                 // 总数量
			reportData.EffectiveAmount,       // 有效库存金额
			reportData.TransferAmount,        // 调出中金额
			reportData.Amount,                // 总金额
		}

		for j, _ := range row1 {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
			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, req.TotalAmount}
	for i, _ := range end {
		cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+3)
		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.MergeCell(fSheet, "A1", "A2")
	_ = file.MergeCell(fSheet, "B1", "B2")
	_ = file.MergeCell(fSheet, "C1", "C2")
	_ = file.MergeCell(fSheet, "D1", "F1")
	_ = file.MergeCell(fSheet, "G1", "G2")
	_ = file.MergeCell(fSheet, "H1", "H2")
	_ = file.MergeCell(fSheet, "I1", "I2")
	_ = file.MergeCell(fSheet, "J1", "J2")
	_ = file.MergeCell(fSheet, "K1", "K2")
	_ = file.MergeCell(fSheet, "L1", "L2")

	//设置单元格高度
	file.SetRowHeight("Sheet1", 1, 20)
	file.SetRowHeight("Sheet1", 2, 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)
	file.SetColWidth("Sheet1", "J", "J", 15)
	file.SetColWidth("Sheet1", "K", "K", 15)
	file.SetColWidth("Sheet1", "L", "L", 15)

	endRow := fmt.Sprintf("L"+"%d", nExcelStartRow+3)
	// 应用样式到整个表格
	_ = 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
}

// 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_commodity.commodity_name IN (?)", commodityNames)
		countQuery = countQuery.Where("erp_inventory_allot_commodity.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 (?)",
				[]uint32{ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive})
			countQuery = countQuery.Where("erp_inventory_allot_order.state IN (?)",
				[]uint32{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 {
		// 生成键
		key := fmt.Sprintf("%d_%d_%d_%d", item.DeliverStoreId, item.ReceiveStoreId, item.CommodityId, 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))
		}

		// 判断分类信息是否有筛选
		if len(m.CategoryID) > 0 { // 商品分类id
			categoryList, err := TransformErpCategoryIds(m.CategoryID)
			if err != nil {
				return nil, err
			}
			if !tools.Uint32SliceContains(categoryList, commodityInfo.ErpCategoryId) {
				continue
			}
		}

		summaryMap[i].CategoryID = commodityInfo.ErpCategoryId
		summaryMap[i].CategoryName = commodityInfo.ErpCategoryName
		summaryMap[i].CommoditySerialNumber = commodityInfo.SerialNumber

		summaryList = append(summaryList, *summary)
		nTotalAllotCount += summary.AllotCount
		nTotalAllotAmount += summary.AllotAmount
	}

	// 排序规则：商品编号小＞调出店铺编号小＞调入门店编号小＞状态为已完成
	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
	})

	// 按照商品编号排序
	SortReportByAllotDataCommodities(summaryList)

	resp.Total = len(summaryList)
	resp.TotalAllotCount = nTotalAllotCount
	resp.TotalAllotAmount = nTotalAllotAmount

	if m.IsExport == 1 {
		resp.List = summaryList
		resp.ExportUrl, err = reportAllotExport(resp)
		if err != nil {
			return nil, err
		}
		resp.List = []ReportByAllotData{}
	} else {
		// 计算分页所需的切片索引
		startIndex := page * m.PageSize
		endIndex := (page + 1) * m.PageSize
		if endIndex > len(summaryList) {
			endIndex = len(summaryList)
		}

		resp.List = summaryList[startIndex:endIndex]
	}

	return resp, nil
}

// reportAllotExport 库存调拨汇总导出excel
func reportAllotExport(req *InventoryReportByAllotResp) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	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.category_id, "+
			"erp_inventory_allot_commodity.category_name, "+
			"erp_inventory_allot_commodity.imei_type, "+
			"erp_inventory_allot_commodity.imei, "+
			"erp_inventory_allot_commodity.count, "+
			"erp_inventory_allot_commodity.remark, "+
			"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 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_commodity.commodity_name IN (?)", commodityNames)
		countQuery = countQuery.Where("erp_inventory_allot_commodity.commodity_name IN (?)", commodityNames)
	}

	if len(m.CategoryID) > 0 { // 商品分类id
		categoryList, err := TransformErpCategoryIds(m.CategoryID)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("erp_inventory_allot_commodity.category_id IN ?", categoryList)
		countQuery = countQuery.Where("erp_inventory_allot_commodity.category_id IN ?", categoryList)
	}

	if m.IMEI != "" {
		qs = qs.Where("erp_inventory_allot_commodity.imei = ?", m.IMEI)
		countQuery = countQuery.Where("erp_inventory_allot_commodity.imei = ?", m.IMEI)
	}

	if m.State != 0 { // 调拨状态
		switch m.State {
		case 1: // 调拨中
			qs = qs.Where("erp_inventory_allot_order.state IN (?)",
				[]uint32{ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive})
			countQuery = countQuery.Where("erp_inventory_allot_order.state IN (?)",
				[]uint32{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
	}

	// Calculate the sum of allot_amount
	var totalAllotAmount float64
	err = countQuery.Select("COALESCE(SUM(erp_inventory_allot_commodity.amount), 0) as total_allot_amount").
		Pluck("total_allot_amount", &totalAllotAmount).Error
	if err != nil {
		logger.Error("Failed to calculate TotalAllotAmount", logger.Field("err", err))
		return nil, err
	}

	// Add the calculated TotalAllotAmount to the response
	resp.TotalAllotAmount = tools.RoundToTwoDecimalPlaces(totalAllotAmount)

	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 := config.ExportConfig.Url
	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, // 调入门店
			reportData.AllotAmount,      // 调拨金额
			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, "", "", 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", 13)
	file.SetColWidth("Sheet1", "B", "B", 28)
	file.SetColWidth("Sheet1", "C", "C", 28)
	file.SetColWidth("Sheet1", "E", "E", 18)
	file.SetColWidth("Sheet1", "F", "F", 18)
	file.SetColWidth("Sheet1", "H", "H", 23)
	file.SetColWidth("Sheet1", "I", "I", 15)
	file.SetColWidth("Sheet1", "K", "K", 15)

	endRow := fmt.Sprintf("K"+"%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
}

// ReportByOtherList 其他出入库汇总
func (m *InventoryReportByOtherReq) ReportByOtherList(c *gin.Context) (*InventoryReportByOtherResp, 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 &InventoryReportByOtherResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	resp := &InventoryReportByOtherResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	// 查询产品入库数据
	var err error
	var productList []ReportOtherDetailData
	productList, err = getProductOrderData(m.StoreId)
	if err != nil {
		return nil, err
	}

	// 查询盘点出入库数据
	var changeList []ReportOtherDetailData
	changeList, err = getChangeOrderData(m.StoreId)
	if err != nil {
		return nil, err
	}

	// 查询系统出库数据
	var systemList []ReportOtherDetailData
	systemList, err = getSystemOutData(m.StoreId)
	if err != nil {
		return nil, err
	}

	// 合并数据
	allData := append(productList, changeList...)
	allData = append(allData, systemList...)

	// 创建 map 用于存储汇总数据
	summaryMap := make(map[string]*ReportByOtherData)
	// 遍历切片
	for _, item := range allData {
		// 默认日期字符串为空
		dateStr := ""
		if item.StockTime != nil {
			// 格式化为 "yyyy-mm-dd"
			dateStr = item.StockTime.Format("2006-01-02")
		}

		// 生成键
		key := fmt.Sprintf("%d_%d_%d_%s", item.CommodityId, item.StoreId, item.Type, dateStr)

		// 检查是否已经存在该键的汇总数据
		if summary, ok := summaryMap[key]; ok {
			// 如果已经存在，累加调拨数量和调拨金额
			summary.Count += 1
			// 假设商品金额在 item.CommodityAmount 中
			summary.Amount += item.PurchasePrice
		} else {
			// 如果不存在，创建新的汇总数据并添加到 map 中
			summaryMap[key] = &ReportByOtherData{
				StoreId:       item.StoreId,
				StoreName:     item.StoreName,
				CommodityId:   item.CommodityId,
				CommodityName: item.CommodityName,
				CategoryID:    item.CategoryID,
				CategoryName:  item.CategoryName,
				StockTime:     item.StockTime,
				Type:          item.Type,
				Count:         1, // 初始化为 1
				Amount:        item.PurchasePrice,
			}
		}
	}

	var summaryList []ReportByOtherData
	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
		summaryMap[i].CommoditySerialNumber = commodityInfo.SerialNumber

		if summary.Type == 3 || summary.Type == 4 {
			summaryMap[i].Count = -summaryMap[i].Count
			summaryMap[i].Amount = -summaryMap[i].Amount
		}

		summaryList = append(summaryList, *summary)
	}

	// 进行条件查询
	var startTime time.Time
	if m.StartTime != "" { // 出入库开始时间
		startTime, err = time.Parse(QueryTimeFormat, m.StartTime)
		if err != nil {
			logger.Errorf("ReportByOtherDetailList err:", err)
			return nil, err
		}
	}
	var endTime time.Time
	if m.EndTime != "" { // 出入库结束时间
		endTime, err = time.Parse(QueryTimeFormat, m.EndTime)
		if err != nil {
			logger.Errorf("ReportByOtherDetailList err:", err)
			return nil, err
		}
	}

	var nTotalAllotCount int64
	var nTotalAllotAmount float64
	filteredData := make([]ReportByOtherData, 0)
	var categoryList []uint32
	if len(m.CategoryID) != 0 {
		categoryList, err = TransformErpCategoryIds(m.CategoryID)
		if err != nil {
			return nil, err
		}
	}
	for _, data := range summaryList {
		if (len(m.StoreId) == 0 || tools.Uint32SliceContains(m.StoreId, data.StoreId)) &&
			(len(m.CommodityName) == 0 || tools.StringSliceContains(m.CommodityName, data.CommodityName)) &&
			(len(m.CategoryID) == 0 || tools.Uint32SliceContains(categoryList, data.CategoryID)) &&
			(m.Type == 0 || m.Type == data.Type) &&
			((m.StartTime == "" && m.EndTime == "") || (data.StockTime.After(startTime) && data.StockTime.Before(endTime))) {
			nTotalAllotCount += data.Count
			nTotalAllotAmount += data.Amount

			filteredData = append(filteredData, data)
		}
	}

	// 使用排序规则函数对汇总数据进行排序
	sortSummaryList(filteredData)
	SortReportByOtherDataCommodities(filteredData)

	// 计算分页所需的切片索引
	startIndex := page * m.PageSize
	endIndex := (page + 1) * m.PageSize
	if endIndex > len(filteredData) {
		endIndex = len(filteredData)
	}

	resp.Total = len(filteredData)
	resp.TotalCount = nTotalAllotCount
	resp.TotalAmount = tools.RoundToTwoDecimalPlaces(nTotalAllotAmount)

	if m.IsExport == 1 {
		resp.List = filteredData
		resp.ExportUrl, err = reportOtherExport(resp)
		if err != nil {
			return nil, err
		}
		resp.List = []ReportByOtherData{}
		resp.TotalCount = 0
		resp.TotalAmount = 0
	} else {
		resp.List = filteredData[startIndex:endIndex]
	}

	return resp, nil
}

// 排序规则函数
// 排序规则：商品编号小＞门店编号小＞产品入库＞盘点入库＞系统出库＞盘点出库
func sortSummaryList(summaryList []ReportByOtherData) {
	sort.Slice(summaryList, func(i, j int) bool {
		//// 按 CommodityId 排序
		//if summaryList[i].CommodityId != summaryList[j].CommodityId {
		//	return summaryList[i].CommodityId < summaryList[j].CommodityId
		//}
		// 如果 CommodityId 相同，则按 StoreId 排序
		if summaryList[i].StoreId != summaryList[j].StoreId {
			return summaryList[i].StoreId < summaryList[j].StoreId
		}
		// 如果 StoreId 相同， 按 Type 排序
		if summaryList[i].Type != summaryList[j].Type {
			return summaryList[i].Type < summaryList[j].Type
		}
		// 如果 Type 相同，则按 Amount 排序
		return summaryList[i].Amount < summaryList[j].Amount
	})
}

// reportOtherExport 其他出入库汇总导出excel
func reportOtherExport(req *InventoryReportByOtherResp) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	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 inventoryType string
		switch reportData.Type {
		case 1:
			inventoryType = "产品入库"
		case 2:
			inventoryType = "盘点入库"
		case 3:
			inventoryType = "系统出库"
		case 4:
			inventoryType = "盘点出库"
		}

		row1 = []interface{}{
			reportData.StoreName,     // 门店
			reportData.CommodityName, // 商品名称
			reportData.CategoryName,  // 商品分类
			inventoryType,            // 出入库方式
			reportData.Count,         // 数量
			reportData.Amount,        // 金额
		}

		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.TotalCount, req.TotalAmount}
	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", 20)
	file.SetColWidth("Sheet1", "D", "D", 20)
	file.SetColWidth("Sheet1", "F", "F", 18)

	endRow := fmt.Sprintf("F"+"%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
}

// ReportByOtherDetailList 其他出入库明细
func (m *InventoryReportOtherDetailReq) ReportByOtherDetailList(c *gin.Context) (*InventoryReportOtherDetailResp, 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 &InventoryReportOtherDetailResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	resp := &InventoryReportOtherDetailResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	// 查询产品入库数据
	var err error
	var productList []ReportOtherDetailData
	productList, err = getProductOrderData(m.StoreId)
	if err != nil {
		return nil, err
	}

	// 查询盘点出入库数据
	var changeList []ReportOtherDetailData
	changeList, err = getChangeOrderData(m.StoreId)
	if err != nil {
		return nil, err
	}

	// 查询系统出库数据
	var systemList []ReportOtherDetailData
	systemList, err = getSystemOutData(m.StoreId)
	if err != nil {
		return nil, err
	}

	// 合并数据
	allData := append(productList, changeList...)
	allData = append(allData, systemList...)

	// 进行条件查询
	var startTime time.Time
	if m.StartTime != "" { // 出入库开始时间
		startTime, err = time.Parse(QueryTimeFormat, m.StartTime)
		if err != nil {
			logger.Errorf("ReportByOtherDetailList err:", err)
			return nil, err
		}
	}
	var endTime time.Time
	if m.EndTime != "" { // 出入库结束时间
		endTime, err = time.Parse(QueryTimeFormat, m.EndTime)
		if err != nil {
			logger.Errorf("ReportByOtherDetailList err:", err)
			return nil, err
		}
	}

	var totalPurchasePrice, totalEmployeePrice float64
	filteredData := make([]ReportOtherDetailData, 0)
	for i, data := range allData {
		if allData[i].CategoryID == 0 {
			// 添加分类信息
			commodityInfo, err := GetCommodity(data.CommodityId)
			if err != nil {
				logger.Error("SetCategory err:", logger.Field("err", err))
			}
			allData[i].CategoryID = commodityInfo.ErpCategoryId
			allData[i].CategoryName = commodityInfo.ErpCategoryName
		}

		if m.IMEI != "" {
			if data.IMEI == m.IMEI {
				if data.Type == 3 || data.Type == 4 { // 系统出库、盘点出库
					totalPurchasePrice -= allData[i].PurchasePrice
					totalEmployeePrice -= allData[i].EmployeePrice

					allData[i].PurchasePrice = -allData[i].PurchasePrice
					allData[i].EmployeePrice = -allData[i].EmployeePrice
				} else {
					totalPurchasePrice += allData[i].PurchasePrice
					totalEmployeePrice += allData[i].EmployeePrice
				}
				filteredData = append(filteredData, allData[i])
				break
			} else {
				continue
			}
		} else {
			var categoryList []uint32
			if len(m.CategoryID) != 0 {
				categoryList, err = TransformErpCategoryIds(m.CategoryID)
				if err != nil {
					return nil, err
				}
			}

			if (len(m.SerialNumber) == 0 || data.SerialNumber == m.SerialNumber) &&
				(len(m.StoreId) == 0 || tools.Uint32SliceContains(m.StoreId, data.StoreId)) &&
				(len(m.CommodityName) == 0 || tools.StringSliceContains(m.CommodityName, data.CommodityName)) &&
				(len(m.CategoryID) == 0 || tools.Uint32SliceContains(categoryList, allData[i].CategoryID)) &&
				(m.Type == 0 || m.Type == data.Type) &&
				((m.StartTime == "" && m.EndTime == "") || (data.StockTime.After(startTime) && data.StockTime.Before(endTime))) {
				if data.Type == 3 || data.Type == 4 { // 系统出库、盘点出库
					totalPurchasePrice -= allData[i].PurchasePrice
					totalEmployeePrice -= allData[i].EmployeePrice

					allData[i].PurchasePrice = -allData[i].PurchasePrice
					allData[i].EmployeePrice = -allData[i].EmployeePrice
				} else {
					totalPurchasePrice += allData[i].PurchasePrice
					totalEmployeePrice += allData[i].EmployeePrice
				}

				filteredData = append(filteredData, allData[i])
			}
		}
	}

	// 进行排序
	sort.Slice(filteredData, func(i, j int) bool {
		return filteredData[i].StockTime.After(*filteredData[j].StockTime)
	})

	resp.TotalPurchasePrice = tools.RoundToTwoDecimalPlaces(totalPurchasePrice)
	resp.TotalEmployeePrice = tools.RoundToTwoDecimalPlaces(totalEmployeePrice)

	if m.IsExport == 1 {
		resp.List = filteredData
		resp.Total = len(filteredData)
		resp.ExportUrl, err = reportOtherDetailExport(resp)
		if err != nil {
			return nil, err
		}
		resp.List = []ReportOtherDetailData{}
		resp.TotalPurchasePrice = 0
		resp.TotalEmployeePrice = 0
	} else {
		// 进行分页处理
		startIndex := page * m.PageSize
		endIndex := startIndex + m.PageSize
		if endIndex > len(filteredData) {
			endIndex = len(filteredData)
		}
		resp.List = filteredData[startIndex:endIndex]
		resp.Total = len(filteredData)
	}

	return resp, nil
}

// 查询产品入库数据
func getProductOrderData(storeList []uint32) ([]ReportOtherDetailData, error) {
	var productList []ReportOtherDetailData

	//err := orm.Eloquent.Debug().Table("erp_inventory_product_order").
	//	Select("erp_inventory_product_order.serial_number, "+
	//		"erp_inventory_product_order.store_id, "+
	//		"erp_inventory_product_order.store_name, "+
	//		"erp_inventory_product_order.audit_time as stock_time, "+
	//		"CASE "+
	//		"WHEN erp_inventory_product_order.state = 2 THEN 1 "+
	//		"ELSE erp_inventory_product_order.state "+
	//		"END AS type, "+
	//		"erp_inventory_product_commodity.commodity_id, "+
	//		"erp_inventory_product_commodity.commodity_name, "+
	//		"erp_inventory_product_commodity.supplier_id, "+
	//		"erp_inventory_product_commodity.supplier_name, "+
	//		"erp_inventory_product_commodity.imei_type, "+
	//		"erp_inventory_product_commodity.imei, "+
	//		"erp_inventory_product_commodity.price as purchase_price, "+
	//		"erp_inventory_product_commodity.employee_price as employee_price").
	//	Joins("JOIN erp_inventory_product_commodity "+
	//		"ON erp_inventory_product_commodity.product_order_id = erp_inventory_product_order.id").
	//	Where("erp_inventory_product_order.state = ?", ErpInventoryProductOrderFinished).
	//	Where("erp_inventory_product_order.store_id in ?", storeList).
	//	Find(&productList).Error // 查询已审核的订单

	qs := orm.Eloquent.Debug().Table("erp_inventory_product_order").
		Select("erp_inventory_product_order.serial_number, "+
			"erp_inventory_product_order.store_id, "+
			"erp_inventory_product_order.store_name, "+
			"erp_inventory_product_order.audit_time as stock_time, "+
			"CASE "+
			"WHEN erp_inventory_product_order.state = 2 THEN 1 "+
			"ELSE erp_inventory_product_order.state "+
			"END AS type, "+
			"erp_inventory_product_commodity.commodity_id, "+
			"erp_inventory_product_commodity.commodity_name, "+
			"erp_inventory_product_commodity.supplier_id, "+
			"erp_inventory_product_commodity.supplier_name, "+
			"erp_inventory_product_commodity.imei_type, "+
			"erp_inventory_product_commodity.imei, "+
			"erp_inventory_product_commodity.price as purchase_price, "+
			"erp_inventory_product_commodity.employee_price as employee_price").
		Joins("JOIN erp_inventory_product_commodity "+
			"ON erp_inventory_product_commodity.product_order_id = erp_inventory_product_order.id").
		Where("erp_inventory_product_order.state = ?", ErpInventoryProductOrderFinished)
	if len(storeList) > 0 {
		qs = qs.Where("erp_inventory_product_order.store_id in ?", storeList)
	}
	err := qs.Find(&productList).Error // 查询已审核的订单

	if err != nil {
		return nil, err
	}

	return productList, nil
}

// 查询盘点出入库数据
func getChangeOrderData(storeList []uint32) ([]ReportOtherDetailData, error) {
	var changeList []ReportOtherDetailData

	//err := orm.Eloquent.Debug().Table("erp_inventory_change_order").
	//	Select("erp_inventory_change_order.serial_number, "+
	//		"erp_inventory_change_order.store_id, "+
	//		"erp_inventory_change_order.store_name, "+
	//		"erp_inventory_change_order.audit_time as stock_time, "+
	//		"CASE "+
	//		"WHEN erp_inventory_change_order.change_type = 'add' THEN 2 "+
	//		"WHEN erp_inventory_change_order.change_type = 'reduce' THEN 4 "+
	//		"ELSE erp_inventory_change_order.state "+
	//		"END AS type, "+
	//		"erp_inventory_change_commodity.commodity_id, "+
	//		"erp_inventory_change_commodity.commodity_name, "+
	//		"erp_inventory_change_commodity.supplier_id, "+
	//		"erp_inventory_change_commodity.supplier_name, "+
	//		"erp_inventory_change_commodity.imei_type, "+
	//		"erp_inventory_change_commodity.imei, "+
	//		"erp_inventory_change_commodity.price as purchase_price, "+
	//		"erp_inventory_change_commodity.employee_price as employee_price").
	//	Joins("JOIN erp_inventory_change_commodity "+
	//		"ON erp_inventory_change_commodity.change_order_id = erp_inventory_change_order.id").
	//	Where("erp_inventory_change_order.state = ?", ErpInventoryChangeOrderFinished).
	//	Where("erp_inventory_change_order.store_id in ?", storeList).
	//	Find(&changeList).Error // 查询已审核的订单

	qs := orm.Eloquent.Debug().Table("erp_inventory_change_order").
		Select("erp_inventory_change_order.serial_number, "+
			"erp_inventory_change_order.store_id, "+
			"erp_inventory_change_order.store_name, "+
			"erp_inventory_change_order.audit_time as stock_time, "+
			"CASE "+
			"WHEN erp_inventory_change_order.change_type = 'add' THEN 2 "+
			"WHEN erp_inventory_change_order.change_type = 'reduce' THEN 4 "+
			"ELSE erp_inventory_change_order.state "+
			"END AS type, "+
			"erp_inventory_change_commodity.commodity_id, "+
			"erp_inventory_change_commodity.commodity_name, "+
			"erp_inventory_change_commodity.supplier_id, "+
			"erp_inventory_change_commodity.supplier_name, "+
			"erp_inventory_change_commodity.imei_type, "+
			"erp_inventory_change_commodity.imei, "+
			"erp_inventory_change_commodity.price as purchase_price, "+
			"erp_inventory_change_commodity.employee_price as employee_price").
		Joins("JOIN erp_inventory_change_commodity "+
			"ON erp_inventory_change_commodity.change_order_id = erp_inventory_change_order.id").
		Where("erp_inventory_change_order.state = ?", ErpInventoryChangeOrderFinished)

	if len(storeList) > 0 {
		qs = qs.Where("erp_inventory_change_order.store_id in ?", storeList)
	}
	err := qs.Find(&changeList).Error // 查询已审核的订单

	if err != nil {
		return nil, err
	}

	return changeList, nil
}

// 查询系统出库数据
func getSystemOutData(storeList []uint32) ([]ReportOtherDetailData, error) {
	var stockCommodities []ErpStockCommodity

	//err := orm.Eloquent.Table("erp_stock_commodity").
	//	Where("state = ?", SystemOut).
	//	Where("store_id in ?", storeList).
	//	Find(&stockCommodities).Error

	qs := orm.Eloquent.Table("erp_stock_commodity").
		Where("state = ?", SystemOut)
	if len(storeList) > 0 {
		qs = qs.Where("store_id in ?", storeList)
	}
	err := qs.Find(&stockCommodities).Error
	if err != nil {
		return nil, err
	}

	var systemOutList []ReportOtherDetailData
	for i, item := range stockCommodities {
		var systemOutData ReportOtherDetailData
		systemOutData.CommodityId = item.ErpCommodityId
		systemOutData.CommodityName = item.ErpCommodityName
		systemOutData.CategoryID = item.ErpCategoryId
		systemOutData.CategoryName = item.ErpCategoryName
		systemOutData.IMEIType = item.IMEIType
		systemOutData.IMEI = item.IMEI
		systemOutData.StoreId = item.StoreId
		systemOutData.StoreName = item.StoreName
		systemOutData.SupplierId = item.ErpSupplierId
		systemOutData.SupplierName = item.ErpSupplierName
		systemOutData.StockTime = &stockCommodities[i].UpdatedAt
		systemOutData.Type = 3
		systemOutData.PurchasePrice = item.WholesalePrice
		systemOutData.EmployeePrice = item.WholesalePrice + item.StaffCostPrice

		systemOutList = append(systemOutList, systemOutData)
	}

	return systemOutList, nil
}

// reportOtherDetailExport 其他出入库明细导出excel
func reportOtherDetailExport(req *InventoryReportOtherDetailResp) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	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 inventoryType string
		switch reportData.Type {
		case 1:
			inventoryType = "产品入库"
		case 2:
			inventoryType = "盘点入库"
		case 3:
			inventoryType = "系统出库"
		case 4:
			inventoryType = "盘点出库"
		}

		var IMEIType string
		switch reportData.IMEIType {
		case 1:
			IMEIType = "非串码"
		case 2, 3:
			IMEIType = "串码类"
		}

		var auditTime string
		if reportData.StockTime != nil {
			auditTime = reportData.StockTime.Format(TimeFormat)
		}

		row1 = []interface{}{
			reportData.CommodityName, // 商品名称
			reportData.CategoryName,  // 商品分类
			IMEIType,                 // 是否串码
			reportData.IMEI,          // 商品串码
			reportData.StoreName,     // 所属门店
			reportData.SupplierName,  // 供应商
			auditTime,                // 出/入库时间
			inventoryType,            // 方式
			reportData.SerialNumber,  // 单据编号
			reportData.PurchasePrice, // 入库采购价
			reportData.EmployeePrice, // 入库员工成本价
		}

		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.TotalPurchasePrice, req.TotalEmployeePrice}
	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", 15)
	file.SetColWidth("Sheet1", "D", "D", 18)
	file.SetColWidth("Sheet1", "E", "E", 28)
	file.SetColWidth("Sheet1", "G", "G", 18)
	file.SetColWidth("Sheet1", "I", "I", 18)
	file.SetColWidth("Sheet1", "J", "J", 18)
	file.SetColWidth("Sheet1", "K", "K", 18)

	endRow := fmt.Sprintf("K"+"%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
}
