package models

import (
	"encoding/json"
	"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"
	"log"
	"math"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	ErpPurchaseOrderUnAudit       = 1 // 待审核
	ErpPurchaseOrderWaitInventory = 2 // 待入库
	ErpPurchaseOrderWaitReject    = 3 // 待退货
	ErpPurchaseOrderFinished      = 4 // 已完成
	ErpPurchaseOrderEnd           = 5 // 已终止
	ErpPurchaseOrderOperation     = 6 // 操作中

	ErpProcureOrder = "procure" // 采购入库订单
	ErpRejectOrder  = "reject"  // 采购退货订单

	ErpDemandStateWait   = 1 // 待采购
	ErpDemandStateFinish = 2 // 完成采购

	ErpPurchaseChangeOrderUnAudit  = 1 // 采购换机-待审核
	ErpPurchaseChangeOrderFinished = 2 // 采购换机-已完成
)

// ErpPurchaseOrder 采购订单表
type ErpPurchaseOrder struct {
	Model
	SerialNumber         string                 `json:"serial_number" gorm:"index"`   // 单据编号
	PurchaseType         string                 `json:"purchase_type"`                // 类型:procure-采购 reject-退货
	StoreId              uint32                 `json:"store_id" gorm:"index"`        // 门店id
	StoreName            string                 `json:"store_name"`                   // 门店名称
	ErpSupplierId        uint32                 `json:"erp_supplier_id" gorm:"index"` // 供应商id
	ErpSupplierName      string                 `json:"erp_supplier_name"`            // 供应商名称
	HandlerId            uint32                 `json:"handler_id" gorm:"index"`      // 经手人id
	HandlerName          string                 `json:"handler_name"`                 // 经手人名称
	MakerTime            *time.Time             `json:"maker_time"`                   // 制单时间
	MakerId              uint32                 `json:"maker_id" gorm:"index"`        // 制单人id
	MakerName            string                 `json:"maker_name"`                   // 制单人名称
	AuditTime            *time.Time             `json:"audit_time"`                   // 审核时间
	AuditorId            uint32                 `json:"auditor_id" gorm:"index"`      // 审核人id
	AuditorName          string                 `json:"auditor_name"`                 // 审核人名称
	State                uint32                 `json:"state"`                        // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 6-操作中
	RejectedSerialNumber string                 `json:"rejected_serial_number"`       // 退货的采购订单单据编号
	ErpCashierId         uint32                 `json:"erp_cashier_id"`               // 付款方式/收款方式id
	ErpCashierName       string                 `json:"erp_cashier_name"`             // 付款方式/收款方式名称
	AccountHolder        string                 `json:"account_holder"`               // 收款人
	OpeningBank          string                 `json:"opening_bank"`                 // 开户行
	BankAccount          string                 `json:"bank_account"`                 // 银行卡号
	DeliveryTime         string                 `json:"delivery_time"`                // 交货日期，如：2024-02-23
	DeliveryAddress      string                 `json:"delivery_address"`             // 交货地址
	Remark               string                 `json:"remark"`                       // 备注
	Commodities          []ErpPurchaseCommodity `json:"commodities" gorm:"-"`         //
	InventoryId          uint32                 `json:"inventory_id" gorm:"-"`        // 最近入库人id
	InventoryName        string                 `json:"inventory_name" gorm:"-"`      // 最近入库人名称
	Amount               float64                `json:"amount" gorm:"-"`              // 计划采购金额
}

// ErpPurchaseCommodity 采购订单商品表
type ErpPurchaseCommodity struct {
	Model
	ErpPurchaseOrderId     uint32  `json:"erp_purchase_order_id" gorm:"index"`   // 采购订单id
	ErpCommodityId         uint32  `json:"erp_commodity_id" gorm:"index"`        // 商品id
	ErpCommodityName       string  `json:"erp_commodity_name"`                   // 商品名称
	CommoditySerialNumber  string  `json:"commodity_serial_number" gorm:"index"` // 商品编号
	IMEIType               uint32  `json:"imei_type"`                            // 1-无串码 2-串码
	IMEI                   string  `json:"imei"`                                 // 商品串码
	RetailPrice            float64 `json:"retail_price"`                         // 指导零售价
	Count                  uint32  `json:"count"`                                // 计划采购数量
	Price                  float64 `json:"price"`                                // 计划采购单价
	Amount                 float64 `json:"amount"`                               // 计划采购金额
	Remark                 string  `json:"remark"`                               // 备注
	RejectedPrice          float64 `json:"rejected_price"`                       // 计划退货单价
	RejectedCount          uint32  `json:"rejected_count"`                       // 计划退货数量
	RejectedAmount         float64 `json:"rejected_amount"`                      // 计划退货金额
	InventoryCount         int32   `json:"inventory_count"`                      // 入库数量（=执行数量）
	ExecutionCount         uint32  `json:"execute_count" gorm:"-"`               // 执行数量
	ExecutionPrice         float64 `json:"execute_price" gorm:"-"`               // 平均采购单价
	ExecutionEmployeePrice float64 `json:"execute_employee_price" gorm:"-"`      // 平均员工成本价
	ExecutionAmount        float64 `json:"execute_amount" gorm:"-"`              // 执行金额
	DefaultEmployeePrice   float64 `json:"default_employee_price" gorm:"-"`      // 默认员工成本价
	EffectiveCount         uint32  `json:"effective_count" gorm:"-"`             // 有效数量（该商品实际库存详情处剩余有效数，不包含已出库的数量）
	ErpCategoryID          uint32  `json:"erp_category_id" gorm:"-"`             // 商品分类id
	ErpCategoryName        string  `json:"erp_category_name" gorm:"-"`           // 商品分类名称
}

// ErpPurchaseInventory 采购入库执行信息
type ErpPurchaseInventory struct {
	Model
	ErpPurchaseOrderId     uint32  `json:"erp_purchase_order_id" gorm:"index"`     // 商品采购订单id
	ErpPurchaseCommodityId uint32  `json:"erp_purchase_commodity_id" gorm:"index"` // 采购订单商品表id
	PurchaseType           string  `json:"purchase_type" binding:"required"`       // 采购类型:procure-采购 reject-退货
	SerialNumber           string  `json:"serial_number" gorm:"index"`             // 入库编号
	ErpCommodityId         uint32  `json:"erp_commodity_id" gorm:"index"`          // 商品id
	ErpCommodityName       string  `json:"erp_commodity_name"`                     // 商品名称
	CommoditySerialNumber  string  `json:"commodity_serial_number" gorm:"index"`   // 商品编号
	ErpCategoryID          uint32  `json:"erp_category_id"  gorm:"index"`          // 商品分类id
	ErpCategoryName        string  `json:"erp_category_name"`                      // 商品分类名称
	IMEIType               uint32  `json:"imei_type"`                              // 1-无串码 2-串码（系统生成） 3-串码（手动添加）
	IMEI                   string  `json:"imei"`                                   // 商品串码
	Price                  float64 `json:"price" gorm:"-"`                         // 计划采购单价
	Count                  uint32  `json:"count"`                                  // 执行数量
	ImplementationPrice    float64 `json:"implementation_price"`                   // 执行单价
	Amount                 float64 `json:"amount"`                                 // 执行金额
	EmployeePrice          float64 `json:"employee_price"`                         // 员工成本价
	InventoryId            uint32  `json:"inventory_id"`                           // 最近入库人id
	InventoryName          string  `json:"inventory_name"`                         // 最近入库人名称
	ErpStockCommodityID    uint32  `json:"erp_stock_commodity_id"`                 // 库存商品表主键id
}

// ErpPurchaseCreateReq 新建采购订单入参
type ErpPurchaseCreateReq struct {
	PurchaseType           string                 `json:"purchase_type" binding:"required"`          // 采购类型：procure-采购 reject-退货
	PurchaseOrderSn        string                 `json:"purchase_order_sn"`                         // 采购退货订单号:出库必传
	StoreId                uint32                 `json:"store_id"`                                  // 门店id:入库必传
	DeliveryAddress        string                 `json:"delivery_address"`                          // 交货地址
	HandlerId              uint32                 `json:"handler_id" binding:"required"`             // 经手人id
	HandlerName            string                 `json:"handler_name"`                              // 经手人名称
	ErpSupplierId          uint32                 `json:"erp_supplier_id"`                           // 供应商id:入库必传
	ErpCashierId           uint32                 `json:"erp_cashier_id"`                            // 付款方式
	AccountHolder          string                 `json:"account_holder"`                            // 收款人
	OpeningBank            string                 `json:"opening_bank"`                              // 开户行
	BankAccount            string                 `json:"bank_account" `                             // 银行卡号
	DeliveryTime           string                 `json:"delivery_time" `                            // 交货日期
	Remark                 string                 `json:"remark"`                                    // 备注
	ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodity" binding:"required"` // 采购商品信息
}

// ErpPurchaseEditReq 编辑采购订单入参
type ErpPurchaseEditReq struct {
	ErpPurchaseOrderId     uint32                 `json:"erp_purchase_order_id" binding:"required"`  // 采购订单id
	PurchaseType           string                 `json:"purchase_type" binding:"required"`          // 采购类型：procure-采购 reject-退货
	PurchaseOrderSn        string                 `json:"purchase_order_sn"`                         // 采购退货订单号:出库必传
	StoreId                uint32                 `json:"store_id"`                                  // 门店id:入库必传
	DeliveryAddress        string                 `json:"delivery_address"`                          // 交货地址
	HandlerId              uint32                 `json:"handler_id" binding:"required"`             // 经手人id
	HandlerName            string                 `json:"handler_name"`                              // 经手人名称
	ErpSupplierId          uint32                 `json:"erp_supplier_id"`                           // 供应商id:入库必传
	ErpCashierId           uint32                 `json:"erp_cashier_id"`                            // 付款方式
	AccountHolder          string                 `json:"account_holder"`                            // 收款人
	OpeningBank            string                 `json:"opening_bank"`                              // 开户行
	BankAccount            string                 `json:"bank_account" `                             // 银行卡号
	DeliveryTime           string                 `json:"delivery_time"`                             // 交货日期
	Remark                 string                 `json:"remark"`                                    // 备注
	ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodity" binding:"required"` // 采购商品信息
}

// ErpPurchaseOrderListReq 查询采购订单列表入参
type ErpPurchaseOrderListReq struct {
	SerialNumber   string   `json:"serial_number"`    // 单据编号
	PurchaseType   string   `json:"purchase_type"`    // 采购类型：procure-采购 reject-退货
	StoreId        uint32   `json:"store_id"`         // 门店id
	ErpSupplierId  uint32   `json:"erp_supplier_id"`  // 供应商id
	MakeTimeStart  string   `json:"make_time_start"`  // 制单开始时间
	MakeTimeEnd    string   `json:"make_time_end"`    // 制单结束时间
	AuditTimeStart string   `json:"audit_time_start"` // 审核开始时间
	AuditTimeEnd   string   `json:"audit_time_end"`   // 审核结束时间
	AuditFlag      string   `json:"audit_flag"`       // 审核标记（默认展示所有）：ON-订单只展示已审核的采购入库订单，含待入库/已终止/已完成/入库中
	State          []uint32 `json:"state"`            // 状态：1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
	HandlerId      uint32   `json:"handler_id"`       // 经手人id
	PageIndex      int      `json:"pageIndex"`        // 页码
	PageSize       int      `json:"pageSize"`         // 页面条数
}

// ErpPurchaseOrderListResp 查询采购订单列表出参
type ErpPurchaseOrderListResp struct {
	List      []ErpPurchaseOrder `json:"list"`
	Total     int                `json:"total"`     // 总条数
	PageIndex int                `json:"pageIndex"` // 页码
	PageSize  int                `json:"pageSize"`  // 页面条数
}

// ErpPurchaseDetailReq 查询采购订单详情入参
type ErpPurchaseDetailReq struct {
	ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
}

// ErpPurchaseInventoryReq 入库（退货）入参
type ErpPurchaseInventoryReq struct {
	ErpPurchaseOrderId uint32                 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
	PurchaseType       string                 `json:"purchase_type" binding:"required"`         // 采购类型:procure-采购 reject-退货
	InventoryId        uint32                 `json:"inventory_id"`                             // 最近入库人id
	InventoryName      string                 `json:"inventory_name"`                           // 最近入库人名称
	Inventories        []ErpPurchaseInventory `json:"inventories" binding:"required"`           // 采购入库执行信息
}

// ErpPurchaseExecuteReq 执行（入库/退货）入参
type ErpPurchaseExecuteReq struct {
	ErpPurchaseOrderId uint32                 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
	PurchaseType       string                 `json:"purchase_type" binding:"required"`         // 采购类型:procure-采购 reject-退货
	Inventories        []ErpPurchaseInventory `json:"inventories" binding:"required"`           // 采购入库执行信息
}

// ErpPurchaseAuditReq 审核采购订单入参
type ErpPurchaseAuditReq struct {
	SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
	State        int    `json:"state"  binding:"required"`        // 审核操作: 1-审核 2-取消审核
}

// ErpPurchaseTerminateReq 终止采购入参
type ErpPurchaseTerminateReq struct {
	SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
	Remark       string `json:"remark"  binding:"required"`       // 备注
}

// ErpPurchaseDeleteReq 删除采购单入参
type ErpPurchaseDeleteReq struct {
	SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
}

// ErpPurchaseExecuteResp 执行（入库/退货）出参
type ErpPurchaseExecuteResp struct {
	List  []ExecuteData `json:"list"`
	Total int           `json:"total"` // 总条数
}

// ExecuteData 库存执行数据
type ExecuteData struct {
	ErpPurchaseOrderId     uint32  `json:"erp_purchase_order_id" gorm:"index"`     // 商品采购订单id
	ErpPurchaseCommodityId uint32  `json:"erp_purchase_commodity_id" gorm:"index"` // 采购订单商品表id
	ErpCommodityId         uint32  `json:"erp_commodity_id" gorm:"index"`          // 商品id
	ErpCommodityName       string  `json:"erp_commodity_name"`                     // 商品名称
	CommoditySerialNumber  string  `json:"commodity_serial_number" gorm:"index"`   // 商品编号
	IMEIType               uint32  `json:"imei_type"`                              // 1-无串码 2-串码
	IMEI                   string  `json:"imei"`                                   // 商品串码
	Price                  float64 `json:"price"`                                  // 计划采购单价
	Count                  uint32  `json:"count"`                                  // 数量
	ImplementationPrice    float64 `json:"implementation_price"`                   // 执行单价
	EmployeePrice          float64 `json:"employee_price"`                         // 员工成本价
}

// ErpPurchaseDemand 采购需求表
type ErpPurchaseDemand struct {
	Model
	ErpCommodityId           uint32     `json:"erp_commodity_id" gorm:"index"`   // 商品id
	ErpCommoditySerialNumber string     `json:"erp_commodity_serial_number"`     // 商品编号
	ErpCommodityName         string     `json:"erp_commodity_name" gorm:"index"` // 商品名称
	ErpSupplierId            uint32     `json:"erp_supplier_id"  gorm:"index"`   // 主供应商id
	StoreId                  uint32     `json:"store_id"`                        // 门店id
	StoreName                string     `json:"store_name"`                      // 门店名称
	Count                    uint32     `json:"count"`                           // 需采购数量
	State                    uint32     `json:"state"`                           // 1-待采购 2-已采购
	MakerId                  uint32     `json:"maker_id"`                        // 制单人id
	FinishTime               *time.Time `json:"finish_time"`                     // 完成采购时间
	//PurchaserId              uint32     `json:"purchaser_id"`                    // 采购人id
	//Remark                   string     `json:"remark"`                          // 备注
}

// ErpPurchaseDemandRemark 采购需求备注表
type ErpPurchaseDemandRemark struct {
	Model
	ErpCommodityId uint32     `json:"erp_commodity_id" gorm:"index"` // 商品id
	State          uint32     `json:"state"`                         // 1-待采购 2-已采购
	MakerId        uint32     `json:"maker_id"`                      // 制单人id
	FinishTime     *time.Time `json:"finish_time"`                   // 完成采购时间
	Remark         string     `json:"remark"`                        // 备注
}

// GetErpPurchaseDemandReq 获取采购需求入参
type GetErpPurchaseDemandReq struct {
	ErpSupplierId            uint32   `json:"erp_supplier_id"`             // 主供应商id
	ErpCategoryId            uint32   `json:"erp_category_id"`             // 商品分类id
	ErpCommoditySerialNumber string   `json:"erp_commodity_serial_number"` // 商品编号
	ErpCommodityName         string   `json:"erp_commodity_name"`          // 商品名称
	StoreId                  []uint32 `json:"store_id"`                    // 门店id
	HideFlag                 string   `json:"hide_flag"`                   // 隐藏标记（默认关闭）：ON-开启，隐藏无采购需求的商品，OFF-关闭，展示所有
	PageIndex                int      `json:"pageIndex"`                   // 页码
	PageSize                 int      `json:"pageSize"`                    // 每页展示数据条数
	IsExport                 uint32   `json:"is_export"`                   // 1-导出
	CallType                 int      `json:"call_type"`                   // 调用类型：1-采购视角；2-店员视角
	SortField                string   `json:"sort_field"`                  // 排序字段：主供应商 erp_supplier_id； 商品编号 erp_commodity_serial_number
	SortType                 string   `json:"sort_type"`                   // 排序类型：desc 降序、asc 升序
}

// DemandData 采购需求数据
type DemandData struct {
	ErpSupplierId            uint32  `json:"erp_supplier_id"`             // 主供应商id
	ErpSupplierName          string  `json:"erp_supplier_name" gorm:"-"`  // 主供应商名称
	ErpCommodityID           uint32  `json:"erp_commodity_id"`            // 商品id
	ErpCommoditySerialNumber string  `json:"erp_commodity_serial_number"` // 商品编号
	ErpCommodityName         string  `json:"erp_commodity_name"`          // 商品名称
	ErpCategoryID            uint32  `json:"erp_category_id"`             // 商品分类id
	ErpCategoryName          string  `json:"erp_category_name"`           // 商品分类名称
	ErpManufacturerCode      string  `json:"erp_manufacturer_code"`       // 商品厂家编码
	Img                      string  `json:"img"`                         // 图片
	RetailPrice              float64 `json:"retail_price"`                // 指导零售价
	LastWholesalePrice       float64 `json:"last_wholesale_price"`        // 最近采购价
	TotalCount               uint32  `json:"total_count"`                 // 需采购总数量
	TotalAmount              float64 `json:"total_amount"`                // 需采购总金额
	Remark                   string  `json:"remark"`                      // 备注
	StoreList                []struct {
		StoreID        uint32 `json:"store_id"`         // 门店id
		StoreName      string `json:"store_name"`       // 门店名称
		LastMonthSales uint32 `json:"last_month_sales"` // 上月销售数
		LastWeekSales  uint32 `json:"last_week_sales"`  // 上周销售数
		StockCount     uint32 `json:"stock_count"`      // 库存数量
		NeedCount      uint32 `json:"need_count"`       // 需采购数
	} `json:"store_list"`
}

// GetErpPurchaseDemandResp 获取采购需求出参
type GetErpPurchaseDemandResp struct {
	List      []DemandData `json:"list"`
	Total     int64        `json:"total"`      // 数据总条数
	PageIndex int          `json:"pageIndex"`  // 页码
	PageSize  int          `json:"pageSize"`   // 每页展示条数
	ExportUrl string       `json:"export_url"` // 文件路径
}

// CreateErpPurchaseDemandReq 创建采购需求入参
type CreateErpPurchaseDemandReq struct {
	ErpCommodityID           uint32 `json:"erp_commodity_id"`            // 商品id
	ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号
	ErpCommodityName         string `json:"erp_commodity_name"`          // 商品名称
	ErpSupplierId            uint32 `json:"erp_supplier_id"`             // 主供应商id
	Remark                   string `json:"remark"`                      // 备注
	List                     []struct {
		StoreID   uint32 `json:"store_id"`   // 门店id
		StoreName string `json:"store_name"` // 门店名称
		NeedCount uint32 `json:"need_count"` // 需采购数
	} `json:"list"`
}

// FinishErpPurchaseDemandReq 完成采购需求入参
type FinishErpPurchaseDemandReq struct {
	ErpCommodityID uint32 `json:"erp_commodity_id" binding:"required"` // 商品id
}

// ErpPurchaseReportByOrderReq 采购报表（按单）入参
type ErpPurchaseReportByOrderReq struct {
	SerialNumber       string   `json:"serial_number"`        // 单据编号
	PurchaseType       string   `json:"purchase_type"`        // 采购类型：procure-采购 reject-退货
	ErpCommodityName   string   `json:"erp_commodity_name"`   // 商品名称
	ErpCategoryID      uint32   `json:"erp_category_id"`      // 商品分类id
	StoreId            []uint32 `json:"store_id"`             // 门店id
	HandlerId          uint32   `json:"handler_id"`           // 经手人id
	ErpSupplierId      []uint32 `json:"erp_supplier_id"`      // 供应商id
	State              uint32   `json:"state"`                // 2-待入库 3-待退货 4-已完成 5-已终止
	AuditTimeStart     string   `json:"audit_time_start"`     // 审核开始时间
	AuditTimeEnd       string   `json:"audit_time_end"`       // 审核结束时间
	InventoryTimeStart string   `json:"inventory_time_start"` // 入库开始时间
	InventoryTimeEnd   string   `json:"inventory_time_end"`   // 入库结束时间
	IsExport           uint32   `json:"is_export"`            // 1-导出
	PageIndex          int      `json:"pageIndex"`            // 页码
	PageSize           int      `json:"pageSize"`             // 页面条数
}

// ErpPurchaseReportByOrderResp 采购报表（按单）出参
type ErpPurchaseReportByOrderResp struct {
	Total     int                 `json:"total"`      // 总条数
	PageIndex int                 `json:"pageIndex"`  // 页码
	PageSize  int                 `json:"pageSize"`   // 页面条数
	Amount    float64             `json:"amount"`     // 已执行金额
	Count     int32               `json:"count"`      // 已执行数量
	ExportUrl string              `json:"export_url"` // 导出excel路径
	List      []ReportByOrderData `json:"list"`       // 采购报表信息
}

type ReportByOrderData struct {
	CommonData
	State         uint32                     `json:"state"`          // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
	Remark        string                     `json:"remark"`         // 备注
	Amount        float64                    `json:"amount"`         // 已执行金额
	Price         float64                    `json:"price"`          // 执行单价
	Count         int32                      `json:"count"`          // 已执行数量
	CommodityData []ErpPurchaseCommodityData `json:"commodity_data"` // 商品信息
}

type CommodityData struct {
	ErpCommodityId   uint32 `json:"erp_commodity_id"`   // 商品id
	ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
	ErpCategoryID    uint32 `json:"erp_category_id"`    // 商品分类id
	ErpCategoryName  string `json:"erp_category_name"`  // 商品分类名称
}

type CommonData struct {
	ErpPurchaseOrderId uint32     `json:"erp_purchase_order_id"` // 采购订单id
	SerialNumber       string     `json:"serial_number"`         // 单据编号
	PurchaseType       string     `json:"purchase_type"`         // 单据类型:procure-采购 reject-退货
	StoreId            uint32     `json:"store_id"`              // 门店id
	StoreName          string     `json:"store_name"`            // 门店名称
	ErpSupplierId      uint32     `json:"erp_supplier_id"`       // 供应商id
	ErpSupplierName    string     `json:"erp_supplier_name"`     // 供应商名称
	HandlerId          uint32     `json:"handler_id"`            // 经手人id
	HandlerName        string     `json:"handler_name"`          // 经手人名称
	MakerTime          *time.Time `json:"maker_time"`            // 制单时间
	MakerId            uint32     `json:"maker_id"`              // 制单人id
	MakerName          string     `json:"maker_name"`            // 制单人名称
	AuditTime          *time.Time `json:"audit_time"`            // 审核时间
	AuditorId          uint32     `json:"auditor_id"`            // 审核人id
	AuditorName        string     `json:"auditor_name"`          // 审核人名称
}

// ErpPurchaseCommodityData 采购订单商品信息
type ErpPurchaseCommodityData struct {
	CommodityData
	Amount        float64    `json:"amount"`         // 已执行金额
	Price         float64    `json:"price"`          // 已执行单价
	Count         int32      `json:"count"`          // 已执行数量
	InventoryTime *time.Time `json:"inventory_time"` // 入库时间
}

// ErpPurchaseReportByCommodityReq 采购报表（按商品）入参
type ErpPurchaseReportByCommodityReq struct {
	SerialNumber     string   `json:"serial_number"`      // 单据编号
	PurchaseType     string   `json:"purchase_type"`      // 采购类型：procure-采购 reject-退货
	ErpCommodityName string   `json:"erp_commodity_name"` // 商品名称
	ErpCategoryID    uint32   `json:"erp_category_id"`    // 商品分类id
	StoreId          []uint32 `json:"store_id"`           // 门店id
	HandlerId        uint32   `json:"handler_id"`         // 经手人id
	ErpSupplierId    []uint32 `json:"erp_supplier_id"`    // 供应商id
	State            uint32   `json:"state"`              // 2-待入库 3-待退货 4-已完成 5-已终止
	AuditTimeStart   string   `json:"audit_time_start"`   // 审核开始时间
	AuditTimeEnd     string   `json:"audit_time_end"`     // 审核结束时间
	IsExport         uint32   `json:"is_export"`          // 1-导出
	PageIndex        int      `json:"pageIndex"`          // 页码
	PageSize         int      `json:"pageSize"`           // 页面条数
}

// ErpPurchaseReportByCommodityResp 采购报表（按商品）出参
type ErpPurchaseReportByCommodityResp struct {
	Total     int `json:"total"`     // 总条数
	PageIndex int `json:"pageIndex"` // 页码
	PageSize  int `json:"pageSize"`  // 页面条数
	PurchaseData
	ExportUrl string                  `json:"export_url"` // 导出excel路径
	List      []ReportByCommodityData `json:"list"`       // 采购报表信息
}

type ReportByCommodityData struct {
	CommodityData
	PurchaseData
	OrderInfo []ErpCommodityPurchaseOrderData `json:"order_info"` // 采购订单信息
}

// ErpCommodityPurchaseOrderData 采购商品的订单信息
type ErpCommodityPurchaseOrderData struct {
	CommonData
	PurchaseData
}

type TempData struct {
	CommodityData
	ErpCommodityPurchaseOrderData
}

// PurchaseData 采购金额和数量
type PurchaseData struct {
	OrderId            uint32  `json:"order_id"`             // 采购订单id
	PlanCount          int32   `json:"plan_count"`           // 计划采购数量
	PlanPrice          float64 `json:"plan_price"`           // 计划采购单价
	PlanAmount         float64 `json:"plan_amount"`          // 计划采购金额
	Amount             float64 `json:"amount"`               // 已执行金额
	Price              float64 `json:"price"`                // 已执行单价
	Count              int32   `json:"count"`                // 已执行数量
	NonExecutionAmount float64 `json:"non_execution_amount"` // 未执行金额
	NonExecutionCount  int32   `json:"non_execution_count"`  // 未执行数量
}

// ErpPurchaseReportBySupplierReq 供应商采购汇总入参
type ErpPurchaseReportBySupplierReq struct {
	PurchaseType     string   `json:"purchase_type"`      // 采购类型：procure-采购 reject-退货
	ErpCommodityName []string `json:"erp_commodity_name"` // 商品名称
	ErpCategoryID    []uint32 `json:"erp_category_id"`    // 商品分类id
	ErpSupplierId    []uint32 `json:"erp_supplier_id"`    // 供应商id
	StartTime        string   `json:"start_time"`         // 入/出库，开始时间
	EndTime          string   `json:"end_time"`           // 入/出库，结束时间
	IsExport         uint32   `json:"is_export"`          // 1-导出
	PageIndex        int      `json:"pageIndex"`          // 页码
	PageSize         int      `json:"pageSize"`           // 页面条数
	StoreList        []uint32 `json:"store_id"`           // 门店复选
}

// ErpPurchaseReportBySupplierResp 供应商采购汇总出参
type ErpPurchaseReportBySupplierResp struct {
	Total        int                  `json:"total"`         // 总条数
	PageIndex    int                  `json:"pageIndex"`     // 页码
	PageSize     int                  `json:"pageSize"`      // 页面条数
	Count        int32                `json:"count"`         // 采购数量
	Amount       float64              `json:"amount"`        // 采购金额
	RejectAmount float64              `json:"reject_amount"` // 退货金额
	Difference   float64              `json:"difference"`    // 差额
	ExportUrl    string               `json:"export_url"`    // 导出excel路径
	List         []PurchaseReportData `json:"list"`          // 供应商采购汇总信息
}

type PurchaseReportData struct {
	ErpPurchaseOrderId uint32  `json:"erp_purchase_order_id"`      // 采购订单id
	SerialNumber       string  `json:"serial_number" gorm:"index"` // 入库编号
	StoreId            uint32  `json:"store_id"`                   // 门店id
	StoreName          string  `json:"store_name"`                 // 门店名称
	PurchaseType       string  `json:"purchase_type"`              // 采购类型:procure-采购 reject-退货
	ErpSupplierId      uint32  `json:"erp_supplier_id"`            // 供应商id
	ErpSupplierName    string  `json:"erp_supplier_name"`          // 供应商名称
	ErpCommodityId     uint32  `json:"erp_commodity_id"`           // 商品id
	ErpCommodityName   string  `json:"erp_commodity_name"`         // 商品名称
	ErpCategoryID      uint32  `json:"erp_category_id"`            // 商品分类id
	ErpCategoryName    string  `json:"erp_category_name"`          // 商品分类名称
	Count              int32   `json:"count"`                      // 采购数量
	Amount             float64 `json:"amount"`                     // 采购金额
	RejectAmount       float64 `json:"reject_amount"`              // 退货金额
	Difference         float64 `json:"difference"`                 // 差额
}

// ErpPurchaseReportDetailReq 采购明细入参
type ErpPurchaseReportDetailReq struct {
	SerialNumber     string   `json:"serial_number"`      // 单据编号
	PurchaseType     string   `json:"purchase_type"`      // 采购类型：procure-采购 reject-退货
	ErpCommodityName string   `json:"erp_commodity_name"` // 商品名称
	ErpCategoryID    uint32   `json:"erp_category_id"`    // 商品分类id
	ErpSupplierId    uint32   `json:"erp_supplier_id"`    // 供应商id
	IMEI             string   `json:"imei"`               // 串码
	StartTime        string   `json:"startTime"`          // 入/出库，开始时间
	EndTime          string   `json:"endTime"`            // 入/出库，结束时间
	IsExport         uint32   `json:"is_export"`          // 1-导出
	PageIndex        int      `json:"pageIndex"`          // 页码
	PageSize         int      `json:"pageSize"`           // 页面条数
	StoreId          []uint32 `json:"store_id"`           // 门店id
}

// ErpPurchaseReportDetailResp 采购明细出参
type ErpPurchaseReportDetailResp struct {
	Total           int                `json:"total"`            // 总条数
	PageIndex       int                `json:"pageIndex"`        // 页码
	PageSize        int                `json:"pageSize"`         // 页面条数
	Price           float64            `json:"price"`            // 采购价
	EmployeePrice   float64            `json:"employee_price"`   // 员工成本价
	RejectPrice     float64            `json:"reject_price"`     // 退货价
	DifferencePrice float64            `json:"difference_price"` // 差价
	ExportUrl       string             `json:"export_url"`       // 导出excel路径
	List            []ReportDetailData `json:"list"`             // 采购明细信息
}

type ReportDetailData struct {
	ErpPurchaseOrderId uint32     `json:"erp_purchase_order_id"` // 采购订单id
	OrderSerialNumber  string     `json:"order_serial_number"`   // 单据编号
	SerialNumber       string     `json:"serial_number"`         // 采购入库编号
	PurchaseType       string     `json:"purchase_type"`         // 单据类型:procure-采购 reject-退货
	ExecuteTime        *time.Time `json:"execute_time"`          // 出/入库时间
	StoreId            uint32     `json:"store_id"`              // 门店id
	StoreName          string     `json:"store_name"`            // 门店名称
	ErpSupplierId      uint32     `json:"erp_supplier_id"`       // 供应商id
	ErpSupplierName    string     `json:"erp_supplier_name"`     // 供应商名称
	ErpCommodityId     uint32     `json:"erp_commodity_id"`      // 商品id
	ErpCommodityName   string     `json:"erp_commodity_name"`    // 商品名称
	ErpCategoryID      uint32     `json:"erp_category_id"`       // 商品分类id
	ErpCategoryName    string     `json:"erp_category_name"`     // 商品分类名称
	IMEIType           uint32     `json:"imei_type"`             // 1-无串码 2-串码
	IMEI               string     `json:"imei"`                  // 商品串码
	Price              float64    `json:"price"`                 // 采购价
	EmployeePrice      float64    `json:"employee_price"`        // 员工成本价
	RejectPrice        float64    `json:"reject_price"`          // 退货价
	DifferencePrice    float64    `json:"difference_price"`      // 差价
}

// List 查询采购订单列表
func (m *ErpPurchaseOrderListReq) List(c *gin.Context) (*ErpPurchaseOrderListResp, error) {
	resp := &ErpPurchaseOrderListResp{
		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.Table("erp_purchase_order")
	var stateList []int
	if m.AuditFlag == "ON" { //2-待入库 4-已完成 5-已终止 6-入库中
		stateList = []int{2, 4, 5, 6}
		qs = qs.Where("state IN ?", stateList)
		qs = qs.Where("purchase_type=?", ErpProcureOrder)
	}
	if m.SerialNumber != "" {
		qs = qs.Where("serial_number=?", m.SerialNumber)
	} else {
		if m.PurchaseType != "" {
			qs = qs.Where("purchase_type=?", m.PurchaseType)
		}
		if m.StoreId != 0 {
			qs = qs.Where("store_id=?", m.StoreId)
		}
		// 非管理员才判断所属门店
		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 {
				if len(storeList) == 1 {
					qs = qs.Where("store_id = ?", storeList[0])
				} else {
					qs = qs.Where("store_id IN (?)", storeList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
		if m.ErpSupplierId != 0 {
			qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId)
		}
		if len(m.State) > 0 {
			qs = qs.Where("state IN (?)", m.State)
		}
		if m.AuditTimeStart != "" {
			parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
			if err != nil {
				logger.Errorf("erpPurchaseOrderList err:", err)
				return nil, err
			}
			qs = qs.Where("audit_time > ?", parse)
		}
		if m.AuditTimeEnd != "" {
			parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
			if err != nil {
				logger.Errorf("erpPurchaseOrderList err:", err)
				return nil, err
			}
			//parse = parse.AddDate(0, 0, 1)
			qs = qs.Where("audit_time < ?", parse)
		}
		if m.MakeTimeStart != "" {
			parse, err := time.Parse(QueryTimeFormat, m.MakeTimeStart)
			if err != nil {
				logger.Errorf("err:", err)
			}
			qs = qs.Where("maker_time > ?", parse)
		}
		if m.MakeTimeEnd != "" {
			parse, err := time.Parse(QueryTimeFormat, m.MakeTimeEnd)
			if err != nil {
				logger.Errorf("err:", err)
			}
			//parse = parse.AddDate(0, 0, 1)
			qs = qs.Where("maker_time < ?", parse)
		}
		if m.HandlerId != 0 {
			qs = qs.Where("handler_id=?", m.HandlerId)
		}
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return resp, err
	}
	resp.Total = int(count)
	var orders []ErpPurchaseOrder
	err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
	if err != nil && err != RecordNotFound {
		logger.Error("erp commodity list err:", logger.Field("err", err))
		return resp, err
	}

	// 校验时间，如果为01-01-01 08:05，则赋值为空
	for i, v := range orders {
		if v.MakerTime != nil && v.MakerTime.IsZero() {
			orders[i].MakerTime = nil
		}

		if v.AuditTime != nil && v.AuditTime.IsZero() {
			orders[i].AuditTime = nil
		}

		nAmount, _ := getPurchaseOrderAmount(v.ID)
		orders[i].Amount = tools.RoundToTwoDecimalPlaces(nAmount)
	}

	resp.List = orders
	return resp, nil
}

func getPurchaseOrderAmount(purchaseOrderId uint32) (float64, error) {
	var amount float64
	err := orm.Eloquent.Table("erp_purchase_commodity").
		Where("erp_purchase_order_id = ?", purchaseOrderId).
		Pluck("sum(amount)", &amount).Error
	if err != nil {
		return 0, err
	}
	return amount, nil
}

// newErpPurchaseSn 生成采购订单号
func newErpPurchaseSn(purchaseType string) string {
	var prefix string
	switch purchaseType {
	case ErpProcureOrder: // 采购入库订单
		prefix = "cgr"
	case ErpRejectOrder: // 采购退货订单
		prefix = "cgt"
	}

	nowTime := time.Now()
	rand.Seed(nowTime.UnixNano())
	max := 1
	for {
		if max > 5 {
			logger.Error("create sn err")
			return ""
		}
		random := rand.Intn(9000) + 1000
		sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE "+
			"serial_number='%s'", prefix+sn))
		if err != nil {
			logger.Error("exist sn err")
		}
		if !exist {
			return prefix + sn
		}

		max++
	}
}

func ErpPurchaseCommodityListPerfectInfo(serialNumber string, purchaseCommodities []ErpPurchaseCommodity) error {
	commodityIds := make([]uint32, 0, len(purchaseCommodities))
	for i, _ := range purchaseCommodities {
		commodityIds = append(commodityIds, purchaseCommodities[i].ID)
	}
	commodityMap, err := GetErpCommodityMap(commodityIds)
	if err != nil {
		logger.Error("purchase commodities err:", logger.Field("err", err))
		return err
	}

	for i, _ := range purchaseCommodities {
		if serialNumber != "" { // 采购退货单才需判断
			// 查询入库商品实际库存详情处剩余有效数，不包含已出库的数量
			nCount, err := GetCommodityStockByPurchaseId(serialNumber, purchaseCommodities[i].ErpCommodityId)
			if err != nil {
				logger.Error("ErpPurchaseCommodityListPerfectInfo GetCommodityStockByPurchaseId err:", logger.Field("err", err))
				return err
			}
			// 如果库存数量不够则报错
			if nCount < purchaseCommodities[i].RejectedCount {
				return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量，请先零售退货", purchaseCommodities[i].ErpCommodityName)
			}
		}

		v, ok := commodityMap[purchaseCommodities[i].ErpCommodityId]
		if ok {
			purchaseCommodities[i].CommoditySerialNumber = v.SerialNumber
			purchaseCommodities[i].IMEIType = v.IMEIType
			//purchaseCommodities[i].IMEI = v.IMEI
			purchaseCommodities[i].ErpCommodityName = v.Name
			if purchaseCommodities[i].Count != 0 {
				purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price
			}
			if purchaseCommodities[i].RejectedCount != 0 {
				purchaseCommodities[i].RejectedAmount = float64(purchaseCommodities[i].RejectedCount) * purchaseCommodities[i].RejectedPrice
			}
		}
	}

	return nil
}

// IdInit 添加商户和供应商信息
func (m *ErpPurchaseOrder) IdInit() error {
	if m.StoreId != 0 {
		store, err := GetStore(m.StoreId)
		if err != nil {
			logger.Error("get store err:", logger.Field("err", err))
			return err
		}
		m.StoreName = store.Name
	}

	if m.ErpSupplierId != 0 {
		supplier, err := GetErpSupplier(m.ErpSupplierId)
		if err != nil {
			logger.Error("get supplier err:", logger.Field("err", err))
			return err
		}
		m.ErpSupplierName = supplier.Name
	}

	//cashier, err := GetAccountDetail(int(m.ErpCashierId))
	//if err != nil {
	//	logger.Error("get cashier err:", logger.Field("err", err))
	//	return err
	//}
	//m.ErpCashierName = cashier.Name

	// 根据字典填充付款方式
	var DictData DictData
	DictData.DictType = "purchase_pay_type"
	result, err := DictData.Get()
	if err != nil {
		return err
	}

	for _, item := range result {
		dictValue, _ := tools.StringToInt(item.DictValue)
		if int(m.ErpCashierId) == dictValue {
			m.ErpCashierName = item.DictLabel
			break
		}
	}
	return nil
}

//// GetPurchaseInventorySn 生成入库编号
//func GetPurchaseInventorySn() string {
//	count := 0
//	for {
//		if count > 5 {
//			return ""
//		}
//		nowTime := time.Now()
//		sn := nowTime.Format("060102")
//		sn += fmt.Sprintf("%d", nowTime.Unix()%100)
//		rand.Seed(nowTime.UnixNano())
//		sn += fmt.Sprintf("%d", rand.Int31n(100))
//		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_inventory WHERE serial_number='%s'", sn))
//		if err != nil {
//			logger.Error("sn err:", logger.Field("err", err))
//			count++
//			continue
//		}
//		if err == nil && !exist {
//			return sn
//		}
//		return ""
//	}
//}

var mu sync.Mutex

// GetPurchaseInventorySn generates a unique inventory serial number
func GetPurchaseInventorySn() string {
	const maxRetries = 5

	mu.Lock()
	defer mu.Unlock()

	for retryCount := 0; retryCount < maxRetries; retryCount++ {
		nowTime := time.Now()
		// 使用日期格式精确到天
		datePart := nowTime.Format("060102") // 格式为 YYMMDD
		// 生成10位随机数
		rand.Seed(nowTime.UnixNano() + int64(retryCount)) // 为了确保每次生成不同的随机数
		randomNum := rand.Int63n(1e10)                    // 10位随机数，范围从0到9999999999
		randomPart := fmt.Sprintf("%010d", randomNum)     // 确保随机数是10位的，前面补零

		// 拼接日期部分和随机数部分
		sn := fmt.Sprintf("%s%s", datePart, randomPart)

		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_inventory WHERE serial_number='%s'", sn))
		if err != nil {
			logger.Error("sn err:", logger.Field("err", err))
			continue
		}
		if !exist {
			return sn
		}
	}

	return "" // 返回空字符串，如果在最大重试次数后仍未找到唯一编号
}

// CheckCreateErpPurchaseOrderParam 新增采购订单-检查参数
func CheckCreateErpPurchaseOrderParam(req *ErpPurchaseCreateReq) error {
	if req.PurchaseType == ErpProcureOrder { // 采购入库订单
		if req.StoreId == 0 {
			return errors.New("操作失败:门店id为空")
		}
		//if req.DeliveryAddress == "" {
		//	return errors.New("操作失败:交货地址为空")
		//}
		if req.ErpSupplierId == 0 {
			return errors.New("操作失败:供应商id为空")
		}
		//if req.AccountHolder == "" {
		//	return errors.New("操作失败:收款人为空")
		//}
		//if req.OpeningBank == "" {
		//	return errors.New("操作失败:开户行为空")
		//}
		//if req.BankAccount == "" {
		//	return errors.New("操作失败:银行卡号为空")
		//}
		//if req.DeliveryTime == "" {
		//	return errors.New("操作失败:交货日期为空")
		//}
		for _, item := range req.ErpPurchaseCommodities {
			if item.Count <= 0 {
				return errors.New("操作失败:采购数量需大于0")
			}
		}
	} else if req.PurchaseType == ErpRejectOrder { // 退货单
		if req.PurchaseOrderSn == "" {
			return errors.New("操作失败:采购退货单据编号为空")
		}
		for _, item := range req.ErpPurchaseCommodities {
			if item.RejectedCount <= 0 {
				return errors.New("操作失败:采购退货数量需大于0")
			}
		}
	} else {
		return errors.New("操作失败:采购类型有误")
	}

	return nil
}

// CheckEditErpPurchaseOrderParam 编辑采购订单-检查参数
func CheckEditErpPurchaseOrderParam(req *ErpPurchaseEditReq) error {
	if req.PurchaseType == ErpProcureOrder { // 采购入库订单
		if req.StoreId == 0 {
			return errors.New("操作失败:门店id为空")
		}
		//if req.DeliveryAddress == "" {
		//	return errors.New("操作失败:交货地址为空")
		//}
		if req.ErpSupplierId == 0 {
			return errors.New("操作失败:供应商id为空")
		}
		//if req.AccountHolder == "" {
		//	return errors.New("操作失败:收款人为空")
		//}
		//if req.OpeningBank == "" {
		//	return errors.New("操作失败:开户行为空")
		//}
		//if req.BankAccount == "" {
		//	return errors.New("操作失败:银行卡号为空")
		//}
		//if req.DeliveryTime == "" {
		//	return errors.New("操作失败:交货日期为空")
		//}
	} else if req.PurchaseType == ErpRejectOrder { // 退货单
		if req.PurchaseOrderSn == "" {
			return errors.New("操作失败:采购退货单据编号为空")
		}
	} else {
		return errors.New("操作失败:采购类型有误")
	}

	return nil
}

// CreateErpPurchaseOrder 新增采购订单
func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
	var err error
	nowTime := time.Now()

	purchaseOrder := &ErpPurchaseOrder{}
	if req.PurchaseType == ErpProcureOrder { // 采购入库订单
		purchaseOrder = &ErpPurchaseOrder{
			SerialNumber:    newErpPurchaseSn(req.PurchaseType),
			PurchaseType:    req.PurchaseType,
			StoreId:         req.StoreId,
			ErpSupplierId:   req.ErpSupplierId,
			MakerTime:       &nowTime,
			HandlerId:       req.HandlerId,
			HandlerName:     req.HandlerName,
			MakerId:         uint32(sysUser.UserId),
			MakerName:       sysUser.NickName,
			State:           ErpPurchaseOrderUnAudit, // 1-待审核
			ErpCashierId:    req.ErpCashierId,
			AccountHolder:   req.AccountHolder,
			OpeningBank:     req.OpeningBank,
			BankAccount:     req.BankAccount,
			DeliveryTime:    req.DeliveryTime,
			DeliveryAddress: req.DeliveryAddress,
			Remark:          req.Remark,
		}
		err = purchaseOrder.IdInit()
	} else if req.PurchaseType == ErpRejectOrder { // 采购退货订单
		if req.PurchaseOrderSn == "" {
			return nil, errors.New("新建失败：采购退货订单号为空")
		}
		var erpPurchaseOrder ErpPurchaseOrder
		err = orm.Eloquent.Table("erp_purchase_order").Where("serial_number=?", req.PurchaseOrderSn).Find(&erpPurchaseOrder).Error
		if err != nil {
			logger.Error("purchase order err:", logger.Field("err", err))
			return nil, err
		}

		purchaseOrder = &ErpPurchaseOrder{
			SerialNumber:         newErpPurchaseSn(req.PurchaseType),
			PurchaseType:         req.PurchaseType,
			StoreId:              erpPurchaseOrder.StoreId,
			ErpSupplierId:        erpPurchaseOrder.ErpSupplierId,
			MakerTime:            &nowTime,
			HandlerId:            req.HandlerId,
			HandlerName:          req.HandlerName,
			MakerId:              uint32(sysUser.UserId),
			MakerName:            sysUser.NickName,
			State:                ErpPurchaseOrderUnAudit, // 1-待审核
			ErpCashierId:         req.ErpCashierId,
			Remark:               req.Remark,
			RejectedSerialNumber: req.PurchaseOrderSn,
		}
		err = purchaseOrder.IdInit()
	} else {
		logger.Errorf("purchase_type err:", req.PurchaseType)
		return nil, errors.New("操作失败:采购类型有误")
	}

	if err != nil {
		logger.Error("info err:", logger.Field("err", err))
		return nil, err
	}
	err = ErpPurchaseCommodityListPerfectInfo(req.PurchaseOrderSn, req.ErpPurchaseCommodities)
	if err != nil {
		logger.Error("info err:", logger.Field("err", err))
		return nil, err
	}
	begin := orm.Eloquent.Begin()
	err = begin.Create(purchaseOrder).Error
	if err != nil {
		begin.Rollback()
		logger.Error("create  purchase order err:", logger.Field("err", err))
		return nil, err
	}

	for i, _ := range req.ErpPurchaseCommodities {
		req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = purchaseOrder.ID
		req.ErpPurchaseCommodities[i].InventoryCount = 0 // todo 数量待核实
		err = begin.Create(&req.ErpPurchaseCommodities[i]).Error
		if err != nil {
			begin.Rollback()
			logger.Error("create purchase commodity err:", logger.Field("err", err))
			return nil, err
		}
	}
	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("commit purchase commodity err:", logger.Field("err", err))
		return nil, err
	}

	return purchaseOrder, nil
}

// EditErpPurchaseOrder 编辑采购订单
func EditErpPurchaseOrder(req *ErpPurchaseEditReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
	// 查询订单信息
	var purchaseOrder ErpPurchaseOrder
	err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
	if err != nil {
		logger.Error("purchase order err:", logger.Field("err", err))
		return nil, err
	}

	if purchaseOrder.State != ErpPurchaseOrderUnAudit { // 只有待审核的订单才能编辑
		return nil, errors.New("订单不是待审核状态")
	}

	if req.StoreId == 0 && req.PurchaseType == ErpProcureOrder {
		return nil, errors.New("操作失败:门店id为空")
	}

	begin := orm.Eloquent.Begin()
	// 1-更新采购订单信息
	purchaseOrder.StoreId = req.StoreId
	purchaseOrder.ErpSupplierId = req.ErpSupplierId
	purchaseOrder.HandlerId = req.HandlerId
	purchaseOrder.HandlerName = req.HandlerName
	purchaseOrder.MakerId = uint32(sysUser.UserId)
	purchaseOrder.MakerName = sysUser.NickName
	purchaseOrder.ErpCashierId = req.ErpCashierId
	purchaseOrder.AccountHolder = req.AccountHolder
	purchaseOrder.OpeningBank = req.OpeningBank
	purchaseOrder.BankAccount = req.BankAccount
	purchaseOrder.DeliveryTime = req.DeliveryTime
	purchaseOrder.DeliveryAddress = req.DeliveryAddress
	purchaseOrder.Remark = req.Remark
	err = purchaseOrder.IdInit()
	if err != nil {
		logger.Error("purchase IdInit err:", logger.Field("err", err))
		return nil, err
	}

	err = begin.Model(&ErpPurchaseOrder{}).Where("id = ?", req.ErpPurchaseOrderId).
		Omit("created_at").Save(purchaseOrder).Error
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_order err:", logger.Field("err", err))
		return nil, err
	}

	// 2-更新采购订单商品表
	err = updatePurchaseCommodityData(begin, req.ErpPurchaseOrderId, req)
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_purchase_commodity err:", logger.Field("err", err))
		return nil, err
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("commit err:", logger.Field("err", err))
		return nil, err
	}

	return &purchaseOrder, nil
}

// updatePurchaseCommodityData 更新采购订单商品信息
func updatePurchaseCommodityData(gdb *gorm.DB, orderId uint32, req *ErpPurchaseEditReq) error {
	// 查询现有的零售订单信息
	var commodities []ErpPurchaseCommodity
	err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error
	if err != nil {
		logger.Error("query erp_purchase_commodity err:", logger.Field("err", err))
		return err
	}

	// 1-删除所有的商品信息
	if len(commodities) != 0 {
		err = gdb.Delete(&commodities).Error
		if err != nil {
			logger.Error("更新商品订单信息-删除 error")
			return errors.New("操作失败:" + err.Error())
		}
	}

	for i, _ := range req.ErpPurchaseCommodities {
		req.ErpPurchaseCommodities[i].ID = 0
		if req.ErpPurchaseCommodities[i].ErpPurchaseOrderId == 0 { //发现前端有时会没传，后端打补丁
			req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = req.ErpPurchaseOrderId
		}
	}

	// 2-更新商品订单信息-新增
	if len(req.ErpPurchaseCommodities) != 0 {
		err = gdb.Create(&req.ErpPurchaseCommodities).Error
		if err != nil {
			logger.Error("更新商品订单信息-新增 error")
			return errors.New("操作失败:" + err.Error())
		}
	}

	return nil
}

// InventoryErpPurchase 采购订单入库
func InventoryErpPurchase(req *ErpPurchaseInventoryReq, c *gin.Context) error {
	// 查询采购订单信息
	var purchaseOrder ErpPurchaseOrder
	err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
	if err != nil {
		logger.Error("purchase order err:", logger.Field("err", err))
		return err
	}

	if purchaseOrder.PurchaseType == ErpProcureOrder {
		if purchaseOrder.State != ErpPurchaseOrderWaitInventory {
			return errors.New("操作失败：订单不是待入库状态")
		}
	}

	if purchaseOrder.PurchaseType == ErpRejectOrder {
		if purchaseOrder.State != ErpPurchaseOrderWaitReject {
			return errors.New("操作失败：订单不是待退货状态")
		}
	}

	// 校验入参门店是否包含在用户所有门店中，是否过期
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return err
		}

		if !CheckUserStore(purchaseOrder.StoreId, sysUser) {
			return errors.New("操作失败：您没有该门店权限")
		}
	}

	err = checkPurchaseInventory(req, true)
	if err != nil {
		logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
		return err
	}

	begin := orm.Eloquent.Begin()
	var inventoryList []ErpPurchaseInventory
	for i, v := range req.Inventories {
		req.Inventories[i].SerialNumber = v.SerialNumber
		// 更新采购商品表的执行数量
		// todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息，可能采购价不同，需要区分入库的是哪一条(已修改）
		err = begin.Model(&ErpPurchaseCommodity{}).
			//Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
			Where("id = ?", v.ErpPurchaseCommodityId).
			UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error
		if err != nil {
			begin.Rollback()
			logger.Error("update inventory count err:", logger.Field("err", err))
			return err
		}
		v.PurchaseType = req.PurchaseType   // 记录采购类型
		v.InventoryId = req.InventoryId     // 记录入库人id
		v.InventoryName = req.InventoryName // 记录入库人姓名

		nCount := v.Count
		nAmount := v.Amount
		for j := 0; j < int(nCount); j++ { // 采购入库记录表都是单笔数据
			if v.PurchaseType == ErpProcureOrder {
				v.SerialNumber = GetPurchaseInventorySn()
			} else {
				v.SerialNumber = purchaseOrder.SerialNumber
			}

			v.ID = 0
			v.Count = 1
			v.Amount = nAmount / float64(nCount) // 前端传的执行金额是总金额
			// 新建采购入库记录
			err = begin.Create(&v).Error
			if err != nil {
				begin.Rollback()
				logger.Error("create erp inventory commodity  err:", logger.Field("err", err))
				return err
			}
			inventoryList = append(inventoryList, v)
		}
	}

	// 更新库存信息表
	if purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单
		err = InventoryErpPurchaseUpdateStock(begin, inventoryList, purchaseOrder)
	} else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单
		err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder, false)
	} else {
		return errors.New("订单类型有误")
	}
	if err != nil {
		begin.Rollback()
		logger.Error("update stock  err:", logger.Field("err", err))
		return err
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("commit err:", logger.Field("err", err))
		return err
	}

	// 查询采购订单商品表入库或退库情况，如果都已经完成了，则更新采购订单的状态为：已完成
	_ = CheckAndUpdatePurchaseOrderState(req.ErpPurchaseOrderId)

	return nil
}

// CheckAndUpdatePurchaseOrderState
// 查询采购订单商品表入库或退库情况，如果都已经完成了，则更新采购订单的状态为：已完成
func CheckAndUpdatePurchaseOrderState(orderId uint32) error {
	var order ErpPurchaseOrder
	if err := orm.Eloquent.Where("id = ?", orderId).First(&order).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fmt.Errorf("purchase order with ID %d not found", orderId)
		}
		return err
	}

	if order.State == ErpPurchaseOrderFinished {
		return nil // Order is already marked as completed
	}

	var commodities []ErpPurchaseCommodity
	if err := orm.Eloquent.Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error; err != nil {
		return err
	}

	for _, commodity := range commodities {
		if order.PurchaseType == ErpProcureOrder && commodity.Count != uint32(commodity.InventoryCount) {
			if err := orm.Eloquent.Model(&order).Updates(map[string]interface{}{
				"state":      ErpPurchaseOrderWaitInventory,
				"updated_at": time.Now(),
			}).Error; err != nil {
				return err
			}
			return nil
		}
		if order.PurchaseType == ErpRejectOrder && commodity.RejectedCount != uint32(commodity.InventoryCount) {
			if err := orm.Eloquent.Model(&order).Updates(map[string]interface{}{
				"state":      ErpPurchaseOrderWaitReject,
				"updated_at": time.Now(),
			}).Error; err != nil {
				return err
			}
			return nil // Order not completed, exit early
		}
	}

	// If all commodities are checked and everything is in order, update the state to completed
	if err := orm.Eloquent.Model(&order).
		Updates(map[string]interface{}{
			"state":      ErpPurchaseOrderFinished,
			"updated_at": time.Now(),
		}).Error; err != nil {
		return err
	}

	return nil
}

// GetInventoryIdAndName 获取采购单最近入库人信息
func GetInventoryIdAndName(orderId uint32) (uint32, string, error) {
	var purchaseInventory ErpPurchaseInventory
	err := orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", orderId).
		Order("created_at DESC").First(&purchaseInventory).Error
	if err != nil {
		logger.Error("purchase order err:", logger.Field("err", err))
		return 0, "", err
	}

	return purchaseInventory.InventoryId, purchaseInventory.InventoryName, nil
}

// InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息
func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
	// 遍历采购入库商品信息
	var stockList []ErpStockCommodity
	var waitCreateStockList []ErpStock
	for _, v := range list {
		commodityInfo, err := GetCommodity(v.ErpCommodityId)
		if err != nil {
			logger.Errorf("GetCommodity err:", err)
			return err
		}
		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
			purchaseOrder.StoreId, v.ErpCommodityId))
		if err != nil {
			logger.Errorf("exist err:", err)
			return err
		}
		if exist {
			err = gdb.Exec(fmt.Sprintf(
				"UPDATE erp_stock SET count=count+%d WHERE  store_id=%d AND erp_commodity_id=%d",
				v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error
			if err != nil {
				logger.Errorf("update stock err:", err)
				return err
			}
		} else {
			// 如果同时入库多个商品，刚好之前又没有记录，则可能生成多条记录
			stock := ErpStock{
				StoreId:               purchaseOrder.StoreId,
				StoreName:             purchaseOrder.StoreName,
				ErpCommodityId:        v.ErpCommodityId,
				ErpCommodityName:      v.ErpCommodityName,
				ErpCategoryId:         commodityInfo.ErpCategoryId,
				ErpCategoryName:       commodityInfo.ErpCategoryName,
				CommoditySerialNumber: v.CommoditySerialNumber,
				IMEIType:              v.IMEIType,
				RetailPrice:           commodityInfo.RetailPrice,
				MinRetailPrice:        commodityInfo.MinRetailPrice,
				Count:                 v.Count,
				DispatchCount:         0,
			}

			waitCreateStockList = append(waitCreateStockList, stock)
			//err = gdb.Create(stock).Error
			//if err != nil {
			//	logger.Errorf("create stock err:", err)
			//	return err
			//}
		}

		nowTime := time.Now()
		stockCommodity := ErpStockCommodity{
			StoreId:               purchaseOrder.StoreId,
			StoreName:             purchaseOrder.StoreName,
			ErpCommodityId:        v.ErpCommodityId,
			ErpCommodityName:      v.ErpCommodityName,
			CommoditySerialNumber: v.CommoditySerialNumber,
			ErpCategoryId:         commodityInfo.ErpCategoryId,
			ErpCategoryName:       commodityInfo.ErpCategoryName,
			ErpSupplierId:         purchaseOrder.ErpSupplierId,
			ErpSupplierName:       purchaseOrder.ErpSupplierName,
			StaffCostPrice:        tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.ImplementationPrice),
			WholesalePrice:        tools.RoundToTwoDecimalPlaces(v.ImplementationPrice),
			State:                 InStock,
			StorageType:           PurchaseInventory, // 采购入库
			FirstStockTime:        nowTime,
			StockTime:             nowTime,
			Count:                 v.Count,
			ErpBarcode:            commodityInfo.ErpBarcode, // 240106新增商品条码
			IMEIType:              v.IMEIType,
			IMEI:                  v.IMEI,
			Remark:                "",
			MemberDiscount:        commodityInfo.MemberDiscount,
			MinRetailPrice:        commodityInfo.MinRetailPrice,
			RetailPrice:           commodityInfo.RetailPrice,
			OriginalSn:            purchaseOrder.SerialNumber,
			StockSn:               v.SerialNumber,
		}
		stockList = append(stockList, stockCommodity)
	}

	// 遍历库存信息，合并重复数据
	if len(waitCreateStockList) > 0 {
		newStockList := combineStocks(waitCreateStockList)
		err := gdb.Debug().Create(&newStockList).Error
		if err != nil {
			logger.Errorf("create erp_stock  err:", err)
			return err
		}
	}

	err := gdb.Debug().Create(&stockList).Error
	if err != nil {
		logger.Errorf("create erp_stock_commodity err:", err)
		return err
	}

	return nil
}

func combineStocks(waitCreateStockList []ErpStock) []ErpStock {
	// 创建一个map，用于存储相同 StoreId 和 ErpCommodityId 的库存信息
	stockMap := make(map[string]*ErpStock)

	// 遍历待处理的库存列表
	for _, stock := range waitCreateStockList {
		// 构建库存信息的唯一标识
		key := fmt.Sprintf("%d_%d", stock.StoreId, stock.ErpCommodityId)

		// 如果该库存信息已经存在于 map 中，则累加数量
		if existingStock, found := stockMap[key]; found {
			existingStock.Count += stock.Count
		} else {
			// 否则，将该库存信息添加到 map 中
			stockMap[key] = &ErpStock{
				StoreId:               stock.StoreId,
				StoreName:             stock.StoreName,
				ErpCommodityId:        stock.ErpCommodityId,
				ErpCommodityName:      stock.ErpCommodityName,
				ErpCategoryId:         stock.ErpCategoryId,
				ErpCategoryName:       stock.ErpCategoryName,
				CommoditySerialNumber: stock.CommoditySerialNumber,
				IMEIType:              stock.IMEIType,
				RetailPrice:           stock.RetailPrice,
				MinRetailPrice:        stock.MinRetailPrice,
				Count:                 stock.Count,
				DispatchCount:         stock.DispatchCount,
			}
		}
	}

	// 将 map 中的库存信息转换为列表
	var combinedStocks []ErpStock
	for _, stock := range stockMap {
		combinedStocks = append(combinedStocks, *stock)
	}

	return combinedStocks
}

// InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息
func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder,
	cancelFlag bool) error {
	usedStockCommodityIdList := make(map[uint32]bool)
	for i, _ := range list {
		if list[i].IMEIType == 2 || list[i].IMEIType == 3 { // 串码商品
			if list[i].IMEI == "" {
				return errors.New("串码为空")
			}

			// 判断该串码商品是否已经销售
			var stockCommodityInfo ErpStockCommodity
			err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI).
				Find(&stockCommodityInfo).Error
			if err != nil {
				logger.Error("Inventory RejectStock query commodities err:", logger.Field("err", err))
				return err
			}
			if stockCommodityInfo.State == SoldOut {
				return fmt.Errorf("商品[%s]已经销售，不能退货", stockCommodityInfo.ErpCommodityName)
			}
			//else if stockCommodityInfo.State == OnSale {
			//	return fmt.Errorf("商品[%s]在销售锁定中，不能退货", stockCommodityInfo.ErpCommodityName)
			//}

			orderState := PurchaseReturn
			if cancelFlag { // 反审核取消即可
				orderState = PurchaseCancel
			}

			err = gdb.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI).
				Updates(&map[string]interface{}{
					"state":      orderState,
					"stock_sn":   list[i].SerialNumber,
					"updated_at": time.Now(),
				}).Error // 状态更新为采购退货
			if err != nil {
				logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
				return err
			}

			err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
				purchaseOrder.StoreId, list[i].ErpCommodityId).
				Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
			if err != nil {
				logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
				return err
			}
		} else {
			// 查询入库商品实际库存详情处剩余有效数，不包含已出库的数量
			nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, list[i].ErpCommodityId)
			if err != nil {
				logger.Error("InventoryErpPurchaseUpdateRejectStock GetCommodityStockByPurchaseId err:", logger.Field("err", err))
				return err
			}
			// 如果库存数量不够则报错
			if nCount < list[i].Count {
				return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量，请先零售退货", list[i].ErpCommodityName)
			}

			var stockCommodity []ErpStockCommodity
			//// 通过门店id，商品id，查找状态为1-在库的非串码商品
			//err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
			//	"and state = ? and imei_type = ? ", list[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1).
			//	Order("id DESC").Find(&stockCommodity).Error

			// 通过首次入库订单编号，查找状态为1-在库的非串码商品
			err = orm.Eloquent.Table("erp_stock_commodity").
				Where("erp_commodity_id = ? and state = ? and imei_type = ? and original_sn = ?",
					list[i].ErpCommodityId, InStock, 1, purchaseOrder.RejectedSerialNumber).
				Order("id DESC").Find(&stockCommodity).Error
			if err != nil {
				logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
				return err
			}
			if stockCommodity == nil {
				return errors.New("RetailTypeRejected find no stock commodity")
			}

			var currentID uint32
			// 找一个可用的库存ID
			for _, item := range stockCommodity {
				_, ok := usedStockCommodityIdList[item.ID]
				if !ok {
					usedStockCommodityIdList[item.ID] = true
					currentID = item.ID
					break
				} else {
					continue
				}
			}
			if currentID == 0 {
				return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量，请先零售退货", list[i].ErpCommodityName)
			}
			err = gdb.Table("erp_stock_commodity").Where("id = ?", currentID).Updates(&map[string]interface{}{
				"state":      PurchaseCancel,
				"stock_sn":   list[i].SerialNumber,
				"updated_at": time.Now(),
			}).Error // 状态更新为采购退货
			if err != nil {
				logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
				return err
			}

			err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
				purchaseOrder.StoreId, list[i].ErpCommodityId).
				Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
			if err != nil {
				logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
				return err
			}
		}
	}

	return nil
}

// CheckDuplicateIMEI 判断入参的串码是否有重复的情况
func CheckDuplicateIMEI(req *ErpPurchaseInventoryReq) (bool, string) {
	// 使用 map 存储已经遍历的 IMEI
	imeiMap := make(map[string]bool)

	for _, inventory := range req.Inventories {
		if inventory.IMEI != "" { // 确保 IMEI 有值
			if imeiMap[inventory.IMEI] {
				// 如果已经存在相同的 IMEI，返回 true 和重复的 IMEI
				return true, inventory.IMEI
			}
			// 将当前 IMEI 添加到 map 中
			imeiMap[inventory.IMEI] = true
		}
	}
	// 如果没有找到重复的 IMEI，返回 false
	return false, ""
}

// 校验入参数据，执行数量是否超过总数；串码商品的串码是否重复
func checkPurchaseInventory(req *ErpPurchaseInventoryReq, imeiCheckFlag bool) error {
	// 查询现有的采购订单信息
	var commodities []ErpPurchaseCommodity
	err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", req.ErpPurchaseOrderId).Find(&commodities).Error
	if err != nil {
		logger.Error("query erp_purchase_commodity err:", logger.Field("err", err))
		return err
	}

	// 判断串码是否重复
	flag, duplicateImei := CheckDuplicateIMEI(req)
	if flag {
		return fmt.Errorf("[%s]串码重复", duplicateImei)
	}

	countMap := make(map[uint32]uint32)
	for i, inventory := range req.Inventories {
		if inventory.ErpCommodityId == 0 {
			return fmt.Errorf("商品Id传参错误，不能为0")
		}
		//countMap[inventory.ErpCommodityId] += inventory.Count
		countMap[inventory.ErpPurchaseCommodityId] += inventory.Count

		if imeiCheckFlag {
			if inventory.IMEIType != NoIMEICommodity && inventory.IMEI == "" {
				return fmt.Errorf("商品[%s]串码为空", inventory.ErpCommodityName)
			}
		}

		// 如果该商品是串码商品，判断其串码是否会重复
		if inventory.IMEI != "" && req.PurchaseType == ErpProcureOrder {
			// 采购订单有反审核的情况，所以查询串码是否重复时应该剔除状态8（采购订单反审核）
			exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET('%s', imei) > 0 and state != 8", inventory.IMEI))
			if err != nil {
				logger.Error("exist sn err")
			}
			if exist {
				return fmt.Errorf("串码有重复项请修改[%s]", inventory.IMEI)
			}
		}

		// 备注：员工成本价在"库存管理-采购单入库"里面的入库操作前端是隐藏不可修改的，会默认传0
		if inventory.EmployeePrice != 0 && inventory.EmployeePrice < inventory.ImplementationPrice {
			return fmt.Errorf("数据错误，员工成本价不能低于采购执行单价")
		}

		erpCommodity, err := GetCommodity(inventory.ErpCommodityId)
		if err != nil {
			logger.Error("checkPurchaseInventory GetCommodity err:", logger.Field("err", err))
			return fmt.Errorf("查询员工成本价报错")
		}
		req.Inventories[i].ErpCategoryID = erpCommodity.ErpCategoryId     // 分类id，入库的时候前端没传，后端补充
		req.Inventories[i].ErpCategoryName = erpCommodity.ErpCategoryName // 分类名称，入库的时候前端没传，后端补充

		//if inventory.EmployeePrice == 0 { // 没有传入员工成本价，则默认按照商品资料设置的员工成本价加价金额
		//	req.Inventories[i].EmployeePrice = inventory.ImplementationPrice + float64(erpCommodity.StaffCostPrice)
		//}
	}

	// 入库的商品信息有误，不在之前的商品列表中
	for commodityID := range countMap {
		found := false
		for _, commodity := range commodities {
			if commodity.ID == commodityID {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("商品编号[%d]不属于该采购订单", commodityID)
		}
	}

	// 本次入库的数量超出该商品未入库数量
	for _, commodity := range commodities {
		if inventoryCount, ok := countMap[commodity.ID]; ok {
			if req.PurchaseType == ErpProcureOrder {
				if commodity.Count-uint32(commodity.InventoryCount) < inventoryCount {
					return fmt.Errorf("本次入库商品[%s]数量[%d]超出该商品未入库数量[%d]", commodity.ErpCommodityName,
						inventoryCount, int32(commodity.Count)-commodity.InventoryCount)
				}
			} else if req.PurchaseType == ErpRejectOrder {
				if commodity.RejectedCount-uint32(commodity.InventoryCount) < inventoryCount {
					return fmt.Errorf("本次退货商品[%s]数量[%d]超出该商品未退货数量[%d]", commodity.ErpCommodityName,
						inventoryCount, int32(commodity.Count)-commodity.InventoryCount)
				}

				// 查询入库商品实际库存详情处剩余有效数，不包含已出库的数量
				var purchaseOrder ErpPurchaseOrder
				err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
				if err != nil {
					logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err))
					return err
				}
				nCount, err := GetCommodityStockByPurchaseIdAndStoreId(purchaseOrder.RejectedSerialNumber,
					commodity.ErpCommodityId, purchaseOrder.StoreId)
				if err != nil {
					logger.Error("checkPurchaseInventory GetCommodityStockByPurchaseId err:", logger.Field("err", err))
					return err
				}
				// 如果库存数量不够则报错
				if nCount < commodity.RejectedCount {
					return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量，请先零售退货", commodity.ErpCommodityName)
				}

			}
		}
	}

	return nil
}

// ExecuteErpPurchase 执行（入库/退货）
func ExecuteErpPurchase(req *ErpPurchaseExecuteReq, c *gin.Context) (*ErpPurchaseExecuteResp, error) {
	// 查询采购订单信息
	var purchaseOrder ErpPurchaseOrder
	err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
	if err != nil {
		logger.Error("purchase order err:", logger.Field("err", err))
		return nil, err
	}

	// 校验入参门店是否包含在用户所有门店中，是否过期
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, err
		}

		if !CheckUserStore(purchaseOrder.StoreId, sysUser) {
			return nil, errors.New("操作失败：您没有该门店权限")
		}
	}

	reqParam := &ErpPurchaseInventoryReq{
		ErpPurchaseOrderId: req.ErpPurchaseOrderId,
		PurchaseType:       req.PurchaseType,
		Inventories:        req.Inventories,
	}
	err = checkPurchaseInventory(reqParam, false)
	if err != nil {
		logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
		return nil, err
	}

	resp := &ErpPurchaseExecuteResp{
		List: make([]ExecuteData, 0),
	}

	// 记录已生成的IMEI，防止重复
	generatedIMEIs := make(map[string]struct{})

	for _, inventory := range req.Inventories {
		if inventory.Count == 0 {
			continue
		}
		// 获取商品信息
		commodityInfo, err := GetCommodity(inventory.ErpCommodityId)
		if err != nil {
			return nil, err
		}
		if commodityInfo.IMEIType == 2 || commodityInfo.IMEIType == 3 {
			// 如果是串码商品，根据 Total 拆分成对应数量的数据
			for i := 0; i < int(inventory.Count); i++ {
				imei := ""                                                                    // 默认退货单执行时不需要串码
				if inventory.PurchaseType == ErpProcureOrder && commodityInfo.IMEIType == 2 { // 采购单
					// 调用函数B生成商品串码
					imei, err = GenerateIMEI(inventory.ErpCommodityId, generatedIMEIs)
					if err != nil {
						return nil, err
					}

					// 将新生成的IMEI记录到集合中
					generatedIMEIs[imei] = struct{}{}
				}
				// 将拆分后的商品信息添加到执行响应中
				resp.List = append(resp.List, ExecuteData{
					ErpPurchaseOrderId:     inventory.ErpPurchaseOrderId,
					ErpCommodityId:         inventory.ErpCommodityId,
					ErpCommodityName:       inventory.ErpCommodityName,
					CommoditySerialNumber:  inventory.CommoditySerialNumber,
					IMEIType:               inventory.IMEIType,
					IMEI:                   imei,
					Count:                  1,
					ImplementationPrice:    inventory.ImplementationPrice,
					EmployeePrice:          inventory.EmployeePrice,
					ErpPurchaseCommodityId: inventory.ErpPurchaseCommodityId,
					Price:                  inventory.Price,
				})
			}
		} else if commodityInfo.IMEIType == 1 {
			// 如果是非串码商品，只需拆分为1条数据
			resp.List = append(resp.List, ExecuteData{
				ErpPurchaseOrderId:     inventory.ErpPurchaseOrderId,
				ErpCommodityId:         inventory.ErpCommodityId,
				ErpCommodityName:       inventory.ErpCommodityName,
				CommoditySerialNumber:  inventory.CommoditySerialNumber,
				IMEIType:               inventory.IMEIType,
				IMEI:                   "",
				Count:                  inventory.Count,
				ImplementationPrice:    inventory.ImplementationPrice,
				EmployeePrice:          inventory.EmployeePrice,
				ErpPurchaseCommodityId: inventory.ErpPurchaseCommodityId,
				Price:                  inventory.Price,
			})
		}
	}

	resp.Total = len(resp.List)

	return resp, nil
}

//// GenerateIMEI 生成串码
//func GenerateIMEI(commodityId uint32) (string, error) {
//	commodity, err := GetCommodity(commodityId)
//	if err != nil {
//		return "", err
//	}
//
//	return GenerateSerialCode(commodity.ErpCategoryId)
//}

// GenerateIMEI 生成串码
func GenerateIMEI(commodityId uint32, generatedIMEIs map[string]struct{}) (string, error) {
	commodity, err := GetCommodity(commodityId)
	if err != nil {
		return "", err
	}

	// 传入 generatedIMEIs，确保生成的串码不与已有的重复
	return GenerateSerialCode(commodity.ErpCategoryId, generatedIMEIs)
}

// CreateErpPurchaseDemand 创建采购需求单
func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error {
	var demandInfo ErpPurchaseDemand
	var demandRemark ErpPurchaseDemandRemark
	var demandList []ErpPurchaseDemand

	// 采购需求信息
	demandInfo.ErpCommodityId = req.ErpCommodityID
	demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber
	demandInfo.ErpCommodityName = req.ErpCommodityName
	demandInfo.ErpSupplierId = req.ErpSupplierId
	demandInfo.State = ErpDemandStateWait // 待采购
	for _, v := range req.List {
		demandInfo.StoreId = v.StoreID
		demandInfo.StoreName = v.StoreName
		demandInfo.Count = v.NeedCount
		demandInfo.MakerId = uint32(sysUser.UserId)
		demandList = append(demandList, demandInfo)
	}

	// 采购需求备注信息
	demandRemark.ErpCommodityId = req.ErpCommodityID
	demandRemark.State = ErpDemandStateWait // 待采购
	demandRemark.MakerId = uint32(sysUser.UserId)
	demandRemark.Remark = req.Remark

	begin := orm.Eloquent.Begin()
	// 查询当前表格，有记录则更新，没有则插入新记录
	for _, v := range demandList {
		var demand ErpPurchaseDemand
		err := orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? and store_id = ? and state = 1",
			v.ErpCommodityId, v.StoreId).Find(&demand).Error
		if err != nil {
			logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
			return err
		}

		if demand.StoreId != 0 { // 有记录
			if demand.Count == v.Count { // 值没变则不更新
				continue
			} else {
				err = begin.Model(&ErpPurchaseDemand{}).Where("erp_commodity_id = ? and store_id = ? and state = 1",
					v.ErpCommodityId, v.StoreId).Updates(map[string]interface{}{
					"count":    v.Count,
					"state":    v.State,
					"maker_id": v.MakerId,
				}).Error
				if err != nil {
					begin.Rollback()
					logger.Error("update erp_order err:", logger.Field("err", err))
					return err
				}
			}
		} else { // 无记录，新建
			err = begin.Create(&v).Error
			if err != nil {
				logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
				return err
			}
		}
	}

	// 更新备注，先查询有无记录，有则更新，没有则插入新记录
	var demandRemarkInfo ErpPurchaseDemandRemark
	err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1",
		req.ErpCommodityID).Find(&demandRemarkInfo).Error
	if err != nil {
		logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err))
		return err
	}

	if demandRemarkInfo.ErpCommodityId != 0 { // 有记录
		if demandRemarkInfo.Remark != req.Remark { // 备注有变化才更新
			err := begin.Model(&ErpPurchaseDemandRemark{}).Where("erp_commodity_id = ? and state = 1",
				req.ErpCommodityID).Updates(map[string]interface{}{
				"state":    demandRemark.State,
				"remark":   demandRemark.Remark,
				"maker_id": demandRemark.MakerId,
			}).Error
			if err != nil {
				begin.Rollback()
				logger.Error("update erp_purchase_demand_remark err:", logger.Field("err", err))
				return err
			}
		}
	} else { // 无记录，新建
		err = begin.Create(&demandRemark).Error
		if err != nil {
			logger.Error("create erp_purchase_demand_remark err:", logger.Field("err", err))
			return err
		}
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("commit err:", logger.Field("err", err))
		return err
	}

	return nil
}

// FinishErpPurchaseDemand 完成采购需求
func FinishErpPurchaseDemand(req *FinishErpPurchaseDemandReq, sysUser *SysUser) error {
	exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_demand WHERE erp_commodity_id='%d'",
		req.ErpCommodityID))
	if err != nil {
		logger.Error("exist sn err")
	}
	if !exist {
		return fmt.Errorf("商品编号[%d]的商品不在采购需求单中", req.ErpCommodityID)
	}

	// 批量更新状态
	err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID).
		Updates(map[string]interface{}{
			"state":        ErpDemandStateFinish,
			"finish_time":  time.Now(),
			"purchaser_id": sysUser.UserId,
		}).Error
	if err != nil {
		logger.Error("update err:", logger.Field("err", err))
		return err
	}

	err = orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID).
		Updates(map[string]interface{}{
			"state":        ErpDemandStateFinish,
			"finish_time":  time.Now(),
			"purchaser_id": sysUser.UserId,
		}).Error
	if err != nil {
		logger.Error("update err:", logger.Field("err", err))
		return err
	}

	return nil
}

// GetErpPurchaseDemand 获取采购需求
func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq, c *gin.Context) (*GetErpPurchaseDemandResp, error) {
	var err error
	resp := new(GetErpPurchaseDemandResp)
	if req.HideFlag == "ON" { // 隐藏无采购需求的商品
		resp, err = getErpPurchaseDemandHide(req, c)
	} else { // 展示所有
		resp, err = getErpPurchaseDemandAll(req, c)
	}
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// 展示所有采购需求
func getErpPurchaseDemandAll(req *GetErpPurchaseDemandReq, c *gin.Context) (*GetErpPurchaseDemandResp, error) {
	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &GetErpPurchaseDemandResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}

	// 批量查询门店信息
	stores, err := GetOnlineStores(c, req.StoreId)
	if err != nil {
		return nil, err
	}
	if len(stores) == 0 {
		return nil, errors.New("无有效门店，请配置门店信息")
	}

	// 组合门店信息
	var storeIdList []uint32
	for _, item := range stores {
		storeIdList = append(storeIdList, item.ID)
	}

	qs := orm.Eloquent.Debug().Table("erp_commodity").Where("stop_purchase != 1")
	if req.ErpCategoryId != 0 {
		categoryInfo, err := GetErpCategory(req.ErpCategoryId)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("serial_number like ?", categoryInfo.Number+"%")
	}
	if req.ErpCommoditySerialNumber != "" {
		qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber)
	}
	if req.ErpCommodityName != "" {
		qs = qs.Where("name=?", req.ErpCommodityName)
	}
	if req.ErpSupplierId != 0 {
		qs = qs.Where("erp_supplier_id=?", req.ErpSupplierId)
	}

	var count int64
	if err := qs.Count(&count).Error; err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return resp, err
	}

	var commodities []ErpCommodity
	err = qs.Order("id DESC").Find(&commodities).Error
	if err != nil && err != RecordNotFound {
		return resp, err
	}

	if req.SortField == "erp_commodity_serial_number" || req.SortField == "erp_commodity_name" {
		switch req.SortType {
		case "desc":
			SortCommoditiesDesc(commodities)
		case "asc":
			SortCommoditiesAsc(commodities)
		default:
			SortCommoditiesAsc(commodities)
		}
	} else {
		// 商品编号排序
		SortCommoditiesAsc(commodities)
	}
	if req.CallType != 2 {
		if req.SortField == "erp_supplier_id" {
			switch req.SortType {
			case "desc":
				// 排序规则：主供应商id大
				SortByErpSupplierId(commodities, true)
			case "asc":
				// 排序规则：主供应商id小
				SortByErpSupplierId(commodities, false)
			default:
				// 排序规则：主供应商id小
				SortByErpSupplierId(commodities, false)
			}
		} else {
			// 排序规则：主供应商id小
			SortByErpSupplierId(commodities, false)
		}
	}

	commodityIDs := make([]uint32, len(commodities))
	for i, commodity := range commodities {
		commodityIDs[i] = commodity.ID
	}

	if len(commodityIDs) == 0 {
		return resp, nil
	}

	// 批量查询商品上月销售数量
	var soldOutCommodities []ErpStockCommodity
	firstDay, lastDay := GetLastMonthRange() // 获取上个月的时间范围

	if len(storeIdList) > 1 {
		err = orm.Eloquent.Table("erp_stock_commodity").
			Where("state = ? AND updated_at BETWEEN ? AND ? AND store_id in (?) AND erp_commodity_id IN (?)",
				SoldOut, firstDay, lastDay, storeIdList, commodityIDs).Find(&soldOutCommodities).Error
	} else {
		err = orm.Eloquent.Table("erp_stock_commodity").
			Where("state = ? AND updated_at BETWEEN ? AND ? AND store_id = ? AND erp_commodity_id IN (?)",
				SoldOut, firstDay, lastDay, storeIdList[0], commodityIDs).Find(&soldOutCommodities).Error
	}
	if err != nil {
		return nil, err
	}
	// 按照 商品id-门店id：销售数量 组合信息
	soldOutMap := make(map[string]uint32)
	for _, item := range soldOutCommodities {
		key := fmt.Sprintf("%d-%d", item.ErpCommodityId, item.StoreId)
		_, exist := soldOutMap[key]
		if exist { // 存在
			soldOutMap[key] += 1
		} else { // 不存在
			soldOutMap[key] = 1
		}
	}

	// 批量查询商品上周销售数量
	var weekSoldOutCommodities []ErpStockCommodity
	firstWeekDay, lastWeekDay := GetLastWeekRange() // 获取上个月的时间范围

	if len(storeIdList) > 1 {
		err = orm.Eloquent.Table("erp_stock_commodity").
			Where("state = ? AND updated_at BETWEEN ? AND ? AND store_id in (?) AND erp_commodity_id IN (?)",
				SoldOut, firstWeekDay, lastWeekDay, storeIdList, commodityIDs).Find(&weekSoldOutCommodities).Error
	} else {
		err = orm.Eloquent.Table("erp_stock_commodity").
			Where("state = ? AND updated_at BETWEEN ? AND ? AND store_id = ? AND erp_commodity_id IN (?)",
				SoldOut, firstWeekDay, lastWeekDay, storeIdList[0], commodityIDs).Find(&weekSoldOutCommodities).Error
	}
	if err != nil {
		return nil, err
	}
	// 按照 商品id-门店id：销售数量 组合信息
	weekSoldOutMap := make(map[string]uint32)
	for _, item := range weekSoldOutCommodities {
		key := fmt.Sprintf("%d-%d", item.ErpCommodityId, item.StoreId)
		_, exist := weekSoldOutMap[key]
		if exist { // 存在
			weekSoldOutMap[key] += 1
		} else { // 不存在
			weekSoldOutMap[key] = 1
		}
	}

	// 批量查询商品的库存情况
	var stockCommodities []ErpStockCommodity
	if len(storeIdList) > 1 {
		err = orm.Eloquent.Table("erp_stock_commodity").
			Where("state = ? AND store_id in (?) AND erp_commodity_id IN (?)",
				InStock, storeIdList, commodityIDs).Find(&stockCommodities).Error
	} else {
		err = orm.Eloquent.Table("erp_stock_commodity").
			Where("state = ? AND store_id = ? AND erp_commodity_id IN (?)",
				InStock, storeIdList[0], commodityIDs).Find(&stockCommodities).Error
	}
	if err != nil {
		return nil, err
	}
	// 按照 商品id-门店id：库存数量 组合信息
	inStockMap := make(map[string]uint32)
	for _, item := range stockCommodities {
		key := fmt.Sprintf("%d-%d", item.ErpCommodityId, item.StoreId)
		_, exist := inStockMap[key]
		if exist { // 存在
			inStockMap[key] += 1
		} else { // 不存在
			inStockMap[key] = 1
		}
	}

	// 查询采购需求单信息
	var demand []ErpPurchaseDemand
	demandQs := orm.Eloquent.Table("erp_purchase_demand").
		Where("state = 1").Where("count <> 0").Where("erp_commodity_id IN (?)", commodityIDs)
	if len(storeIdList) > 0 {
		if len(storeIdList) == 1 {
			demandQs = demandQs.Where("store_id = ?", storeIdList[0])
		} else {
			demandQs = demandQs.Where("store_id IN (?)", storeIdList)
		}
	}
	err = demandQs.Find(&demand).Error
	if err != nil {
		return nil, err
	}

	// 查询采购备注信息
	var demandRemarkInfo []ErpPurchaseDemandRemark
	demandRemarkQs := orm.Eloquent.Table("erp_purchase_demand_remark").
		Where("state = 1").
		Where("remark IS NOT NULL").
		Where("remark <> ''").Where("erp_commodity_id IN (?)", commodityIDs)
	err = demandRemarkQs.Find(&demandRemarkInfo).Error
	if err != nil {
		return nil, err
	}

	// 按照 商品ID-门店ID：采购信息 组合
	demandsMap := make(map[string]ErpPurchaseDemand)
	storesMap := make(map[uint32][]uint32)                       // 按照 商品id：门店id列表 组合
	demandRemarksMap := make(map[uint32]ErpPurchaseDemandRemark) // 按照 商品id：采购备注信息 组合

	for _, d := range demand {
		key := fmt.Sprintf("%d-%d", d.ErpCommodityId, d.StoreId)
		demandsMap[key] = d

		// 更新 storesMap
		if _, exists := storesMap[d.ErpCommodityId]; !exists {
			storesMap[d.ErpCommodityId] = []uint32{d.StoreId}
		} else {
			storesMap[d.ErpCommodityId] = append(storesMap[d.ErpCommodityId], d.StoreId)
		}
	}

	for _, r := range demandRemarkInfo {
		demandRemarksMap[r.ErpCommodityId] = r
	}

	// 并行查询需求数据
	var wg sync.WaitGroup
	var tempCommodities []ErpCommodity
	if req.IsExport == 1 {
		tempCommodities = commodities
	} else {
		// 计算分页
		startIndex := page * req.PageSize
		if startIndex > len(commodities) {
			startIndex = 0
		}
		endIndex := (page + 1) * req.PageSize
		if endIndex > len(commodities) {
			endIndex = len(commodities)
		}
		tempCommodities = commodities[startIndex:endIndex]
	}
	demandDataList := make([]DemandData, len(tempCommodities))

	for i, v := range tempCommodities {
		wg.Add(1)
		go func(index int, commodity ErpCommodity) {
			defer wg.Done()
			demandData, err := convertToDemandDataAll(commodity, storesMap[commodity.ID], stores, soldOutMap, weekSoldOutMap, inStockMap,
				demandsMap, demandRemarksMap)
			if err != nil {
				// Handle error
				return
			}
			demandDataList[index] = demandData
		}(i, v)
	}
	wg.Wait()

	if req.IsExport == 1 { // 导出excel
		if len(demandDataList) == 0 {
			return nil, errors.New("未查询到数据")
		}
		if req.CallType == 2 { // 店员视角
			resp.ExportUrl, err = demandDataExportOnShopAssistant(demandDataList)
		} else { // 采购视角
			resp.ExportUrl, err = demandDataExport(demandDataList)
		}
		if err != nil {
			return nil, err
		}
	} else {
		resp.List = demandDataList
		resp.Total = count
	}

	return resp, nil
}

// convertToDemandDataAll 将商品转换为采购需求数据
func convertToDemandDataAll(commodity ErpCommodity, usedStore []uint32, stores []Store, soldOutMap, weekSoldOutMap, stockMap map[string]uint32,
	demandMap map[string]ErpPurchaseDemand, demandRemarkMap map[uint32]ErpPurchaseDemandRemark) (DemandData, error) {
	demandData := DemandData{
		ErpSupplierId:            commodity.ErpSupplierId,
		ErpSupplierName:          commodity.ErpSupplierName,
		ErpCommodityID:           commodity.ID,
		ErpCommoditySerialNumber: commodity.SerialNumber,
		ErpCommodityName:         commodity.Name,
		ErpManufacturerCode:      commodity.ManufacturerCode,
		ErpCategoryID:            commodity.ErpCategoryId,
		ErpCategoryName:          commodity.ErpCategoryName,
		RetailPrice:              commodity.RetailPrice,
		Remark:                   demandRemarkMap[commodity.ID].Remark,
		Img:                      commodity.Img,
	}

	var demands []ErpPurchaseDemand
	for _, store := range usedStore {
		key := fmt.Sprintf("%d-%d", commodity.ID, store)
		v, ok := demandMap[key]
		if !ok {
			continue
		}

		demands = append(demands, v)
	}

	// 查询最近采购价
	var lastWholesalePrices map[uint32]float64
	lastWholesalePrices, _ = GetCommodityLastWholesalePrices(commodity.ID)

	var totalCount uint32 // 总需采购数量
	// 构建需求数据
	demandData.StoreList = make([]struct {
		StoreID        uint32 `json:"store_id"`
		StoreName      string `json:"store_name"`
		LastMonthSales uint32 `json:"last_month_sales"`
		LastWeekSales  uint32 `json:"last_week_sales"`
		StockCount     uint32 `json:"stock_count"`
		NeedCount      uint32 `json:"need_count"`
	}, len(stores))

	for i, store := range stores {
		demandData.StoreList[i].StoreID = store.ID
		demandData.StoreList[i].StoreName = store.Name

		key := fmt.Sprintf("%d-%d", commodity.ID, store.ID)
		demandData.StoreList[i].StockCount = stockMap[key]
		demandData.StoreList[i].LastMonthSales = soldOutMap[key]
		demandData.StoreList[i].LastWeekSales = weekSoldOutMap[key]

		// 设置最近采购价
		demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]

		// 设置采购需求量
		for _, demand := range demands {
			if demand.StoreId == store.ID {
				demandData.StoreList[i].NeedCount = demand.Count
				totalCount += demand.Count
				break
			}
		}
	}

	demandData.TotalCount = totalCount
	demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice

	return demandData, nil
}

// 隐藏无采购需求的商品
func getErpPurchaseDemandHide(req *GetErpPurchaseDemandReq, c *gin.Context) (*GetErpPurchaseDemandResp, error) {
	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

	resp := &GetErpPurchaseDemandResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}

	// 批量查询门店信息
	stores, err := GetOnlineStores(c, req.StoreId)
	if err != nil {
		return nil, err
	}
	if len(stores) == 0 {
		return nil, errors.New("无有效门店，请配置门店信息")
	}
	// 组合门店信息
	var storeIdList []uint32
	for _, item := range stores {
		storeIdList = append(storeIdList, item.ID)
	}

	// 查询采购需求单信息，筛选出有采购需求的商品id
	var demand []ErpPurchaseDemand
	demandQs := orm.Eloquent.Table("erp_purchase_demand").
		Where("state = 1").Where("count <> 0")
	if len(storeIdList) > 0 {
		if len(storeIdList) == 1 {
			demandQs = demandQs.Where("store_id = ?", storeIdList[0])
		} else {
			demandQs = demandQs.Where("store_id IN (?)", storeIdList)
		}
	}
	if req.ErpCommodityName != "" {
		demandQs = demandQs.Where("erp_commodity_name = ?", req.ErpCommodityName)
	}
	if req.ErpSupplierId != 0 {
		demandQs = demandQs.Where("erp_supplier_id=?", req.ErpSupplierId)
	}
	err = demandQs.Find(&demand).Error
	if err != nil {
		return nil, err
	}

	// 查询采购需求备注信息
	var demandRemarkInfo []ErpPurchaseDemandRemark
	demandRemarkQs := orm.Eloquent.Table("erp_purchase_demand_remark").
		Where("state = 1").
		Where("remark IS NOT NULL").
		Where("remark <> ''")
	if req.ErpCommodityName != "" {
		var erpCommodity ErpCommodity
		err = orm.Eloquent.Table("erp_commodity").Where("name = ?", req.ErpCommodityName).
			Find(&erpCommodity).Error
		if err != nil {
			return nil, err
		}
		demandRemarkQs = demandRemarkQs.Where("erp_commodity_id = ?", erpCommodity.ID)
	}
	err = demandRemarkQs.Find(&demandRemarkInfo).Error
	if err != nil {
		return nil, err
	}

	demandsMap := make(map[string]ErpPurchaseDemand)
	storesMap := make(map[uint32][]uint32)
	demandRemarksMap := make(map[uint32]ErpPurchaseDemandRemark)

	// 用 sync.Map 存储已经出现过的 ErpCommodityId
	commodityIds := sync.Map{}
	var uniqueCommodityIds []uint32

	for _, d := range demand {
		if _, ok := commodityIds.Load(d.ErpCommodityId); !ok {
			commodityIds.Store(d.ErpCommodityId, true)
			uniqueCommodityIds = append(uniqueCommodityIds, d.ErpCommodityId)
		}
		key := fmt.Sprintf("%d-%d", d.ErpCommodityId, d.StoreId)
		demandsMap[key] = d

		// 更新 storesMap
		if _, exists := storesMap[d.ErpCommodityId]; !exists {
			storesMap[d.ErpCommodityId] = []uint32{d.StoreId}
		} else {
			storesMap[d.ErpCommodityId] = append(storesMap[d.ErpCommodityId], d.StoreId)
		}
	}

	for _, r := range demandRemarkInfo {
		demandRemarksMap[r.ErpCommodityId] = r
	}

	// 查询商品信息
	var commodities []ErpCommodity
	if len(demand) > 0 {
		qs := orm.Eloquent.Debug().Table("erp_commodity")
		if req.ErpCategoryId != 0 {
			categoryInfo, err := GetErpCategory(req.ErpCategoryId)
			if err != nil {
				return nil, err
			}
			qs = qs.Where("serial_number like ?", categoryInfo.Number+"%")
		}
		if req.ErpCommoditySerialNumber != "" {
			qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber)
		}
		if req.ErpCommodityName != "" {
			qs = qs.Where("name=?", req.ErpCommodityName)
		}
		if req.ErpSupplierId != 0 {
			qs = qs.Where("erp_supplier_id=?", req.ErpSupplierId)
		}

		var count int64
		if err := qs.Count(&count).Error; err != nil {
			logger.Error("count err:", logger.Field("err", err))
			return resp, err
		}

		err = qs.Order("id DESC").Find(&commodities).Error
		if err != nil && err != RecordNotFound {
			return resp, err
		}
	}

	// 匹配商品id，有则继续查询返回数据，没有则不返回
	var matchedCommodities []ErpCommodity
	for _, item := range commodities {
		if _, ok := commodityIds.Load(item.ID); ok {
			matchedCommodities = append(matchedCommodities, item)
		}
	}

	if len(matchedCommodities) == 0 {
		resp.List = nil
	} else {
		// 排序
		if req.SortField == "erp_commodity_serial_number" {
			switch req.SortType {
			case "desc":
				SortCommoditiesDesc(matchedCommodities)
			case "asc":
				SortCommoditiesAsc(matchedCommodities)
			default:
				SortCommoditiesAsc(matchedCommodities)
			}
		} else {
			// 商品编号排序
			SortCommoditiesAsc(matchedCommodities)
		}

		if req.CallType != 2 {
			if req.SortField == "erp_supplier_id" {
				switch req.SortType {
				case "desc":
					// 排序规则：主供应商id大
					SortByErpSupplierId(matchedCommodities, true)
				case "asc":
					// 排序规则：主供应商id小
					SortByErpSupplierId(matchedCommodities, false)
				default:
					// 排序规则：主供应商id小
					SortByErpSupplierId(matchedCommodities, false)
				}
			} else {
				// 排序规则：主供应商id小
				SortByErpSupplierId(matchedCommodities, false)
			}
		}

		// 并行查询需求数据
		var wg sync.WaitGroup
		var tempCommodities []ErpCommodity
		if req.IsExport == 1 {
			tempCommodities = matchedCommodities
		} else {
			// 计算分页
			startIndex := page * req.PageSize
			if startIndex > len(matchedCommodities) {
				startIndex = 0
			}
			endIndex := (page + 1) * req.PageSize
			if endIndex > len(matchedCommodities) {
				endIndex = len(matchedCommodities)
			}
			tempCommodities = matchedCommodities[startIndex:endIndex]
		}
		demandDataList := make([]DemandData, len(tempCommodities))

		for i, v := range tempCommodities {
			wg.Add(1)
			go func(index int, commodity ErpCommodity) {
				defer wg.Done()
				demandData, err := convertToDemandData(commodity, storesMap[commodity.ID], stores, demandRemarksMap, demandsMap)
				if err != nil {
					// Handle error
					return
				}
				demandDataList[index] = demandData
			}(i, v)
		}

		wg.Wait()

		if req.IsExport == 1 { // 导出excel
			if len(demandDataList) == 0 {
				return nil, errors.New("未查询到数据")
			}
			if req.CallType == 2 { // 店员视角
				resp.ExportUrl, err = demandDataExportOnShopAssistant(demandDataList)
			} else { // 采购视角
				resp.ExportUrl, err = demandDataExport(demandDataList)
			}
			if err != nil {
				return nil, err
			}
		} else {
			resp.List = demandDataList
			resp.Total = int64(len(matchedCommodities))
		}
	}

	return resp, nil
}

// convertToDemandData 将商品转换为采购需求数据
func convertToDemandData(commodity ErpCommodity, usedStore []uint32, stores []Store,
	demandRemarksMap map[uint32]ErpPurchaseDemandRemark, demandMap map[string]ErpPurchaseDemand) (DemandData, error) {
	demandData := DemandData{
		ErpSupplierId:            commodity.ErpSupplierId,
		ErpSupplierName:          commodity.ErpSupplierName,
		ErpCommodityID:           commodity.ID,
		ErpCommoditySerialNumber: commodity.SerialNumber,
		ErpCommodityName:         commodity.Name,
		ErpManufacturerCode:      commodity.ManufacturerCode,
		ErpCategoryID:            commodity.ErpCategoryId,
		ErpCategoryName:          commodity.ErpCategoryName,
		RetailPrice:              commodity.RetailPrice,
		Remark:                   demandRemarksMap[commodity.ID].Remark,
		Img:                      commodity.Img,
	}

	var demands []ErpPurchaseDemand
	for _, store := range usedStore {
		key := fmt.Sprintf("%d-%d", commodity.ID, store)
		v, ok := demandMap[key]
		if !ok {
			continue
		}

		demands = append(demands, v)
	}

	var lastWholesalePrices map[uint32]float64
	var stockCounts map[uint32]uint32
	var lastMonthSales map[uint32]uint32
	var lastWeekSales map[uint32]uint32

	lastWholesalePrices, _ = GetCommodityLastWholesalePrices(commodity.ID)
	stockCounts, _ = GetCommodityStocksByStoreID(commodity.ID, usedStore)
	lastMonthSales, _ = GetCommodityLastMonthSales(commodity.ID, usedStore)
	lastWeekSales, _ = GetCommodityLastWeekSales(commodity.ID, usedStore)

	var totalCount uint32
	demandData.StoreList = make([]struct {
		StoreID        uint32 `json:"store_id"`
		StoreName      string `json:"store_name"`
		LastMonthSales uint32 `json:"last_month_sales"`
		LastWeekSales  uint32 `json:"last_week_sales"`
		StockCount     uint32 `json:"stock_count"`
		NeedCount      uint32 `json:"need_count"`
	}, len(stores))

	for i, store := range stores {
		demandData.StoreList[i].StoreID = store.ID
		demandData.StoreList[i].StoreName = store.Name

		demandData.StoreList[i].StockCount = stockCounts[store.ID]
		demandData.StoreList[i].LastMonthSales = lastMonthSales[store.ID]
		demandData.StoreList[i].LastWeekSales = lastWeekSales[store.ID]

		demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]

		for _, demand := range demands {
			if demand.StoreId == store.ID {
				demandData.StoreList[i].NeedCount = demand.Count
				totalCount += demand.Count
				break
			}
		}
	}

	demandData.TotalCount = totalCount
	demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice

	return demandData, nil
}

// GetCommodityPurchaseDemands 查询商品的采购需求单
func GetCommodityPurchaseDemands(commodityID uint32, stores []Store) ([]ErpPurchaseDemand, error) {
	var wg sync.WaitGroup
	var mu sync.Mutex
	var demands []ErpPurchaseDemand
	wg.Add(len(stores))

	for _, store := range stores {
		go func(storeID uint32) {
			defer wg.Done()
			var demand ErpPurchaseDemand
			err := orm.Eloquent.Table("erp_purchase_demand").
				Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", commodityID, storeID).
				First(&demand).Error
			if err != nil && err != gorm.ErrRecordNotFound {
				// Log the error but do not return it, to ensure other goroutines complete
				logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
				return
			}

			// If no record is found, err == gorm.ErrRecordNotFound, we ignore it and not append to demands
			if err == nil {
				mu.Lock()
				demands = append(demands, demand)
				mu.Unlock()
			}
		}(store.ID)
	}

	wg.Wait()

	return demands, nil
}

// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
	// 查询最近采购价
	var prices []struct {
		ErpCommodityID uint32
		Price          float64
	}
	err := orm.Eloquent.Table("erp_purchase_inventory").
		Select("erp_commodity_id, implementation_price AS price").
		Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
		//Group("erp_commodity_id").
		Order("created_at DESC").
		First(&prices).Error
	if err != nil {
		return nil, err
	}

	// 构建结果
	result := make(map[uint32]float64)
	for _, p := range prices {
		result[p.ErpCommodityID] = p.Price
	}
	return result, nil
}

// GetCommodityStocksByStoreID 批量查询商品的库存情况
func GetCommodityStocksByStoreID(commodityID uint32, stores []uint32) (map[uint32]uint32, error) {
	// 并行查询库存情况
	var wg sync.WaitGroup
	wg.Add(len(stores))

	result := make(map[uint32]uint32)
	var mu sync.Mutex // 用于保护 `result`

	for _, store := range stores {
		go func(storeID uint32) {
			defer wg.Done()
			// 查询库存情况
			var stockCount int64
			err := orm.Eloquent.Table("erp_stock_commodity").
				Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID).
				Count(&stockCount).Error
			if err != nil {
				// Handle error
				return
			}
			mu.Lock() // 加锁
			result[storeID] = uint32(stockCount)
			mu.Unlock() // 解锁
		}(store)
	}

	wg.Wait()

	return result, nil
}

// GetCommodityStockByPurchaseId 查询入库商品实际库存详情处剩余有效数，不包含已出库的数量
func GetCommodityStockByPurchaseId(serialNumber string, orderId uint32) (uint32, error) {
	var count int64
	err := orm.Eloquent.Table("erp_stock_commodity").Where("original_sn = ? and erp_commodity_id = ? and state = ?",
		serialNumber, orderId, InStock).Count(&count).Error
	if err != nil {
		return 0, err
	}

	return uint32(count), nil
}

// GetCommodityStockByPurchaseIdAndStoreId 查询入库商品实际库存详情处剩余有效数，不包含已出库的数量
func GetCommodityStockByPurchaseIdAndStoreId(serialNumber string, orderId, storeId uint32) (uint32, error) {
	var count int64
	err := orm.Eloquent.Table("erp_stock_commodity").Where("original_sn = ? and erp_commodity_id = ? "+
		"and state = ? and store_id = ?", serialNumber, orderId, InStock, storeId).Count(&count).Error
	if err != nil {
		return 0, err
	}

	return uint32(count), nil
}

// GetCommodityLastMonthSales 批量查询商品的上月销售数量
func GetCommodityLastMonthSales(commodityID uint32, stores []uint32) (map[uint32]uint32, error) {
	// 获取上个月的时间范围
	firstDay, lastDay := GetLastMonthRange()

	// 并行查询上月销售数量
	var wg sync.WaitGroup
	wg.Add(len(stores))

	result := make(map[uint32]uint32)
	var mu sync.Mutex // 用于保护 totalSales 的并发访问

	for _, store := range stores {
		go func(storeID uint32) {
			defer wg.Done()
			// 查询上月销售数量
			var sales int64
			err := orm.Eloquent.Table("erp_stock_commodity").
				Where("state = ? AND erp_commodity_id = ? AND store_id = ? AND updated_at BETWEEN ? AND ?",
					SoldOut, commodityID, storeID, firstDay, lastDay).Count(&sales).Error
			if err != nil {
				// Handle error
				return
			}

			// 保护 totalSales 的并发访问
			mu.Lock()
			defer mu.Unlock()
			result[storeID] = uint32(sales)
		}(store)
	}

	wg.Wait()

	return result, nil
}

// GetCommodityLastWeekSales 批量查询商品的上周销售数量
func GetCommodityLastWeekSales(commodityID uint32, stores []uint32) (map[uint32]uint32, error) {
	// 获取上个月的时间范围
	firstDay, lastDay := GetLastWeekRange()

	// 并行查询上月销售数量
	var wg sync.WaitGroup
	wg.Add(len(stores))

	result := make(map[uint32]uint32)
	var mu sync.Mutex // 用于保护 totalSales 的并发访问

	for _, store := range stores {
		go func(storeID uint32) {
			defer wg.Done()
			// 查询上月销售数量
			var sales int64
			err := orm.Eloquent.Table("erp_stock_commodity").
				Where("state = ? AND erp_commodity_id = ? AND store_id = ? AND updated_at BETWEEN ? AND ?",
					SoldOut, commodityID, storeID, firstDay, lastDay).Count(&sales).Error
			if err != nil {
				// Handle error
				return
			}

			// 保护 totalSales 的并发访问
			mu.Lock()
			defer mu.Unlock()
			result[storeID] = uint32(sales)
		}(store)
	}

	wg.Wait()

	return result, nil
}

// GetLastWeekRange 获取上周的时间范围
func GetLastWeekRange() (time.Time, time.Time) {
	now := time.Now()
	// 获取当前时间的星期几，周日为0，周一为1，依次类推
	weekday := int(now.Weekday())
	if weekday == 0 {
		weekday = 7 // 将周日设为7，方便计算
	}

	// 计算上周的开始日期和结束日期
	// 上周结束日期为上周日
	lastWeekEnd := now.AddDate(0, 0, -weekday)
	// 上周开始日期为上周一
	lastWeekStart := lastWeekEnd.AddDate(0, 0, -6)

	// 设置时间为零点
	startOfDay := func(t time.Time) time.Time {
		year, month, day := t.Date()
		return time.Date(year, month, day, 0, 0, 0, 0, t.Location())
	}

	endOfDay := func(t time.Time) time.Time {
		year, month, day := t.Date()
		return time.Date(year, month, day, 23, 59, 59, 0, t.Location())
	}

	return startOfDay(lastWeekStart), endOfDay(lastWeekEnd)
}

// GetLastMonthRange  获取上个月的时间范围
func GetLastMonthRange() (time.Time, time.Time) {
	now := time.Now()
	year, month, _ := now.Date()
	firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
	lastDay := firstDay.AddDate(0, 1, -1)
	lastDay = time.Date(lastDay.Year(), lastDay.Month(), lastDay.Day(), 23, 59, 59, 0, now.Location())

	return firstDay, lastDay
}

// GetOnlineStores 查询有效门店信息
func GetOnlineStores(c *gin.Context, reqStoreList []uint32) ([]Store, error) {
	user, err := GetSysUserByCtx(c)
	if err != nil {
		return nil, err
	}

	var stores []Store
	if user.RoleId == 1 { // 系统管理员
		err = orm.Eloquent.Table("store").Where("cooperative_business_id = ? ",
			user.CooperativeBusinessId).Find(&stores).Error
		if err != nil {
			return nil, err
		}
	} else {
		// 解析门店数据
		if err = json.Unmarshal([]byte(user.StoreData), &user.StoreList); err != nil {
			return nil, err
		}

		if len(user.StoreList) == 0 {
			return nil, errors.New("no stores found")
		}

		// 当前时间
		now := time.Now()

		// 过滤掉过期的门店
		for _, store := range user.StoreList {
			expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
			if err != nil {
				log.Println("Error parsing time:", err, "ExpireTime:", store.ExpireTime)
				continue
			}

			// 包含当天有效时间
			expireTime = expireTime.Add(24*time.Hour - time.Second)
			if expireTime.After(now) {
				tempStore := Store{
					Name: store.StoreName,
				}
				tempStore.ID = uint32(store.StoreID)
				stores = append(stores, tempStore)
			}
		}
	}

	if len(stores) == 0 {
		return nil, nil
	}

	// 如果 reqStoreList 不为空，筛选匹配的门店
	if len(reqStoreList) > 0 {
		reqStoreSet := make(map[uint32]struct{}, len(reqStoreList))
		for _, storeID := range reqStoreList {
			reqStoreSet[storeID] = struct{}{}
		}

		var matchedStores []Store
		for _, store := range stores {
			if _, exists := reqStoreSet[store.ID]; exists {
				matchedStores = append(matchedStores, store)
			}
		}

		// 如果没有匹配的门店，返回空结果
		if len(matchedStores) == 0 {
			return nil, nil
		}

		return matchedStores, nil
	}

	return stores, nil
}

type Result struct {
	TotalCount             uint32  `gorm:"column:total_count"`
	AvgImplementationPrice float64 `gorm:"column:avg_implementation_price"`
	TotalAmount            float64 `gorm:"column:total_amount"`
	AvgEmployeePrice       float64 `gorm:"column:avg_employee_price"`
}

//// GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价
//func GetTotalsAndAveragesByCommodityID(commodityID, orderID uint32) (Result, error) {
//	var result Result
//	err := orm.Eloquent.Table("erp_purchase_inventory").
//		Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+
//			"SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price").
//		Where("erp_commodity_id = ? and erp_purchase_order_id = ?", commodityID, orderID).
//		Scan(&result).Error
//	if err != nil {
//		return Result{}, err
//	}
//
//	return result, nil
//}

// GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价
func GetTotalsAndAveragesByCommodityID(commodityID uint32) (Result, error) {
	var result Result
	err := orm.Eloquent.Table("erp_purchase_inventory").
		Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+
			"SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price").
		Where("erp_purchase_commodity_id = ?", commodityID).
		Scan(&result).Error
	if err != nil {
		return Result{}, err
	}

	return result, nil
}

type ResultPrice struct {
	TotalWholesalePrice float64 `gorm:"column:total_wholesale_price"`
}

// GetTotalWholesalePrice 查询采购退货订单对应的采购金额
func GetTotalWholesalePrice(commodityID uint32, serialNumber string) (ResultPrice, error) {
	var result ResultPrice
	err := orm.Eloquent.Table("erp_stock_commodity").
		Select("SUM(`wholesale_price`) AS total_wholesale_price").
		Where("erp_commodity_id = ? and stock_sn = ?", commodityID, serialNumber).
		Scan(&result).Error
	if err != nil {
		return ResultPrice{}, err
	}

	return result, nil
}

// UpdateRetailPrice 更新指导零售价
func UpdateRetailPrice(begin *gorm.DB, commodityId uint32, retailPrice float64) error {
	// 更新商品信息表
	err := begin.Table("erp_commodity").Where("id=?", commodityId).
		Updates(map[string]interface{}{
			"retail_price": retailPrice,
		}).Error
	if err != nil {
		return err
	}

	// 更新库存表
	err = begin.Table("erp_stock").Where("erp_commodity_id=?", commodityId).
		Updates(map[string]interface{}{
			"retail_price": retailPrice,
		}).Error
	if err != nil {
		return err
	}

	// 更新库存商品表
	err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5,6)", commodityId).
		Updates(map[string]interface{}{
			"retail_price": retailPrice,
		}).Error
	if err != nil {
		return err
	}

	return nil
}

// 导出采购需求excel-采购视角
func demandDataExport(list []DemandData) (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{}{"主供应商", "商品名称", "商品编号", "商品分类", "厂家编码", "指导零售价", "最近采购价"}
	storeCount := len(list[0].StoreList)
	var mergeCells []string // 存储需要合并的单元格范围

	for _, v := range list[0].StoreList {
		for i := 0; i < 4; i++ {
			title1 = append(title1, v.StoreName)
		}
	}

	for i := 0; i < storeCount; i++ {
		// 计算每个商户名称的起始和结束单元格
		startCol, _ := excelize.ColumnNumberToName(8 + i*4) // 从第8列开始，每个商户占4列
		endCol, _ := excelize.ColumnNumberToName(11 + i*4)
		mergeCell := startCol + "1:" + endCol + "1"
		mergeCells = append(mergeCells, mergeCell)
	}

	title1 = append(title1, "需采购总数量")
	title1 = append(title1, "需采购总金额")
	title1 = append(title1, "备注")

	// 合并单元格
	for _, mergeCell := range mergeCells {
		startCell, endCell := splitMergeCellCoordinates(mergeCell)
		_ = file.MergeCell(fSheet, startCell, endCell)
	}

	// 组合标题栏第二行数据
	title2 := []interface{}{"主供应商", "商品名称", "商品编号", "商品分类", "厂家编码", "指导零售价", "最近采购价"}
	for _, _ = range list[0].StoreList {
		title2 = append(title2, "上月销售数")
		title2 = append(title2, "上周销售数")
		title2 = append(title2, "库存数量")
		title2 = append(title2, "需采购数")
	}
	title2 = append(title2, "需采购总数量")
	title2 = append(title2, "需采购总金额")
	title2 = append(title2, "备注")

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

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

	var row []interface{}
	nExcelStartRow := 0
	for i := 0; i < len(list); i++ {
		row = []interface{}{
			list[i].ErpSupplierName,          // 主供应商名称
			list[i].ErpCommodityName,         // 商品名称
			list[i].ErpCommoditySerialNumber, // 商品编号
			list[i].ErpCategoryName,          // 商品分类名称
			list[i].ErpManufacturerCode,      // 商品厂家编码
			list[i].RetailPrice,              // 指导零售价
			list[i].LastWholesalePrice,       // 最近采购价
		}

		for _, v := range list[i].StoreList {
			if v.LastMonthSales != 0 {
				row = append(row, v.LastMonthSales) // 上月销售数
			} else {
				row = append(row, "")
			}

			if v.LastWeekSales != 0 {
				row = append(row, v.LastWeekSales) // 上周销售数
			} else {
				row = append(row, "")
			}

			if v.StockCount != 0 {
				row = append(row, v.StockCount) // 库存数量
			} else {
				row = append(row, "")
			}

			if v.NeedCount != 0 {
				row = append(row, v.NeedCount) // 需采购数
			} else {
				row = append(row, "")
			}
		}

		if list[i].TotalCount != 0 {
			row = append(row, list[i].TotalCount) // 需采购总数量
		} else {
			row = append(row, "")
		}

		if list[i].TotalAmount != 0 {
			row = append(row, list[i].TotalAmount) // 需采购总金额
		} else {
			row = append(row, "")
		}

		row = append(row, list[i].Remark) // 备注

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
			err := file.SetCellValue(fSheet, cell, row[j])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		nExcelStartRow++
	}

	// 合并 "需采购总数量"，"需采购总金额" 和 "备注" 列的单元格
	strTotalCountCol, strTotalAmountCol, strRemarkCol := computeExtraColumns("G", storeCount)
	_ = file.MergeCell(fSheet, strTotalCountCol+"1", strTotalCountCol+"2")
	_ = file.MergeCell(fSheet, strTotalAmountCol+"1", strTotalAmountCol+"2")
	_ = file.MergeCell(fSheet, strRemarkCol+"1", strRemarkCol+"2")

	// 设置所有单元格的样式: 居中、加边框
	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}]}`)

	endRow := fmt.Sprintf(strRemarkCol+"%d", nExcelStartRow+2)
	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)

	_ = file.MergeCell(fSheet, "A1", "A2")
	_ = file.MergeCell(fSheet, "B1", "B2")
	_ = file.MergeCell(fSheet, "C1", "C2")
	_ = file.MergeCell(fSheet, "D1", "D2")
	_ = file.MergeCell(fSheet, "E1", "E2")
	_ = file.MergeCell(fSheet, "F1", "F2")
	_ = file.MergeCell(fSheet, "G1", "G2")

	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
}

// 导出采购需求excel-店员视角
func demandDataExportOnShopAssistant(list []DemandData) (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{}{"商品名称", "商品编号", "商品分类", "指导零售价"}
	storeCount := len(list[0].StoreList)
	var mergeCells []string // 存储需要合并的单元格范围

	for _, v := range list[0].StoreList {
		for i := 0; i < 3; i++ {
			title1 = append(title1, v.StoreName)
		}
	}

	for i := 0; i < storeCount; i++ {
		// 计算每个商户名称的起始和结束单元格
		startCol, _ := excelize.ColumnNumberToName(5 + i*4) // 从第5列开始，每个商户占4列
		endCol, _ := excelize.ColumnNumberToName(7 + i*4)
		mergeCell := startCol + "1:" + endCol + "1"
		mergeCells = append(mergeCells, mergeCell)
	}

	title1 = append(title1, "备注")

	// 合并单元格
	for _, mergeCell := range mergeCells {
		startCell, endCell := splitMergeCellCoordinates(mergeCell)
		_ = file.MergeCell(fSheet, startCell, endCell)
	}

	// 组合标题栏第二行数据
	title2 := []interface{}{"商品名称", "商品编号", "商品分类", "指导零售价"}
	for _, _ = range list[0].StoreList {
		title2 = append(title2, "上月销售数")
		title2 = append(title2, "上周销售数")
		title2 = append(title2, "库存数量")
		title2 = append(title2, "需采购数")
	}
	title2 = append(title2, "备注")

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

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

	var row []interface{}
	nExcelStartRow := 0
	for i := 0; i < len(list); i++ {
		row = []interface{}{
			list[i].ErpCommodityName,         // 商品名称
			list[i].ErpCommoditySerialNumber, // 商品编号
			list[i].ErpCategoryName,          // 商品分类名称
			list[i].RetailPrice,              // 指导零售价
		}

		for _, v := range list[i].StoreList {
			if v.LastMonthSales != 0 {
				row = append(row, v.LastMonthSales) // 上月销售数
			} else {
				row = append(row, "")
			}

			if v.LastWeekSales != 0 {
				row = append(row, v.LastWeekSales) // 上周销售数
			} else {
				row = append(row, "")
			}

			if v.StockCount != 0 {
				row = append(row, v.StockCount) // 库存数量
			} else {
				row = append(row, "")
			}

			if v.NeedCount != 0 {
				row = append(row, v.NeedCount) // 需采购数
			} else {
				row = append(row, "")
			}
		}

		row = append(row, list[i].Remark) // 备注

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
			err := file.SetCellValue(fSheet, cell, row[j])
			if err != nil {
				logger.Error("file set value err:", logger.Field("err", err))
			}
		}
		nExcelStartRow++
	}

	// 合并 "需采购总数量"，"需采购总金额" 和 "备注" 列的单元格
	strTotalCountCol, _, _ := computeExtraColumns("D", storeCount)
	_ = file.MergeCell(fSheet, strTotalCountCol+"1", strTotalCountCol+"2")

	// 设置所有单元格的样式: 居中、加边框
	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}]}`)

	endRow := fmt.Sprintf(strTotalCountCol+"%d", nExcelStartRow+2)
	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)

	_ = file.MergeCell(fSheet, "A1", "A2")
	_ = file.MergeCell(fSheet, "B1", "B2")
	_ = file.MergeCell(fSheet, "C1", "C2")
	_ = file.MergeCell(fSheet, "D1", "D2")

	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
}

// 根据合并单元格的字符串获取左上角和右下角的坐标
func splitMergeCellCoordinates(cell string) (string, string) {
	split := strings.Split(cell, ":")
	if len(split) != 2 {
		return "", ""
	}
	return split[0], split[1]
}

// 计算 "需采购总数量"，"需采购总金额" 和 "备注" 列的坐标字符串
func computeExtraColumns(startCol string, storeCount int) (string, string, string) {
	// "需采购总数量" 列在商户列表结束后的下一列
	totalCountCol := convertColumnToLetters(convertLettersToColumn(startCol) + storeCount*4 + 1)

	// "需采购总金额" 列在 "需采购总数量" 列的下一列
	totalAmountCol := convertColumnToLetters(convertLettersToColumn(totalCountCol) + 1)

	// "备注" 列在 "需采购总金额" 列的下一列
	remarkCol := convertColumnToLetters(convertLettersToColumn(totalAmountCol) + 1)

	return totalCountCol, totalAmountCol, remarkCol
}

// 将列号转换为字母
func convertColumnToLetters(column int) string {
	var result string
	for column > 0 {
		column--
		result = string('A'+column%26) + result
		column /= 26
	}
	return result
}

// 将字母转换为列号
func convertLettersToColumn(letters string) int {
	result := 0
	for _, letter := range letters {
		result *= 26
		result += int(letter) - 'A' + 1
	}
	return result
}

// GetReportByOrder 查询采购报表（按单）
func GetReportByOrder(req *ErpPurchaseReportByOrderReq, c *gin.Context) (*ErpPurchaseReportByOrderResp, error) {
	var err error
	resp := new(ErpPurchaseReportByOrderResp)
	//if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
	//	// 先筛选商品入库信息表，然后再补充采购订单信息
	//	resp, err = getReportByOrderFromCommodityOrCategory(req, c)
	//} else {
	//	// 先筛选采购订单表，再补充商品入库信息
	//	resp, err = getReportByOrderFromCommon(req, c)
	//}

	resp, err = getReportByOrderFromCommon(req, c)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// 查询采购报表（按单）：先筛选商品入库信息表，然后再补充采购订单信息
func getReportByOrderFromCommodityOrCategory(req *ErpPurchaseReportByOrderReq, c *gin.Context) (
	*ErpPurchaseReportByOrderResp, 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 {
			req.StoreId = CompareLists(storeList, req.StoreId)
			if len(req.StoreId) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &ErpPurchaseReportByOrderResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &ErpPurchaseReportByOrderResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}
	qs := orm.Eloquent.Table("erp_purchase_inventory")
	if req.ErpCommodityName != "" {
		qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
	}
	if req.ErpCategoryID != 0 {
		qs = qs.Where("erp_category_id=?", req.ErpCategoryID)
	}

	var inventoryList []ErpPurchaseInventory
	var err error
	if req.IsExport == 1 { // 导出excel
		err = qs.Order("id DESC").Find(&inventoryList).Error
	} else {
		err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&inventoryList).Error
	}
	if err != nil && err != RecordNotFound {
		logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err))
		return resp, err
	}

	// 创建一个 map，用于存储不同的 ErpCommodityId
	commodityMap := make(map[uint32]uint32)

	// 遍历 inventoryList，将不同的 ErpCommodityId 存入 map 中
	for _, inventory := range inventoryList {
		//commodityMap[inventory.ErpCommodityId] = inventory.ErpPurchaseOrderId
		commodityMap[inventory.ErpPurchaseOrderId] = inventory.ErpCommodityId
	}
	// 计算不同的 ErpCommodityId 的数量
	differentCommodityCount := len(commodityMap)

	var reportOrderDataList []ReportByOrderData
	var nTotalAmount float64
	var nTotalCount int32
	// 查询采购订单信息
	for k, _ := range commodityMap {
		var purchaseOrder ErpPurchaseOrder
		var commodityList []ErpPurchaseCommodityData

		query := orm.Eloquent.Table("erp_purchase_order")

		if len(req.ErpSupplierId) > 0 { // 供应商复选
			query = query.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId)
		}
		if len(req.StoreId) > 0 { // 门店复选
			query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
		}

		err = query.Where("id = ?", k).Find(&purchaseOrder).Error
		if err != nil {
			return nil, err
		}
		var reportByOrderData ReportByOrderData
		reportByOrderData.ErpPurchaseOrderId = purchaseOrder.ID
		reportByOrderData.SerialNumber = purchaseOrder.SerialNumber
		reportByOrderData.PurchaseType = purchaseOrder.PurchaseType
		reportByOrderData.StoreId = purchaseOrder.StoreId
		reportByOrderData.StoreName = purchaseOrder.StoreName
		reportByOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
		reportByOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
		reportByOrderData.HandlerId = purchaseOrder.HandlerId
		reportByOrderData.HandlerName = purchaseOrder.HandlerName
		reportByOrderData.MakerTime = purchaseOrder.MakerTime
		reportByOrderData.MakerId = purchaseOrder.MakerId
		reportByOrderData.MakerName = purchaseOrder.MakerName
		reportByOrderData.AuditorId = purchaseOrder.AuditorId
		reportByOrderData.AuditTime = purchaseOrder.AuditTime
		reportByOrderData.AuditorName = purchaseOrder.AuditorName
		reportByOrderData.State = purchaseOrder.State
		reportByOrderData.Remark = purchaseOrder.Remark

		if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
			reportByOrderData.MakerTime = nil
		} else {
			reportByOrderData.MakerTime = purchaseOrder.MakerTime
		}

		if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
			reportByOrderData.AuditTime = nil
		} else {
			reportByOrderData.AuditTime = purchaseOrder.AuditTime
		}

		var nAmount float64
		var nCount int32
		// 使用 map 来组合相同 ErpCommodityId 的数据
		commodityMapInfo := make(map[uint32]ErpPurchaseCommodityData)

		for _, inventory := range inventoryList {
			if inventory.ErpPurchaseOrderId == purchaseOrder.ID {
				var vCount int32
				var vAmount float64
				if inventory.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
					vAmount = -inventory.Amount
					vCount = -int32(inventory.Count)
				} else {
					vCount = int32(inventory.Count)
					vAmount = inventory.Amount
				}

				if existingData, ok := commodityMapInfo[inventory.ErpCommodityId]; ok {
					// 如果已经存在相同 ErpCommodityId 的数据，则累加 Amount 和 Total
					existingData.Amount += vAmount
					existingData.Count += vCount
					existingData.Price = existingData.Amount / float64(existingData.Count)
					commodityMapInfo[inventory.ErpCommodityId] = existingData
				} else {
					// 否则，创建新的数据
					commodityMapInfo[inventory.ErpCommodityId] = ErpPurchaseCommodityData{
						CommodityData: CommodityData{
							ErpCommodityId:   inventory.ErpCommodityId,
							ErpCommodityName: inventory.ErpCommodityName,
							ErpCategoryID:    inventory.ErpCategoryID,
							ErpCategoryName:  inventory.ErpCategoryName,
						},
						Amount: vAmount,
						Price:  inventory.ImplementationPrice,
						Count:  vCount,
					}
				}
				// 累加总金额和总数量
				nAmount += vAmount
				nCount += vCount

			}
		}

		// 将 map 中的值转换为 slice
		for _, data := range commodityMapInfo {
			commodityList = append(commodityList, data)
		}

		reportByOrderData.CommodityData = commodityList
		reportByOrderData.Amount = nAmount
		reportByOrderData.Count = nCount
		if nCount != 0 {
			reportByOrderData.Price = nAmount / float64(nCount)
		}
		reportOrderDataList = append(reportOrderDataList, reportByOrderData)

		nTotalAmount += nAmount
		nTotalCount += nCount
	}

	resp.Total = differentCommodityCount
	resp.List = reportOrderDataList
	resp.Amount = nTotalAmount
	resp.Count = nTotalCount

	if req.IsExport == 1 {
		filePath, err := reportByOrderExport(resp)
		if err != nil {
			return nil, err
		}
		resp = &ErpPurchaseReportByOrderResp{}
		resp.ExportUrl = filePath
	}

	return resp, nil
}

// 查询采购报表（按单）： 先筛选采购订单表，再补充商品入库信息
func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context) (
	*ErpPurchaseReportByOrderResp, 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 {
			req.StoreId = CompareLists(storeList, req.StoreId)
			if len(req.StoreId) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &ErpPurchaseReportByOrderResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &ErpPurchaseReportByOrderResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}
	qs := orm.Eloquent.Table("erp_purchase_order").
		Joins("JOIN erp_purchase_commodity ON erp_purchase_order.id = erp_purchase_commodity.erp_purchase_order_id").
		Where("erp_purchase_order.state != ?", ErpPurchaseOrderUnAudit).                           // 未审核订单不展示
		Where("NOT (erp_purchase_order.state = 2 AND erp_purchase_commodity.inventory_count = 0)") // 排除 commodity 表中 state=2 且 inventory_count = 0 的记录
	if req.SerialNumber != "" { // 单据编号
		qs = qs.Where("erp_purchase_order.serial_number=?", req.SerialNumber)
	}
	if req.PurchaseType != "" { // 采购类型
		qs = qs.Where("erp_purchase_order.purchase_type=?", req.PurchaseType)
	}
	if len(req.ErpSupplierId) > 0 { // 供应商复选
		var supplierIDs []uint32
		for _, supplier := range req.ErpSupplierId {
			supplierIDs = append(supplierIDs, supplier)
		}
		qs = qs.Where("erp_purchase_order.erp_supplier_id IN (?)", supplierIDs)
	}
	if len(req.StoreId) > 0 { // 门店复选
		var storeIDs []uint32
		for _, store := range req.StoreId {
			storeIDs = append(storeIDs, store)
		}
		qs = qs.Where("erp_purchase_order.store_id IN (?)", storeIDs)
	}
	if req.HandlerId != 0 { // 经手人id
		qs = qs.Where("erp_purchase_order.handler_id=?", req.HandlerId)
	}
	if req.State != 0 { // 订单状态
		qs = qs.Where("erp_purchase_order.state=?", req.State)
	}
	if req.AuditTimeStart != "" { // 审核开始时间
		parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return nil, err
		}
		qs = qs.Where("erp_purchase_order.audit_time >= ?", parse)
	}
	if req.AuditTimeEnd != "" { // 审核结束时间
		parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return nil, err
		}
		//parse = parse.AddDate(0, 0, 1)
		qs = qs.Where("erp_purchase_order.audit_time <= ?", parse)
	}
	if req.ErpCommodityName != "" { // 商品名称
		qs = qs.Where("erp_purchase_commodity.erp_commodity_name=?", req.ErpCommodityName)
	}
	if req.ErpCategoryID != 0 { // 商品分类
		categoryInfo, err := GetErpCategory(req.ErpCategoryID)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("erp_purchase_commodity.commodity_serial_number LIKE ?", categoryInfo.Number+"%")
	}

	var count int64
	err := qs.Distinct("erp_purchase_order.id").Count(&count).Error
	if err != nil {
		logger.Error("getReportByOrderFromCommon count err:", logger.Field("err", err))
		return resp, err
	}
	resp.Total = int(count)
	var orders []ErpPurchaseOrder
	if req.ErpCategoryID != 0 || req.ErpCommodityName != "" || req.InventoryTimeStart != "" || req.IsExport == 1 {
		err = qs.Order("erp_purchase_order.id DESC").Distinct("erp_purchase_order.*").Find(&orders).Error
	} else {
		err = qs.Order("erp_purchase_order.id DESC").Distinct("erp_purchase_order.*").
			Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
	}
	if err != nil && err != RecordNotFound {
		logger.Error("getReportByOrderFromCommon erp_purchase_order err:", logger.Field("err", err))
		return resp, err
	}

	storeMap, _ := GetAllStoreData()

	var reportByOrderDataList []ReportByOrderData
	var nTotalAmount float64
	var nTotalCount int32
	for i, v := range orders {
		// 同步门店名称，可能修改
		if len(storeMap) != 0 {
			temp := storeMap[orders[i].StoreId].Name
			if temp != "" {
				orders[i].StoreName = temp
			}
		}

		var reportByOrderData ReportByOrderData
		var nAmount float64
		var nCount int32

		reportByOrderData.ErpPurchaseOrderId = v.ID
		reportByOrderData.SerialNumber = v.SerialNumber
		reportByOrderData.PurchaseType = v.PurchaseType
		reportByOrderData.StoreId = v.StoreId
		reportByOrderData.StoreName = orders[i].StoreName
		reportByOrderData.ErpSupplierId = v.ErpSupplierId
		reportByOrderData.ErpSupplierName = v.ErpSupplierName
		reportByOrderData.HandlerId = v.HandlerId
		reportByOrderData.HandlerName = v.HandlerName
		//reportByOrderData.MakerTime = v.MakerTime
		reportByOrderData.MakerId = v.MakerId
		reportByOrderData.MakerName = v.MakerName
		reportByOrderData.AuditorId = v.AuditorId
		//reportByOrderData.AuditTime = v.AuditTime
		reportByOrderData.AuditorName = v.AuditorName
		reportByOrderData.State = v.State
		reportByOrderData.Remark = v.Remark

		if v.MakerTime != nil && v.MakerTime.IsZero() {
			reportByOrderData.MakerTime = nil
		} else {
			reportByOrderData.MakerTime = v.MakerTime
		}

		if v.AuditTime != nil && v.AuditTime.IsZero() {
			reportByOrderData.AuditTime = nil
		} else {
			reportByOrderData.AuditTime = v.AuditTime
		}

		reportByOrderData.CommodityData, nAmount, nCount, err = getOrderInventoryInfo(req, v.ID)
		if err != nil {
			return nil, err
		}

		if reportByOrderData.CommodityData == nil && req.InventoryTimeStart != "" {
			continue
		}

		reportByOrderData.Amount = nAmount
		reportByOrderData.Amount = math.Round(reportByOrderData.Amount*100) / 100
		reportByOrderData.Count = nCount
		if nCount != 0 {
			reportByOrderData.Price = nAmount / float64(nCount)
			reportByOrderData.Price = math.Round(reportByOrderData.Price*100) / 100
		}
		reportByOrderDataList = append(reportByOrderDataList, reportByOrderData)
		nTotalAmount += nAmount
		nTotalCount += nCount
	}

	if req.IsExport == 1 {
		resp.Total = len(reportByOrderDataList)
		resp.List = reportByOrderDataList
		nTotalAmount = math.Round(nTotalAmount*100) / 100
		resp.Amount = nTotalAmount
		resp.Count = nTotalCount
		filePath, err := reportByOrderExport(resp)
		if err != nil {
			return nil, err
		}
		resp = &ErpPurchaseReportByOrderResp{}
		resp.ExportUrl = filePath
	} else if req.ErpCategoryID != 0 || req.ErpCommodityName != "" || req.InventoryTimeStart != "" {
		resp.Total = len(reportByOrderDataList)
		// 计算分页所需的切片索引
		startIndex := page * req.PageSize
		endIndex := (page + 1) * req.PageSize
		if endIndex > len(reportByOrderDataList) {
			endIndex = len(reportByOrderDataList)
		}

		resp.List = reportByOrderDataList[startIndex:endIndex]
		nTotalAmount = math.Round(nTotalAmount*100) / 100
		resp.Amount = nTotalAmount
		resp.Count = nTotalCount
	} else {
		resp.List = reportByOrderDataList
		// 查询订单总的执行金额和数量
		totalAmount, totalCount, err := getOrderInventorySumData(req)
		if err != nil {
			return nil, err
		}
		resp.Amount = totalAmount
		resp.Count = totalCount
	}

	return resp, nil
}

type OrderInventorySum struct {
	TotalAmount float64 `gorm:"column:totalAmount"`
	TotalCount  int32   `gorm:"column:totalCount"`
}

// 查询采购订单的汇总信息：总金额，总执行数量
func getOrderInventorySumData(req *ErpPurchaseReportByOrderReq) (float64, int32, error) {
	qs := orm.Eloquent.Table("erp_purchase_order").Where("state != ?", ErpPurchaseOrderUnAudit) // 未审核订单不展示
	if req.SerialNumber != "" {                                                                 // 单据编号
		qs = qs.Where("serial_number=?", req.SerialNumber)
	}
	if req.PurchaseType != "" { // 采购类型
		qs = qs.Where("purchase_type=?", req.PurchaseType)
	}
	if len(req.ErpSupplierId) > 0 { // 供应商复选
		var supplierIDs []uint32
		for _, supplier := range req.ErpSupplierId {
			supplierIDs = append(supplierIDs, supplier)
		}
		qs = qs.Where("erp_supplier_id IN (?)", supplierIDs)
	}
	if len(req.StoreId) > 0 { // 门店复选
		var storeIDs []uint32
		for _, store := range req.StoreId {
			storeIDs = append(storeIDs, store)
		}
		qs = qs.Where("store_id IN (?)", storeIDs)
	}
	if req.HandlerId != 0 { // 经手人id
		qs = qs.Where("handler_id=?", req.HandlerId)
	}
	if req.State != 0 { // 订单状态
		qs = qs.Where("state=?", req.State)
	}
	if req.AuditTimeStart != "" { // 审核开始时间
		parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return 0, 0, err
		}
		qs = qs.Where("audit_time > ?", parse)
	}
	if req.AuditTimeEnd != "" { // 审核结束时间
		parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return 0, 0, err
		}
		qs = qs.Where("audit_time < ?", parse)
	}

	var result OrderInventorySum

	// 使用联表查询获取总金额和总执行数量
	err := qs.Joins("LEFT JOIN erp_purchase_inventory ON erp_purchase_inventory.erp_purchase_order_id = erp_purchase_order.id").
		Select("SUM(CASE WHEN erp_purchase_order.purchase_type = 'reject' THEN -erp_purchase_inventory.amount ELSE erp_purchase_inventory.amount END) as totalAmount, " +
			"SUM(CASE WHEN erp_purchase_order.purchase_type = 'reject' THEN -erp_purchase_inventory.count ELSE erp_purchase_inventory.count END) as totalCount").
		Scan(&result).Error
	if err != nil {
		logger.Errorf("getOrderInventorySumData err:", err)
		return 0, 0, err
	}

	// 四舍五入保留2位小数
	result.TotalAmount = math.Round(result.TotalAmount*100) / 100

	return result.TotalAmount, result.TotalCount, nil
}

// 查询采购订单的入库信息
func getOrderInventoryInfo(req *ErpPurchaseReportByOrderReq, erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, int32, error) {
	var inventoryList []ErpPurchaseInventory
	qs := orm.Eloquent.Table("erp_purchase_inventory").
		Where("erp_purchase_order_id = ?", erpPurchaseOrderId)

	if req.ErpCommodityName != "" { // 商品名称
		qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
	}
	if req.ErpCategoryID != 0 { // 商品分类
		categoryInfo, err := GetErpCategory(req.ErpCategoryID)
		if err != nil {
			return nil, 0, 0, err
		}
		qs = qs.Where("commodity_serial_number LIKE ?", categoryInfo.Number+"%")
	}
	if req.InventoryTimeStart != "" { // 入库开始时间
		parse, err := time.Parse(QueryTimeFormat, req.InventoryTimeStart)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return nil, 0, 0, err
		}
		qs = qs.Where("created_at >= ?", parse)
	}
	if req.InventoryTimeEnd != "" { // 入库结束时间
		parse, err := time.Parse(QueryTimeFormat, req.InventoryTimeEnd)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return nil, 0, 0, err
		}
		qs = qs.Where("created_at <= ?", parse)
	}

	err := qs.Find(&inventoryList).Error
	if err != nil {
		logger.Error("getOrderInventoryInfo err:", logger.Field("err", err))
		return nil, 0, 0, err
	}

	//if len(inventoryList) == 0 {
	//	//return nil, 0, 0, errors.New("未查询到采购订单的入库信息")
	//	return nil, 0, 0, nil
	//}

	if len(inventoryList) == 0 && req.InventoryTimeStart != "" {
		return nil, 0, 0, nil
	}

	// 使用 map 来组合相同 ErpCommodityId 的数据
	//commodityMap := make(map[uint32]ErpPurchaseCommodityData)
	commodityMap := make(map[uint32]map[time.Time]ErpPurchaseCommodityData)
	var nAmount float64
	var nCount int32

	// 遍历库存列表，组合相同 ErpCommodityId 的数据
	for _, v := range inventoryList {
		if _, exists := commodityMap[v.ErpCommodityId]; !exists {
			commodityMap[v.ErpCommodityId] = make(map[time.Time]ErpPurchaseCommodityData)
		}

		var vCount int32
		var vAmount float64

		//// 商品名称和分类筛选
		//if req.ErpCommodityName != "" && v.ErpCommodityName != req.ErpCommodityName {
		//	continue
		//}
		//if req.ErpCategoryID != 0 && v.ErpCategoryID != req.ErpCategoryID {
		//	continue
		//}

		if v.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
			vAmount = -v.Amount
			vCount = -int32(v.Count)
		} else {
			vCount = int32(v.Count)
			vAmount = v.Amount
		}

		if existingData, ok := commodityMap[v.ErpCommodityId][v.CreatedAt]; ok {
			// 如果已经存在相同 ErpCommodityId 的数据，则累加 Amount 和 Total
			existingData.Amount += vAmount
			existingData.Count += vCount
			existingData.Price = existingData.Amount / float64(existingData.Count)
			commodityMap[v.ErpCommodityId][v.CreatedAt] = existingData
		} else {
			inventoryTime := v.CreatedAt
			// 否则，创建新的数据
			commodityMap[v.ErpCommodityId][v.CreatedAt] = ErpPurchaseCommodityData{
				CommodityData: CommodityData{
					ErpCommodityId:   v.ErpCommodityId,
					ErpCommodityName: v.ErpCommodityName,
					ErpCategoryID:    v.ErpCategoryID,
					ErpCategoryName:  v.ErpCategoryName,
				},
				Amount:        vAmount,
				Price:         v.ImplementationPrice,
				Count:         vCount,
				InventoryTime: &inventoryTime,
			}
		}
		// 累加总金额和总数量
		nAmount += vAmount
		nCount += vCount
	}

	if len(inventoryList) == 0 { // 没有入库信息，默认展示商品名称和分类
		es := orm.Eloquent.Table("erp_purchase_commodity").
			Where("erp_purchase_order_id = ?", erpPurchaseOrderId)

		if req.ErpCommodityName != "" { // 商品名称
			es = es.Where("erp_commodity_name=?", req.ErpCommodityName)
		}
		if req.ErpCategoryID != 0 { // 商品分类
			categoryInfo, err := GetErpCategory(req.ErpCategoryID)
			if err != nil {
				return nil, 0, 0, err
			}
			es = es.Where("commodity_serial_number LIKE ?", categoryInfo.Number+"%")
		}

		var commodityList []ErpPurchaseCommodity
		err = es.Find(&commodityList).Error
		if err != nil {
			return nil, 0, 0, err
		}

		for _, v := range commodityList {
			if _, exists := commodityMap[v.ErpCommodityId]; !exists {
				commodityMap[v.ErpCommodityId] = make(map[time.Time]ErpPurchaseCommodityData)
			}

			commodityMap[v.ErpCommodityId][v.CreatedAt] = ErpPurchaseCommodityData{
				CommodityData: CommodityData{
					ErpCommodityId:   v.ErpCommodityId,
					ErpCommodityName: v.ErpCommodityName,
					ErpCategoryID:    v.ErpCategoryID,
					ErpCategoryName:  v.ErpCategoryName,
				},
				Amount: 0,
				Price:  0,
				Count:  0,
			}
		}
	}

	// 将 map 中的值转换为 slice
	var resp []ErpPurchaseCommodityData
	for _, timeMap := range commodityMap {
		for _, data := range timeMap {
			data.Price = math.Round(data.Price*100) / 100
			data.Amount = math.Round(data.Amount*100) / 100
			resp = append(resp, data)
		}
	}

	return resp, nAmount, nCount, nil
}

// 导出采购报表（按单）excel
func reportByOrderExport(req *ErpPurchaseReportByOrderResp) (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{}
	var row2 []interface{}
	nExcelStartRow := 0
	for _, orderData := range req.List {
		var orderType string
		switch orderData.PurchaseType {
		case "procure":
			orderType = "采购入库"
		case "reject":
			orderType = "采购退货"
		}

		var orderStatus string
		switch orderData.State { // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
		case ErpPurchaseOrderUnAudit:
			orderStatus = "待审核"
		case ErpPurchaseOrderWaitInventory:
			orderStatus = "待入库"
		case ErpPurchaseOrderWaitReject:
			orderStatus = "待退货"
		case ErpPurchaseOrderFinished:
			orderStatus = "已完成"
		case ErpPurchaseOrderEnd:
			orderStatus = "已终止"
		}

		var strTime string
		if orderData.AuditTime != nil {
			strTime = orderData.AuditTime.Format(ExcelTimeFormat)
		} else {
			strTime = ""
		}

		row1 = []interface{}{
			orderData.SerialNumber,    // 单据编号
			orderType,                 // 类型
			orderData.StoreName,       // 店铺名称
			orderData.Remark,          // 备注
			orderData.ErpSupplierName, // 供应商
			orderData.HandlerName,     // 经手人
			orderData.MakerName,       // 制单人
			strTime,                   // 审核时间
			orderStatus,               // 订单状态
			"",                        // 商品名称
			"",                        // 一级分类
			"",                        // 二级分类
			"",                        // 三级分类
			orderData.Amount,          // 已执行金额
			orderData.Price,           // 执行单价
			orderData.Count,           // 已执行数量
			"",                        // 入库时间
		}

		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++

		for _, commodity := range orderData.CommodityData {
			var inventoryTime string
			if commodity.InventoryTime != nil {
				inventoryTime = commodity.InventoryTime.Format(ExcelTimeFormat)
			} else {
				inventoryTime = ""
			}

			categoryLevels, _ := GetCategoryLevels(commodity.ErpCategoryID)
			row2 = []interface{}{
				orderData.SerialNumber,     // 单据编号
				orderType,                  // 类型
				orderData.StoreName,        // 店铺名称
				orderData.Remark,           // 备注
				orderData.ErpSupplierName,  // 供应商
				orderData.HandlerName,      // 经手人
				orderData.MakerName,        // 制单人
				strTime,                    // 审核时间
				orderStatus,                // 订单状态
				commodity.ErpCommodityName, // 商品名称
				categoryLevels.Level1.Name, // 一级分类
				categoryLevels.Level2.Name, // 二级分类
				categoryLevels.Level3.Name, // 三级分类
				commodity.Amount,           // 已执行金额
				commodity.Price,            // 执行单价
				commodity.Count,            // 已执行数量
				inventoryTime,              // 入库时间
			}

			for j, _ := range row2 {
				cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
				err := file.SetCellValue(fSheet, cell, row2[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.Amount, "--", req.Count, ""}
	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", "D2")
	_ = file.MergeCell(fSheet, "E1", "E2")
	_ = file.MergeCell(fSheet, "F1", "F2")
	_ = file.MergeCell(fSheet, "G1", "G2")
	_ = file.MergeCell(fSheet, "H1", "H2")
	_ = file.MergeCell(fSheet, "I1", "I2")
	_ = file.MergeCell(fSheet, "J1", "J2")
	_ = file.MergeCell(fSheet, "N1", "N2")
	_ = file.MergeCell(fSheet, "O1", "O2")
	_ = file.MergeCell(fSheet, "P1", "P2")
	_ = file.MergeCell(fSheet, "Q1", "Q2")

	_ = file.MergeCell(fSheet, "K1", "M1")

	//设置单元格高度
	file.SetRowHeight("Sheet1", 1, 20)

	// 设置单元格大小
	file.SetColWidth("Sheet1", "A", "A", 13)
	file.SetColWidth("Sheet1", "C", "C", 25)
	file.SetColWidth("Sheet1", "H", "H", 20)
	file.SetColWidth("Sheet1", "J", "J", 18)
	file.SetColWidth("Sheet1", "Q", "Q", 20)

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

// GetReportByCommodity 查询采购报表（按商品）
func GetReportByCommodity(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (*ErpPurchaseReportByCommodityResp, error) {
	var err error
	resp := new(ErpPurchaseReportByCommodityResp)
	//if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
	//	// 先筛选商品入库信息表，然后再补充采购订单信息
	//	resp, err = getReportByCommodityFromCommodityOrCategory(req, c)
	//} else {
	//	// 先筛选采购订单表，再补充商品入库信息
	//	resp, err = getReportByCommodityFromCommon(req, c)
	//}

	resp, err = getReportByCommodityFromCommon(req, c)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// 查询采购报表（按商品）：先筛选商品入库信息表，然后再补充采购订单信息
func getReportByCommodityFromCommodityOrCategory(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (
	*ErpPurchaseReportByCommodityResp, 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 {
			req.StoreId = CompareLists(storeList, req.StoreId)
			if len(req.StoreId) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &ErpPurchaseReportByCommodityResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &ErpPurchaseReportByCommodityResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}

	qs := orm.Eloquent.Table("erp_purchase_inventory")
	if req.ErpCommodityName != "" {
		qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
	}
	if req.ErpCategoryID != 0 {
		qs = qs.Where("erp_category_id=?", req.ErpCategoryID)
	}

	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error("getReportByOrderFromCommodityOrCategory count err:", logger.Field("err", err))
		return resp, err
	}

	var inventoryList []ErpPurchaseInventory
	err = qs.Order("id DESC").Find(&inventoryList).Error
	if err != nil && err != RecordNotFound {
		logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err))
		return resp, err
	}

	commodityIDMap := make(map[uint32]map[uint32]ErpPurchaseInventory)
	// 遍历 inventoryList
	for _, inventory := range inventoryList {
		// 如果该商品id已经在map中，则将该订单id加入到对应的set中
		if ids, ok := commodityIDMap[inventory.ErpCommodityId]; ok {
			ids[inventory.ErpPurchaseOrderId] = inventory
		} else {
			// 如果该商品id不在map中，则创建一个新的map并加入订单id及其对应的 ErpPurchaseInventory
			commodityIDMap[inventory.ErpCommodityId] = map[uint32]ErpPurchaseInventory{
				inventory.ErpPurchaseOrderId: inventory,
			}
		}
	}
	resp.Total = len(commodityIDMap)

	var reportByCommodityDataList []ReportByCommodityData
	var totalData PurchaseData

	// 遍历 map 获取去重的 ErpPurchaseOrderId
	for _, orderIdSet := range commodityIDMap {
		var reportByCommodityData ReportByCommodityData
		if len(orderIdSet) != 0 {
			for _, item := range orderIdSet {
				reportByCommodityData.ErpCommodityId = item.ErpCommodityId
				reportByCommodityData.ErpCommodityName = item.ErpCommodityName
				reportByCommodityData.ErpCategoryID = item.ErpCategoryID
				reportByCommodityData.ErpCategoryName = item.ErpCategoryName
				break
			}
		}

		var totalPurchaseData PurchaseData
		var purchaseOrderDataList []ErpCommodityPurchaseOrderData
		for orderId := range orderIdSet {
			purchaseOrderData, err := getPurchaseOrderData(orderId, req)
			if err != nil {
				return nil, err
			}

			purchaseOrderDataList = append(purchaseOrderDataList, purchaseOrderData)

			totalPurchaseData.PlanCount += purchaseOrderData.PlanCount
			totalPurchaseData.PlanPrice += purchaseOrderData.PlanPrice
			totalPurchaseData.PlanAmount += purchaseOrderData.PlanAmount
			totalPurchaseData.Amount += purchaseOrderData.Amount
			totalPurchaseData.Price += purchaseOrderData.Price
			totalPurchaseData.Count += purchaseOrderData.Count
			totalPurchaseData.NonExecutionAmount += purchaseOrderData.NonExecutionAmount
			totalPurchaseData.NonExecutionCount += purchaseOrderData.NonExecutionCount
		}

		reportByCommodityData.PlanCount = totalPurchaseData.PlanCount
		reportByCommodityData.PlanPrice = totalPurchaseData.PlanPrice
		reportByCommodityData.PlanAmount = totalPurchaseData.PlanAmount
		reportByCommodityData.Amount = totalPurchaseData.Amount
		reportByCommodityData.Price = totalPurchaseData.Price
		reportByCommodityData.Count = totalPurchaseData.Count
		reportByCommodityData.NonExecutionAmount = totalPurchaseData.NonExecutionAmount
		reportByCommodityData.NonExecutionCount = totalPurchaseData.NonExecutionCount

		totalData.PlanCount += reportByCommodityData.PlanCount
		totalData.PlanAmount += reportByCommodityData.PlanAmount
		totalData.Amount += reportByCommodityData.Amount
		totalData.Count += reportByCommodityData.Count
		totalData.NonExecutionAmount += reportByCommodityData.NonExecutionAmount
		totalData.NonExecutionCount += reportByCommodityData.NonExecutionCount

		reportByCommodityData.OrderInfo = purchaseOrderDataList
		reportByCommodityDataList = append(reportByCommodityDataList, reportByCommodityData)
	}

	sortByCommodityIDDesc(reportByCommodityDataList)
	resp.Total = len(reportByCommodityDataList)

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

	resp.List = reportByCommodityDataList[startIndex:endIndex]
	resp.PlanCount = totalData.PlanCount
	resp.PlanAmount = totalData.PlanAmount
	resp.Amount = totalData.Amount
	resp.Count = totalData.Count
	resp.NonExecutionAmount = totalData.NonExecutionAmount
	resp.NonExecutionCount = totalData.NonExecutionCount

	if req.IsExport == 1 {
		filePath, err := reportByCommodityExport(resp)
		if err != nil {
			return nil, err
		}
		resp = &ErpPurchaseReportByCommodityResp{}
		resp.ExportUrl = filePath
	}

	return resp, nil
}

// 查询采购订单信息
func getPurchaseOrderData(orderID uint32, req *ErpPurchaseReportByCommodityReq) (ErpCommodityPurchaseOrderData, error) {
	var purchaseOrderData ErpCommodityPurchaseOrderData
	// 查询采购订单信息
	var purchaseOrder ErpPurchaseOrder
	qs := orm.Eloquent.Table("erp_purchase_order")

	if len(req.ErpSupplierId) > 0 { // 供应商复选
		qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId)
	}
	if len(req.StoreId) > 0 { // 门店复选
		qs = qs.Where("store_id IN (?)", req.StoreId)
	}
	err := qs.Where("id = ?", orderID).Find(&purchaseOrder).Error
	if err != nil {
		return purchaseOrderData, err
	}

	// 查询采购订单的计划和执行信息
	purchaseData, err := getPurchaseData(purchaseOrder.ID)
	if err != nil {
		return purchaseOrderData, err
	}

	// 组合数据
	purchaseOrderData.ErpPurchaseOrderId = purchaseOrder.ID
	purchaseOrderData.SerialNumber = purchaseOrder.SerialNumber
	purchaseOrderData.PurchaseType = purchaseOrder.PurchaseType
	purchaseOrderData.StoreId = purchaseOrder.StoreId
	purchaseOrderData.StoreName = purchaseOrder.StoreName
	purchaseOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
	purchaseOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
	purchaseOrderData.HandlerId = purchaseOrder.HandlerId
	purchaseOrderData.HandlerName = purchaseOrder.HandlerName
	//purchaseOrderData.MakerTime = purchaseOrder.MakerTime
	purchaseOrderData.MakerId = purchaseOrder.MakerId
	purchaseOrderData.MakerName = purchaseOrder.MakerName
	purchaseOrderData.AuditorId = purchaseOrder.AuditorId
	//purchaseOrderData.AuditTime = purchaseOrder.AuditTime
	purchaseOrderData.AuditorName = purchaseOrder.AuditorName

	if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
		purchaseOrderData.MakerTime = nil
	} else {
		purchaseOrderData.MakerTime = purchaseOrder.MakerTime
	}
	if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
		purchaseOrderData.AuditTime = nil
	} else {
		purchaseOrderData.AuditTime = purchaseOrder.AuditTime
	}

	purchaseOrderData.PlanCount = purchaseData.PlanCount
	purchaseOrderData.PlanPrice = purchaseData.PlanPrice
	purchaseOrderData.PlanAmount = purchaseData.PlanAmount
	purchaseOrderData.Amount = purchaseData.Amount
	purchaseOrderData.Price = purchaseData.Price
	purchaseOrderData.Count = purchaseData.Count
	purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount
	purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount

	if purchaseOrder.PurchaseType == ErpRejectOrder { // 退货单
		purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount
		purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount
		purchaseOrderData.Amount = -purchaseOrderData.Amount
		purchaseOrderData.Count = -purchaseOrderData.Count
		purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount
		purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount
	}

	return purchaseOrderData, nil
}

// getPurchaseData 根据 ErpPurchaseCommodity 表查询采购数据
func getPurchaseData(erpPurchaseOrderId uint32) (PurchaseData, error) {
	var purchaseData PurchaseData

	err := orm.Eloquent.Raw(`
		SELECT
			SUM(pc.count) AS plan_count,
			AVG(pc.price) AS plan_price,
			SUM(pc.amount) AS plan_amount,
			SUM(pi.count) AS count,
			AVG(pi.implementation_price) AS price,
			SUM(pi.amount) AS amount
		FROM
			erp_purchase_commodity pc
		JOIN
			erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
		WHERE
			pc.erp_purchase_order_id = ?
		GROUP BY
			pc.erp_purchase_order_id
	`, erpPurchaseOrderId).Scan(&purchaseData).Error
	if err != nil {
		logger.Error("getPurchaseData err:", logger.Field("err", err))
		return purchaseData, err
	}

	// 计算未执行金额和未执行数量
	purchaseData.NonExecutionAmount = purchaseData.PlanAmount - purchaseData.Amount
	purchaseData.NonExecutionCount = purchaseData.PlanCount - purchaseData.Count

	return purchaseData, nil
}

// 查询采购报表（按商品）：先筛选采购订单表，再补充商品入库信息
func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (
	*ErpPurchaseReportByCommodityResp, 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 {
			req.StoreId = CompareLists(storeList, req.StoreId)
			if len(req.StoreId) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &ErpPurchaseReportByCommodityResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &ErpPurchaseReportByCommodityResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}
	qs := orm.Eloquent.Table("erp_purchase_order").
		Joins("JOIN erp_purchase_commodity ON erp_purchase_order.id = erp_purchase_commodity.erp_purchase_order_id").
		Where("state NOT IN (?, ?)", ErpPurchaseOrderUnAudit, ErpPurchaseOrderEnd)
	if req.SerialNumber != "" { // 单据编号
		qs = qs.Where("erp_purchase_order.serial_number=?", req.SerialNumber)
	}
	if req.PurchaseType != "" { // 采购类型
		qs = qs.Where("erp_purchase_order.purchase_type=?", req.PurchaseType)
	}
	if len(req.ErpSupplierId) > 0 { // 供应商复选
		qs = qs.Where("erp_purchase_order.erp_supplier_id IN ?", req.ErpSupplierId)
	}
	if len(req.StoreId) > 0 { // 门店复选
		qs = qs.Where("erp_purchase_order.store_id IN ?", req.StoreId)
	}
	if req.HandlerId != 0 { // 经手人id
		qs = qs.Where("erp_purchase_order.handler_id=?", req.HandlerId)
	}
	if req.State != 0 { // 订单状态
		qs = qs.Where("erp_purchase_order.state=?", req.State)
	}
	if req.AuditTimeStart != "" { // 审核开始时间
		parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return nil, err
		}
		qs = qs.Where("erp_purchase_order.audit_time > ?", parse)
	}
	if req.AuditTimeEnd != "" { // 审核结束时间
		parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
		if err != nil {
			logger.Errorf("erpPurchaseOrderList err:", err)
			return nil, err
		}
		//parse = parse.AddDate(0, 0, 1)
		qs = qs.Where("erp_purchase_order.audit_time < ?", parse)
	}

	if req.ErpCommodityName != "" { // 商品名称
		qs = qs.Where("erp_purchase_commodity.erp_commodity_name=?", req.ErpCommodityName)
	}
	if req.ErpCategoryID != 0 { // 商品分类
		categoryInfo, err := GetErpCategory(req.ErpCategoryID)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("erp_purchase_commodity.commodity_serial_number LIKE ?", categoryInfo.Number+"%")
	}

	var count int64
	err := qs.Distinct("erp_purchase_order.id").Count(&count).Error
	if err != nil {
		logger.Error("getReportByOrderFromCommon count err:", logger.Field("err", err))
		return resp, err
	}

	var orders []ErpPurchaseOrder
	err = qs.Order("erp_purchase_order.id DESC").Distinct("erp_purchase_order.*").Find(&orders).Error
	if err != nil && err != RecordNotFound {
		logger.Error("getReportByOrderFromCommon erp_purchase_order err:", logger.Field("err", err))
		return resp, err
	}

	// 查询所有商品id及其对应的orderId
	//commodityAndOrderIdMap, err := getAllOrderCommodity(page, req.PageSize, int(req.IsExport))
	commodityAndOrderIdMap, err := getAllOrderCommodity(req)
	if err != nil {
		return nil, err
	}

	//var wg sync.WaitGroup
	//ch := make(chan TempData, len(orders)*len(commodityAndOrderIdMap))
	//
	//// 补充所有采购订单的商品信息和采购执行数量
	//for _, v := range orders {
	//	commodityIds := findCommodityIDsByOrderID(v.ID, commodityAndOrderIdMap)
	//	// 获取每个采购订单的每个商品的采购和执行信息
	//	for _, commodityId := range commodityIds {
	//		purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(v.ID, commodityId)
	//		if err != nil {
	//			return nil, err
	//		}
	//
	//		tempData := TempData{
	//			CommodityData:                 commodityData,
	//			ErpCommodityPurchaseOrderData: purchaseOrderData,
	//		}
	//		tempDataMap[commodityId] = append(tempDataMap[commodityId], tempData)
	//	}
	//}
	//wg.Wait()
	//close(ch)

	// 并发查询的限制
	const maxConcurrency = 10
	sem := make(chan struct{}, maxConcurrency)
	var wg sync.WaitGroup
	ch := make(chan TempData, len(orders)*len(commodityAndOrderIdMap))

	// 并发查询每个采购订单的每个商品的采购和执行信息
	for _, v := range orders {
		commodityIds := findCommodityIDsByOrderID(v.ID, commodityAndOrderIdMap)
		for _, commodityID := range commodityIds {
			wg.Add(1)
			sem <- struct{}{}
			go func(orderID, commodityID uint32) {
				defer wg.Done()
				defer func() { <-sem }()
				purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(orderID, commodityID)
				if err != nil {
					logger.Errorf("getPurchaseOrderAndCommodityData err:", err)
					return
				}
				tempData := TempData{
					CommodityData:                 commodityData,
					ErpCommodityPurchaseOrderData: purchaseOrderData,
				}
				ch <- tempData
			}(v.ID, commodityID)
		}
	}

	go func() {
		wg.Wait()
		close(ch)
	}()

	tempDataMap := make(map[uint32][]TempData)
	for data := range ch {
		tempDataMap[data.ErpCommodityId] = append(tempDataMap[data.ErpCommodityId], data)
	}

	storeMap, _ := GetAllStoreData()

	var dataList []ReportByCommodityData
	var totalData PurchaseData
	// tempDataList，按照商品id进行归类
	for _, tempDataList := range tempDataMap {
		var reportData ReportByCommodityData
		for _, v := range tempDataList {
			//// 商品名称和分类筛选
			//if req.ErpCommodityName != "" && v.ErpCommodityName != req.ErpCommodityName {
			//	continue
			//}
			//if req.ErpCategoryID != 0 && v.ErpCategoryID != req.ErpCategoryID {
			//	continue
			//}

			reportData.ErpCategoryID = v.ErpCategoryID
			reportData.ErpCategoryName = v.ErpCategoryName
			reportData.ErpCommodityId = v.ErpCommodityId
			reportData.ErpCommodityName = v.ErpCommodityName

			reportData.PlanCount += v.PlanCount
			reportData.PlanAmount += v.PlanAmount
			reportData.Amount += v.Amount
			reportData.Count += v.Count
			reportData.NonExecutionAmount += v.NonExecutionAmount
			reportData.NonExecutionCount += v.NonExecutionCount
			if reportData.PlanCount != 0 {
				reportData.PlanPrice = reportData.PlanAmount / float64(reportData.PlanCount)
				reportData.PlanPrice = math.Round(reportData.PlanPrice*100) / 100
			}
			if reportData.Count != 0 {
				reportData.Price = reportData.Amount / float64(reportData.Count)
				reportData.Price = math.Round(reportData.Price*100) / 100
			}

			purchaseOrderData := ErpCommodityPurchaseOrderData{
				CommonData{
					ErpPurchaseOrderId: v.ErpPurchaseOrderId,
					SerialNumber:       v.SerialNumber,
					PurchaseType:       v.PurchaseType,
					StoreId:            v.StoreId,
					StoreName:          v.StoreName,
					ErpSupplierId:      v.ErpSupplierId,
					ErpSupplierName:    v.ErpSupplierName,
					HandlerId:          v.HandlerId,
					HandlerName:        v.HandlerName,
					//MakerTime:          v.MakerTime,
					MakerId:   v.MakerId,
					MakerName: v.MakerName,
					AuditorId: v.AuditorId,
					//AuditTime:          v.AuditTime,
					AuditorName: v.AuditorName,
				},
				PurchaseData{
					PlanCount:          v.PlanCount,
					PlanPrice:          math.Round(v.PlanPrice*100) / 100,
					PlanAmount:         math.Round(v.PlanAmount*100) / 100,
					Amount:             math.Round(v.Amount*100) / 100,
					Price:              math.Round(v.Price*100) / 100,
					Count:              v.Count,
					NonExecutionAmount: math.Round(v.NonExecutionAmount*100) / 100,
					NonExecutionCount:  v.NonExecutionCount,
				},
			}

			if len(storeMap) != 0 {
				temp := storeMap[v.StoreId].Name
				if temp != "" {
					purchaseOrderData.StoreName = temp
				}
			}

			//if v.PurchaseType == ErpRejectOrder { // 退货单
			//	reportData.PlanCount = -reportData.PlanCount
			//	reportData.PlanAmount = -reportData.PlanAmount
			//	reportData.Amount = -reportData.Amount
			//	reportData.Count = -reportData.Count
			//	reportData.NonExecutionAmount = -reportData.NonExecutionAmount
			//	reportData.NonExecutionCount = -reportData.NonExecutionCount
			//
			//	purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount
			//	purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount
			//	purchaseOrderData.Amount = -purchaseOrderData.Amount
			//	purchaseOrderData.Count = -purchaseOrderData.Count
			//	purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount
			//	purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount
			//}

			if v.MakerTime != nil && v.MakerTime.IsZero() {
				purchaseOrderData.MakerTime = nil
			} else {
				purchaseOrderData.MakerTime = v.MakerTime
			}

			if v.AuditTime != nil && v.AuditTime.IsZero() {
				purchaseOrderData.AuditTime = nil
			} else {
				purchaseOrderData.AuditTime = v.AuditTime
			}

			reportData.PlanAmount = math.Round(reportData.PlanAmount*100) / 100
			reportData.Amount = math.Round(reportData.Amount*100) / 100
			reportData.NonExecutionAmount = math.Round(reportData.NonExecutionAmount*100) / 100
			reportData.OrderInfo = append(reportData.OrderInfo, purchaseOrderData)
		}
		if reportData.ErpCategoryID == 0 || len(reportData.OrderInfo) == 0 {
			continue
		}

		dataList = append(dataList, reportData)

		totalData.PlanCount += reportData.PlanCount
		totalData.PlanAmount += reportData.PlanAmount
		totalData.Amount += reportData.Amount
		totalData.Count += reportData.Count
		totalData.NonExecutionAmount += reportData.NonExecutionAmount
		totalData.NonExecutionCount += reportData.NonExecutionCount
	}

	sortByCommodityIDDesc(dataList)
	resp.Total = len(dataList)

	if req.IsExport == 1 {
		resp.List = dataList
	} else {
		// 计算分页所需的切片索引
		startIndex := page * req.PageSize
		endIndex := (page + 1) * req.PageSize
		if endIndex > len(dataList) {
			endIndex = len(dataList)
		}
		resp.List = dataList[startIndex:endIndex]
	}

	resp.PlanCount = totalData.PlanCount
	resp.PlanAmount = math.Round(totalData.PlanAmount*100) / 100
	resp.Amount = math.Round(totalData.Amount*100) / 100
	resp.Count = totalData.Count
	resp.NonExecutionAmount = math.Round(totalData.NonExecutionAmount*100) / 100
	resp.NonExecutionCount = totalData.NonExecutionCount

	if req.IsExport == 1 {
		filePath, err := reportByCommodityExport(resp)
		if err != nil {
			return nil, err
		}
		resp = &ErpPurchaseReportByCommodityResp{}
		resp.ExportUrl = filePath
	}

	return resp, nil
}

func getPurchaseOrderAndCommodityDataAsync(orderID, commodityID uint32, ch chan<- TempData, wg *sync.WaitGroup) {
	defer wg.Done()

	purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(orderID, commodityID)
	if err != nil {
		logger.Errorf("getPurchaseOrderAndCommodityDataAsync err:", err)
		return
	}

	tempData := TempData{
		CommodityData:                 commodityData,
		ErpCommodityPurchaseOrderData: purchaseOrderData,
	}
	ch <- tempData
}

// 按照商品ID进行倒序排序的 less 函数
func sortByCommodityIDDesc(dataList []ReportByCommodityData) {
	sort.Slice(dataList, func(i, j int) bool {
		return dataList[i].ErpCommodityId > dataList[j].ErpCommodityId
	})
}

// 查询采购订单信息
func getPurchaseOrderAndCommodityData(orderID, commodityId uint32) (ErpCommodityPurchaseOrderData, CommodityData, error) {
	var purchaseOrderData ErpCommodityPurchaseOrderData
	// 查询采购订单信息
	var purchaseOrder ErpPurchaseOrder
	err := orm.Eloquent.Table("erp_purchase_order").Where("id = ?", orderID).Find(&purchaseOrder).Error
	if err != nil {
		return ErpCommodityPurchaseOrderData{}, CommodityData{}, err
	}

	// 查询采购订单的计划和执行信息
	purchaseData, commodityData, err := getSignalPurchaseData(purchaseOrder.ID, commodityId, purchaseOrder.PurchaseType)
	if err != nil {
		return ErpCommodityPurchaseOrderData{}, CommodityData{}, err
	}

	// 组合数据
	purchaseOrderData.ErpPurchaseOrderId = purchaseOrder.ID
	purchaseOrderData.SerialNumber = purchaseOrder.SerialNumber
	purchaseOrderData.PurchaseType = purchaseOrder.PurchaseType
	purchaseOrderData.StoreId = purchaseOrder.StoreId
	purchaseOrderData.StoreName = purchaseOrder.StoreName
	purchaseOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
	purchaseOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
	purchaseOrderData.HandlerId = purchaseOrder.HandlerId
	purchaseOrderData.HandlerName = purchaseOrder.HandlerName
	purchaseOrderData.MakerId = purchaseOrder.MakerId
	purchaseOrderData.MakerName = purchaseOrder.MakerName
	purchaseOrderData.AuditorId = purchaseOrder.AuditorId
	purchaseOrderData.AuditTime = purchaseOrder.AuditTime
	purchaseOrderData.AuditorName = purchaseOrder.AuditorName

	if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
		purchaseOrderData.MakerTime = nil
	} else {
		purchaseOrderData.MakerTime = purchaseOrder.MakerTime
	}

	if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
		purchaseOrderData.AuditTime = nil
	} else {
		purchaseOrderData.AuditTime = purchaseOrder.AuditTime
	}

	purchaseOrderData.PlanCount = purchaseData.PlanCount
	purchaseOrderData.PlanPrice = purchaseData.PlanPrice
	purchaseOrderData.PlanAmount = purchaseData.PlanAmount
	purchaseOrderData.Amount = purchaseData.Amount
	purchaseOrderData.Price = purchaseData.Price
	purchaseOrderData.Count = purchaseData.Count
	if purchaseOrder.State != ErpPurchaseOrderEnd {
		purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount
		purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount
	}

	return purchaseOrderData, commodityData, nil
}

// getSignalPurchaseData 根据 ErpPurchaseCommodity 表查询采购数据
func getSignalPurchaseData(erpPurchaseOrderId, commodityId uint32, purchaseType string) (PurchaseData, CommodityData, error) {
	var purchaseData PurchaseData
	var commodityData CommodityData

	//err := orm.Eloquent.Raw(`
	//	SELECT
	//		SUM(pc.count) AS plan_count,
	//		AVG(pc.price) AS plan_price,
	//		SUM(pc.amount) AS plan_amount,
	//		SUM(pi.count) AS count,
	//		AVG(pi.implementation_price) AS price,
	//		SUM(pi.amount) AS amount
	//	FROM
	//		erp_purchase_commodity pc
	//	JOIN
	//		erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
	//	WHERE
	//		pc.erp_purchase_order_id = ? and pc.erp_commodity_id = ?
	//	GROUP BY
	//		pc.erp_purchase_order_id
	//`, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error

	var err error
	if purchaseType == ErpProcureOrder {
		err = orm.Eloquent.Raw(`
		    SELECT
    plan.plan_count AS plan_count,
    plan.plan_price AS plan_price,
    plan.plan_amount AS plan_amount,
    inventory.count AS count,
    inventory.price AS price,
    inventory.amount AS amount
FROM
    (
        SELECT
            SUM(pc.count) AS plan_count,
            AVG(pc.price) AS plan_price,
            SUM(pc.amount) AS plan_amount
        FROM
            erp_purchase_commodity pc
        WHERE
            pc.erp_purchase_order_id = ? AND pc.erp_commodity_id = ?
        GROUP BY
            pc.erp_purchase_order_id
    ) AS plan
LEFT JOIN
    (
        SELECT
            SUM(pi.count) AS count,
            AVG(pi.implementation_price) AS price,
            SUM(pi.amount) AS amount
        FROM
            erp_purchase_inventory pi 
        WHERE
            pi.erp_purchase_order_id = ? AND pi.erp_commodity_id = ?
        GROUP BY
            pi.erp_purchase_order_id
    ) AS inventory ON 1 = 1
	`, erpPurchaseOrderId, commodityId, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
	} else {
		err = orm.Eloquent.Raw(`
		    SELECT
    plan.plan_count AS plan_count,
    plan.plan_price AS plan_price,
    plan.plan_amount AS plan_amount,
    inventory.count AS count,
    inventory.price AS price,
    inventory.amount AS amount
FROM
    (
        SELECT
            SUM(pc.rejected_count) AS plan_count,
            AVG(pc.rejected_price) AS plan_price,
            SUM(pc.rejected_amount) AS plan_amount
        FROM
            erp_purchase_commodity pc
        WHERE
            pc.erp_purchase_order_id = ? AND pc.erp_commodity_id = ?
        GROUP BY
            pc.erp_purchase_order_id
    ) AS plan
LEFT JOIN
    (
        SELECT
            SUM(pi.count) AS count,
            AVG(pi.implementation_price) AS price,
            SUM(pi.amount) AS amount
        FROM
            erp_purchase_inventory pi 
        WHERE
            pi.erp_purchase_order_id = ? AND pi.erp_commodity_id = ?
        GROUP BY
            pi.erp_purchase_order_id
    ) AS inventory ON 1 = 1
	`, erpPurchaseOrderId, commodityId, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
	}

	if err != nil {
		logger.Error("getPurchaseData err:", logger.Field("err", err))
		return PurchaseData{}, CommodityData{}, err
	}

	// 计算未执行金额和未执行数量
	purchaseData.NonExecutionAmount = purchaseData.PlanAmount - purchaseData.Amount
	if purchaseData.NonExecutionAmount < 0 {
		purchaseData.NonExecutionAmount = 0
	}

	purchaseData.NonExecutionCount = purchaseData.PlanCount - purchaseData.Count
	if purchaseData.NonExecutionCount < 0 {
		purchaseData.NonExecutionCount = 0
	}

	if purchaseType == ErpRejectOrder {
		purchaseData.PlanCount = -purchaseData.PlanCount
		purchaseData.PlanAmount = -purchaseData.PlanAmount
		purchaseData.Amount = -purchaseData.Amount
		purchaseData.Count = -purchaseData.Count
		purchaseData.NonExecutionAmount = -purchaseData.NonExecutionAmount
		purchaseData.NonExecutionCount = -purchaseData.NonExecutionCount
	}

	// 查询订单对应的商品信息
	commodityInfo, err := GetCommodity(commodityId)
	if err != nil {
		return PurchaseData{}, CommodityData{}, err
	}

	commodityData.ErpCommodityId = commodityInfo.ID
	commodityData.ErpCommodityName = commodityInfo.Name
	commodityData.ErpCategoryID = commodityInfo.ErpCategoryId
	commodityData.ErpCategoryName = commodityInfo.ErpCategoryName

	return purchaseData, commodityData, nil
}

//// 查询所有商品信息
//func getAllOrderCommodity(pageIndex, pageSize int) (map[uint32][]uint32, error) {
//	qs := orm.Eloquent.Table("erp_purchase_commodity")
//
//	var count int64
//	err := qs.Total(&count).Error
//	if err != nil {
//		logger.Error("getAllOrderCommodity count err:", logger.Field("err", err))
//		return nil, err
//	}
//
//	var commodityList []ErpPurchaseCommodity
//	err = qs.Order("id DESC").Offset(pageIndex * pageSize).Limit(pageSize).Find(&commodityList).Error
//	if err != nil && err != RecordNotFound {
//		logger.Error("getAllOrderCommodity erp_purchase_commodity err:", logger.Field("err", err))
//		return nil, err
//	}
//
//	commodityMap := make(map[uint32][]uint32)
//	for _, v := range commodityList {
//		if !contains(commodityMap[v.ErpCommodityId], v.ErpPurchaseOrderId) {
//			commodityMap[v.ErpCommodityId] = append(commodityMap[v.ErpCommodityId], v.ErpPurchaseOrderId)
//		}
//	}
//
//	return commodityMap, nil
//}
//
//func contains(slice []uint32, item uint32) bool {
//	for _, value := range slice {
//		if value == item {
//			return true
//		}
//	}
//	return false
//}

// 查询所有商品信息，每页展示不同商品ID及其对应的订单ID
//func getAllOrderCommodity(req *ErpPurchaseReportByCommodityReq) (map[uint32][]uint32, error) {
//	var commodityMap = make(map[uint32][]uint32)
//	var query string
//
//	// 执行原生 SQL 查询，联结表格，按照每个商品ID列出所有的订单ID
//	query = fmt.Sprintf(`
//        SELECT erp_commodity_id, GROUP_CONCAT(erp_purchase_order_id) AS order_ids FROM erp_purchase_commodity
//GROUP BY erp_commodity_id`)
//
//	rows, err := orm.Eloquent.Raw(query).Rows()
//	if err != nil {
//		logger.Error("getAllOrderCommodity erp_purchase_commodity err:", logger.Field("err", err))
//		return nil, err
//	}
//	defer rows.Close()
//
//	for rows.Next() {
//		var commodityID uint32
//		var orderIDs string
//		if err := rows.Scan(&commodityID, &orderIDs); err != nil {
//			logger.Error("getAllOrderCommodity rows scan err:", logger.Field("err", err))
//			return nil, err
//		}
//
//		// 将 orderIDs 字符串拆分为字符串数组
//		orderIDStrList := strings.Split(orderIDs, ",")
//
//		// 去重并转换为 uint32 数组
//		var orderIDList []uint32
//		seen := make(map[uint32]bool)
//		for _, idStr := range orderIDStrList {
//			id, err := strconv.ParseUint(idStr, 10, 32)
//			if err != nil {
//				logger.Error("getAllOrderCommodity parse orderID err:", logger.Field("err", err))
//				return nil, err
//			}
//
//			// 如果该订单ID未被添加过，则添加到列表中
//			if _, ok := seen[uint32(id)]; !ok {
//				orderIDList = append(orderIDList, uint32(id))
//				seen[uint32(id)] = true
//			}
//		}
//
//		// 添加到 map 中
//		commodityMap[commodityID] = orderIDList
//	}
//
//	return commodityMap, nil
//}

func getAllOrderCommodity(req *ErpPurchaseReportByCommodityReq) (map[uint32][]uint32, error) {
	var commodityMap = make(map[uint32][]uint32)
	var queryBuilder strings.Builder

	// Construct the base query
	queryBuilder.WriteString(`
        SELECT erp_commodity_id, GROUP_CONCAT(erp_purchase_order_id) AS order_ids 
        FROM erp_purchase_commodity`)

	var args []interface{}
	// Add conditions if provided
	if req.ErpCommodityName != "" {
		queryBuilder.WriteString(" WHERE erp_commodity_name = ?")
		args = append(args, req.ErpCommodityName)
	}

	if req.ErpCategoryID != 0 {
		// Fetch category info for the serial number prefix
		categoryInfo, err := GetErpCategory(req.ErpCategoryID)
		if err != nil {
			return nil, err
		}
		if req.ErpCommodityName != "" {
			queryBuilder.WriteString(" AND commodity_serial_number LIKE ?")
		} else {
			queryBuilder.WriteString(" WHERE commodity_serial_number LIKE ?")
		}

		args = append(args, categoryInfo.Number+"%")
	}

	// Group by commodity ID
	queryBuilder.WriteString(" GROUP BY erp_commodity_id")
	// Prepare query with conditions
	query := queryBuilder.String()

	// Execute the query
	rows, err := orm.Eloquent.Raw(query, args...).Rows()
	if err != nil {
		logger.Error("getAllOrderCommodity erp_purchase_commodity err:", logger.Field("err", err))
		return nil, err
	}
	defer rows.Close()

	// Process the query results
	for rows.Next() {
		var commodityID uint32
		var orderIDs string
		if err := rows.Scan(&commodityID, &orderIDs); err != nil {
			logger.Error("getAllOrderCommodity rows scan err:", logger.Field("err", err))
			return nil, err
		}

		// Split and deduplicate order IDs
		orderIDStrList := strings.Split(orderIDs, ",")
		var orderIDList []uint32
		seen := make(map[uint32]bool)
		for _, idStr := range orderIDStrList {
			id, err := strconv.ParseUint(idStr, 10, 32)
			if err != nil {
				logger.Error("getAllOrderCommodity parse orderID err:", logger.Field("err", err))
				return nil, err
			}
			if !seen[uint32(id)] {
				orderIDList = append(orderIDList, uint32(id))
				seen[uint32(id)] = true
			}
		}

		// Add to the map
		commodityMap[commodityID] = orderIDList
	}

	return commodityMap, nil
}

func findCommodityIDsByOrderID(orderID uint32, commodityMap map[uint32][]uint32) []uint32 {
	var commodityIDs []uint32

	for commodityID, orderIDs := range commodityMap {
		for _, id := range orderIDs {
			if id == orderID {
				commodityIDs = append(commodityIDs, commodityID)
				break
			}
		}
	}

	return commodityIDs
}

// 导出采购报表（按商品）excel
func reportByCommodityExport(req *ErpPurchaseReportByCommodityResp) (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{}
	var row2 []interface{}
	nExcelStartRow := 0
	for _, commodityData := range req.List {
		categoryLevels, _ := GetCategoryLevels(commodityData.ErpCategoryID)
		row1 = []interface{}{
			commodityData.ErpCommodityName,   // 商品名称
			categoryLevels.Level1.Name,       // 一级分类
			categoryLevels.Level2.Name,       // 二级分类
			categoryLevels.Level3.Name,       // 三级分类
			"",                               // 单据编号
			"",                               // 类型
			"",                               // 店铺名称
			"",                               // 供应商
			"",                               // 经手人
			"",                               // 制单人
			"",                               // 审核时间
			commodityData.PlanAmount,         // 计划采购金额
			commodityData.PlanPrice,          // 计划采购单价
			commodityData.PlanCount,          // 计划采购数量
			commodityData.Amount,             // 已执行金额
			commodityData.Price,              // 已执行单价
			commodityData.Count,              // 已执行数量
			commodityData.NonExecutionAmount, // 未执行金额
			commodityData.NonExecutionCount,  // 未执行数量
		}

		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++

		for _, orderData := range commodityData.OrderInfo {
			var orderType string
			switch orderData.PurchaseType {
			case "procure":
				orderType = "采购入库"
			case "reject":
				orderType = "采购退货"
			}

			var strTime string
			if orderData.AuditTime != nil {
				strTime = orderData.AuditTime.Format(ExcelTimeFormat)
			} else {
				strTime = "--"
			}

			row2 = []interface{}{
				commodityData.ErpCommodityName, // 商品名称
				categoryLevels.Level1.Name,     // 一级分类
				categoryLevels.Level2.Name,     // 二级分类
				categoryLevels.Level3.Name,     // 三级分类
				orderData.SerialNumber,         // 单据编号
				orderType,                      // 类型
				orderData.StoreName,            // 店铺名称
				orderData.ErpSupplierName,      // 供应商
				orderData.HandlerName,          // 经手人
				orderData.MakerName,            // 制单人
				strTime,                        // 审核时间
				orderData.PlanAmount,           // 计划采购金额
				orderData.PlanPrice,            // 计划采购单价
				orderData.PlanCount,            // 计划采购数量
				orderData.Amount,               // 已执行金额
				orderData.Price,                // 已执行单价
				orderData.Count,                // 已执行数量
				orderData.NonExecutionAmount,   // 未执行金额
				orderData.NonExecutionCount,    // 未执行数量
			}

			for j, _ := range row2 {
				cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
				err := file.SetCellValue(fSheet, cell, row2[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.PlanAmount,         // 计划采购金额
		"--",                   // 计划采购单价
		req.PlanCount,          // 计划采购数量
		req.Amount,             // 已执行金额
		"--",                   // 已执行单价
		req.Count,              // 已执行数量
		req.NonExecutionAmount, // 未执行金额
		req.NonExecutionCount,  // 未执行数量
	}
	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", "D1")
	_ = file.MergeCell(fSheet, "E1", "E2")
	_ = file.MergeCell(fSheet, "F1", "F2")
	_ = 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", "N1")
	_ = file.MergeCell(fSheet, "O1", "Q1")
	_ = file.MergeCell(fSheet, "R1", "S1")

	//设置单元格高度
	file.SetRowHeight("Sheet1", 1, 20)
	file.SetRowHeight("Sheet1", 2, 20)

	// 设置单元格大小
	file.SetColWidth("Sheet1", "A", "A", 30)
	file.SetColWidth("Sheet1", "B", "B", 10)
	file.SetColWidth("Sheet1", "E", "E", 13)
	file.SetColWidth("Sheet1", "G", "G", 25)

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

// GetReportBySupplier 查询供应商采购汇总
func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq, c *gin.Context) (
	*ErpPurchaseReportBySupplierResp, 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 {
			req.StoreList = CompareLists(storeList, req.StoreList)
			if len(req.StoreList) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &ErpPurchaseReportBySupplierResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &ErpPurchaseReportBySupplierResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}

	// 构建查询条件
	query := orm.Eloquent.Model(&ErpPurchaseInventory{}).
		Select("erp_purchase_inventory.erp_purchase_order_id, " +
			"erp_purchase_inventory.purchase_type, erp_purchase_inventory.serial_number, " +
			"erp_purchase_order.store_id, store.name as store_name, erp_purchase_order.erp_supplier_id, " +
			"erp_purchase_order.erp_supplier_name, " +
			"erp_purchase_inventory.erp_commodity_id, erp_commodity.name as erp_commodity_name, " +
			"erp_purchase_inventory.erp_category_id, erp_purchase_inventory.erp_category_name, " +
			"SUM(erp_purchase_inventory.count) AS count, " +
			"SUM(erp_purchase_inventory.amount) AS amount").
		Joins("JOIN erp_purchase_order ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
		Joins("LEFT JOIN erp_commodity ON erp_purchase_inventory.erp_commodity_id = erp_commodity.id").
		Joins("LEFT JOIN store ON erp_purchase_order.store_id = store.id").
		Group("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.erp_commodity_id, " +
			"erp_purchase_inventory.erp_commodity_name, erp_purchase_inventory.erp_category_id, " +
			"erp_purchase_inventory.serial_number")

	countQuery := orm.Eloquent.Model(&ErpPurchaseInventory{}).
		Select("erp_purchase_inventory.erp_purchase_order_id, " +
			"erp_purchase_inventory.purchase_type, erp_purchase_inventory.serial_number, " +
			"erp_purchase_order.store_id, store.name as store_name, erp_purchase_order.erp_supplier_id, " +
			"erp_purchase_order.erp_supplier_name, " +
			"erp_purchase_inventory.erp_commodity_id, erp_commodity.name as erp_commodity_name, " +
			"erp_purchase_inventory.erp_category_id, erp_purchase_inventory.erp_category_name, " +
			"SUM(erp_purchase_inventory.count) AS count, " +
			"SUM(erp_purchase_inventory.amount) AS amount").
		Joins("JOIN erp_purchase_order ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
		Joins("LEFT JOIN erp_commodity ON erp_purchase_inventory.erp_commodity_id = erp_commodity.id").
		Joins("LEFT JOIN store ON erp_purchase_order.store_id = store.id").
		Group("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.erp_commodity_id, " +
			"erp_purchase_inventory.erp_commodity_name, erp_purchase_inventory.erp_category_id, " +
			"erp_purchase_inventory.serial_number")

	// 根据请求参数过滤数据
	if req.PurchaseType != "" {
		query = query.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType)
		countQuery = countQuery.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType)
	}
	if len(req.ErpCommodityName) > 0 {
		query = query.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
		countQuery = countQuery.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
	}

	if len(req.ErpCategoryID) > 0 {
		categoryList, err := TransformErpCategoryIds(req.ErpCategoryID)
		if err != nil {
			return nil, err
		}
		query = query.Where("erp_purchase_inventory.erp_category_id IN ?", categoryList)
		countQuery = countQuery.Where("erp_purchase_inventory.erp_category_id IN ?", categoryList)
	}

	if req.StartTime != "" { // 入/出库开始时间
		parse, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Errorf("GetReportDetail err:", err)
			return nil, err
		}
		query = query.Where("erp_purchase_inventory.created_at >= ?", parse)
		countQuery = countQuery.Where("erp_purchase_inventory.created_at >= ?", parse)
	}

	if req.EndTime != "" { // 入/出库结束时间
		parse, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Errorf("GetReportDetail err:", err)
			return nil, err
		}
		query = query.Where("erp_purchase_inventory.created_at <= ?", parse)
		countQuery = countQuery.Where("erp_purchase_inventory.created_at <= ?", parse)
	}

	if len(req.StoreList) > 0 {
		if len(req.StoreList) == 1 {
			query = query.Where("erp_purchase_order.store_id = ?", req.StoreList[0])
			countQuery = countQuery.Where("erp_purchase_order.store_id = ?", req.StoreList[0])
		} else {
			query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
			countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
		}
	}

	//获取总数
	var total int64
	countQuery.Count(&total)
	resp.Total = int(total)

	var err error
	err = query.Find(&resp.List).Error
	if err != nil {
		return nil, err
	}

	var esData []PurchaseReportData

	if len(req.ErpSupplierId) > 0 {
		var purchaseOrder []ErpPurchaseOrder
		err = orm.Eloquent.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId).Find(&purchaseOrder).Error
		if err != nil {
			return nil, err
		}

		// 创建缓存 map 存储 ErpCommodityId 和 SerialNumber 对应的价格信息
		priceCache := make(map[string]ResultPrice)

		// 循环遍历采购订单
		for _, po := range purchaseOrder {
			// 在resp.List中查找匹配的订单
			for _, respItem := range resp.List {
				if po.ID == respItem.ErpPurchaseOrderId {
					// 如果找到匹配的订单，将其添加到esData中
					data := PurchaseReportData{
						ErpPurchaseOrderId: po.ID,
						StoreId:            po.StoreId,
						StoreName:          respItem.StoreName,
						PurchaseType:       respItem.PurchaseType,
						ErpSupplierId:      po.ErpSupplierId,
						ErpSupplierName:    po.ErpSupplierName,
						ErpCommodityId:     respItem.ErpCommodityId,
						ErpCommodityName:   respItem.ErpCommodityName,
						ErpCategoryID:      respItem.ErpCategoryID,
						ErpCategoryName:    respItem.ErpCategoryName,
						Count:              respItem.Count,
						Amount:             respItem.Amount,
						RejectAmount:       respItem.RejectAmount,
						Difference:         respItem.Difference,
					}

					if data.PurchaseType == "reject" {
						cacheKey := fmt.Sprintf("%d-%s", respItem.ErpCommodityId, respItem.SerialNumber)

						// 检查缓存中是否已有对应的采购记录
						resultInfo, exists := priceCache[cacheKey]
						if !exists {
							// 缓存中没有，调用 GetTotalWholesalePrice 获取数据，并存入缓存
							var err error
							resultInfo, err = GetTotalWholesalePrice(respItem.ErpCommodityId, respItem.SerialNumber)
							if err != nil {
								return nil, err
							}
							priceCache[cacheKey] = resultInfo
						}

						data.Difference = -(resultInfo.TotalWholesalePrice - data.Amount)
						data.RejectAmount = -data.Amount
						data.Count = -data.Count

						// 前端合并了采购价退货价，都使用的amount字段，所以当是采购退货时，将RejectAmount赋值给Amount
						//data.Amount = -resultInfo.TotalWholesalePrice
						data.Amount = data.RejectAmount
					}

					esData = append(esData, data)
				}
			}
		}
		resp.List = esData
	} else {
		// 补充关联的供应商和店铺信息
		// 创建缓存 map 存储 ErpPurchaseOrderId 和 ErpPurchaseOrder 结果
		purchaseOrderCache := make(map[uint32]ErpPurchaseOrder)
		// 创建缓存 map 存储 ErpCommodityId 和 SerialNumber 对应的价格信息
		priceCache := make(map[string]ResultPrice)

		for i := range resp.List {
			erpPurchaseOrderId := resp.List[i].ErpPurchaseOrderId

			// 检查缓存中是否已有对应的采购订单信息
			purchaseOrderInfo, exists := purchaseOrderCache[erpPurchaseOrderId]
			if !exists {
				// 缓存中没有，查询采购订单信息并存入缓存
				err = orm.Eloquent.Where("id = ?", erpPurchaseOrderId).First(&purchaseOrderInfo).Error
				if err != nil {
					return nil, err
				}
				purchaseOrderCache[erpPurchaseOrderId] = purchaseOrderInfo
			}

			resp.List[i].StoreId = purchaseOrderInfo.StoreId
			//resp.List[i].StoreName = purchaseOrderInfo.StoreName
			resp.List[i].ErpSupplierId = purchaseOrderInfo.ErpSupplierId
			resp.List[i].ErpSupplierName = purchaseOrderInfo.ErpSupplierName

			if resp.List[i].PurchaseType == "reject" {
				cacheKey := fmt.Sprintf("%d-%s", resp.List[i].ErpCommodityId, resp.List[i].SerialNumber)

				// 检查缓存中是否已有对应的采购记录
				resultInfo, exists := priceCache[cacheKey]
				if !exists {
					// 缓存中没有，调用 GetTotalWholesalePrice 获取数据，并存入缓存
					var err error
					resultInfo, err = GetTotalWholesalePrice(resp.List[i].ErpCommodityId, resp.List[i].SerialNumber)
					if err != nil {
						return nil, err
					}
					priceCache[cacheKey] = resultInfo
				}

				// 计算差额，并处理退货金额和数量的负值
				resp.List[i].Difference = -(resultInfo.TotalWholesalePrice - resp.List[i].Amount)
				resp.List[i].RejectAmount = -math.Abs(resp.List[i].Amount)
				resp.List[i].Count = -resp.List[i].Count

				// 将 RejectAmount 赋值给 Amount
				resp.List[i].Amount = resp.List[i].RejectAmount
			}

			resp.List[i].Amount = math.Round(resp.List[i].Amount*100) / 100
		}
	}

	mergedData := mergeData(resp.List)

	// 统计总计数量和金额
	var totalAmount float64
	var totalCount int32
	var totalRejectAmount float64
	var totalDifference float64
	for _, item := range mergedData {
		totalAmount += item.Amount
		totalCount += item.Count
		totalRejectAmount += item.RejectAmount
		totalDifference += item.Difference
	}

	resp.Amount = math.Round(totalAmount*100) / 100
	resp.Count = totalCount
	resp.RejectAmount = math.Round(totalRejectAmount*100) / 100
	resp.Difference = math.Round(totalDifference*100) / 100
	resp.Total = len(mergedData)

	// 排序规则：供应商编号小＞商品编号小>店铺编号小＞类型为采购入库
	sort.Slice(mergedData, func(i, j int) bool {
		if mergedData[i].ErpSupplierId != mergedData[j].ErpSupplierId {
			return mergedData[i].ErpSupplierId < mergedData[j].ErpSupplierId
		}
		if mergedData[i].ErpCommodityId != mergedData[j].ErpCommodityId {
			return mergedData[i].ErpCommodityId < mergedData[j].ErpCommodityId
		}
		if mergedData[i].StoreId != mergedData[j].StoreId {
			return mergedData[i].StoreId < mergedData[j].StoreId
		}
		if mergedData[i].PurchaseType == ErpProcureOrder && mergedData[j].PurchaseType != ErpProcureOrder {
			return true
		}
		if mergedData[i].PurchaseType != ErpProcureOrder && mergedData[j].PurchaseType == ErpProcureOrder {
			return false
		}
		return false // 默认情况下相等
	})

	if req.IsExport == 1 {
		resp.List = mergedData
		filePath, err := reportBySupplierExport(resp)
		if err != nil {
			return nil, err
		}
		resp = &ErpPurchaseReportBySupplierResp{}
		resp.ExportUrl = filePath
	} else {
		// 分页处理
		startIdx := (resp.PageIndex - 1) * resp.PageSize
		endIdx := resp.PageIndex * resp.PageSize

		// 确保不超出索引范围
		if startIdx >= len(mergedData) {
			resp.List = []PurchaseReportData{}
		} else if endIdx > len(mergedData) {
			resp.List = mergedData[startIdx:]
		} else {
			resp.List = mergedData[startIdx:endIdx]
		}
	}

	return resp, nil
}

//func mergeData(esData []PurchaseReportData) []PurchaseReportData {
//	mergedMap := make(map[string]*PurchaseReportData)
//
//	// 遍历 esData 数据
//	for _, data := range esData {
//		key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType)
//		if _, ok := mergedMap[key]; !ok {
//			// 如果键不存在，创建新条目
//			mergedMap[key] = &PurchaseReportData{
//				StoreId:          data.StoreId,
//				ErpSupplierId:    data.ErpSupplierId,
//				ErpCommodityId:   data.ErpCommodityId,
//				StoreName:        data.StoreName,
//				PurchaseType:     data.PurchaseType,
//				ErpSupplierName:  data.ErpSupplierName,
//				ErpCommodityName: data.ErpCommodityName,
//				ErpCategoryID:    data.ErpCategoryID,
//				ErpCategoryName:  data.ErpCategoryName,
//				Total:            data.Total,
//				Amount:           data.Amount,
//				RejectAmount:     data.RejectAmount,
//				Difference:       data.Difference,
//			}
//		} else {
//			// 如果键已存在，进行累加操作
//			mergedMap[key].Total += data.Total
//			mergedMap[key].Amount += data.Amount
//			mergedMap[key].RejectAmount += data.RejectAmount
//			mergedMap[key].Difference += data.Difference
//		}
//	}
//
//	// 将合并后的数据转换为数组返回
//	var mergedData []PurchaseReportData
//	for _, v := range mergedMap {
//		mergedData = append(mergedData, *v)
//	}
//
//	return mergedData
//}

func mergeData(esData []PurchaseReportData) []PurchaseReportData {
	mergedMap := make(map[string]*PurchaseReportData)
	var keys []string // 用于记录键的顺序

	// 遍历 esData 数据
	for _, data := range esData {
		key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType)
		if _, ok := mergedMap[key]; !ok {
			// 如果键不存在，创建新条目
			mergedMap[key] = &PurchaseReportData{
				StoreId:          data.StoreId,
				ErpSupplierId:    data.ErpSupplierId,
				ErpCommodityId:   data.ErpCommodityId,
				StoreName:        data.StoreName,
				PurchaseType:     data.PurchaseType,
				ErpSupplierName:  data.ErpSupplierName,
				ErpCommodityName: data.ErpCommodityName,
				ErpCategoryID:    data.ErpCategoryID,
				ErpCategoryName:  data.ErpCategoryName,
				Count:            data.Count,
				Amount:           data.Amount,
				RejectAmount:     data.RejectAmount,
				Difference:       data.Difference,
			}

			keys = append(keys, key) // 将键添加到有序的键列表中
		} else {
			// 如果键已存在，进行累加操作
			mergedMap[key].Count += data.Count
			mergedMap[key].Amount += data.Amount
			mergedMap[key].RejectAmount += data.RejectAmount
			mergedMap[key].Difference += data.Difference
		}
	}

	// 根据有序的键列表顺序构建返回的数组
	var mergedData []PurchaseReportData
	for _, key := range keys {
		mergedMap[key].Amount = math.Round(mergedMap[key].Amount*100) / 100
		mergedMap[key].RejectAmount = math.Round(mergedMap[key].RejectAmount*100) / 100
		mergedData = append(mergedData, *mergedMap[key])
	}

	return mergedData
}

// 导出供应商采购汇总excel
func reportBySupplierExport(req *ErpPurchaseReportBySupplierResp) (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.Errorf("file set value err:", err)
		}
	}

	var row []interface{}
	nExcelStartRow := 0
	for _, supplierData := range req.List {
		var orderType string
		switch supplierData.PurchaseType {
		case "procure":
			orderType = "采购入库"
		case "reject":
			orderType = "采购退货"
		}
		row = []interface{}{
			supplierData.StoreName,        // 店铺名称
			orderType,                     // 采购类型
			supplierData.ErpSupplierName,  // 供应商
			supplierData.ErpCommodityName, // 商品名称
			supplierData.ErpCategoryName,  // 商品分类
			supplierData.Count,            // 采购数量
			supplierData.Amount,           // 采购金额
			supplierData.RejectAmount,     // 退货金额
			supplierData.Difference,       // 差额
		}

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
			err := file.SetCellValue(fSheet, cell, row[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.Count,        // 采购数量
		req.Amount,       // 采购金额
		req.RejectAmount, // 退货金额
		req.Difference,   // 差额
	}
	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", 25)
	file.SetColWidth("Sheet1", "D", "D", 15)

	endRow := fmt.Sprintf("I"+"%d", nExcelStartRow+2)
	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)

	fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		fmt.Println(err)
	}
	return url + fileName, nil
}

// GetReportDetail 查询采购明细
func GetReportDetail(req *ErpPurchaseReportDetailReq, c *gin.Context) (*ErpPurchaseReportDetailResp, 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 {
			req.StoreId = CompareLists(storeList, req.StoreId)
			if len(req.StoreId) == 0 { // 没有匹配的数据，表示入参门店不是用户有权限的门店
				return &ErpPurchaseReportDetailResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}
	resp := &ErpPurchaseReportDetailResp{
		PageIndex: page + 1,
		PageSize:  req.PageSize,
	}

	// 差额只有采购退货单才存在，差额=采购价-退货价；这里sql查询的不准确
	qs := orm.Eloquent.Debug().Table("erp_purchase_order").
		Select("erp_purchase_order.id as erp_purchase_order_id, " +
			"erp_purchase_order.serial_number as order_serial_number, " +
			"erp_purchase_inventory.serial_number, " +
			"erp_purchase_order.purchase_type, " +
			"erp_purchase_inventory.created_at as execute_time, " +
			"erp_purchase_order.store_id, " +
			"erp_purchase_order.store_name, " +
			"erp_purchase_order.erp_supplier_id, " +
			"erp_purchase_order.erp_supplier_name, " +
			"erp_purchase_inventory.erp_commodity_id, " +
			"erp_purchase_inventory.erp_commodity_name, " +
			"erp_purchase_inventory.erp_category_id, " +
			"erp_purchase_inventory.erp_category_name, " +
			"erp_purchase_inventory.imei_type, " +
			"erp_purchase_inventory.imei, " +
			"CASE " +
			"WHEN erp_purchase_order.purchase_type = 'procure' THEN erp_purchase_inventory.implementation_price " +
			"WHEN erp_purchase_order.purchase_type = 'reject' THEN erp_purchase_inventory.implementation_price " +
			"ELSE 0 END AS price, " +
			"CASE " +
			"WHEN erp_purchase_order.purchase_type = 'procure' THEN 0 " +
			"WHEN erp_purchase_order.purchase_type = 'reject' THEN erp_purchase_inventory.implementation_price " +
			"ELSE 0 END AS reject_price, " +
			"erp_purchase_inventory.employee_price, " +
			"(erp_purchase_inventory.implementation_price - erp_purchase_inventory.employee_price) as difference_price").
		Joins("JOIN erp_purchase_inventory ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id")
	//Where("erp_purchase_order.state <> ?", 5) // 排除已终止的订单

	// 创建一个新的查询对象，用于 count 查询
	countQuery := orm.Eloquent.Debug().Table("erp_purchase_order").
		Joins("JOIN erp_purchase_inventory ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id")
	//Where("erp_purchase_order.state <> ?", 5) // 排除已终止的订单

	if req.SerialNumber != "" {
		qs = qs.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
		countQuery = countQuery.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
	}
	if req.PurchaseType != "" {
		qs = qs.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
		countQuery = countQuery.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
	}
	if req.ErpCommodityName != "" {
		qs = qs.Where("erp_purchase_inventory.erp_commodity_name LIKE ?", "%"+req.ErpCommodityName+"%")
		countQuery = countQuery.Where("erp_purchase_inventory.erp_commodity_name LIKE ?", "%"+req.ErpCommodityName+"%")
	}
	if req.ErpCategoryID != 0 {
		qs = qs.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
		countQuery = countQuery.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
	}
	if req.ErpSupplierId != 0 {
		qs = qs.Where("erp_purchase_order.erp_supplier_id = ?", req.ErpSupplierId)
		countQuery = countQuery.Where("erp_purchase_order.erp_supplier_id = ?", req.ErpSupplierId)
	}
	if req.IMEI != "" {
		qs = qs.Where("erp_purchase_inventory.imei = ?", req.IMEI)
		countQuery = countQuery.Where("erp_purchase_inventory.imei = ?", req.IMEI)
	}
	if req.StartTime != "" { // 入/出库开始时间
		parse, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Errorf("GetReportDetail err:", err)
			return nil, err
		}
		qs = qs.Where("erp_purchase_inventory.created_at >= ?", parse)
		countQuery = countQuery.Where("erp_purchase_inventory.created_at >= ?", parse)
	}
	if req.EndTime != "" { // 入/出库结束时间
		parse, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Errorf("GetReportDetail err:", err)
			return nil, err
		}
		qs = qs.Where("erp_purchase_inventory.created_at <= ?", parse)
		countQuery = countQuery.Where("erp_purchase_inventory.created_at <= ?", parse)
	}

	if len(req.StoreId) > 0 {
		qs = qs.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
		countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
	}

	var count int64
	err := countQuery.Count(&count).Error
	if err != nil {
		logger.Errorf("GetReportDetail count err:", err)
		return nil, err
	}

	var reportList []ReportDetailData
	err = qs.Order("erp_purchase_inventory.created_at desc").Scan(&reportList).Error
	if err != nil {
		logger.Errorf("GetReportDetail scan err:", err)
		return nil, err
	}

	// 定义一个缓存map存储 SerialNumber 对应的 price
	priceCache := make(map[string]float64)

	// 根据订单类型调整价格的正负性
	for i := range reportList {
		reportList[i].DifferencePrice = 0 // 采购单不存在差额

		// 根据目前最新的需求，页面"采购/退货金额"合并到一起了，但前端统一使用的时price字段
		// 所以对 reject 采购退货单进行特殊处理，将RejectPrice赋值给price
		if reportList[i].PurchaseType == "reject" {
			serialNumber := reportList[i].SerialNumber

			// 如果缓存中已经有该 SerialNumber 对应的价格，直接使用
			price, exists := priceCache[serialNumber]
			if !exists {
				// 缓存中没有，调用 getPrice 获取价格，并存入缓存
				var err error
				price, err = getPrice(serialNumber)
				if err != nil {
					return nil, err
				}
				priceCache[serialNumber] = price
			}

			reportList[i].DifferencePrice = -reportList[i].DifferencePrice
			reportList[i].RejectPrice = -reportList[i].RejectPrice
			reportList[i].EmployeePrice = -reportList[i].EmployeePrice
			reportList[i].Price = reportList[i].RejectPrice

			//差额=采购价-退货价
			reportList[i].DifferencePrice = math.Abs(reportList[i].RejectPrice) - math.Abs(price)
		}
	}

	resp.Total = int(count)
	resp.Price, resp.EmployeePrice, resp.RejectPrice, resp.DifferencePrice = calculatePrices(reportList)

	// 四舍五入保留2位小数
	resp.Price = math.Round(resp.Price*100) / 100
	resp.EmployeePrice = math.Round(resp.EmployeePrice*100) / 100
	resp.RejectPrice = math.Round(resp.RejectPrice*100) / 100
	resp.DifferencePrice = math.Round(resp.DifferencePrice*100) / 100

	if req.IsExport == 1 {
		resp.List = reportList
		filePath, err := reportDetailExport(resp, c)
		if err != nil {
			return nil, err
		}
		resp = &ErpPurchaseReportDetailResp{}
		resp.ExportUrl = filePath
	} else {
		// 分页处理
		startIdx := (resp.PageIndex - 1) * resp.PageSize
		endIdx := resp.PageIndex * resp.PageSize

		// 确保不超出索引范围
		if startIdx >= len(reportList) {
			resp.List = []ReportDetailData{}
		} else if endIdx > len(reportList) {
			resp.List = reportList[startIdx:]
		} else {
			resp.List = reportList[startIdx:endIdx]
		}
	}

	return resp, nil
}

// 根据采购单据号查询入库采购价
func getPrice(serialNumber string) (float64, error) {
	var stockCommodity ErpStockCommodity
	err := orm.Eloquent.Table("erp_stock_commodity").Where("stock_sn = ?", serialNumber).
		Find(&stockCommodity).Error
	if err != nil {
		return 0, err
	}

	return stockCommodity.WholesalePrice, nil
}

// 计算价格信息
func calculatePrices(list []ReportDetailData) (price, employeePrice, rejectPrice, differencePrice float64) {
	for _, item := range list {
		price += item.Price
		employeePrice += item.EmployeePrice
		rejectPrice += item.RejectPrice
		differencePrice += item.DifferencePrice
	}
	return
}

// 导出采购明细excel
func reportDetailExport(req *ErpPurchaseReportDetailResp, c *gin.Context) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "采购明细" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	// 判断是否有入库采购价、入库员工成本价的权限
	exportPrice, _ := checkRoleMenu(c, PriceMenu)
	exportEmployeePrice, _ := checkRoleMenu(c, EmployeePriceMenu)
	exportDifferencePrice, _ := checkRoleMenu(c, DifferencePriceMenu)
	fmt.Println("exportPrice is:", exportPrice)
	fmt.Println("exportEmployeePrice is:", exportEmployeePrice)
	fmt.Println("exportDifferencePrice is:", exportDifferencePrice)
	logger.Info("exportPrice is:", logger.Field("exportPrice", exportPrice))
	logger.Info("exportEmployeePrice is:", logger.Field("exportEmployeePrice", exportEmployeePrice))
	logger.Info("exportDifferencePrice is:", logger.Field("exportDifferencePrice", exportDifferencePrice))

	nEndCount := 0
	// 组合标题栏数据
	title := []interface{}{"单据编号", "单据类型", "出/入库时间", "店铺名称", "供应商", "商品名称", "商品分类", "是否串码", "串码"}

	if exportPrice { // 采购/退货价
		title = append(title, "采购/退货价")
		nEndCount += 1
	}
	if exportEmployeePrice { // 员工成本价
		title = append(title, "员工成本价")
		nEndCount += 1
	}
	if exportDifferencePrice { // 差额
		title = append(title, "差额")
		nEndCount += 1
	}

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

	var row []interface{}
	nExcelStartRow := 0
	price := float64(0)
	for _, detailData := range req.List {
		var orderType string
		switch detailData.PurchaseType {
		case "procure":
			orderType = "采购入库"
			price = detailData.Price
		case "reject":
			orderType = "采购退货"
			price = detailData.RejectPrice
		}

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

		row = []interface{}{
			detailData.OrderSerialNumber, // 单据编号
			orderType,                    // 单据类型
			detailData.ExecuteTime.Format(TimeFormat), // 出/入库时间
			detailData.StoreName,                      // 店铺名称
			detailData.ErpSupplierName,                // 供应商
			detailData.ErpCommodityName,               // 商品名称
			detailData.ErpCategoryName,                // 商品分类
			IMEIType,                                  // 是否串码
			detailData.IMEI,                           // 串码
		}
		// 控制是否导出：采购/退货价、员工成本价、差额
		if exportPrice { // 采购/退货价
			row = append(row, price)
		}
		if exportEmployeePrice { // 员工成本价
			row = append(row, detailData.EmployeePrice)
		}
		if exportDifferencePrice { // 差额
			row = append(row, detailData.DifferencePrice)
		}

		for j, _ := range row {
			cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
			err := file.SetCellValue(fSheet, cell, row[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, "", "", "", "", "", "", "", ""}
	// 控制是否导出：采购/退货价、员工成本价、差额
	if exportPrice { // 采购/退货价
		end = append(end, req.Price)
	}
	if exportEmployeePrice { // 员工成本价
		end = append(end, req.EmployeePrice)
	}
	if exportDifferencePrice { // 差额
		end = append(end, req.DifferencePrice)
	}

	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", 15)
	file.SetColWidth("Sheet1", "C", "C", 20)
	file.SetColWidth("Sheet1", "D", "D", 26)
	file.SetColWidth("Sheet1", "F", "F", 18)
	file.SetColWidth("Sheet1", "I", "I", 18)

	var endRow string
	switch nEndCount {
	case 1:
		endRow = fmt.Sprintf("J"+"%d", nExcelStartRow+2)
	case 2:
		endRow = fmt.Sprintf("K"+"%d", nExcelStartRow+2)
	case 3:
		endRow = fmt.Sprintf("L"+"%d", nExcelStartRow+2)
	default:
		endRow = fmt.Sprintf("I"+"%d", nExcelStartRow+2)
	}

	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)

	fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		fmt.Println(err)
	}
	return url + fileName, nil
}

// CancelAuditUpdateStock 反审核后更新库存信息
// 查询订单有无入库信息
// 采购单，有入库信息，则退库；如果有已审核的退货单则不能反审核，报错提示
// 退货单，有入库信息，则入库
func CancelAuditUpdateStock(begin *gorm.DB, req ErpPurchaseOrder) error {
	var purchaseOrder ErpPurchaseOrder
	err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ID).Find(&purchaseOrder).Error
	if err != nil {
		logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err))
		return err
	}

	var inventoryList []ErpPurchaseInventory
	err = orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", req.ID).
		Find(&inventoryList).Error
	if err != nil {
		logger.Error("purchase commodities err:", logger.Field("err", err))
		return err
	}

	if len(inventoryList) == 0 { // 还没有入库记录，直接取消审核
		return nil
	}

	if req.PurchaseType == ErpProcureOrder { // 采购单反审核
		// 查询有无退货订单
		var count int64
		stateList := []int{ErpPurchaseOrderUnAudit, ErpPurchaseOrderEnd}
		err = orm.Eloquent.Table("erp_purchase_order").Where("rejected_serial_number = ? and state NOT IN (?)",
			req.SerialNumber, stateList).Count(&count).Error
		if err != nil {
			return err
		}

		if count > 0 { // 有已审核的退货单
			return errors.New("取消审核失败:已存在采购退库订单，请先将其取消")
		}

		//// 更新入库的商品为"采购退库"
		//reqParam := &ErpPurchaseInventoryReq{
		//	ErpPurchaseOrderId: req.ID,
		//	PurchaseType:       ErpRejectOrder,
		//	Inventories:        inventoryList,
		//}

		// 赋值采购退货单号
		purchaseOrder.RejectedSerialNumber = purchaseOrder.SerialNumber

		// 按照采购退货更新库存
		err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder, true)
		if err != nil {
			return fmt.Errorf("取消审核失败：%s", err.Error())
		}

		// 更新采购商品表的入库数量
		for _, v := range inventoryList {
			err = begin.Model(&ErpPurchaseCommodity{}).
				Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
				UpdateColumn("inventory_count", gorm.Expr("inventory_count - ?", v.Count)).Error
			if err != nil {
				logger.Error("update inventory count err:", logger.Field("err", err))
				return err
			}
		}
	} else if req.PurchaseType == ErpRejectOrder { // 退货单反审核
		// 更新入库的商品为"采购退库"
		reqParam := &ErpPurchaseInventoryReq{
			ErpPurchaseOrderId: req.ID,
			PurchaseType:       ErpProcureOrder,
			Inventories:        inventoryList,
		}

		// 采购退货单反审核更新库存
		err = ErpRejectOrderCancelAuditUpdateStock(begin, reqParam, purchaseOrder)
		if err != nil {
			return fmt.Errorf("取消审核失败：%s", err.Error())
		}

		// 更新采购商品表的入库数量
		for _, v := range inventoryList {
			err = begin.Model(&ErpPurchaseCommodity{}).
				Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
				UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error
			if err != nil {
				logger.Error("update inventory count err:", logger.Field("err", err))
				return err
			}
		}
	} else {
		return errors.New("取消审核失败:采购类型有误")
	}

	// 删除采购入库的记录
	err = begin.Table("erp_purchase_inventory").Where("erp_purchase_order_id = ? and purchase_type = ?",
		req.ID, req.PurchaseType).Delete(&ErpPurchaseInventory{}).Error
	if err != nil {
		return err
	}

	return nil
}

// ErpRejectOrderCancelAuditUpdateStock 采购退货单反审核更新库存
func ErpRejectOrderCancelAuditUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error {
	// 遍历采购入库商品信息
	var stockList []ErpStockCommodity
	for _, v := range req.Inventories {
		commodityInfo, err := GetCommodity(v.ErpCommodityId)
		if err != nil {
			logger.Errorf("GetCommodity err:", err)
			return err
		}
		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
			purchaseOrder.StoreId, v.ErpCommodityId))
		if err != nil {
			logger.Errorf("exist err:", err)
			return err
		}
		if exist {
			err = gdb.Exec(fmt.Sprintf(
				"UPDATE erp_stock SET count=count+%d WHERE  store_id=%d AND erp_commodity_id=%d;",
				v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error
			if err != nil {
				logger.Errorf("update stock err:", err)
				return err
			}
		} else {
			return errors.New("未查询到商品库存信息")
		}

		// 更新商品库存信息
		// 串码商品直接更新状态为：在库
		if v.IMEIType == 2 || v.IMEIType == 3 { // 串码商品
			if v.IMEI == "" {
				return fmt.Errorf("商品[%s]串码为空", v.ErpCommodityName)
			}

			err = gdb.Table("erp_stock_commodity").Where("imei = ?", v.IMEI).
				Updates(map[string]interface{}{"state": InStock}).Error // 状态更新为采购退货
			if err != nil {
				logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
				return err
			}
		}

		// 非串码商品则新建
		nowTime := time.Now()
		stockCommodity := ErpStockCommodity{
			StoreId:               purchaseOrder.StoreId,
			StoreName:             purchaseOrder.StoreName,
			ErpCommodityId:        v.ErpCommodityId,
			ErpCommodityName:      v.ErpCommodityName,
			CommoditySerialNumber: v.CommoditySerialNumber,
			ErpCategoryId:         commodityInfo.ErpCategoryId,
			ErpCategoryName:       commodityInfo.ErpCategoryName,
			ErpSupplierId:         purchaseOrder.ErpSupplierId,
			ErpSupplierName:       purchaseOrder.ErpSupplierName,
			StaffCostPrice:        tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.ImplementationPrice),
			WholesalePrice:        tools.RoundToTwoDecimalPlaces(v.ImplementationPrice),
			State:                 InStock,
			StorageType:           PurchaseInventory, // 采购入库
			FirstStockTime:        nowTime,
			StockTime:             nowTime,
			Count:                 v.Count,
			ErpBarcode:            commodityInfo.ErpBarcode, // 240106新增商品条码
			IMEIType:              v.IMEIType,
			IMEI:                  v.IMEI,
			Remark:                "",
			MemberDiscount:        commodityInfo.MemberDiscount,
			MinRetailPrice:        commodityInfo.MinRetailPrice,
			RetailPrice:           commodityInfo.RetailPrice,
			OriginalSn:            purchaseOrder.SerialNumber,
		}
		stockList = append(stockList, stockCommodity)
	}

	err := gdb.Debug().Create(&stockList).Error
	if err != nil {
		logger.Errorf("create stock commodity err:", err)
		return err
	}

	return nil
}
