package models

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go-admin/app/admin/apis/pay"
	utils "go-admin/app/admin/models/tools"
	orm "go-admin/common/global"
	"go-admin/logger"
	"go-admin/tools"
	"go-admin/tools/config"
	"gorm.io/gorm"
	"math"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	ErpOrderStateUnAudit = "un_audit" // 未审核
	ErpOrderStateAudited = "audited"  // 已审核

	ErpOrderMemberTypeGeneral = "general" // 普通
	ErpOrderMemberTypeMember  = "member"  // 会员

	RetailTypeSale     = "sale"     // 零售订单
	RetailTypeRejected = "rejected" // 零售退货订单

	NoCreatePayOrder = 0 // 未创建
	WaitForPaying    = 1 // 待支付
	HavePaid         = 2 // 已支付

	NoPrint     = 1 // 未打印
	HavePrinted = 2 // 已打印

	OnlinePay = 1 // 线上支付（微信/支付宝/云闪付扫码）

	NoPayOrder = "no_pay_order"
	PayInit    = "pay_init"
	Paying     = "paying"
	PayOk      = "pay_ok"
	PayFailed  = "pay_failed"
	PayUnknown = "pay_unknown"
)

// ErpOrder 零售订单表
type ErpOrder struct {
	Model

	BillSn              string              `json:"bill_sn" gorm:"index"`           // 单据编号
	RetailType          string              `json:"retail_type"`                    // 销售类型:sale 零售销售； rejected 零售退货
	Uid                 int                 `json:"uid"`                            // 用户id
	UserType            int                 `json:"user_type"`                      // 会员类别：1-普通会员 2-黄金会员 4-白金会员 5-黑金会员 6-尊享会员 7-黄金&尊享 8-白金&尊享 9-黑金&尊享
	Tel                 string              `json:"tel" gorm:"index"`               // 客户手机号
	StoreId             uint32              `json:"store_id" gorm:"index"`          // 门店id
	StoreName           string              `json:"store_name"`                     // 门店名称
	MakerId             uint32              `json:"maker_id" gorm:"index"`          // 制单人id
	MakerName           string              `json:"maker_name"`                     // 制单人名称
	MakerTime           time.Time           `json:"maker_time"`                     // 制单时间
	AuditorId           uint32              `json:"auditor_id" gorm:"index"`        // 审核人id
	AuditorName         string              `json:"auditor_name"`                   // 审核人姓名
	AuditTime           *time.Time          `json:"audit_time"`                     // 审核时间
	CashierList         string              `json:"cashier_list" gorm:"type:text"`  // 付款方式，存储json数据
	SalesmanList        string              `json:"salesman_list" gorm:"type:text"` // 销售员信息，存储json数据
	MemberType          string              `json:"member_type"`                    // 会员类型:general 普通； member 会员
	State               string              `json:"state" gorm:"index"`             // 订单状态:un_audit 待审核； audited 已审核
	TotalRetailPrice    float64             `json:"total_retail_price"`             // 订单总指导零售价
	TotalAmount         float64             `json:"total_amount"`                   // 订单实收金额
	TotalCount          int32               `json:"total_count"`                    // 订单商品数量
	TotalSalesProfit    float64             `json:"total_sales_profit"`             // 订单总销售毛利
	TotalStaffProfit    float64             `json:"total_staff_profit"`             // 订单总员工毛利
	VmCount             uint32              `json:"vm_count"`                       // 使用会员积分
	SaleOrderId         uint32              `json:"sale_order_id"`                  // 销售订单id
	PayStatus           uint32              `json:"pay_status"`                     // 支付状态 0-未创建 ；1-待支付； 2-已支付
	IsPrint             uint32              `json:"is_print"`                       // 是否打印小票 1-未打印 2-已打印
	PrintCount          uint32              `json:"print_count"`                    // 小票打印次数
	InvoiceCode         string              `json:"invoice_code"`                   // 发票代码
	InvoiceNumber       string              `json:"invoice_number"`                 // 发票编码
	RejectedTotalAmount float64             `json:"rejected_total_amount" gorm:"-"` // 订单总退货金额
	RejectedTotalCount  uint32              `json:"rejected_total_count" gorm:"-"`  // 订单总退货数量
	StorePer            float64             `json:"store_per"`                      // 门店提成：订单总员工毛利X该门店设置好的提成比例，保留到小数后两位多余舍去
	TotalDiscount       float64             `json:"total_discount"`                 // 订单总优惠：订单所有商品零售优惠+会员优惠+会员积分抵扣之和
	BankTrxNo           string              `json:"bank_trx_no"  gorm:"-"`          // 银行流水号
	Commodities         []ErpOrderCommodity `json:"commodities" gorm:"-"`           // 零售订单商品信息
	Cashiers            []ErpOrderCashier   `json:"cashiers" gorm:"-"`              // 收付款方式
	Salesman            []ErpOrderSales     `json:"salesman" gorm:"-"`              // 销售员信息
}

// ErpOrderCommodity 零售订单商品表
type ErpOrderCommodity struct {
	Model

	ErpOrderId               uint32  `json:"erp_order_id" gorm:"index"`        // 零售订单id（后端生成）
	ErpCategoryId            uint32  `json:"erp_category_id" gorm:"index"`     // 分类id
	ErpCategoryName          string  `json:"erp_category_name"`                // 分类名称
	ErpCommodityId           uint32  `json:"erp_commodity_id" gorm:"index"`    // 商品id
	ErpCommodityName         string  `json:"erp_commodity_name"`               // 商品名称
	ErpSupplierId            uint32  `json:"erp_supplier_id" gorm:"index"`     // 主供应商id
	ErpSupplierName          string  `json:"erp_supplier_name"`                // 主供应商名称
	IMEIType                 uint32  `json:"imei_type"`                        // 1-无串码 2-串码
	IMEI                     string  `json:"imei" gorm:"index"`                // 串码
	PresentType              uint32  `json:"present_type"`                     // 赠送类型:1-非赠送 2-赠送
	RetailPrice              float64 `json:"retail_price"`                     // 指导零售价
	SalePrice                float64 `json:"sale_price"`                       // 零售价
	Count                    int32   `json:"count"`                            // 销售数量
	SaleDiscount             float64 `json:"sale_discount"`                    // 零售优惠
	MemberDiscount           float64 `json:"member_discount"`                  // 会员优惠
	VmDiscount               float64 `json:"vm_discount"`                      // 会员积分抵扣
	CouponID                 uint32  `json:"coupon_id"`                        // 优惠券ID
	CouponDiscount           float64 `json:"coupon_discount"`                  // 优惠券抵扣
	CouponCode               string  `json:"coupon_code"`                      // 优惠券券码
	CouponName               string  `json:"coupon_name"`                      // 优惠券名称
	Amount                   float64 `json:"amount"`                           // 实际零售价
	ReceivedAmount           float64 `json:"received_amount"`                  // 商品实收金额
	Remark                   string  `json:"remark"`                           // 销售备注
	RejectedRemark           string  `json:"rejected_remark"`                  // 退货备注
	RejectedPrice            float64 `json:"rejected_price"`                   // 退货单价
	RejectedCount            uint32  `json:"rejected_count"`                   // 退货数量
	RejectedAmount           float64 `json:"rejected_amount"`                  // 退货金额
	RejectedOrderCommodityId uint32  `json:"rejected_order_commodity_id"`      // 退货订单商品id
	StaffCostPrice           float64 `json:"staff_cost_price"`                 // 员工成本价加价（如：加价50，不是加价后的价格）
	WholesalePrice           float64 `json:"wholesale_price"`                  // 指导采购价
	SalesProfit              float64 `json:"sales_profit"`                     // 销售毛利：实际零售价-采购单价；如果为退货订单，则为实际退货价-采购单价
	StaffProfit              float64 `json:"staff_profit"`                     // 员工毛利：实际零售价-员工成本价；如果为退货订单，则为实际退货价-员工成本价
	ErpStockCommodityID      string  `json:"erp_stock_commodity_id"`           // 库存商品表主键id
	StaffPrice               float64 `json:"staff_price"  gorm:"-"`            // 员工成本价
	CommoditySerialNumber    string  `json:"commodity_serial_number" gorm:"-"` // 商品编号
	CategoryNumber           string  `json:"category_number" gorm:"-"`         // 商品分类编号
}

// ErpOrderCashier 订单收款方式
type ErpOrderCashier struct {
	CashierId uint32  `json:"cashier_id"` // 收付款方式id
	Name      string  `json:"name"`       // 收付款方式名称
	Amount    float64 `json:"amount"`     // 金额
}

// ErpOrderPayWay 订单支付方式记录
type ErpOrderPayWay struct {
	Model

	ErpOrderId uint32  `json:"erp_order_id" gorm:"index"` // 零售订单id（后端生成）
	CashierId  uint32  `json:"cashier_id"`                // 收付款方式id
	Name       string  `json:"name"`                      // 收付款方式名称
	Amount     float64 `json:"amount"`                    // 金额
}

// ErpOrderSales 销售员信息
type ErpOrderSales struct {
	Model

	ErpOrderId     uint32  `json:"erp_order_id" gorm:"index"` // 零售订单id（后端生成）
	Uid            uint32  `json:"userId" binding:"required"` // 销售员用户ID（20240322：更换为系统用户表主键id）
	Name           string  `json:"name"`                      // 销售员用户姓名
	SalesProfitPer float64 `json:"sales_profit_per"`          // 销售毛利提成：每个商品销售毛利X其对应的提成比例后求和；如果是两个销售员参与则分别除以2 ，保留到小数后两位多余舍去
	StaffProfitPer float64 `json:"staff_profit_per"`          // 员工毛利提成：每个商品员工毛利X其对应的提成比例后求和；如果是两个销售员参与则分别除以2 ，保留到小数后两位多余舍去
	SalesmanPer    float64 `json:"salesman_per"`              // 销售员提成：订单总员工毛利X该销售员设置好的提成比例；如果是两个销售员参与，那么两个人算出的提成均除以2，保留到小数后两位多余舍去
}

// ErpOrderRecord 订单支付记录表
type ErpOrderRecord struct {
	Model

	ErpOrderId  uint32  `json:"erp_order_id" gorm:"index"` // 零售订单id
	BillSn      string  `json:"bill_sn" gorm:"index"`      // 单据编号
	OutOrderNo  string  `json:"out_order_no"`              // 商户订单号
	PlatTrxNo   string  `json:"plat_trx_no"`               // 平台交易流水号
	BankOrderNo string  `json:"bank_order_no"`             // 银行订单号
	BankTrxNo   string  `json:"bank_trx_no"`               // 银行流水号
	TotalAmount float64 `json:"total_amount"`              // 订单总金额
	PayWay      string  `json:"pay_way"`                   // 支付方式
	Status      string  `json:"status"`                    // 支付状态
}

// ErpOrderCreateReq 订单创建入参
type ErpOrderCreateReq struct {
	BillSn              string              `json:"bill_sn"`                                  // 单据编号
	StoreId             uint32              `json:"store_id" binding:"required"`              // 门店id
	StoreName           string              `json:"store_name" binding:"required"`            // 门店名称
	RetailType          string              `json:"retail_type" binding:"required"`           // 销售类型：sale 零售销售； rejected 零售退货
	Tel                 string              `json:"tel"`                                      // 会员手机号
	MemberType          string              `json:"member_type"`                              // 会员类型：general 普通； member 会员
	TotalRetailPrice    float64             `json:"total_retail_price"`                       // 订单总指导零售价：如果是赠送商品，金额可以为0
	TotalAmount         float64             `json:"total_amount"`                             // 订单实收金额：如果只有1个赠送商品，金额可以为0
	TotalCount          uint32              `json:"total_count" binding:"required"`           // 订单商品数量
	VmAmount            uint32              `json:"vm_count"`                                 // 使用会员积分
	Cashiers            []ErpOrderCashier   `json:"cashiers"  binding:"required"`             // 收付款方式
	ErpOrderCommodities []ErpOrderCommodity `json:"erp_order_commodities" binding:"required"` // 零售订单商品信息
	Salesman            []ErpOrderSales     `json:"salesman"  binding:"required"`             // 销售员信息
}

// ErpOrderListReq 查询零售订单列表入参
type ErpOrderListReq struct {
	ScanCode       string `json:"scan_code"`        // 扫码枪扫码数据：串码
	BillSn         string `json:"bill_sn"`          // 单据编号
	RetailType     string `json:"retail_type"`      // 销售类型：sale 零售销售； rejected 零售退货
	CommodityName  string `json:"commodity_name"`   // 商品名称
	Uid            int    `json:"uid"`              // 用户ID
	Tel            string `json:"tel"`              // 客户手机号
	Salesman       uint32 `json:"salesman"`         // 销售人员ID
	StoreId        uint32 `json:"store_id"`         // 门店ID
	State          string `json:"state"`            // 订单状态
	PayStatus      uint32 `json:"pay_status"`       // 支付状态 0-未创建 ；1-待支付； 2-已支付
	MakeTimeStart  string `json:"make_time_start"`  // 制单开始时间
	MakeTimeEnd    string `json:"make_time_end"`    // 制单结束时间
	AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
	AuditTimeEnd   string `json:"audit_time_end"`   // 审核结束时间
	PageIndex      int    `json:"pageIndex"`        // 页码
	PageSize       int    `json:"pageSize"`         // 页面条数
}

// ErpOrderListResp 查询零售订单列表出参
type ErpOrderListResp struct {
	List      []ErpOrder `json:"list"`
	Total     int        `json:"total"`                       // 总条数
	PageIndex int        `json:"pageIndex"`                   // 页码
	PageSize  int        `json:"pageSize"`                    // 每页展示条数
	ShowAll   string     `json:"show_all" binding:"required"` // 展示所有订单配置：ON-打开，OFF-关闭
	ExportUrl string     `json:"export_url"`
}

// ErpOrderDeleteReq 删除零售订单入参
type ErpOrderDeleteReq struct {
	BillSn string `json:"bill_sn" binding:"required"` // 单据编号
}

// ErpOrderPayReq 收款入参
type ErpOrderPayReq struct {
	BillSn   string `json:"bill_sn" binding:"required"`    // 单据编号
	AuthCode string `json:"auth_code"  binding:"required"` // 用户付款码
}

// ErpOrderPayResp 收款出参
type ErpOrderPayResp struct {
	Status string `json:"status"` // 支付成功：pay_ok；支付失败：pay_failed ；等待支付：paying; 未知状态：pay_unknown; 未创建支付订单：no_pay_order
}

// ErpOrderAuditReq 审核零售订单入参
type ErpOrderAuditReq struct {
	BillSn string `json:"bill_sn" binding:"required"` // 单据编号
	State  int    `json:"state"  binding:"required"`  // 审核操作: 1-审核 2-取消审核
}

// ErpOrderAddInvoiceReq 开发票入参
type ErpOrderAddInvoiceReq struct {
	BillSn        string `json:"bill_sn" binding:"required"`        // 单据编号
	InvoiceCode   string `json:"invoice_code" binding:"required"`   // 发票代码
	InvoiceNumber string `json:"invoice_number" binding:"required"` // 发票编码
}

// ErpOrderStoreManageDataReq 查询门店经营入参
type ErpOrderStoreManageDataReq struct {
	StoreId   []uint32 `json:"store_id"`   // 门店ID
	StartTime string   `json:"start_time"` // 开始时间
	EndTime   string   `json:"end_time"`   // 结束时间
	PageIndex int      `json:"pageIndex"`  // 页码
	PageSize  int      `json:"pageSize"`   // 页面条数
	IsExport  uint32   `json:"is_export"`  // 1-导出
	SortType  string   `json:"sort_type"`  // 排序类型：desc 降序、asc 升序
}

// ErpOrderStoreManageDataResp 查询门店经营出参
type ErpOrderStoreManageDataResp struct {
	List              []StoreManageData `json:"list"`
	Total             int               `json:"total"`     // 总条数
	PageIndex         int               `json:"pageIndex"` // 页码
	PageSize          int               `json:"pageSize"`  // 每页展示条数
	ExportUrl         string            `json:"export_url"`
	TotalSalesAmount  float64           `json:"total_sales_amount"`  // 总销售额
	TotalPromotionFee float64           `json:"total_promotion_fee"` // 总推广费
	TotalSalesProfit  float64           `json:"total_sales_profit"`  // 总销售毛利
	TotalStaffProfit  float64           `json:"total_staff_profit"`  // 总员工毛利
	TotalCount        int64             `json:"total_count"`         // 总销售数量
}

// StoreManageData 门店经营数据
type StoreManageData struct {
	Date             string  `json:"date"`               // 时间，如："2023-12-25"
	TotalSalesAmount float64 `json:"total_sales_amount"` // 销售额
	PromotionFee     float64 `json:"promotion_fee"`      // 推广费
	SalesProfit      float64 `json:"sales_profit"`       // 销售毛利
	StaffProfit      float64 `json:"staff_profit"`       // 员工毛利
	Count            int64   `json:"count"`              // 销售数量
}

// ErpOrderRetailMarginReq 查询商品零售毛利汇总入参
type ErpOrderRetailMarginReq struct {
	StoreId          []uint32 `json:"store_id"`                     // 门店ID
	RetailType       []string `json:"retail_type"`                  // 销售类型:sale 零售销售； rejected 零售退货
	ErpCommodityName []string `json:"erp_commodity_name"`           // 商品名称
	ErpCategoryId    []uint32 `json:"erp_category_id" gorm:"index"` // 分类id
	StartTime        string   `json:"start_time"`                   // 开始时间
	EndTime          string   `json:"end_time"`                     // 结束时间
	PageIndex        int      `json:"pageIndex"`                    // 页码
	PageSize         int      `json:"pageSize"`                     // 页面条数
	IsExport         uint32   `json:"is_export"`                    // 1-导出
}

// ErpOrderRetailMarginResp 查询商品零售毛利汇总出参
type ErpOrderRetailMarginResp struct {
	List                      []RetailMarginData `json:"list"`
	Total                     int                `json:"total"`                        // 总条数
	PageIndex                 int                `json:"pageIndex"`                    // 页码
	PageSize                  int                `json:"pageSize"`                     // 每页展示条数
	TotalCount                int32              `json:"total_count"`                  // 总销售数量
	TotalSalesAmount          float64            `json:"total_sales_amount"`           // 总销售/退货金额
	TotalSalesCost            float64            `json:"total_sales_cost"`             // 总销售成本：销售采购价之和
	TotalEmployeeCost         float64            `json:"total_employee_cost"`          // 总员工成本：商品员工成本价之和
	TotalSalesMargin          float64            `json:"total_sales_margin"`           // 总销售毛利：销售/退货金额-销售成本
	TotalGrossMargins         string             `json:"total_gross_margins"`          // 销售毛利率:销售毛利/销售/退货金额
	TotalEmployeeMargin       float64            `json:"total_employee_margin"`        // 总员工毛利：销售金额/实际退货金额-员工成本
	TotalEmployeeGrossMargins string             `json:"total_employee_gross_margins"` // 总员工毛利率: 员工毛利/销售/退货金额
	ExportUrl                 string             `json:"export_url"`
}

// RetailMarginData 商品零售毛利数据
type RetailMarginData struct {
	StoreId              uint32  `json:"store_id" gorm:"index"`         // 门店id
	StoreName            string  `json:"store_name"`                    // 门店名称
	RetailType           string  `json:"retail_type"`                   // 销售类型:sale 零售销售； rejected 零售退货
	ErpCommodityId       uint32  `json:"erp_commodity_id" gorm:"index"` // 商品id
	ErpCommodityName     string  `json:"erp_commodity_name"`            // 商品名称
	ErpCategoryId        uint32  `json:"erp_category_id" gorm:"index"`  // 分类id
	ErpCategoryName      string  `json:"erp_category_name"`             // 分类名称
	Count                int32   `json:"count"`                         // 销售数量
	SalesAmount          float64 `json:"sales_amount"`                  // 销售/退货金额
	SalesCost            float64 `json:"sales_cost"`                    // 销售成本：销售采购价之和
	EmployeeCost         float64 `json:"employee_cost"`                 // 员工成本：商品员工成本价之和
	SalesMargin          float64 `json:"sales_margin"`                  // 销售毛利：销售/退货金额-销售成本
	GrossMargins         string  `json:"gross_margins"`                 // 销售毛利率:销售毛利/销售/退货金额
	EmployeeMargin       float64 `json:"employee_margin"`               // 员工毛利：零售销售时：销售金额-员工成本 零售退货时：实际退货金额-员工成本
	EmployeeGrossMargins string  `json:"employee_gross_margins"`        // 员工毛利率: 零售销售时：员工毛利/销售金额 零售退货时：员工毛利/退货金额
}

// ErpOrderRetailDetailReq 零售明细汇总入参
type ErpOrderRetailDetailReq struct {
	BillSn           string   `json:"bill_sn"`            // 单据编号
	RetailType       string   `json:"retail_type"`        // 销售类型：sale 零售销售； rejected 零售退货
	Uid              int      `json:"uid"`                // 用户ID
	Tel              string   `json:"tel"`                // 客户手机号
	StoreId          []uint32 `json:"store_id"`           // 门店ID
	ErpCategoryId    []uint32 `json:"erp_category_id"`    // 分类id
	ErpCommodityName string   `json:"erp_commodity_name"` // 商品名称
	Salesman         uint32   `json:"salesman"`           // 销售人员ID
	IMEI             string   `json:"imei"`               // 串码
	StartTime        string   `json:"start_time"`         // 开始时间
	EndTime          string   `json:"end_time"`           // 结束时间
	BankTrxNo        string   `json:"bank_trx_no"`        // 银联流水号
	CashierId        uint32   `json:"cashier_id"`         // 收付款方式id
	PageIndex        int      `json:"pageIndex"`          // 页码
	PageSize         int      `json:"pageSize"`           // 页面条数
	IsExport         uint32   `json:"is_export"`          // 1-导出
}

// ErpOrderRetailDetailResp 零售明细汇总出参
type ErpOrderRetailDetailResp struct {
	Total     int                   `json:"total"`      // 总条数（总订单数）
	PageIndex int                   `json:"pageIndex"`  // 页码
	PageSize  int                   `json:"pageSize"`   // 每页展示条数
	ExportUrl string                `json:"export_url"` // 导出excel地址
	List      []ErpOrder            `json:"list"`       // 零售明细
	SumData   RetailDetailTotalData `json:"sumData"`    // 汇总数据
}

// RetailDetailTotalData 零售明细相关金额汇总
type RetailDetailTotalData struct {
	Count            int32   `json:"count"`              // 销售数量
	RetailPrice      float64 `json:"retail_price"`       // 指导零售价
	SalePrice        float64 `json:"sale_price"`         // 零售价
	SaleDiscount     float64 `json:"sale_discount"`      // 零售优惠
	MemberDiscount   float64 `json:"member_discount"`    // 会员优惠
	VmDiscount       float64 `json:"vm_discount"`        // 会员积分抵扣
	CouponDiscount   float64 `json:"coupon_discount"`    // 优惠券抵扣
	Amount           float64 `json:"amount"`             // 实际零售价
	WholesalePrice   float64 `json:"wholesale_price"`    // 采购单价
	StaffPrice       float64 `json:"staff_price"`        // 员工成本价
	SalesProfit      float64 `json:"sales_profit"`       // 销售毛利
	StaffProfit      float64 `json:"staff_profit"`       // 员工毛利
	TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价
	TotalDiscount    float64 `json:"total_discount"`     // 订单总优惠：订单所有商品零售优惠+会员优惠+会员积分抵扣之和
	TotalAmount      float64 `json:"total_amount"`       // 订单实收金额
	//TotalCashierData
	TotalCashierData []ErpOrderCashier `json:"total_cashier_data" gorm:"-"` // 订单实收金额
	TotalSalesProfit float64           `json:"total_sales_profit"`          // 订单总销售毛利
	TotalStaffProfit float64           `json:"total_staff_profit"`          // 订单总员工毛利
	TotalPerData
	StorePer float64 `json:"store_per"` // 门店提成
}

// TotalPerData 员工提成
type TotalPerData struct {
	TotalSalesProfitPer float64 `json:"total_sales_profit_per"` // 销售毛利提成
	TotalStaffProfitPer float64 `json:"total_staff_profit_per"` // 员工毛利提成
	SalesmanPer         float64 `json:"salesman_per"`           // 销售员提成
}

// TotalCashierData 支付方式金额汇总
type TotalCashierData struct {
	ScanAmount    float64 `json:"scan_amount"`     // 扫码付
	CashAmount    float64 `json:"cash_amount"`     // 现金收款
	PosAmount     float64 `json:"pos_amount"`      // pos机收款
	StoreVmAmount float64 `json:"store_vm_amount"` // 商场积分抵扣
	OtherAmount   float64 `json:"other_amount"`    // 其他付款方式
}

// ErpOrderReceiptDataResp 查询小票数据出参
type ErpOrderReceiptDataResp struct {
	StoreName         string                     `json:"storeName"`         // 门店名称
	Barcode           string                     `json:"barcode"`           // 单据编号：条码
	OddNum            string                     `json:"oddNum" `           // 单据编号
	Time              time.Time                  `json:"time"`              // 审核时间
	CollectS          string                     `json:"collectS"`          // 收银人员：制单人
	ChandiseObj       map[string]TableData       `json:"chandiseObj"`       // 商品信息
	TotalRetailP      float64                    `json:"totalRetailP"`      // 零售价合计
	TotalNum          uint32                     `json:"totalNum"`          // 数量合计
	TotalAmount       float64                    `json:"totalAmount"`       // 零售优惠总金额
	MembersAmount     float64                    `json:"membersAmount"`     // 会员优惠总金额
	CouponAmount      float64                    `json:"couponAmount"`      // 优惠券优惠总金额
	IntegrationAmount float64                    `json:"integrationAmount"` // 积分抵扣总金额
	ToDealWith        float64                    `json:"toDealWith"`        // 零售价合计 - 零售优惠总额 - 会员优惠总和 - 积分抵扣总额
	ModeOfPayment     map[string]ErpOrderCashier `json:"modeOfPayment"`     // 支付信息
	ActualPayment     float64                    `json:"actualPayment"`     // 所有支付方式金额总和
	Tel               string                     `json:"tel"`               // 买家电话
	StoreTel          string                     `json:"storeTel"`          // 卖家电话
	StoreAddress      string                     `json:"storeAddress"`      // 店铺地址
	Uid               int                        `json:"uid"`               // 用户id
	IsShowImei        int                        `json:"is_show_imei"`      // 是否打印商品串码,1-打印串码，0-不打印
}

type TableData struct {
	Name string  `json:"name"`
	SL   uint32  `json:"SL"`   // 销售数量
	DJ   float64 `json:"DJ"`   // 商品指导零售价
	JE   float64 `json:"JE"`   // 商品指导零售价乘以销售数量
	IMEI string  `json:"imei"` // 串码
}

type ErpOrderBatchImportReq struct {
	StoreId uint32 `json:"store_id"  binding:"required"` // 门店id
}

type ErpOrderBatchImportResp struct {
	Commodities []ErpOrderCommodity `json:"commodities"` // 零售订单商品信息
}

// Contains 判断id是否在list中
func Contains(list []uint32, id uint32) bool {
	for _, item := range list {
		if item == id {
			return true
		}
	}
	return false
}

// CompareLists 返回共有的数据
func CompareLists(list1 []uint32, list2 []uint32) []uint32 {
	if len(list2) == 0 { // 如果list2为空，则直接使用list1的数据
		return list1
	}
	// 创建一个 map 用于存储 list1 中的数据
	list1Map := make(map[uint32]bool)
	for _, id := range list1 {
		list1Map[id] = true
	}

	var commonIds []uint32
	// 遍历 list2，如果在 list1Map 中找到相同的元素，则加入到 commonIds 中
	for _, id := range list2 {
		if list1Map[id] {
			commonIds = append(commonIds, id)
		}
	}

	return commonIds
}

// GetValidStoreIDs 返回未过期门店的ID列表
func GetValidStoreIDs(storeData string) []uint32 {
	// 解析门店数据
	var stores []StoreInfo
	if err := json.Unmarshal([]byte(storeData), &stores); err != nil {
		return nil
	}

	var validStoreIDs []uint32
	// 遍历每个门店，检查是否过期
	for _, store := range stores {
		expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
		if err != nil {
			continue
		}
		expireTime = expireTime.Add(24*time.Hour - time.Second)
		// 如果过期时间在当前时间之后，则未过期，将门店ID添加到列表中
		if expireTime.After(time.Now()) {
			validStoreIDs = append(validStoreIDs, uint32(store.StoreID))
		}
	}

	return validStoreIDs
}

// List 查询零售订单列表
func (m *ErpOrderListReq) List(c *gin.Context) (*ErpOrderListResp, error) {
	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}
	resp := &ErpOrderListResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	if m.ScanCode != "" { // 扫描了串码，需要查询已售的商品数据
		return QueryListByScanCode(m.StoreId, m.ScanCode, showConfig.ShowAll, c)
	}

	if m.CommodityName != "" { // 输入了商品名称进行查询
		return QueryListByCommodityName(m, showConfig.ShowAll, c)
	}

	qs := orm.Eloquent.Table("erp_order")
	if showConfig.ShowAll == "OFF" { // 关闭后未开小票的零售销售订单隐藏
		qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
	}
	// 非管理员才判断所属门店
	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.BillSn != "" {
		qs = qs.Where("bill_sn=?", m.BillSn)
	} else {
		if m.RetailType != "" {
			qs = qs.Where("retail_type=?", m.RetailType)
		}
		if m.Uid != 0 {
			qs = qs.Where("uid=?", m.Uid)
		}
		if m.Tel != "" {
			qs = qs.Where("tel=?", m.Tel)
		}
		if m.StoreId != 0 {
			qs = qs.Where("store_id=?", m.StoreId)
		}
		if m.Salesman != 0 {
			qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, m.Salesman))
		}
		if m.PayStatus != 0 {
			qs = qs.Where("pay_status=?", m.PayStatus)
		}
		if m.State != "" {
			qs = qs.Where("state=?", m.State)
		}
		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.AuditTimeStart != "" {
			parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
			if err != nil {
				logger.Errorf("err:", err)
			}
			qs = qs.Where("audit_time > ?", parse)
		}
		if m.AuditTimeEnd != "" {
			parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
			if err != nil {
				logger.Errorf("err:", err)
			}
			//parse = parse.AddDate(0, 0, 1)
			qs = qs.Where("audit_time < ?", parse)
		}
	}

	var count int64
	err = qs.Count(&count).Error
	if err != nil {
		logger.Error("count err:", logger.Field("err", err))
		return resp, err
	}
	var orders []ErpOrder
	err = qs.Debug().Order("maker_time 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
	}

	// 添加付款、销售员、商品信息
	erpOrderListSetCommodity(orders)
	erpOrderListSetCashier(orders)
	erpOrderListSetSalesman(orders)
	erpOrderSetBankTrxNo(orders)

	resp.List = orders

	//跟之前保持一致
	resp.Total = int(count)
	resp.PageIndex = page + 1
	resp.PageSize = m.PageSize
	resp.ShowAll = showConfig.ShowAll

	return resp, nil
}

// QueryListByScanCode 通过扫描串码查询列表
func QueryListByScanCode(storeId uint32, scanCode, showConfig string, c *gin.Context) (*ErpOrderListResp, error) {
	resp := &ErpOrderListResp{}

	// 查询扫码串码的零售销售订单的商品信息，查询最近的零售订单；可能存在重复的情况：销售-退货-销售-退货-销售
	// 需保证：（1）退货退的是最近的零售订单，每个零售订单的售价可能不同；（2）已经退货的商品不能重复退（待修复）；
	var commodity []ErpOrderCommodity
	//err := orm.Eloquent.Table("erp_order_commodity").Where("imei = ? and rejected_count = 0", scanCode).Find(&commodity).Error
	err := orm.Eloquent.Table("erp_order_commodity").Where("imei = ? and rejected_count = 0", scanCode).Order("created_at DESC").Find(&commodity).Error
	if err != nil && err != RecordNotFound {
		logger.Error("get erp_order_commodity err:", logger.Field("err", err))
		return resp, err
	}

	if len(commodity) == 0 {
		return &ErpOrderListResp{}, nil
	}

	// 判断该串码商品是否已经退货退回库存列表
	var stockCount int64
	err = orm.Eloquent.Table("erp_stock_commodity").
		Where("state = 1 AND imei = ?", scanCode).Count(&stockCount).Error
	if err != nil {
		return nil, err
	}
	if stockCount > 0 {
		return nil, errors.New("库存已有该串码商品")
	}

	var orders []ErpOrder
	for _, item := range commodity {
		if showConfig == "OFF" {
			err = orm.Eloquent.Table("erp_order").
				Where("id = ? and pay_status = ? and is_print != ?", item.ErpOrderId, HavePaid, NoPrint).
				Order("audit_time DESC").Find(&orders).Error
		} else {
			err = orm.Eloquent.Table("erp_order").
				Where("id = ? and pay_status = ?", item.ErpOrderId, HavePaid).
				Order("audit_time DESC").Find(&orders).Error
		}
		if err != nil && err != RecordNotFound {
			logger.Error("get erp_order err:", logger.Field("err", err))
			return resp, err
		}

		if len(orders) == 0 {
			continue
		} else {
			break
		}
	}

	if len(orders) != 0 {
		// 非管理员才判断所属门店
		if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
			sysUser, err := GetSysUserByCtx(c)
			if err != nil {
				return nil, errors.New("查询失败:" + err.Error())
			}

			if !CheckUserStore(orders[0].StoreId, sysUser) {
				return &ErpOrderListResp{}, errors.New("您没有该门店权限")
			}
		}

		if orders[0].StoreId != storeId && storeId != 0 {
			return &ErpOrderListResp{}, errors.New("非当前门店所售商品，需前往对应门店退货")
		}
	}

	// 添加付款、销售员、商品信息
	erpOrderListSetCommodity(orders)
	erpOrderListSetCashier(orders)
	erpOrderListSetSalesman(orders)

	//orders[0].Commodities = commodity
	orders[0].Commodities = nil
	orders[0].Commodities = append(orders[0].Commodities, commodity[0])
	if len(orders) != 0 {
		// 查询该串码商品是否已经退过货
		resp.List = append(resp.List, orders[0])
	} else {
		resp.List = orders
	}

	//跟之前保持一致
	resp.Total = len(resp.List)
	resp.PageIndex = 1
	resp.PageSize = 10

	return resp, nil
}

// QueryListByCommodityName 通过商品名称查询列表
func QueryListByCommodityName(req *ErpOrderListReq, showConfig string, c *gin.Context) (*ErpOrderListResp, error) {
	resp := &ErpOrderListResp{
		PageIndex: req.PageIndex,
		PageSize:  req.PageSize,
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

	qs := orm.Eloquent.Debug().Table("erp_order_commodity").
		Select("erp_order_commodity.*, erp_order.*").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")
	if req.CommodityName != "" { // 商品名称
		qs = qs.Where("erp_order_commodity.erp_commodity_name like ?", "%"+req.CommodityName+"%")
	}

	if showConfig == "OFF" {
		qs = qs.Where("invoice_code != ?", 0)
	}

	if req.BillSn != "" {
		qs = qs.Where("erp_order.bill_sn=?", req.BillSn)
	}

	if req.Tel != "" { // 用户手机号
		qs = qs.Where("erp_order.tel=?", req.Tel)
	}
	if req.StoreId != 0 { // 门店ID
		qs = qs.Where("erp_order.store_id=?", req.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("erp_order.store_id = ?", storeList[0])
			} else {
				qs = qs.Where("erp_order.store_id IN (?)", storeList)
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}
	qs.Where("erp_order.pay_status = ?", HavePaid)
	es := qs

	var result []RetailDetailByJoin

	err := qs.Order("erp_order.audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&result).Error
	if err != nil && err != RecordNotFound {
		logger.Error("erp commodity list err:", logger.Field("err", err))
		return resp, err
	}

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

	orders := packData(result)
	erpOrderListSetCashier(orders)
	erpOrderListSetSalesman(orders)

	resp.List = orders

	//跟之前保持一致
	resp.Total = int(count)
	resp.PageIndex = page + 1
	resp.PageSize = req.PageSize

	return resp, nil
}

// 数组转字符串
func intArrayToString(arr []uint32) string {
	var strArr []string
	for _, num := range arr {
		strArr = append(strArr, fmt.Sprintf("%d", num))
	}
	return strings.Join(strArr, ",")
}

// 字符串转数组
func stringToIntArray(str string) ([]uint32, error) {
	var arr []uint32
	strArr := strings.Split(str, ",")
	for _, s := range strArr {
		num, err := strconv.Atoi(s)
		if err != nil {
			return nil, err
		}
		arr = append(arr, uint32(num))
	}
	return arr, nil
}

// 更新零售订单商品表的库存商品表主键id字段
func updateErpStockCommodityID(gdb *gorm.DB, commodity ErpOrderCommodity, nIdList []uint32) error {
	fmt.Println("nIdList is:", nIdList)
	strId := intArrayToString(nIdList)

	// 查找在库的非串码商品
	var stockCommodity ErpStockCommodity
	err := orm.Eloquent.Table("erp_stock_commodity").Where("id = ?", strId).First(&stockCommodity).Error
	if err != nil {
		logger.Error("get erp_stock_commodity err:", logger.Field("err", err))
		return err
	}

	err = gdb.Table("erp_order_commodity").Where("id = ?", commodity.ID).
		Updates(map[string]interface{}{
			"erp_stock_commodity_id": strId,
			"retail_price":           stockCommodity.RetailPrice,
			"wholesale_price":        stockCommodity.WholesalePrice,
			"staff_cost_price":       stockCommodity.StaffCostPrice,
			"sales_profit":           commodity.ReceivedAmount - stockCommodity.WholesalePrice,
			"staff_profit":           commodity.ReceivedAmount - stockCommodity.WholesalePrice - stockCommodity.StaffCostPrice,
		}).Error
	//Update("erp_stock_commodity_id", strId).Error
	if err != nil {
		logger.Error("commodities err:", logger.Field("err", err))
		return err
	}

	return nil
}

// FindRightErpStockCommodityId 找一个可用的库存商品表主键ID
func FindRightErpStockCommodityId(idList map[uint32][]uint32, commodityId uint32, stockCommodity []ErpStockCommodity) (uint32, error) {
	// 获取给定商品ID对应的ID列表
	existingIds, ok := idList[commodityId]
	if !ok || len(existingIds) == 0 {
		// 如果对应的ID列表不存在或为空，直接返回第一个库存商品的ID
		if len(stockCommodity) > 0 {
			return stockCommodity[0].ID, nil
		}
		return 0, fmt.Errorf("empty stock commodity list")
	}

	// 创建一个 map 用于快速查找已有的 ID
	existingIdMap := make(map[uint32]bool)
	for _, id := range existingIds {
		existingIdMap[id] = true
	}

	// 遍历库存商品，找到第一个不在已有ID列表中的ID并返回
	for _, item := range stockCommodity {
		if _, found := existingIdMap[item.ID]; !found {
			return item.ID, nil
		}
	}

	// 如果所有库存商品的ID都在已有的ID列表中，则返回错误
	return 0, fmt.Errorf("no available ID found for commodity ID: %d", commodityId)
}

// UpdateStock 扣减or添加库存
// 零售订单：
// 有串码，通过串码查找库存详情表，然后更改对应库存的状态为"已售"；
// 非串码，通过门店id、商品id、商品名称查找库存详情表，找到库存时间最长的，然后更改其状态为"已售"。
// 同时扣减库存表对应的数量，-1
// 零售退货：
// 有串码，通过串码查找库存详情表，然后更改对应库存的状态为"在库"；
// 非串码，通过门店id、商品id、商品名称查找库存详情表，找到状态为"已售"且时间最近的单，将其状态改为"在库"
// 同时扣减库存表对应的数量，+1
func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state, payStatus, auditState int) error {
	var commodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", erpOrder.ID).
		Find(&commodities).Error
	if err != nil {
		logger.Error("commodities err:", logger.Field("err", err))
		return err
	}

	usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id

	if erpOrder.RetailType == RetailTypeSale { // 零售订单
		for i, _ := range commodities {
			if commodities[i].IMEIType == 2 || commodities[i].IMEIType == 3 { // 串码商品
				if commodities[i].IMEI == "" {
					return errors.New("串码为空")
				}

				err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
					Updates(map[string]interface{}{
						"state":      state,
						"updated_at": time.Now(),
					}).Error // 状态更新为已销售；反审核则更新为在库
				if err != nil {
					logger.Error("commodities err:", logger.Field("err", err))
					return err
				}

				if state == SoldOut { // 已售的订单才更新库存数量
					err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
						erpOrder.StoreId, commodities[i].ErpCommodityId).
						Updates(map[string]interface{}{
							"count":      gorm.Expr("count - ?", 1),
							"updated_at": time.Now(),
						}).Error // 库存数量-1
					if err != nil {
						logger.Error("commodities err:", logger.Field("err", err))
						return err
					}
				} else { // 反审核时则库存数量+1
					err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
						erpOrder.StoreId, commodities[i].ErpCommodityId).
						Updates(map[string]interface{}{
							"count":      gorm.Expr("count + ?", 1),
							"updated_at": time.Now(),
						}).Error // 库存数量+1
					if err != nil {
						logger.Error("commodities err:", logger.Field("err", err))
						return err
					}
				}
			} else { // 非串码商品
				if state == InStock { // 零售订单反审核
					err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID).
						Updates(map[string]interface{}{
							"state":      state,
							"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 = ?",
						erpOrder.StoreId, commodities[i].ErpCommodityId).
						Updates(map[string]interface{}{
							"count":      gorm.Expr("count + ?", 1),
							"updated_at": time.Now(),
						}).Error // 库存数量+1
					if err != nil {
						logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
						return err
					}

					err = gdb.Table("erp_order_commodity").Where("id = ?", commodities[i].ID).
						Updates(map[string]interface{}{
							"erp_stock_commodity_id": "",
						}).Error
					if err != nil {
						logger.Error("commodities err:", logger.Field("err", err))
						return err
					}
				} else { // 正常销售
					if commodities[i].ErpStockCommodityID != "" { // 零售退货单反审核，默认当作销售单
						err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID).
							Updates(map[string]interface{}{
								"state":      SoldOut,
								"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 = ?",
							erpOrder.StoreId, commodities[i].ErpCommodityId).
							Updates(map[string]interface{}{
								"count":      gorm.Expr("count - ?", 1),
								"updated_at": time.Now(),
							}).Error // 库存数量-1
						if err != nil {
							logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
							return err
						}
					} else { // 正常销售
						var stockCommodity []ErpStockCommodity
						// 添加的一条零售商品包含的非串码商品可能不止1个
						var stockCommodityIdList []uint32
						// 通过门店id，商品id，查找状态为1-在库的非串码商品
						err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
							"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, InStock, 1).
							Order("first_stock_time ASC").Find(&stockCommodity).Error
						if err != nil {
							logger.Error("commodities err:", logger.Field("err", err))
							return err
						}
						if stockCommodity == nil || len(stockCommodity) == 0 {
							return errors.New("find commodity  no stock ")
						}

						// 找一个可用的库存商品表主键ID，使用零售商品表的主键ID作为key
						rightId, err := FindRightErpStockCommodityId(usedStockCommodityIdList,
							commodities[i].ErpCommodityId, stockCommodity)
						if err != nil {
							return err
						}

						logger.Info("rightId is:", logger.Field("rightId", rightId))
						if rightId == 0 {
							logger.Error("rightId is 0")
							return errors.New("查询商品库存出错")
						}

						// 优先出库库存时间最长的数据
						err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
							Updates(map[string]interface{}{
								"state":      state,
								"updated_at": time.Now(),
							}).Error // 状态更新为销售锁定中；反审核则更新为在库
						if err != nil {
							logger.Error("commodities err:", logger.Field("err", err))
							return err
						}

						if state == SoldOut { // 已售的订单才更新库存数量
							err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
								erpOrder.StoreId, commodities[i].ErpCommodityId).
								Updates(map[string]interface{}{
									"count":      gorm.Expr("count - ?", 1),
									"updated_at": time.Now(),
								}).Error // 库存数量-1
							if err != nil {
								logger.Error("commodities err:", logger.Field("err", err))
								return err
							}
						}
						stockCommodityIdList = append(stockCommodityIdList, rightId)
						usedStockCommodityIdList[commodities[i].ErpCommodityId] = append(usedStockCommodityIdList[commodities[i].ErpCommodityId], rightId)

						err = updateErpStockCommodityID(gdb, commodities[i], stockCommodityIdList)
						if err != nil {
							return err
						}
					}
				}
			}
		}
	} else if erpOrder.RetailType == RetailTypeRejected { // 零售退货订单
		for i, _ := range commodities {
			if commodities[i].IMEIType == 2 || commodities[i].IMEIType == 3 { // 串码商品
				if commodities[i].IMEI == "" {
					return errors.New("串码为空")
				}

				err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
					Updates(map[string]interface{}{
						"state":      InStock,
						"updated_at": 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 = ?",
					erpOrder.StoreId, commodities[i].ErpCommodityId).
					Updates(map[string]interface{}{
						"count":      gorm.Expr("count + ?", 1),
						"updated_at": time.Now(),
					}).Error // 库存数量+1
				if err != nil {
					logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
					return err
				}
			} else { // 非串码商品
				var stockCommodity []ErpStockCommodity
				var stockCommodityIdList []uint32

				stockCommodityID, _ := tools.StringToInt(commodities[i].ErpStockCommodityID)
				if stockCommodityID > 0 {
					err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID).
						Updates(map[string]interface{}{
							"state":      InStock,
							"updated_at": 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 = ?",
						erpOrder.StoreId, commodities[i].ErpCommodityId).
						Updates(map[string]interface{}{
							"count":      gorm.Expr("count + ?", 1),
							"updated_at": time.Now(),
						}).Error // 库存数量+1
					if err != nil {
						logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
						return err
					}
				} else {
					// 添加的一条零售商品包含的非串码商品可能不止1个
					for j := 0; j < int(commodities[i].Count); j++ {
						// 通过门店id，商品id，查找状态为2-已售的非串码商品
						err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
							"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, SoldOut, NoIMEICommodity).
							Order("first_stock_time 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")
						}

						// 找一个可用的库存商品表主键ID
						rightId, err := FindRightErpStockCommodityId(usedStockCommodityIdList,
							commodities[i].ErpCommodityId, stockCommodity)
						if err != nil {
							return err
						}

						err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
							Updates(map[string]interface{}{
								"state":      InStock,
								"updated_at": 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 = ?",
							erpOrder.StoreId, commodities[i].ErpCommodityId).
							Updates(map[string]interface{}{
								"count":      gorm.Expr("count + ?", 1),
								"updated_at": time.Now(),
							}).Error // 库存数量+1
						if err != nil {
							logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
							return err
						}
						stockCommodityIdList = append(stockCommodityIdList, rightId)
						usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId)
					}
					err = updateErpStockCommodityID(gdb, commodities[i], stockCommodityIdList)
					if err != nil {
						return err
					}
				}
			}
		}
	} else {
		return errors.New("订单类型错误")
	}

	// 判断用户是不是会员，只有会员才会积分，否则不积分
	userInfo, err := GetUserInfoByUid(uint32(erpOrder.Uid))
	if err != nil {
		logger.Error("UpdateStock GetUserInfoByUid err:", logger.Field("err", err))
		return err
	}

	if IsInMemberLevels(userInfo.MemberLevel) {
		// 更新用户积分
		var vmCount int
		var describe, event string
		if erpOrder.RetailType == RetailTypeSale && state == SoldOut && payStatus == HavePaid { // 零售订单，而且订单已支付，更新用户积分
			if auditState == 2 {
				describe = "零售退货反审核获得积分"
			} else {
				describe = "零售销售获得积分"
			}

			event = VmEventErpOrderSale
			vmCount = tools.RoundFloat64(erpOrder.TotalAmount)
			if vmCount == 0 { // 0元无需积分
				return nil
			}
		} else if erpOrder.RetailType == RetailTypeRejected { // 退货订单，扣减用户积分（需校验购物时已积分，有则扣除）
			// 查询退货订单对应销售订单信息
			var erpSaleOrder ErpOrder
			err = orm.Eloquent.Table("erp_order").Where("id = ?", erpOrder.SaleOrderId).Find(&erpSaleOrder).Error
			if err != nil {
				logger.Errorf("query erpSaleOrder error, id is:", erpOrder.SaleOrderId)
			}

			var count int64
			err = orm.Eloquent.Table("user_vm_record").Where("bill_sn = ?", erpSaleOrder.BillSn).
				Count(&count).Error
			if err != nil {
				logger.Errorf("query user_vm_record error, bill_sn is:", erpSaleOrder.BillSn)
			}

			// 积过分才扣除
			if count > 0 {
				describe = "零售退货扣除积分"
				event = VmEventErpOrderReject
				vmCount = 0 - tools.RoundFloat64(erpOrder.TotalAmount)
			} else {
				return nil
			}
		} else {
			return nil
		}

		err = UserVmUpdate(gdb, erpOrder.BillSn, uint32(erpOrder.Uid), vmCount, event, describe)
		if err != nil {
			logger.Errorf("err:", err)
			return err
		}
	}

	return nil
}

// CheckIsOnlinePay 检查是否包含线上支付
func CheckIsOnlinePay(jCashier []ErpOrderCashier) bool {
	for _, cashier := range jCashier {
		//if cashier.CashierId == OnlinePay || strings.Contains(cashier.Name, "微信") || strings.Contains(cashier.Name, "支付宝") {
		if cashier.CashierId == OnlinePay {
			return true
		}
	}
	return false
}

// UpdateCoupon 更新对应优惠券的状态为已使用状态
func UpdateCoupon(gdb *gorm.DB, erpOrder ErpOrder, state int) error {
	var commodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", erpOrder.ID).
		Find(&commodities).Error
	if err != nil {
		logger.Error("commodities err:", logger.Field("err", err))
		return err
	}

	for i, _ := range commodities {
		var userCoupon UserCoupon
		err = orm.Eloquent.Table("user_coupon").Where("id = ?", commodities[i].CouponID).
			Find(&userCoupon).Error
		if err != nil || err == RecordNotFound {
			return errors.New("未查询到优惠券")
		}

		var coupon Coupon
		err = orm.Eloquent.Table("coupon").Where("id = ?", userCoupon.CouponId).Find(&coupon).Error
		if err != nil || err == RecordNotFound {
			return errors.New("审核失败，未查询到优惠券信息：" + err.Error())
		}

		couponState := userCoupon.State            // 优惠券状态
		if erpOrder.RetailType == RetailTypeSale { // 零售销售订单
			if state == InStock { // 反审核，在库状态，此时优惠券应该更新为：未使用/已过期
				if userCoupon.ActiveEnd.Before(time.Now()) {
					couponState = 3 // 已过期
				} else {
					couponState = 1 // 未使用
				}
			} else if state == SoldOut { // 审核，已售状态，此时优惠券应该更新为：已使用
				switch userCoupon.State {
				case 2: // 已使用
					return errors.New(fmt.Sprintf("审核失败：优惠券[%s]已使用，请重新选择",
						coupon.Name))
				case 3: // 已过期
					return errors.New(fmt.Sprintf("审核失败：优惠券[%s]已过期，请重新选择",
						coupon.Name))
				}
				couponState = 2 // 已使用
			}
		} else if erpOrder.RetailType == RetailTypeRejected { // 零售退货订单
			if state == InStock { // 审核，在库状态，此时优惠券应该更新为：未使用/已过期
				if userCoupon.ActiveEnd.Before(time.Now()) {
					couponState = 3 // 已过期
				} else {
					couponState = 1 // 未使用
				}
			} else if state == SoldOut { // 反审核，已售状态，此时优惠券应该更新为：已使用
				switch userCoupon.State {
				case 2: // 已使用
					return errors.New(fmt.Sprintf("反审核失败：优惠券[%s]已使用，请重新选择",
						coupon.Name))
				case 3: // 已过期
					return errors.New(fmt.Sprintf("反审核失败：优惠券[%s]已过期，请重新选择",
						coupon.Name))
				}
				couponState = 2 // 已使用
			}
		}
		err = gdb.Table("user_coupon").Where("id = ?", commodities[i].CouponID).Updates(map[string]interface{}{
			"state":      couponState,
			"updated_at": time.Now(),
			"use_time":   time.Now(),
		}).Error
		if err != nil {
			logger.Error("UpdateCoupon err:", logger.Field("err", err))
			return err
		}

		// 根据优惠券状态执行相应的处理逻辑
		switch couponState {
		case 1, 3: // 未使用，已过期；则扣减支付金额和已使用数量
			// 这里可以根据需要添加扣减的 SQL 更新逻辑，例如：
			sql := `
				UPDATE erp_coupon
				SET used_count = used_count - 1, 
					total_pay_amount = total_pay_amount - ?, 
					per_customer_amount = (total_pay_amount - ?) / (used_count - 1)
				WHERE ID = ?`
			err = gdb.Exec(sql, commodities[i].ReceivedAmount, commodities[i].ReceivedAmount, coupon.ErpCouponId).Error
			if err != nil {
				logger.Error("扣减优惠券数据失败:", logger.Field("err", err))
				//return err
			}
		case 2: // 已使用；则增加支付金额和已使用数量
			// 增加支付金额和已使用数量
			sql := `
				UPDATE erp_coupon
				SET used_count = used_count + 1, 
					total_pay_amount = total_pay_amount + ?, 
					per_customer_amount = (total_pay_amount + ?) / (used_count + 1)
				WHERE ID = ?`
			err = gdb.Exec(sql, commodities[i].ReceivedAmount, commodities[i].ReceivedAmount, coupon.ErpCouponId).Error
			if err != nil {
				logger.Error("更新优惠券数据失败:", logger.Field("err", err))
				//return err
			}
		}
	}

	return nil
}

// NewErpBillSn 生成零售订单号
func NewErpBillSn() string {
	nowTime := time.Now()
	rand.Seed(nowTime.UnixNano())
	max := 1
	for {
		if max > 5 {
			logger.Error("create sn err")
			return ""
		}
		random := rand.Int31n(9999) + 1000
		sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_order WHERE bill_sn='%s'", sn))
		if err != nil {
			logger.Error("exist sn err")
		}
		if !exist {
			return sn
		}

		max++
	}
}

// 添加零售订单的银行流水号
func erpOrderSetBankTrxNoAI(list []ErpOrder) {
	if len(list) == 0 {
		return // 如果列表为空，直接返回
	}

	// 提取所有的 BillSn
	billSnList := make([]string, len(list))
	for i, order := range list {
		billSnList[i] = order.BillSn
	}

	// 批量查询
	var orderPayWays []ErpOrderRecord
	err := orm.Eloquent.Table("erp_order_record").
		Where("bill_sn IN (?) AND status = ?", billSnList, PayOk).
		Find(&orderPayWays).Error
	if err != nil {
		logger.Error("SetBankTrxNo query erp_order_record err:", logger.Field("err", err))
		return
	}

	// 将银行流水号映射到订单
	bankTrxNoMap := make(map[string]string)
	for _, record := range orderPayWays {
		bankTrxNoMap[record.BillSn] = record.BankTrxNo
	}

	// 设置每个订单的银行流水号
	for i := range list {
		list[i].BankTrxNo = bankTrxNoMap[list[i].BillSn]
	}
}

// 添加零售订单的银行流水号
func erpOrderSetBankTrxNo(list []ErpOrder) {
	for i, _ := range list {
		list[i].SetBankTrxNo()
	}
}

func (m *ErpOrder) SetBankTrxNo() {
	var orderPayWay ErpOrderRecord
	err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", m.BillSn, PayOk).Find(&orderPayWay).Error
	if err != nil {
		logger.Error("SetBankTrxNo query erp_order_record err:", logger.Field("err", err))
	}

	m.BankTrxNo = orderPayWay.BankTrxNo
}

// ErpOrderRetailDetailSetCommodity 添加零售明细中订单的商品信息
func ErpOrderRetailDetailSetCommodity(list []ErpOrder) {
	for i, _ := range list {
		list[i].SetRetailDetailCommodity()
		list[i].StorePer = tools.RoundToTwoDecimalPlaces(list[i].StorePer)
		if list[i].RetailType == RetailTypeRejected { // 退货订单，金额需要转换为负值
			list[i].TotalRetailPrice = -math.Abs(list[i].TotalRetailPrice)
			list[i].TotalAmount = -math.Abs(list[i].TotalAmount)
			list[i].TotalCount = -int32(math.Abs(float64(list[i].TotalCount)))
			//list[i].TotalSalesProfit = -math.Abs(list[i].TotalSalesProfit)
			//list[i].TotalStaffProfit = -math.Abs(list[i].TotalStaffProfit)
			list[i].TotalSalesProfit = -list[i].TotalSalesProfit
			list[i].TotalStaffProfit = -list[i].TotalStaffProfit
			list[i].TotalDiscount = -math.Abs(list[i].TotalDiscount)
			list[i].VmCount = -uint32(math.Abs(float64(list[i].VmCount)))
			if list[i].TotalStaffProfit > 0 {
				list[i].StorePer = math.Abs(list[i].StorePer)
			} else {
				list[i].StorePer = -math.Abs(list[i].StorePer)
			}

		}
	}
}

func (m *ErpOrder) SetRetailDetailCommodity() {
	var orderCommodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", m.ID).Find(&orderCommodities).Error
	if err != nil {
		logger.Error("SetCommodity query erp_order_commodity err:", logger.Field("err", err))
	}

	var respOrderCommodities []ErpOrderCommodity
	nonSerialMap := make(map[string]ErpOrderCommodity)

	for _, item := range orderCommodities {
		if m.RetailType == RetailTypeRejected { // 退货订单，金额需要转换为负值
			item.Count = -item.Count
			item.RetailPrice = -item.RetailPrice
			item.SalePrice = -item.SalePrice
			item.Amount = -item.Amount
			item.SaleDiscount = -item.SaleDiscount
			item.MemberDiscount = -item.MemberDiscount
			item.VmDiscount = -item.VmDiscount
			item.ReceivedAmount = -item.ReceivedAmount
			item.RejectedAmount = -item.RejectedAmount
			item.SalesProfit = -item.SalesProfit
			item.StaffProfit = -item.StaffProfit
			item.StaffCostPrice = -item.StaffCostPrice
			item.WholesalePrice = -item.WholesalePrice
			item.CouponDiscount = -item.CouponDiscount
		}
		item.StaffPrice = item.StaffCostPrice + item.WholesalePrice

		if item.IMEIType == 2 || item.IMEIType == 3 || item.IMEI != "" { // 串码
			respOrderCommodities = append(respOrderCommodities, item)
		} else { // 非串码
			idList, err := stringToIntArray(item.ErpStockCommodityID)
			if err != nil {
				respOrderCommodities = append(respOrderCommodities, item)
				continue
			}

			for _, stockCommodityId := range idList {
				orderCommodity := item
				orderCommodity.Count = 1
				if m.RetailType == RetailTypeRejected { // 退货订单，数量需要转换为负值
					orderCommodity.Count = -1
				}

				nCount := math.Abs(float64(item.Count))
				orderCommodity.SaleDiscount = item.SaleDiscount / nCount
				orderCommodity.VmDiscount = item.VmDiscount / nCount
				orderCommodity.ReceivedAmount = item.ReceivedAmount / nCount
				orderCommodity.RejectedAmount = item.RejectedAmount / nCount
				orderCommodity.SalesProfit = item.SalesProfit / nCount
				orderCommodity.StaffProfit = item.StaffProfit / nCount

				// 查询库存商品信息
				var stockCommodity ErpStockCommodity
				err = orm.Eloquent.Table("erp_stock_commodity").
					Where("id = ?", stockCommodityId).Find(&stockCommodity).Error
				if err != nil {
					respOrderCommodities = append(respOrderCommodities, item)
					continue
				}

				orderCommodity.ErpSupplierId = stockCommodity.ErpSupplierId
				orderCommodity.ErpSupplierName = stockCommodity.ErpSupplierName
				//orderCommodity.WholesalePrice = stockCommodity.WholesalePrice
				//orderCommodity.StaffCostPrice = stockCommodity.StaffCostPrice
				//orderCommodity.StaffPrice = orderCommodity.WholesalePrice + orderCommodity.StaffCostPrice
				if m.RetailType == RetailTypeRejected { // 退货订单，数量需要转换为负值
					orderCommodity.WholesalePrice = -orderCommodity.WholesalePrice
					orderCommodity.StaffCostPrice = -orderCommodity.StaffCostPrice
					orderCommodity.StaffPrice = -orderCommodity.StaffPrice
				}

				// 用商品ID和库存商品ID组合作为合并key
				key := fmt.Sprintf("%d_%.2f", orderCommodity.ErpCommodityId, orderCommodity.SalePrice)
				if existing, ok := nonSerialMap[key]; ok {
					// 合并相同商品：累加数量、各金额/折扣
					existing.Count += orderCommodity.Count
					existing.SaleDiscount += orderCommodity.SaleDiscount
					existing.MemberDiscount += orderCommodity.MemberDiscount
					existing.VmDiscount += orderCommodity.VmDiscount
					existing.Amount += orderCommodity.Amount
					existing.ReceivedAmount += orderCommodity.ReceivedAmount
					existing.RejectedCount += orderCommodity.RejectedCount
					existing.RejectedAmount += orderCommodity.RejectedAmount
					existing.SalesProfit += orderCommodity.SalesProfit
					existing.StaffProfit += orderCommodity.StaffProfit
					existing.StaffCostPrice += orderCommodity.StaffCostPrice
					existing.WholesalePrice += orderCommodity.WholesalePrice
					//existing.RetailPrice += orderCommodity.RetailPrice
					//existing.SalePrice += orderCommodity.SalePrice
					existing.StaffPrice = existing.WholesalePrice + existing.StaffCostPrice

					nonSerialMap[key] = existing
				} else {
					nonSerialMap[key] = orderCommodity
				}
			}
		}
	}

	// 将合并后的非串码商品追加到返回结果中
	for _, commodity := range nonSerialMap {
		commodity.WholesalePrice = tools.RoundToTwoDecimalPlaces(commodity.WholesalePrice)
		commodity.StaffPrice = tools.RoundToTwoDecimalPlaces(commodity.WholesalePrice + commodity.StaffCostPrice)
		respOrderCommodities = append(respOrderCommodities, commodity)
	}

	m.Commodities = respOrderCommodities
}

// ErpOrderRetailDetailSetCommodityAI 添加零售明细中订单的商品信息
func ErpOrderRetailDetailSetCommodityAI(list []ErpOrder) {
	// 构建订单ID的切片
	var orderIDs []uint32
	for _, order := range list {
		orderIDs = append(orderIDs, order.ID)
	}

	// 批量查询所有商品信息
	var orderCommodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").Find(&orderCommodities).Error
	if err != nil {
		logger.Error("Batch query erp_order_commodity err:", logger.Field("err", err))
		return
	}

	// 创建一个映射，便于根据订单ID查找商品信息
	commodityMap := make(map[uint32][]ErpOrderCommodity)
	for _, commodity := range orderCommodities {
		commodityMap[commodity.ErpOrderId] = append(commodityMap[commodity.ErpOrderId], commodity)
	}

	// 批量查询所有已售的非串码商品信息
	var stockCommodities []ErpStockCommodity
	err = orm.Eloquent.Table("erp_stock_commodity").Where("state = ? and imei = ?", SoldOut, "").Find(&stockCommodities).Error
	if err != nil {
		logger.Error("Batch query erp_stock_commodity err:", logger.Field("err", err))
		return
	}

	// 创建一个映射，便于根据库存商品ID查找商品信息
	stockMap := make(map[uint32]ErpStockCommodity)
	for _, stock := range stockCommodities {
		stockMap[stock.ID] = stock
	}

	// 批量查询销售员信息
	var salesmanInfo []ErpOrderSales
	err = orm.Eloquent.Model(&ErpOrderSales{}).Find(&salesmanInfo).Error
	if err != nil {
		logger.Error("Batch query ErpOrderSales err:", logger.Field("err", err))
		return
	}

	// 创建用户信息的映射，便于快速查找
	salesMap := make(map[uint32][]ErpOrderSales)
	for _, user := range salesmanInfo {
		salesMap[user.ErpOrderId] = append(salesMap[user.ErpOrderId], user)
	}

	// 批量查询系统用户信息
	userMap, err := GetSysUserInfoByIds()
	if err != nil {
		return
	}

	// 批量查询商品信息
	var erpCommodities []ErpCommodity
	err = orm.Eloquent.Table("erp_commodity").Find(&erpCommodities).Error
	if err != nil {
		logger.Error("Batch query erp_commodity err:", logger.Field("err", err))
		return
	}
	erpCommodityMap := make(map[uint32]ErpCommodity)
	for _, commodity := range erpCommodities {
		erpCommodityMap[commodity.ID] = commodity
	}

	for i := range list {
		list[i].SetRetailDetailCommodityAI(commodityMap[list[i].ID], stockMap)
		list[i].StorePer = tools.RoundToTwoDecimalPlaces(list[i].StorePer)

		if list[i].RetailType == RetailTypeRejected { // 退货订单，金额需要转换为负值
			list[i].TotalRetailPrice = -math.Abs(list[i].TotalRetailPrice)
			list[i].TotalAmount = -math.Abs(list[i].TotalAmount)
			list[i].TotalCount = -int32(math.Abs(float64(list[i].TotalCount)))
			list[i].TotalSalesProfit = -list[i].TotalSalesProfit
			list[i].TotalStaffProfit = -list[i].TotalStaffProfit
			list[i].TotalDiscount = -math.Abs(list[i].TotalDiscount)
			list[i].VmCount = -uint32(math.Abs(float64(list[i].VmCount)))
			if list[i].TotalStaffProfit > 0 {
				list[i].StorePer = math.Abs(list[i].StorePer)
			} else {
				list[i].StorePer = -math.Abs(list[i].StorePer)
			}
		}

		_ = list[i].SetOrderSalesmanAI(erpCommodityMap, salesMap, userMap)
	}
}

func (m *ErpOrder) SetRetailDetailCommodityAI(orderCommodities []ErpOrderCommodity, stockMap map[uint32]ErpStockCommodity) {
	var respOrderCommodities []ErpOrderCommodity

	// 对非串码商品做合并处理：key格式为 "ErpCommodityId_stockCommodityId"
	nonSerialMap := make(map[string]ErpOrderCommodity)

	for _, item := range orderCommodities {
		fmt.Println("orderId is:", item.ErpOrderId)
		if m.RetailType == RetailTypeRejected { // 退货订单，金额需要转换为负值
			item.Count = -item.Count
			item.RetailPrice = -item.RetailPrice
			item.SalePrice = -item.SalePrice
			item.Amount = -item.Amount
			item.SaleDiscount = -item.SaleDiscount
			item.MemberDiscount = -item.MemberDiscount
			item.VmDiscount = -item.VmDiscount
			item.ReceivedAmount = -item.ReceivedAmount
			item.RejectedAmount = -item.RejectedAmount
			item.SalesProfit = -item.SalesProfit
			item.StaffProfit = -item.StaffProfit
			item.StaffCostPrice = -item.StaffCostPrice
			item.WholesalePrice = -item.WholesalePrice
			item.CouponDiscount = -item.CouponDiscount
		}
		item.StaffPrice = item.StaffCostPrice + item.WholesalePrice

		if item.IMEIType == 2 || item.IMEIType == 3 || item.IMEI != "" { // 串码
			respOrderCommodities = append(respOrderCommodities, item)
		} else { // 非串码
			idList, err := stringToIntArray(item.ErpStockCommodityID)
			if err != nil {
				respOrderCommodities = append(respOrderCommodities, item)
				continue
			}

			for _, stockCommodityId := range idList {
				fmt.Println("stockCommodityId is:", stockCommodityId)
				var orderCommodity ErpOrderCommodity
				orderCommodity = item
				if m.RetailType == RetailTypeRejected { // 退货订单，数量需要转换为负值
					orderCommodity.Count = -1
				} else {
					orderCommodity.Count = 1
				}

				nCount := math.Abs(float64(item.Count))
				orderCommodity.SaleDiscount = item.SaleDiscount / nCount
				orderCommodity.VmDiscount = item.VmDiscount / nCount
				orderCommodity.ReceivedAmount = item.ReceivedAmount / nCount
				orderCommodity.RejectedAmount = item.RejectedAmount / nCount
				orderCommodity.SalesProfit = item.SalesProfit / nCount
				orderCommodity.StaffProfit = item.StaffProfit / nCount

				// 获取库存商品信息
				stockCommodity, exists := stockMap[stockCommodityId]
				if !exists {
					respOrderCommodities = append(respOrderCommodities, item)
					continue
				}

				orderCommodity.ErpSupplierId = stockCommodity.ErpSupplierId
				orderCommodity.ErpSupplierName = stockCommodity.ErpSupplierName
				// 备注：创建零售订单时的采购价应该已经计算，以那边为准
				//orderCommodity.WholesalePrice = stockCommodity.WholesalePrice
				//orderCommodity.StaffCostPrice = stockCommodity.StaffCostPrice
				//orderCommodity.StaffPrice = orderCommodity.WholesalePrice + orderCommodity.StaffCostPrice
				if m.RetailType == RetailTypeRejected { // 退货订单，数量需要转换为负值
					orderCommodity.WholesalePrice = -orderCommodity.WholesalePrice
					orderCommodity.StaffCostPrice = -orderCommodity.StaffCostPrice
					orderCommodity.StaffPrice = -orderCommodity.StaffPrice
				}

				// 用商品ID和库存商品ID组合作为合并key
				key := fmt.Sprintf("%d_%.2f", orderCommodity.ErpCommodityId, orderCommodity.SalePrice)
				if existing, ok := nonSerialMap[key]; ok {
					// 合并相同商品：累加数量、各金额/折扣
					existing.Count += orderCommodity.Count
					existing.SaleDiscount += orderCommodity.SaleDiscount
					existing.MemberDiscount += orderCommodity.MemberDiscount
					existing.VmDiscount += orderCommodity.VmDiscount
					existing.Amount += orderCommodity.Amount
					existing.ReceivedAmount += orderCommodity.ReceivedAmount
					existing.RejectedCount += orderCommodity.RejectedCount
					existing.RejectedAmount += orderCommodity.RejectedAmount
					existing.SalesProfit += orderCommodity.SalesProfit
					existing.StaffProfit += orderCommodity.StaffProfit
					existing.StaffCostPrice += orderCommodity.StaffCostPrice
					existing.WholesalePrice += orderCommodity.WholesalePrice
					//existing.RetailPrice += orderCommodity.RetailPrice
					//existing.SalePrice += orderCommodity.SalePrice
					existing.StaffPrice = existing.WholesalePrice + existing.StaffCostPrice

					nonSerialMap[key] = existing
				} else {
					nonSerialMap[key] = orderCommodity
				}
			}
		}
	}

	// 将合并后的非串码商品追加到返回结果中
	for _, commodity := range nonSerialMap {
		commodity.WholesalePrice = tools.RoundToTwoDecimalPlaces(commodity.WholesalePrice)
		commodity.StaffPrice = tools.RoundToTwoDecimalPlaces(commodity.WholesalePrice + commodity.StaffCostPrice)
		respOrderCommodities = append(respOrderCommodities, commodity)
	}

	m.Commodities = respOrderCommodities
}

// 添加订单的商品信息
func erpOrderListSetCommodity(list []ErpOrder) {
	for i, _ := range list {
		list[i].SetCommodity()
	}
}

func (m *ErpOrder) SetCommodity() {
	var orderCommodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", m.ID).Find(&orderCommodities).Error
	if err != nil {
		logger.Error("SetCommodity query erp_order_commodity err:", logger.Field("err", err))
	}

	commodities := mergeOrderCommodities(orderCommodities)
	for i, _ := range commodities {
		categoryInfo, _ := GetErpCategory(commodities[i].ErpCategoryId)
		if categoryInfo != nil {
			commodities[i].CategoryNumber = categoryInfo.Number
			commodities[i].ErpCategoryName = categoryInfo.Name
		}

		commodityInfo, _ := GetCommodity(commodities[i].ErpCommodityId)
		if commodityInfo != nil {
			commodities[i].CommoditySerialNumber = commodityInfo.SerialNumber
			//commodities[i].ErpCommodityName = commodityInfo.Name
		}
	}
	m.Commodities = commodities
}

// 合并重复的商品数据
func mergeOrderCommodities(orderCommodities []ErpOrderCommodity) []ErpOrderCommodity {
	// 创建一个map来存储每个(ErpOrderId, ErpCommodityId)组合的合并结果
	type key struct {
		ErpOrderId     uint32
		ErpCommodityId uint32
		IMEI           string
		CouponID       uint32
		SalePrice      float64
	}
	commodityMap := make(map[key]*ErpOrderCommodity)

	// 遍历orderCommodities，将相同ErpCommodityId的数量累加
	for _, commodity := range orderCommodities {
		comboKey := key{
			ErpOrderId:     commodity.ErpOrderId,
			ErpCommodityId: commodity.ErpCommodityId,
			IMEI:           commodity.IMEI,
			CouponID:       commodity.CouponID,
			SalePrice:      commodity.SalePrice,
		}
		if existingCommodity, exists := commodityMap[comboKey]; exists {
			existingCommodity.Count += commodity.Count
			existingCommodity.SalesProfit += commodity.SalesProfit
			existingCommodity.StaffProfit += commodity.StaffProfit
			existingCommodity.SaleDiscount += commodity.SaleDiscount
			existingCommodity.MemberDiscount += commodity.MemberDiscount
			existingCommodity.ReceivedAmount += commodity.ReceivedAmount
			existingCommodity.RejectedCount += commodity.RejectedCount
			existingCommodity.RejectedAmount += commodity.RejectedAmount
			stockCommodityID, _ := tools.StringToInt(commodity.ErpStockCommodityID)
			if stockCommodityID > 0 {
				existingCommodity.ErpStockCommodityID = strings.Join([]string{existingCommodity.ErpStockCommodityID, commodity.ErpStockCommodityID}, ",")
			}
		} else {
			// 使用commodity的副本避免对原始数据的修改
			commodityCopy := commodity
			commodityMap[comboKey] = &commodityCopy
		}
	}

	// 将map转换回orderCommodities列表
	var mergedCommodities []ErpOrderCommodity
	for _, commodity := range commodityMap {
		// 对float64类型的字段进行四舍五入处理
		commodity.SalesProfit = tools.RoundFloat(commodity.SalesProfit)
		commodity.StaffProfit = tools.RoundFloat(commodity.StaffProfit)
		commodity.SaleDiscount = tools.RoundFloat(commodity.SaleDiscount)
		commodity.MemberDiscount = tools.RoundFloat(commodity.MemberDiscount)
		commodity.ReceivedAmount = tools.RoundFloat(commodity.ReceivedAmount)
		commodity.RejectedPrice = tools.RoundFloat(commodity.RejectedPrice)
		commodity.RejectedAmount = tools.RoundFloat(commodity.RejectedAmount)
		commodity.StaffCostPrice = tools.RoundFloat(commodity.StaffCostPrice)
		commodity.WholesalePrice = tools.RoundFloat(commodity.WholesalePrice)

		mergedCommodities = append(mergedCommodities, *commodity)
	}

	// 对mergedCommodities按ErpCommodityId进行排序
	sort.Slice(mergedCommodities, func(i, j int) bool {
		return mergedCommodities[i].ID < mergedCommodities[j].ID
	})

	return mergedCommodities
}

// 添加订单的销售员信息
func erpOrderListSetSalesmanByRetailDetail(userId uint32, list []ErpOrder) {
	for i, _ := range list {
		_ = list[i].SetOrderSalesmanRetailDetail(userId)
	}
}

func (m *ErpOrder) SetOrderSalesmanRetailDetail(userId uint32) error {
	var salesProfit, staffProfit, totalStaffProfit float64
	//获取销售毛利、员工毛利数据
	for _, item := range m.Commodities {
		erpCommodity, err := GetCommodity(item.ErpCommodityId)
		if err != nil {
			logger.Error("GetCommodity err:", logger.Field("err", err))
		}
		salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
		staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
		totalStaffProfit += item.StaffProfit
	}
	// 四舍五入并保留两位小数
	salesProfit = math.Round(salesProfit*100) / 100
	staffProfit = math.Round(staffProfit*100) / 100
	totalStaffProfit = math.Round(totalStaffProfit*100) / 100

	var salesmanInfo []ErpOrderSales
	err := orm.Eloquent.Model(&ErpOrderSales{}).Where("erp_order_id = ?", m.ID).Find(&salesmanInfo).Error
	if err != nil {
		return err
	}

	var salesmanList []ErpOrderSales
	for _, item := range salesmanInfo {
		item.SalesProfitPer = salesProfit / float64(len(salesmanInfo))
		item.StaffProfitPer = staffProfit / float64(len(salesmanInfo))

		// 获取员工毛利
		userInfo, err := GetSysUserInfoById(item.Uid)
		if err != nil {
			logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
		}
		item.Name = userInfo.NickName
		item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(salesmanInfo))

		//if m.RetailType == RetailTypeRejected {
		//	item.SalesProfitPer = -item.SalesProfitPer
		//	item.StaffProfitPer = -item.StaffProfitPer
		//	item.SalesmanPer = -item.SalesmanPer
		//}

		if userId != item.Uid {
			item.SalesProfitPer = 0
			item.StaffProfitPer = 0
			item.SalesmanPer = 0
		}

		salesmanList = append(salesmanList, item)
	}

	if len(salesmanList) == 0 {
		m.Salesman = []ErpOrderSales{}
	} else {
		m.Salesman = salesmanList
	}

	m.SalesmanList = ""

	return nil
}

// GetSysUserInfoByIds 批量获取用户信息
func GetSysUserInfoByIds() (map[uint32]SysUser, error) {
	var userInfos []SysUser
	err := orm.Eloquent.Debug().Table("sys_user").Find(&userInfos).Error
	if err != nil {
		logger.Error("Batch query sys_user err:", logger.Field("err", err))
		return nil, err
	}

	// 创建用户信息的映射，便于快速查找
	userMap := make(map[uint32]SysUser)
	for _, user := range userInfos {
		if countDigits(user.Uid) == 8 {
			userMap[user.Uid] = user
		}
		userMap[uint32(user.UserId)] = user
	}

	return userMap, nil
}

func (m *ErpOrder) SetOrderSalesmanAI(erpCommodityMap map[uint32]ErpCommodity, salesMap map[uint32][]ErpOrderSales, userMap map[uint32]SysUser) error {
	var salesProfit, staffProfit, totalStaffProfit float64
	//获取销售毛利、员工毛利数据
	for _, item := range m.Commodities {
		erpCommodity := erpCommodityMap[item.ErpCommodityId]
		salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
		staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
		totalStaffProfit += item.StaffProfit
	}
	// 四舍五入并保留两位小数
	salesProfit = math.Round(salesProfit*100) / 100
	staffProfit = math.Round(staffProfit*100) / 100
	totalStaffProfit = math.Round(totalStaffProfit*100) / 100

	var salesmanInfo []ErpOrderSales
	salesmanInfo = salesMap[m.ID]

	var salesmanList []ErpOrderSales
	for _, item := range salesmanInfo {
		item.SalesProfitPer = salesProfit / float64(len(salesmanInfo))
		item.StaffProfitPer = staffProfit / float64(len(salesmanInfo))

		// 获取员工毛利
		userInfo := userMap[item.Uid]
		if userInfo.UserId != 0 {
			item.Name = userInfo.NickName
		}
		item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(salesmanInfo))

		salesmanList = append(salesmanList, item)
	}

	if len(salesmanList) == 0 {
		m.Salesman = []ErpOrderSales{}
	} else {
		m.Salesman = salesmanList
	}

	m.SalesmanList = ""

	return nil
}

// 添加订单的销售员信息
func erpOrderListSetSalesman(list []ErpOrder) {
	storeMap, _ := GetAllStoreData()
	for i, _ := range list {
		_ = list[i].SetOrderSalesman()
		if len(storeMap) != 0 {
			temp := storeMap[list[i].StoreId].Name
			if temp != "" {
				list[i].StoreName = temp
			}
		}
	}
}

func (m *ErpOrder) SetOrderSalesman() error {
	var salesProfit, staffProfit, totalStaffProfit float64
	//获取销售毛利、员工毛利数据
	for _, item := range m.Commodities {
		erpCommodity, err := GetCommodity(item.ErpCommodityId)
		if err != nil {
			logger.Error("GetCommodity err:", logger.Field("err", err))
		}

		//// 商品名称可能修改，历史订单没有主动更新，此处查询
		//m.Commodities[i].ErpCommodityName = erpCommodity.Name

		salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
		staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
		totalStaffProfit += item.StaffProfit
	}
	// 四舍五入并保留两位小数
	salesProfit = math.Round(salesProfit*100) / 100
	staffProfit = math.Round(staffProfit*100) / 100
	totalStaffProfit = math.Round(totalStaffProfit*100) / 100

	var salesmanInfo []ErpOrderSales
	err := orm.Eloquent.Model(&ErpOrderSales{}).Where("erp_order_id = ?", m.ID).Find(&salesmanInfo).Error
	if err != nil {
		return err
	}

	var salesmanList []ErpOrderSales
	for _, item := range salesmanInfo {
		item.SalesProfitPer = salesProfit / float64(len(salesmanInfo))
		item.StaffProfitPer = staffProfit / float64(len(salesmanInfo))

		// 获取员工毛利
		userInfo, err := GetSysUserInfoById(item.Uid)
		if err != nil {
			logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
		}
		if userInfo.UserId != 0 {
			item.Name = userInfo.NickName
		}

		item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(salesmanInfo))

		//if m.RetailType == RetailTypeRejected {
		//	item.SalesProfitPer = -item.SalesProfitPer
		//	item.StaffProfitPer = -item.StaffProfitPer
		//	item.SalesmanPer = -item.SalesmanPer
		//}

		salesmanList = append(salesmanList, item)
	}

	if len(salesmanList) == 0 {
		m.Salesman = []ErpOrderSales{}
	} else {
		m.Salesman = salesmanList
	}

	m.SalesmanList = ""

	return nil
}

func (m *ErpOrder) SetSalesman() {
	if m.SalesmanList != "" {
		var salesman []ErpOrderSales
		err := json.Unmarshal([]byte(m.SalesmanList), &salesman)
		if err != nil {
			logger.Error("unmarshal err:", logger.Field("err", err))
		}
		m.Salesman = salesman
		m.SalesmanList = ""
	}
}

func (m *ErpOrderCreateReq) GetSalesmanList() (string, error) {
	var salesProfit, staffProfit, totalStaffProfit float64
	//获取销售毛利、员工毛利数据
	for _, item := range m.ErpOrderCommodities {
		erpCommodity, err := GetCommodity(item.ErpCommodityId)
		if err != nil {
			logger.Error("GetCommodity err:", logger.Field("err", err))
		}
		salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
		staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
		totalStaffProfit += item.StaffProfit
	}

	var salesmanList []ErpOrderSales
	for _, item := range m.Salesman {
		item.SalesProfitPer = salesProfit / float64(len(m.Salesman))
		item.StaffProfitPer = staffProfit / float64(len(m.Salesman))

		// 获取员工毛利
		userInfo, err := GetSysUserInfoById(item.Uid)
		if err != nil {
			logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
		}
		item.Name = userInfo.NickName
		//item.SalesmanPer = staffProfit * userInfo.SalesCommRate * 0.01 / float64(len(m.Salesman))
		item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(m.Salesman))

		// 四舍五入并保留两位小数
		item.SalesProfitPer = math.Round(item.SalesProfitPer*100) / 100
		item.StaffProfitPer = math.Round(item.StaffProfitPer*100) / 100
		item.SalesmanPer = math.Round(item.SalesmanPer*100) / 100

		salesmanList = append(salesmanList, item)
	}

	m.Salesman = salesmanList
	jSalesman, err := json.Marshal(m.Salesman)
	if err != nil {
		logger.Error("salesman marshal err:", logger.Field("err", err))
		return "", err
	}

	return string(jSalesman), nil
}

// 添加订单的付款信息
func erpOrderListSetCashier(list []ErpOrder) {
	for i, _ := range list {
		list[i].SetErpCashier()
	}
}

func (m *ErpOrder) SetErpCashier() {
	//if m.CashierList != "" && m.RetailType == RetailTypeSale { // 临时限制，退货订单不展示具体付款方式
	if m.CashierList != "" {
		var cashiers []ErpOrderCashier
		err := json.Unmarshal([]byte(m.CashierList), &cashiers)
		if err != nil {
			logger.Error("unmarshal err:", logger.Field("err", err))
		}
		if m.RetailType == RetailTypeRejected {
			for i, _ := range cashiers {
				cashiers[i].Amount = -cashiers[i].Amount
			}
		}
		m.Cashiers = cashiers
		m.CashierList = ""
	}
}

// 添加订单的付款信息
func erpRetailDetailSetCashier(list []ErpOrder) {
	for i, _ := range list {
		list[i].SetErpRetailDetailCashier()
	}
}

func (m *ErpOrder) SetErpRetailDetailCashier() {
	if m.CashierList != "" {
		var cashiers []ErpOrderCashier
		err := json.Unmarshal([]byte(m.CashierList), &cashiers)
		if err != nil {
			logger.Error("unmarshal err:", logger.Field("err", err))
		}
		if m.RetailType == RetailTypeRejected {
			for i, _ := range cashiers {
				cashiers[i].Amount = -cashiers[i].Amount
			}
		}

		var nTotalOtherAmount float64
		var newCashiers []ErpOrderCashier
		for _, item := range cashiers {
			if item.CashierId > 4 {
				nTotalOtherAmount += item.Amount
			} else {
				newCashiers = append(newCashiers, item)
			}
		}
		// 将所有其他类型的支付方式合并到一起
		newCashiers = append(newCashiers, ErpOrderCashier{8090, "", nTotalOtherAmount})
		m.Cashiers = newCashiers
		m.CashierList = ""
	}
}

func GetErpOrderCommodityMap(ids []uint32, req *ErpOrderCreateReq) (map[uint32]ErpOrderCommodity, error) {
	commodityMap := make(map[uint32]ErpOrderCommodity, 0)
	if len(ids) == 0 {
		return commodityMap, nil
	}

	var commodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id ").
		Where("erp_order_commodity.erp_commodity_id IN (?) and erp_order.store_id = ? "+
			"and erp_order.retail_type = ? and erp_order.pay_status = ? and erp_order.tel = ?",
			ids, req.StoreId, RetailTypeSale, HavePaid, req.Tel).
		Find(&commodities).Order("audit_time DESC").Error
	//var commodities []ErpOrderCommodity
	//err := orm.Eloquent.Table("erp_order_commodity").Where("erp_commodity_id IN (?)", ids).Find(&commodities).Error
	if err != nil {
		logger.Error("commodities err:", logger.Field("err", err))
		return commodityMap, err
	}
	// 合并数据
	commodities = mergeOrderCommodities(commodities)
	for i, _ := range commodities {
		commodityMap[commodities[i].ErpCommodityId] = commodities[i]
	}
	return commodityMap, nil
}

func SetUserInfo(tel string) {
	var user UserInfo
	err := orm.Eloquent.Table("user").Where("tel=?", tel).Find(&user).Error
	if err != nil {
		logger.Error("user err:", logger.Field("err", err))
		return
	}
	if user.FirstRetailOrder == nil {
		err := orm.Eloquent.Table("user").Where("uid=?", user.Uid).
			Updates(map[string]interface{}{"first_retail_order": time.Now()}).Error
		if err != nil {
			logger.Error("update user err:", logger.Field("err", err))
		}
	}
}

// SetInvoice 设置发票内容
func SetInvoice(req *ErpOrderAddInvoiceReq, c *gin.Context) error {
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		logger.Errorf("err:%#v", err)
		return err
	}

	var orderInfo ErpOrder
	err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error
	if err != nil {
		logger.Error("操作失败，未查询到订单", logger.Field("err", err))
		return errors.New("未查询到订单")
	}

	if orderInfo.State == ErpOrderStateUnAudit {
		logger.Errorf("order delete err, state is:", orderInfo.State)
		return errors.New("订单未审核")
	}

	if orderInfo.PayStatus != 2 {
		logger.Errorf("order delete err, state is:", orderInfo.State)
		return errors.New("订单未支付")
	}

	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		// 校验入参门店是否包含在用户所有门店中，是否过期
		if !CheckUserStore(orderInfo.StoreId, sysUser) {
			return errors.New("操作失败：您没有该门店权限")
		}
	}

	err = orm.Eloquent.Table("erp_order").Where("id = ?", orderInfo.ID).Updates(map[string]interface{}{
		"invoice_code":   req.InvoiceCode,
		"invoice_number": req.InvoiceNumber,
	}).Error
	if err != nil {
		logger.Error("AddInvoice err:", logger.Field("err", err))
		return err
	}

	return nil
}

// DeleteOrder 删除订单
func DeleteOrder(req *ErpOrderDeleteReq, c *gin.Context) error {
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		logger.Errorf("err:%#v", err)
		return err
	}

	var orderInfo ErpOrder
	err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error
	if err != nil {
		logger.Error("order delete err:", logger.Field("err", err))
		return errors.New("未查询到订单")
	}

	if orderInfo.State != ErpOrderStateUnAudit {
		logger.Errorf("order delete err, state is:", orderInfo.State)
		return errors.New("已审核订单不能删除")
	}

	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		// 校验入参门店是否包含在用户所有门店中，是否过期
		if !CheckUserStore(orderInfo.StoreId, sysUser) {
			return errors.New("操作失败：您没有该门店权限")
		}
	}

	var orderCommodities []ErpOrderCommodity
	err = orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", orderInfo.ID).Find(&orderCommodities).Error
	if err != nil {
		logger.Error("order delete err:", logger.Field("err", err))
		return errors.New("未查询到订单商品信息")
	}

	begin := orm.Eloquent.Begin()
	err = begin.Delete(&orderCommodities).Error
	if err != nil {
		begin.Rollback()
		logger.Error("order delete1 err:", logger.Field("err", err))
		return err
	}

	err = begin.Delete(orderInfo).Error
	if err != nil {
		begin.Rollback()
		logger.Error("order delete2 err:", logger.Field("err", err))
		return err
	}

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

	return nil
}

// 生成序列号
func genErpOrderSerialNo() string {
	currentDate := time.Now().Format("20060102")
	tradeNO := "sale" + currentDate + pay.RandomNumString(10000000, 99999999)
	return tradeNO
}

// GetErpOrderSn 生成零售订单号
func GetErpOrderSn() string {
	var erpOrderSn string
	for {
		erpOrderSn = genErpOrderSerialNo()
		var count int64
		err := orm.Eloquent.Table("erp_order_record").Where("out_order_no=?", erpOrderSn).Count(&count)
		if err != nil {
			logger.Error("err:", logger.Field("err", err))
		}
		if count == 0 {
			break
		}
	}
	return erpOrderSn
}

// 查询是否有已支付的订单
func checkIsPayOk(billSn string) bool {
	var count int64
	err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, PayOk).
		Count(&count).Error
	if err != nil {
		logger.Error("checkIsPayOk err:", logger.Field("err", err))
	}

	return count > 0
}

// 查询是否有待支付的订单
func checkIsPaying(billSn string) bool {
	var count int64
	err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, Paying).
		Count(&count).Error
	if err != nil {
		logger.Error("checkIsPayOk err:", logger.Field("err", err))
	}

	return count > 0
}

// 查询是否有刚初始化的订单
func checkIsPayInit(billSn string) bool {
	var count int64
	err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, PayInit).
		Count(&count).Error
	if err != nil {
		logger.Error("checkIsPayOk err:", logger.Field("err", err))
	}

	return count > 0
}

// ErpOrderPay 零售订单支付
func ErpOrderPay(req *ErpOrderPayReq, c *gin.Context) (*ErpOrderPayResp, error) {
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		logger.Errorf("err:%#v", err)
		return nil, err
	}

	resp := &ErpOrderPayResp{
		Status: PayFailed,
	}
	//通过单据号查询收款金额
	var orderInfo ErpOrder
	err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error
	if err != nil {
		logger.Error("未查询到订单:", logger.Field("err", err))
		return resp, err
	}

	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		// 校验入参门店是否包含在用户所有门店中，是否过期
		if !CheckUserStore(orderInfo.StoreId, sysUser) {
			return nil, errors.New("操作失败：您没有该门店权限")
		}
	}

	if orderInfo.PayStatus == HavePaid {
		logger.Error("ErpOrderPay err, 订单已支付")
		return resp, errors.New("订单已支付")
	}

	if orderInfo.PayStatus != WaitForPaying {
		logger.Error("ErpOrderPay err, 订单不是待支付状态")
		return resp, errors.New("订单不是待支付状态")
	}

	var cashiers []ErpOrderCashier
	err = json.Unmarshal([]byte(orderInfo.CashierList), &cashiers)
	if err != nil {
		logger.Error("unmarshal CashierList err:", logger.Field("err", err))
	}

	var amount float64
	for i, _ := range cashiers {
		if cashiers[i].CashierId == OnlinePay { //线上支付
			amount = cashiers[i].Amount
			break
		}
	}
	if amount == 0 {
		logger.Error("ErpOrderPay err, 订单金额为0")
		return resp, errors.New("订单金额为0")
	}

	// dev环境测试默认金额都为0.1元
	if config.ApplicationConfig.Mode == "dev" {
		amount = 0.1
	}

	// 查询是否有已支付的订单
	if checkIsPayOk(req.BillSn) {
		// 更新零售订单表
		err = orm.Eloquent.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).
			Updates(map[string]interface{}{"pay_status": HavePaid}).Error
		if err != nil {
			logger.Error("ErpOrderPay update erp_order_record err:", logger.Field("err", err))
		}
		resp.Status = PayOk
		logger.Error("ErpOrderPay err2, 订单已支付")
		return resp, errors.New("订单已支付")
	}

	// 查询是否有待支付订单
	if checkIsPaying(req.BillSn) {
		queryResp, err := QueryErpOrderPayStatus(req.BillSn)
		if err != nil {
			logger.Error("查询订单失败", logger.Field("err", err))
			return resp, err
		}

		// 等待支付或成功支付则返回，否则新建订单
		if queryResp.Status == Paying || queryResp.Status == PayOk {
			resp.Status = queryResp.Status
			return resp, nil
		}
	}

	// 查询是否有刚初始化的订单
	var orderSn string
	if checkIsPayInit(req.BillSn) {
		var orderRecordInfo ErpOrderRecord
		err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", req.BillSn, PayInit).
			Find(&orderRecordInfo).Error
		if err != nil {
			logger.Error("未查询到订单:", logger.Field("err", err))
			return resp, errors.New("未查询到待支付订单")
		}
		orderSn = orderRecordInfo.OutOrderNo
	} else {
		// 创建支付订单号，并记录到支付记录表，关联零售订单号
		orderSn = GetErpOrderSn()
		var erpOrderRecord ErpOrderRecord
		erpOrderRecord.ErpOrderId = orderInfo.ID
		erpOrderRecord.BillSn = orderInfo.BillSn
		erpOrderRecord.OutOrderNo = orderSn
		erpOrderRecord.Status = PayInit
		err = orm.Eloquent.Table("erp_order_record").Create(&erpOrderRecord).Error
		if err != nil {
			logger.Error("Create erp_order_record err:", logger.Field("err", err))
			return resp, err
		}
	}
	resp.Status = Paying

	// 发起支付扣款
	hmPayResp, err := pay.HmJsPayBToCOrder(orderInfo.StoreId, orderSn, amount, req.AuthCode, "")
	if err != nil {
		logger.Error("HmJsPayBToCOrder err")
		return resp, err
	}

	// 更新支付状态
	var payStatus string
	switch hmPayResp.SubCode {
	case "SUCCESS":
		payStatus = PayOk
	case "FAILED":
		payStatus = PayFailed
	case "WAITING_PAYMENT":
		payStatus = Paying
		//default:
		//	payStatus = PayUnknown
	}
	updateInfo := map[string]interface{}{
		"bank_order_no": hmPayResp.BankOrderNo,
		"plat_trx_no":   hmPayResp.PlatTrxNo,
		"bank_trx_no":   hmPayResp.BankTrxNo,
		"total_amount":  hmPayResp.TotalAmount,
		"pay_way":       hmPayResp.PayWay,
		"status":        payStatus,
	}

	begin := orm.Eloquent.Begin()
	err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderSn).
		Updates(updateInfo).Error
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_order_record err:", logger.Field("err", err))
		return resp, err
	}

	if payStatus == PayOk { // 支付成功
		// 更新零售订单表
		err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).
			Updates(map[string]interface{}{"pay_status": HavePaid}).Error
		if err != nil {
			begin.Rollback()
			logger.Error("update erp_order_record err:", logger.Field("err", err))
			return resp, err
		}

		//// 更新库存订单表
		//err = updateErpStockCommodity(begin, req.BillSn)
		//if err != nil {
		//	logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err))
		//	return resp, err
		//}
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		return resp, fmt.Errorf("ErpOrderPay[commit err]：%v", err)
	}

	resp.Status = payStatus

	// 判断用户是不是会员，只有会员才会积分，否则不积分
	userInfo, err := GetUserInfoByUid(uint32(orderInfo.Uid))
	if err != nil {
		logger.Error("UpdateStock GetUserInfoByUid err:", logger.Field("err", err))
	}

	if IsInMemberLevels(userInfo.MemberLevel) {
		// 更新用户积分
		var vmCount int
		var describe, event string
		if orderInfo.RetailType == RetailTypeSale { // 零售订单，而且订单已支付，更新用户积分
			describe = "零售销售获得积分"
			event = VmEventErpOrderSale
			vmCount = tools.RoundFloat64(orderInfo.TotalAmount)
			if vmCount == 0 { // 0元无需积分
				return resp, nil
			}
		} else {
			return resp, nil
		}

		err = UserVmUpdate(nil, orderInfo.BillSn, uint32(orderInfo.Uid), vmCount, event, describe)
		if err != nil {
			logger.Errorf("UserVmUpdate err:", err)
		}
	}

	if payStatus == PayOk { // 已完成支付的订单判断是否发优惠券
		// 发放尊享会员优惠券
		UpdateSwitchUserCoupon(orderInfo.ID, orderInfo.Uid, orderInfo.RetailType)
	}

	return resp, nil
}

// QueryErpOrderPayStatus 查询零售订单支付状态
func QueryErpOrderPayStatus(billSn string) (*ErpOrderPayResp, error) {
	resp := &ErpOrderPayResp{
		Status: Paying,
	}

	// 查询订单信息
	var orderInfo ErpOrder
	err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", billSn).Find(&orderInfo).Error
	if err != nil {
		logger.Error("未查询到订单:", logger.Field("err", err))
		resp.Status = PayFailed
		return resp, errors.New("未查询到待支付订单")
	}

	// 查询待支付订单
	var orderRecordInfo ErpOrderRecord
	err = orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status in (?)", billSn, []string{PayInit, Paying, PayOk}).
		Find(&orderRecordInfo).Error
	if err != nil {
		logger.Error("未查询到订单:", logger.Field("err", err))
		resp.Status = PayFailed
		return resp, errors.New("未查询到待支付订单")
	}

	if orderRecordInfo.OutOrderNo == "" {
		logger.Info("还未创建支付订单")
		resp.Status = NoPayOrder
		return resp, nil
	}

	if orderRecordInfo.Status == PayOk {
		logger.Info("订单已支付")
		resp.Status = PayOk
		return resp, nil
	}

	// 查询支付状态
	hmQueryResp, err := pay.HmQueryOrder(orderRecordInfo.OutOrderNo, orderInfo.StoreId)
	if err != nil {
		logger.Error("查询失败:", logger.Field("err", err))
		return resp, err
	}

	// 更新订单状态
	var payStatus string
	switch hmQueryResp.SubCode {
	case "SUCCESS":
		payStatus = PayOk
	case "FAILED":
		payStatus = PayFailed
	case "WAITING_PAYMENT":
		payStatus = Paying
		//default:
		//	payStatus = PayUnknown
	}
	updateInfo := map[string]interface{}{
		"bank_order_no": hmQueryResp.BankOrderNo,
		"plat_trx_no":   hmQueryResp.PlatTrxNo,
		"bank_trx_no":   hmQueryResp.BankTrxNo,
		"total_amount":  hmQueryResp.TotalAmount,
		"pay_way":       hmQueryResp.PayWayCode,
		"status":        payStatus,
		"updated_at":    time.Now(),
	}

	begin := orm.Eloquent.Begin()
	err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderRecordInfo.OutOrderNo).
		Updates(updateInfo).Error
	if err != nil {
		begin.Rollback()
		logger.Error("query update erp_order_record err:", logger.Field("err", err))
		return resp, err
	}

	if payStatus == PayOk { // 支付成功
		// 更新零售订单表
		err = begin.Model(&ErpOrder{}).Where("id = ?", orderRecordInfo.ErpOrderId).
			Updates(map[string]interface{}{
				"pay_status": HavePaid,
				"updated_at": time.Now(),
			}).Error
		if err != nil {
			begin.Rollback()
			logger.Error("query update erp_order_record err:", logger.Field("err", err))
			return resp, err
		}

		//// 更新库存订单表
		//err = updateErpStockCommodity(begin, billSn)
		//if err != nil {
		//	logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err))
		//	return resp, err
		//}
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		return resp, fmt.Errorf("QueryErpOrderPayStatus[commit err]：%v", err)
	}

	if payStatus == PayOk { // 已完成支付的订单判断是否发优惠券
		// 发放尊享会员优惠券
		UpdateSwitchUserCoupon(orderInfo.ID, orderInfo.Uid, orderInfo.RetailType)
	}

	resp.Status = payStatus
	return resp, nil
}

// 更新库存订单表
func updateErpStockCommodity(gdb *gorm.DB, billSn string) error {
	//通过单据号查询订单
	var erpOrderInfo []ErpOrder
	err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", billSn).Find(&erpOrderInfo).Error
	if err != nil {
		logger.Error("erp_order 未查询到订单:", logger.Field("err", err))
		return err
	}

	if len(erpOrderInfo) == 0 {
		return errors.New("未查询到订单")
	}

	err = UpdateStock(gdb, erpOrderInfo[0], SoldOut, HavePaid, 0)
	if err != nil {
		gdb.Rollback()
		logger.Error("updateErpStockCommodity UpdateStock err:", logger.Field("err", err))
		return errors.New("审核失败:" + err.Error())
	}

	return nil
}

// CommodityIsHaveStock 查询商品是否有库存
func CommodityIsHaveStock(req ErpOrderCommodity, storeId uint32) bool {
	qs := orm.Eloquent.Table("erp_stock_commodity")
	if req.IMEI != "" { // 串码商品
		qs.Where("imei = ? and state = ?", req.IMEI, InStock)
	} else { // 非串码商品
		qs.Where("erp_commodity_id = ? and store_id = ? and state = ? and imei_type = ?",
			req.ErpCommodityId, storeId, InStock, NoIMEICommodity)
	}

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

	return count > 0
}

// QueryStoreManageData 查询门店经营数据
func QueryStoreManageData(req *ErpOrderStoreManageDataReq, c *gin.Context) (*ErpOrderStoreManageDataResp, error) {
	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

	resp := &ErpOrderStoreManageDataResp{
		PageIndex: req.PageIndex,
		PageSize:  req.PageSize,
	}
	var storeManageDataList []StoreManageData

	// 构建查询条件
	qs := orm.Eloquent.Model(&ErpOrder{})
	if len(req.StoreId) != 0 {
		qs.Where("erp_order.store_id in ?", req.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 showConfig.ShowAll == "OFF" {
		qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
	}

	if req.StartTime != "" && req.EndTime != "" {
		startTime, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Error("startTime parse err")
		}

		endTime, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Error("endTime parse err")
		}

		//startTime, _ := time.Parse("2006-01-02", req.StartTime)
		//endTime, _ := time.Parse("2006-01-02", req.EndTime)
		qs = qs.Where("maker_time BETWEEN ? AND ?", startTime, endTime)
	} else {
		qs = qs.Where("maker_time IS NOT NULL")
	}
	qs.Where("state = ?", ErpOrderStateAudited)

	// 查询汇总数据
	var summary struct {
		TotalSalesAmount  float64
		TotalPromotionFee float64
		TotalSalesProfit  float64
		TotalStaffProfit  float64
		TotalCount        int64
	}
	err = qs.Select("SUM(CASE WHEN retail_type = 'sale' THEN total_amount ELSE -total_amount END) AS total_sales_amount, " +
		"SUM(CASE WHEN retail_type = 'sale' THEN total_discount ELSE -total_discount END) AS total_promotion_fee, " +
		"SUM(CASE WHEN retail_type = 'sale' THEN total_sales_profit ELSE -total_sales_profit END) AS total_sales_profit, " +
		"SUM(CASE WHEN retail_type = 'sale' THEN total_staff_profit ELSE -total_staff_profit END) AS total_staff_profit, " +
		"SUM(CASE WHEN retail_type = 'sale' THEN total_count ELSE -total_count END) AS total_count").
		Find(&summary).Error
	if err != nil {
		logger.Error("QueryStoreManageData summary err:", logger.Field("err", err))
		return nil, err
	}

	// 查询分页数据
	if req.SortType == "asc" {
		err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_discount ELSE -total_discount END) AS promotion_fee, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_amount ELSE -total_amount END) AS total_sales_amount, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_sales_profit ELSE -total_sales_profit END) AS sales_profit, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_staff_profit ELSE -total_staff_profit END) AS staff_profit, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_count ELSE -total_count END) AS count").
			Group("date").
			Order("date ASC").
			Find(&storeManageDataList).Error
	} else {
		err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_discount ELSE -total_discount END) AS promotion_fee, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_amount ELSE -total_amount END) AS total_sales_amount, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_sales_profit ELSE -total_sales_profit END) AS sales_profit, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_staff_profit ELSE -total_staff_profit END) AS staff_profit, " +
			"SUM(CASE WHEN retail_type = 'sale' THEN total_count ELSE -total_count END) AS count").
			Group("date").
			Order("date DESC").
			Find(&storeManageDataList).Error
	}
	if err != nil {
		logger.Error("QueryStoreManageData err:", logger.Field("err", err))
		return nil, err
	}

	finalStoreManageDataList := constructFinalStoreManageDataList(storeManageDataList, req)

	// 汇总数据赋值给响应
	resp.TotalSalesAmount = math.Round(summary.TotalSalesAmount*100) / 100
	resp.TotalPromotionFee = math.Round(summary.TotalPromotionFee*100) / 100
	resp.TotalSalesProfit = math.Round(summary.TotalSalesProfit*100) / 100
	resp.TotalStaffProfit = math.Round(summary.TotalStaffProfit*100) / 100
	resp.TotalCount = summary.TotalCount

	if req.IsExport == 1 { //导出excel
		//storeName := "所有门店"
		//if req.StoreId != 0 {
		//	storeInfo, err := GetStore(req.StoreId)
		//	if err != nil {
		//		logger.Error("GetStore err:", logger.Field("err", err))
		//		return nil, err
		//	}
		//	storeName = storeInfo.Name
		//}

		finalStoreManageDataList = constructFinalStoreManageDataList(storeManageDataList, req)
		filePath, err := storeManageDataExport(finalStoreManageDataList, "门店", summary, c)
		if err != nil {
			logger.Error("StoreManageDataExport err:", logger.Field("err", err))
			return nil, err
		}

		resp.ExportUrl = filePath
	} else {
		// 根据页码和页面条数截取结果
		startIndex := (req.PageIndex - 1) * req.PageSize
		endIndex := startIndex + req.PageSize
		if endIndex > len(finalStoreManageDataList) {
			endIndex = len(finalStoreManageDataList)
		}
		resp.List = finalStoreManageDataList[startIndex:endIndex]

		resp.Total = len(finalStoreManageDataList)
	}

	return resp, nil
}

// 查询门店经营数据，为空的日期默认填充数据为0
func constructFinalStoreManageDataList(storeManageDataList []StoreManageData, req *ErpOrderStoreManageDataReq) []StoreManageData {
	// Create a map to store data by date for easier processing
	storeDataMap := make(map[string]StoreManageData)
	for _, data := range storeManageDataList {
		data.TotalSalesAmount = math.Round(data.TotalSalesAmount*100) / 100
		data.PromotionFee = math.Round(data.PromotionFee*100) / 100
		data.SalesProfit = math.Round(data.SalesProfit*100) / 100
		data.StaffProfit = math.Round(data.StaffProfit*100) / 100
		storeDataMap[data.Date] = data
	}

	// Construct the final response with consecutive dates and defaulting to 0 for missing data
	var finalStoreManageDataList []StoreManageData
	startDate, err := time.Parse(QueryTimeFormat, req.StartTime)
	if err != nil {
		logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err))
		return storeManageDataList
	}
	endDate, err := time.Parse(QueryTimeFormat, req.EndTime)
	if err != nil {
		logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err))
		return storeManageDataList
	}

	for d := endDate; d.After(startDate) || d.Equal(startDate); d = d.AddDate(0, 0, -1) {
		dateStr := d.Format("2006-01-02")
		data, found := storeDataMap[dateStr]
		if !found {
			data = StoreManageData{
				Date:             dateStr,
				TotalSalesAmount: 0,
				PromotionFee:     0,
				SalesProfit:      0,
				StaffProfit:      0,
				Count:            0,
			}
		}
		finalStoreManageDataList = append(finalStoreManageDataList, data)
	}

	sortType := strings.ToLower(req.SortType)
	switch sortType {
	case "asc":
		sort.Slice(finalStoreManageDataList, func(i, j int) bool {
			return finalStoreManageDataList[i].Date < finalStoreManageDataList[j].Date
		})
	case "desc":
		sort.Slice(finalStoreManageDataList, func(i, j int) bool {
			return finalStoreManageDataList[i].Date > finalStoreManageDataList[j].Date
		})
	}

	return finalStoreManageDataList
}

// StoreManageDataExport 导出门店经营数据
func storeManageDataExport(list []StoreManageData, storeName string, summary struct {
	TotalSalesAmount  float64
	TotalPromotionFee float64
	TotalSalesProfit  float64
	TotalStaffProfit  float64
	TotalCount        int64
}, c *gin.Context) (string, error) {
	file := excelize.NewFile()
	fSheet := "Sheet1"

	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + storeName + "经营数据" + ".xlsx"
	fmt.Println("url fileName:", url+fileName)

	// 判断是否有入销售毛利、员工毛利的权限
	flag1, _ := checkRoleMenu(c, SalesProfitMenu)
	flag2, _ := checkRoleMenu(c, StaffProfitMenu)
	fmt.Println("flag1 is:", flag1)
	fmt.Println("flag2 is:", flag2)
	logger.Info("flag1 is:", logger.Field("flag1", flag1))
	logger.Info("flag2 is:", logger.Field("flag2", flag2))

	nEndCount := 0
	title := []interface{}{"时间", "销售额", "推广费"}
	if flag1 { // 销售毛利
		title = append(title, "销售毛利")
		nEndCount += 1
	}
	if flag2 { // 员工毛利
		title = append(title, "员工毛利")
		nEndCount += 1
	}
	title = append(title, "销售数量")

	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 rowId := 0; rowId < len(list); rowId++ {
		row = []interface{}{
			list[rowId].Date,
			list[rowId].TotalSalesAmount,
			list[rowId].PromotionFee,
		}

		// 控制是否导出
		if flag1 { // 销售毛利
			row = append(row, list[rowId].SalesProfit)
		}
		if flag2 { // 员工毛利
			row = append(row, list[rowId].StaffProfit)
		}
		row = append(row, list[rowId].Count)

		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(len(list)), 10)
	end := []interface{}{totalData, summary.TotalSalesAmount, summary.TotalPromotionFee}

	if flag1 { // 销售毛利
		end = append(end, summary.TotalSalesProfit)
	}
	if flag2 { // 员工毛利
		end = append(end, summary.TotalStaffProfit)
	}
	end = append(end, summary.TotalCount)

	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", 18)

	var endRow string
	switch nEndCount {
	case 1:
		endRow = fmt.Sprintf("E"+"%d", nExcelStartRow+2)
	case 2:
		endRow = fmt.Sprintf("F"+"%d", nExcelStartRow+2)
	default:
		endRow = fmt.Sprintf("D"+"%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
}

// retailMarginDataExport 导出商品零售毛利汇总数据
func retailMarginDataExport(req *ErpOrderRetailMarginResp, 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)

	nEndCount := 0
	title := []interface{}{"店铺名称", "零售类型", "商品名称", "商品分类", "数量", "销售/退货金额"}
	// 判断是否有权限
	flag1, _ := checkRoleMenu(c, SalesCostMenu)
	flag2, _ := checkRoleMenu(c, EmployeeCostMenu)
	flag3, _ := checkRoleMenu(c, SalesMarginMenu)
	flag4, _ := checkRoleMenu(c, EmployeeMarginMenu)
	flag5, _ := checkRoleMenu(c, GrossMarginsMenu)
	flag6, _ := checkRoleMenu(c, EmployeeGrossMarginsMenu)
	if flag1 {
		title = append(title, "销售成本")
		nEndCount += 1
	}
	if flag2 {
		title = append(title, "员工成本")
		nEndCount += 1
	}
	if flag3 {
		title = append(title, "销售毛利")
		nEndCount += 1
	}
	if flag4 {
		title = append(title, "员工毛利")
		nEndCount += 1
	}
	if flag5 {
		title = append(title, "销售毛利率")
		nEndCount += 1
	}
	if flag6 {
		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
	for rowId := 0; rowId < len(req.List); rowId++ {
		var saleType string
		if req.List[rowId].RetailType == RetailTypeSale {
			saleType = "零售销售"
		} else if req.List[rowId].RetailType == RetailTypeRejected {
			saleType = "零售退货"
		} else {
			logger.Error("订单类型异常")
			return "", errors.New("RetailMarginDataExport, 订单类型异常:" + req.List[rowId].RetailType)
		}
		row = []interface{}{
			req.List[rowId].StoreName,
			saleType,
			req.List[rowId].ErpCommodityName,
			req.List[rowId].ErpCategoryName,
			req.List[rowId].Count,
			req.List[rowId].SalesAmount,
		}

		if flag1 { // 销售成本
			row = append(row, req.List[rowId].SalesCost)
		}
		if flag2 { // 员工成本
			row = append(row, req.List[rowId].EmployeeCost)
		}
		if flag3 { // 销售毛利
			row = append(row, req.List[rowId].SalesMargin)
		}
		if flag4 { // 员工毛利
			row = append(row, req.List[rowId].EmployeeMargin)
		}
		if flag5 { // 销售毛利率
			row = append(row, req.List[rowId].GrossMargins)
		}
		if flag6 { // 员工毛利率
			row = append(row, req.List[rowId].EmployeeGrossMargins)
		}

		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.TotalCount), 10)
	end := []interface{}{totalData, "", "", "", req.TotalCount, fmt.Sprintf("%.2f", req.TotalSalesAmount)}

	if flag1 { // 销售成本
		end = append(end, req.TotalSalesCost)
	}
	if flag2 { // 员工成本
		end = append(end, req.TotalEmployeeCost)
	}
	if flag3 { // 销售毛利
		end = append(end, req.TotalSalesMargin)
	}
	if flag4 { // 员工毛利
		end = append(end, req.TotalEmployeeMargin)
	}
	if flag5 { // 销售毛利率
		end = append(end, req.TotalGrossMargins)
	}
	if flag6 { // 员工毛利率
		end = append(end, req.TotalEmployeeGrossMargins)
	}

	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, 30)
	// 设置单元格大小
	file.SetColWidth("Sheet1", "A", "A", 26)
	file.SetColWidth("Sheet1", "C", "C", 45)
	file.SetColWidth("Sheet1", "F", "F", 15)

	var endRow string
	switch nEndCount {
	case 1:
		endRow = fmt.Sprintf("G"+"%d", nExcelStartRow+2)
	case 2:
		endRow = fmt.Sprintf("H"+"%d", nExcelStartRow+2)
	case 3:
		endRow = fmt.Sprintf("I"+"%d", nExcelStartRow+2)
	case 4:
		endRow = fmt.Sprintf("J"+"%d", nExcelStartRow+2)
	case 5:
		endRow = fmt.Sprintf("K"+"%d", nExcelStartRow+2)
	case 6:
		endRow = fmt.Sprintf("L"+"%d", nExcelStartRow+2)
	default:
		endRow = fmt.Sprintf("F"+"%d", nExcelStartRow+2)
	}
	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)

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

	return url + fileName, nil
}

// QueryRetailMargin 查询零售毛利汇总数据
func QueryRetailMargin(req *ErpOrderRetailMarginReq, c *gin.Context) (*ErpOrderRetailMarginResp, 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 &ErpOrderRetailMarginResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}
	resp := &ErpOrderRetailMarginResp{
		PageIndex: req.PageIndex,
		PageSize:  req.PageSize,
	}
	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

	qs := orm.Eloquent.Debug().Table("erp_order_commodity").
		Select("erp_order_commodity.*, erp_order.store_id, store.name as store_name, erp_order.retail_type," +
			"erp_commodity.name as erp_commodity_name").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
		Joins("LEFT JOIN erp_commodity ON erp_order_commodity.erp_commodity_id = erp_commodity.id").
		Joins("LEFT JOIN store ON erp_order.store_id = store.id")

	if len(req.StoreId) != 0 {
		qs.Where("erp_order.store_id in ?", req.StoreId)
	}
	if len(req.RetailType) != 0 {
		qs.Where("erp_order.retail_type in ?", req.RetailType)
	}
	if len(req.ErpCommodityName) != 0 {
		qs.Where("erp_order_commodity.erp_commodity_name in ?", req.ErpCommodityName)
	}
	if len(req.ErpCategoryId) != 0 {
		categoryList, err := TransformErpCategoryIds(req.ErpCategoryId)
		if err != nil {
			return nil, err
		}
		qs.Where("erp_order_commodity.erp_category_id in ?", categoryList)
	}
	if req.StartTime != "" {
		startTime, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err == nil {
			qs = qs.Where("erp_order.audit_time>?", startTime)
		} else {
			logger.Errorf("QueryRetailMargin time start parse err:", err.Error())
		}
	}
	if req.EndTime != "" {
		endTime, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err == nil {
			qs = qs.Where("erp_order.audit_time<?", endTime)
		} else {
			logger.Errorf("QueryRetailMargin time end parse err:", err.Error())
		}
	}
	if showConfig.ShowAll == "OFF" {
		qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
	}
	if tools.GetRoleName(c) == "shopper" {
		qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, tools.GetUserId(c)))
	}

	var result []struct {
		ErpOrderCommodity
		StoreID    uint32
		StoreName  string
		RetailType string
	}
	qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	// 添加排序规则
	//qs = qs.Order("erp_order_commodity.erp_commodity_id ASC, erp_order.store_id ASC, erp_order.retail_type ASC")
	qs = qs.Order(`
	erp_order_commodity.erp_commodity_id ASC,
	erp_order.store_id ASC,
	CASE erp_order.retail_type
		WHEN 'sale' THEN 0
		WHEN 'rejected' THEN 1
		ELSE 2
	END ASC`)

	if req.IsExport == 1 { //导出excel
		err := qs.Find(&result).Error
		if err != nil {
			logger.Errorf("QueryRetailMargin find err:", err.Error())
			return nil, err
		}
	} else {
		err := qs.Find(&result).Offset(page * req.PageSize).Limit(req.PageSize).Error
		if err != nil {
			logger.Errorf("QueryRetailMargin find err:", err.Error())
			return nil, err
		}
	}

	//var data RetailMarginData
	var list []RetailMarginData
	//for _, item := range result {
	//	data.StoreId = item.StoreID
	//	data.StoreName = item.StoreName
	//	data.RetailType = item.RetailType
	//	data.ErpCommodityId = item.ErpCommodityId
	//	data.ErpCommodityName = item.ErpCommodityName
	//	data.ErpCategoryId = item.ErpCategoryId
	//	data.ErpCategoryName = item.ErpCategoryName
	//	data.Total = item.Total
	//	data.SalesAmount = item.ReceivedAmount
	//	data.SalesCost = float64(item.WholesalePrice * item.Total)
	//	data.SalesMargin = data.SalesAmount - data.SalesCost
	//	data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount)
	//	if data.RetailType == RetailTypeRejected {
	//		data.SalesAmount = -data.SalesAmount
	//		data.SalesCost = -data.SalesCost
	//		data.SalesMargin = -data.SalesMargin
	//	}
	//	list = append(list, data)
	//
	//	resp.TotalCount += data.Total
	//	resp.TotalSalesAmount += data.SalesAmount
	//	resp.TotalSalesCost += data.SalesCost
	//	resp.TotalSalesMargin += data.SalesMargin
	//}
	//
	//if resp.TotalSalesAmount != 0 {
	//	resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount)
	//}

	// 创建一个 map 用来存储已经处理过的数据，key 是 StoreId 和 ErpCommodityId 的组合
	processedData := make(map[string]*RetailMarginData)

	// 遍历 result 中的每一条数据
	for _, item := range result {
		// 生成一个唯一的键，可以使用 StoreId 和 ErpCommodityId 的组合
		key := fmt.Sprintf("%d_%d_%s", item.StoreID, item.ErpCommodityId, item.RetailType)

		var nCount int32
		var salesAmount, salesCost, employeeCost, salesMargin, employeeMargin float64
		if item.RetailType == RetailTypeRejected {
			nCount = -int32(item.Count)
			salesAmount = -item.RejectedAmount // 退货订单要以实际退货金额为准
			salesCost = -item.WholesalePrice * float64(item.Count)
			employeeCost = -(item.WholesalePrice + item.StaffCostPrice) * float64(item.Count)
			salesMargin = -(item.ReceivedAmount - item.WholesalePrice*float64(item.Count))
			employeeMargin = -(item.ReceivedAmount - (item.WholesalePrice+item.StaffCostPrice)*float64(item.Count))
		} else {
			nCount = int32(item.Count)
			salesAmount = item.ReceivedAmount
			salesCost = item.WholesalePrice * float64(item.Count)
			employeeCost = (item.WholesalePrice + item.StaffCostPrice) * float64(item.Count)
			salesMargin = item.ReceivedAmount - item.WholesalePrice*float64(item.Count)
			employeeMargin = item.ReceivedAmount - (item.WholesalePrice+item.StaffCostPrice)*float64(item.Count)
		}
		// 检查是否已经处理过这个组合的数据
		if existingData, ok := processedData[key]; ok {
			// 如果存在，说明已经有数据，进行合并操作
			existingData.Count += nCount
			existingData.SalesAmount += salesAmount
			existingData.SalesCost += salesCost
			existingData.SalesMargin += salesMargin
			existingData.EmployeeCost += employeeCost
			existingData.EmployeeMargin += employeeMargin

			// 处理数据，四舍五入保留2位小数
			existingData.SalesAmount = math.Round(existingData.SalesAmount*100) / 100
			existingData.SalesCost = math.Round(existingData.SalesCost*100) / 100
			existingData.SalesMargin = math.Round(existingData.SalesMargin*100) / 100
			existingData.EmployeeCost = math.Round(existingData.EmployeeCost*100) / 100
			existingData.EmployeeMargin = math.Round(existingData.EmployeeMargin*100) / 100

			if existingData.SalesAmount == 0 {
				existingData.GrossMargins = "--"
				existingData.EmployeeGrossMargins = "--"
			} else {
				existingData.GrossMargins = float64ToPercentage(existingData.SalesMargin / existingData.SalesAmount)
				existingData.EmployeeGrossMargins = float64ToPercentage(existingData.EmployeeMargin / existingData.SalesAmount)
			}
		} else {
			// 如果不存在，说明是新数据，直接添加到列表中
			data := &RetailMarginData{
				StoreId:              item.StoreID,
				StoreName:            item.StoreName,
				RetailType:           item.RetailType,
				ErpCommodityId:       item.ErpCommodityId,
				ErpCommodityName:     item.ErpCommodityName,
				ErpCategoryId:        item.ErpCategoryId,
				ErpCategoryName:      item.ErpCategoryName,
				Count:                nCount,
				SalesAmount:          item.ReceivedAmount,
				SalesCost:            item.WholesalePrice * float64(item.Count),
				EmployeeCost:         (item.WholesalePrice + item.StaffCostPrice) * float64(item.Count),
				SalesMargin:          item.ReceivedAmount - item.WholesalePrice*float64(item.Count),
				GrossMargins:         "--",
				EmployeeMargin:       item.ReceivedAmount - (item.WholesalePrice+item.StaffCostPrice)*float64(item.Count),
				EmployeeGrossMargins: "--",
				//GrossMargins:     float64ToPercentage((item.ReceivedAmount - float64(int32(item.WholesalePrice)*item.Total)) / item.ReceivedAmount),
			}
			if item.ReceivedAmount != 0 {
				data.GrossMargins = float64ToPercentage((item.ReceivedAmount - item.WholesalePrice*float64(item.Count)) / item.ReceivedAmount)
				data.EmployeeGrossMargins = float64ToPercentage((item.ReceivedAmount - (item.WholesalePrice+item.StaffCostPrice)*float64(item.Count)) / item.ReceivedAmount)
			}

			// 如果是零售退货订单，进行相应的处理
			if data.RetailType == RetailTypeRejected {
				data.SalesAmount = -data.SalesAmount
				data.SalesCost = -data.SalesCost
				data.SalesMargin = -data.SalesMargin
				data.EmployeeCost = -data.EmployeeCost
				data.EmployeeMargin = -data.EmployeeMargin
			}

			// 处理数据，四舍五入保留2位小数
			data.SalesAmount = math.Round(data.SalesAmount*100) / 100
			data.SalesCost = math.Round(data.SalesCost*100) / 100
			data.SalesMargin = math.Round(data.SalesMargin*100) / 100
			data.EmployeeCost = math.Round(data.EmployeeCost*100) / 100
			data.EmployeeMargin = math.Round(data.EmployeeMargin*100) / 100

			// 将新数据添加到 map 中
			processedData[key] = data
		}
	}

	// 将处理过的数据添加到 resp.List 中
	for _, data := range processedData {
		list = append(list, *data)
	}

	// 计算总数
	for _, data := range list {
		resp.TotalCount += data.Count
		resp.TotalSalesAmount += data.SalesAmount
		resp.TotalSalesCost += data.SalesCost
		resp.TotalSalesMargin += data.SalesMargin
		resp.TotalEmployeeCost += data.EmployeeCost
		resp.TotalEmployeeMargin += data.EmployeeMargin
	}

	// 处理数据，四舍五入保留2位小数
	resp.TotalSalesAmount = math.Round(resp.TotalSalesAmount*100) / 100
	resp.TotalSalesCost = math.Round(resp.TotalSalesCost*100) / 100
	resp.TotalSalesMargin = math.Round(resp.TotalSalesMargin*100) / 100
	resp.TotalEmployeeCost = math.Round(resp.TotalEmployeeCost*100) / 100
	resp.TotalEmployeeMargin = math.Round(resp.TotalEmployeeMargin*100) / 100
	if resp.TotalSalesAmount != 0 {
		resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount)
		resp.TotalEmployeeGrossMargins = float64ToPercentage(resp.TotalEmployeeMargin / resp.TotalSalesAmount)
	} else {
		resp.TotalGrossMargins = "--"
		resp.TotalEmployeeGrossMargins = "--"
	}

	// 对列表按照您想要的顺序进行排序
	sort.Slice(list, func(i, j int) bool {
		// 按照 StoreId 升序排列
		if list[i].StoreId != list[j].StoreId {
			return list[i].StoreId < list[j].StoreId
		}
		// 按照 ErpCommodityId 升序排列
		if list[i].ErpCommodityId != list[j].ErpCommodityId {
			return list[i].ErpCommodityId < list[j].ErpCommodityId
		}
		// 按照 RetailType 的顺序进行排序
		retailTypeOrder := map[string]int{"sale": 0, "rejected": 1}
		return retailTypeOrder[list[i].RetailType] < retailTypeOrder[list[j].RetailType]
	})

	// 将结果赋值给 resp.List
	resp.List = list

	if req.IsExport == 1 { //导出excel
		filePath, err := retailMarginDataExport(resp, c)
		if err != nil {
			logger.Error("StoreManageDataExport err:", logger.Field("err", err))
			return nil, err
		}
		resp.ExportUrl = filePath
		resp.List = nil
	} else {
		// 计算分页所需的切片索引
		startIndex := page * req.PageSize
		endIndex := (page + 1) * req.PageSize
		if endIndex > len(list) {
			endIndex = len(list)
		}
		resp.List = list[startIndex:endIndex]
		resp.Total = len(list)
		resp.PageIndex = req.PageIndex
		resp.PageSize = req.PageSize
	}

	return resp, nil
}

// 将float64转换为百分比
func float64ToPercentage(value float64) string {
	// 将浮点数乘以100，然后格式化为字符串
	percentage := fmt.Sprintf("%.2f%%", value*100)
	return percentage
}

// QueryRetailDetail 查询零售明细
func QueryRetailDetail(req *ErpOrderRetailDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
	resp := &ErpOrderRetailDetailResp{}

	// 通过银行流水号查询
	if req.BankTrxNo != "" {
		var orderPayWay ErpOrderRecord
		err := orm.Eloquent.Table("erp_order_record").Where("bank_trx_no = ? and status = ?",
			req.BankTrxNo, PayOk).Find(&orderPayWay).Error
		if err != nil {
			logger.Error("query erp_order_record err:", logger.Field("err", err))
			return nil, err
		}
		req.BillSn = orderPayWay.BillSn
	}

	var err error
	if (len(req.ErpCategoryId) != 0 || req.ErpCommodityName != "" || req.IMEI != "") && req.BillSn == "" { // 商品分类or商品名称不为空且订单编号为空
		// 联表查询
		resp, err = queryRetailDetailByJoin(req, c)
	} else {
		// 普通单表查询，然后补充收款数据和商品数据
		resp, err = queryRetailDetailCommon(req, c)
	}
	if err != nil {
		logger.Error("queryRetailDetailCommon err")
		return nil, err
	}

	return resp, nil
}

//// 导出零售明细报表excel-合并单元格版本
//func retailDetailExportBack(list []ErpOrder, sumData RetailDetailTotalData) (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{}{"订单编号", "订单类型", "用户ID", "客户手机号", "审核时间", "店铺", "销售员", "商品分类", "商品名称",
//		"供应商", "是否串码", "商品串码", "是否赠送", "销售数量", "指导零售价", "零售价", "零售优惠", "会员优惠", "实际零售价/退货价",
//		"采购单价", "员工成本价", "销售毛利", "员工毛利", "订单总指导零售价", "订单总优惠", "订单实收", "【扫码付", "现金收款", "pos机收款",
//		"商场积分抵扣", "其他付款方式】", "订单总销售毛利", "订单总员工毛利", "销售毛利提成", "员工毛利提成", "销售员提成", "门店提成", "备注"}
//	for i, _ := range title {
//		cell, _ := excelize.CoordinatesToCellName(1+i, 1)
//		err := file.SetCellValue(fSheet, cell, title[i])
//		if err != nil {
//			logger.Error("file set value err:", logger.Field("err", err))
//		}
//	}
//
//	var row []interface{}
//	nAmount := 0.0
//	nExcelStartRow := 0
//	for i := 0; i < len(list); i++ {
//		var saleType string
//		if list[i].RetailType == RetailTypeSale {
//			saleType = "零售销售"
//		} else if list[i].RetailType == RetailTypeRejected {
//			saleType = "零售退货"
//		} else {
//			logger.Error("订单类型异常")
//			return "", errors.New("RetailMarginDataExport, 订单类型异常:" + list[i].RetailType)
//		}
//
//		commodityIdMap := make(map[uint32]bool)
//		// 先判断商品数量，确定要写几行数据
//		for rowId := 0; rowId < len(list[i].Commodities); rowId++ {
//			if list[i].RetailType == RetailTypeSale {
//				nAmount = list[i].Commodities[rowId].Amount
//			} else if list[i].RetailType == RetailTypeRejected {
//				nAmount = list[i].Commodities[rowId].RejectedAmount
//				list[i].CashierList = "" // 目前零售退货订单暂时不展示各个方式的付款金额
//			}
//
//			isIMEIType := "是"
//			if list[i].Commodities[rowId].IMEIType == 1 {
//				isIMEIType = "否"
//			}
//
//			strPresentType := "非赠送"
//			if list[i].Commodities[rowId].PresentType == 2 {
//				strPresentType = "赠送"
//			}
//
//			// 组合销售员名称，提成数据
//			salesMan := ""
//			strSalesProfitPer := ""
//			strStaffProfitPer := ""
//			strSalesmanPer := ""
//			//var salesList []ErpOrderSales
//			//err := json.Unmarshal([]byte(list[i].SalesmanList), &salesList)
//			//if err != nil {
//			//	logger.Error("unmarshal err:", logger.Field("err", err))
//			//}
//			for j, item := range list[i].Salesman {
//				salesMan += item.Name
//				// 将浮点数转换为字符串，保留两位小数
//				strNumber1 := strconv.FormatFloat(item.SalesProfitPer, 'f', 2, 64)
//				strSalesProfitPer += strNumber1
//				strNumber2 := strconv.FormatFloat(item.StaffProfitPer, 'f', 2, 64)
//				strStaffProfitPer += strNumber2
//				strNumber3 := strconv.FormatFloat(item.SalesmanPer, 'f', 2, 64)
//				strSalesmanPer += strNumber3
//
//				if j < len(list[i].Salesman)-1 {
//					salesMan += "\n"
//					strSalesProfitPer += "\n"
//					strStaffProfitPer += "\n"
//					strSalesmanPer += "\n"
//				}
//			}
//
//			// 组合支付相关信息
//			var cashierData TotalCashierData
//			var cashiers []ErpOrderCashier
//			err := json.Unmarshal([]byte(list[i].CashierList), &cashiers)
//			if err != nil {
//				logger.Error("unmarshal err:", logger.Field("err", err))
//			}
//			for _, item := range cashiers {
//				switch item.CashierId {
//				case 1:
//					cashierData.ScanAmount = item.Amount
//				case 2:
//					cashierData.CashAmount = item.Amount
//				case 3:
//					cashierData.PosAmount = item.Amount
//				case 4:
//					cashierData.StoreVmAmount = item.Amount
//				default:
//					cashierData.OtherAmount += item.Amount
//				}
//			}
//
//			// 单个订单的汇总数据只记录一次
//			var temp RetailDetailTotalData
//			if !commodityIdMap[list[i].Commodities[rowId].ErpCommodityId] {
//				commodityIdMap[list[i].Commodities[rowId].ErpCommodityId] = true
//				temp.TotalRetailPrice = list[i].TotalRetailPrice
//				temp.TotalDiscount = list[i].TotalDiscount
//				temp.TotalAmount = list[i].TotalAmount
//				temp.TotalSalesProfit = list[i].TotalSalesProfit
//				temp.TotalStaffProfit = list[i].TotalStaffProfit
//				temp.StorePer = list[i].StorePer
//			}
//
//			row = []interface{}{
//				list[i].BillSn,
//				saleType,
//				list[i].Uid,
//				list[i].Tel,
//				list[i].AuditTime,
//				list[i].StoreName,
//				salesMan, //销售员
//				list[i].Commodities[rowId].ErpCategoryName,
//				list[i].Commodities[rowId].ErpCommodityName,
//				list[i].Commodities[rowId].ErpSupplierName, //供应商
//				isIMEIType,
//				list[i].Commodities[rowId].IMEI,
//				strPresentType,
//				list[i].Commodities[rowId].Count,
//				list[i].Commodities[rowId].RetailPrice,
//				list[i].Commodities[rowId].SalePrice,
//				list[i].Commodities[rowId].SaleDiscount,
//				list[i].Commodities[rowId].MemberDiscount,
//				nAmount,
//				list[i].Commodities[rowId].WholesalePrice,
//				list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
//				list[i].Commodities[rowId].SalesProfit,
//				list[i].Commodities[rowId].StaffProfit,
//				temp.TotalRetailPrice,
//				temp.TotalDiscount,
//				temp.TotalAmount,
//				cashierData.ScanAmount,    // 扫码付
//				cashierData.CashAmount,    // 现金收款
//				cashierData.PosAmount,     // pos机收款
//				cashierData.StoreVmAmount, // 商场积分抵扣
//				cashierData.OtherAmount,   // 其他付款方式
//				temp.TotalSalesProfit,
//				temp.TotalStaffProfit,
//				strSalesProfitPer, // 销售毛利提成
//				strStaffProfitPer, // 员工毛利提成
//				strSalesmanPer,    // 销售员提成
//				temp.StorePer,
//				list[i].Commodities[rowId].Remark,
//			}
//
//			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++
//		}
//
//		//合并单元格
//		nRow := len(list[i].Commodities)
//		if nRow > 1 {
//			for j := 'A'; j <= 'G'; j++ {
//				colName := string(j)
//				str1 := fmt.Sprintf("%s%d", colName, nExcelStartRow-nRow+2)
//				str2 := fmt.Sprintf("%s%d", colName, nExcelStartRow+1)
//				_ = file.MergeCell(fSheet, str1, str2)
//			}
//
//			for j := 'X'; j <= 'Z'; j++ {
//				colName := string(j)
//				str1 := fmt.Sprintf("%s%d", colName, nExcelStartRow-nRow+2)
//				str2 := fmt.Sprintf("%s%d", colName, nExcelStartRow+1)
//				_ = file.MergeCell(fSheet, str1, str2)
//			}
//
//			for j := 'A'; j <= 'L'; j++ {
//				colName := string(j)
//				str1 := fmt.Sprintf("A%s%d", colName, nExcelStartRow-nRow+2)
//				str2 := fmt.Sprintf("A%s%d", colName, nExcelStartRow+1)
//				_ = file.MergeCell(fSheet, str1, str2)
//			}
//		}
//	}
//
//	totalData := "订单数:" + strconv.FormatInt(int64(sumData.Count), 10)
//	end := []interface{}{totalData, "", "", "", "", "", "", "", "", "", "", "", "",
//		sumData.Count,
//		sumData.RetailPrice,
//		sumData.SalePrice,
//		sumData.SaleDiscount,
//		sumData.MemberDiscount,
//		sumData.Amount,
//		sumData.WholesalePrice,
//		sumData.StaffPrice,
//		sumData.SalesProfit,
//		sumData.StaffProfit,
//		sumData.TotalRetailPrice,
//		sumData.TotalDiscount,
//		sumData.TotalAmount,
//		sumData.ScanAmount,    // 扫码付
//		sumData.CashAmount,    // 现金收款
//		sumData.PosAmount,     // pos机收款
//		sumData.StoreVmAmount, // 商场积分抵扣
//		sumData.OtherAmount,   // 其他付款方式
//		sumData.TotalSalesProfit,
//		sumData.TotalStaffProfit,
//		sumData.TotalSalesProfitPer, // 销售毛利提成
//		sumData.TotalStaffProfitPer, // 员工毛利提成
//		sumData.SalesmanPer,         // 销售员提成
//		sumData.StorePer,
//		""}
//
//	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}]}`)
//
//	// 设置单元格的样式: 居中、加边框、自动换行
//	style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
//	"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("AL%d", nExcelStartRow+2)
//	// 应用样式到整个表格
//	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
//
//	//需要自动换行的列
//	endRow1 := fmt.Sprintf("G%d", nExcelStartRow+2)
//	endRow2 := fmt.Sprintf("AH%d", nExcelStartRow+2)
//	endRow3 := fmt.Sprintf("AI%d", nExcelStartRow+2)
//	endRow4 := fmt.Sprintf("AJ%d", nExcelStartRow+2)
//	_ = file.SetCellStyle("Sheet1", "A1", "AL1", style1)
//	_ = file.SetCellStyle("Sheet1", "G2", endRow1, style1)
//	_ = file.SetCellStyle("Sheet1", "AH2", endRow2, style1)
//	_ = file.SetCellStyle("Sheet1", "AI2", endRow3, style1)
//	_ = file.SetCellStyle("Sheet1", "AJ2", endRow4, style1)
//
//	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 retailDetailExport(list []ErpOrder, sumData RetailDetailTotalData, 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)

	// 查询所有支付方式
	var sysCashierList []ErpCashier
	err := orm.Eloquent.Table("erp_cashier").Order("id ASC").Find(&sysCashierList).Error
	if err != nil {
		return "", err
	}

	// 判断是否有权限
	flag1, _ := checkRoleMenu(c, DetailWholesalePriceMenu)
	flag2, _ := checkRoleMenu(c, DetailEmployeeCostMenu)
	flag3, _ := checkRoleMenu(c, DetailSalesProfitMenu)
	flag4, _ := checkRoleMenu(c, DetailStaffProfitMenu)
	flag5, _ := checkRoleMenu(c, DetailTotalSalesProfitMenu)
	flag6, _ := checkRoleMenu(c, DetailTotalStaffProfitMenu)
	flag7, _ := checkRoleMenu(c, DetailSalesProfitPerMenu)
	flag8, _ := checkRoleMenu(c, DetailStaffProfitPerMenu)
	flag9, _ := checkRoleMenu(c, DetailSalesmanPerMenu)
	flag10, _ := checkRoleMenu(c, DetailStorePerMenu)

	nEndCount := 0
	title := []interface{}{"订单编号", "订单类型", "用户ID", "客户手机号", "日期", "审核时间", "店铺", "银联流水号", "销售员1", "销售员2", "一级分类", "二级分类", "三级分类", "商品名称",
		"供应商", "是否串码", "商品串码", "是否赠送", "销售数量", "指导零售价", "零售价", "零售优惠", "会员优惠", "实际零售价/退货价"}

	if flag1 { // 采购单价
		title = append(title, "采购价")
		nEndCount += 1
	}
	if flag2 { // 员工成本价
		title = append(title, "员工成本价")
		nEndCount += 1
	}
	if flag3 { // 销售毛利
		title = append(title, "销售毛利")
		nEndCount += 1
	}
	if flag4 { // 员工毛利
		title = append(title, "员工毛利")
		nEndCount += 1
	}

	title = append(title, "订单总指导零售价", "订单总优惠", "订单实收")

	for i, value := range sysCashierList {
		if value.ID == 1 {
			title = append(title, "【扫码付")
		} else if i+1 == len(sysCashierList) {
			title = append(title, value.Name+"】")
		} else {
			title = append(title, value.Name)
		}
		nEndCount += 1
	}

	if flag5 { // 订单总销售毛利
		title = append(title, "订单总销售毛利")
		nEndCount += 1
	}
	if flag6 { // 订单总员工毛利
		title = append(title, "订单总员工毛利")
		nEndCount += 1
	}
	if flag7 { // 销售毛利提成
		title = append(title, "销售毛利提成")
		nEndCount += 1
	}
	if flag8 { // 员工毛利提成
		title = append(title, "员工毛利提成")
		nEndCount += 1
	}
	if flag9 { // 销售员提成
		title = append(title, "销售员提成")
		nEndCount += 1
	}
	if flag10 { // 门店提成
		title = append(title, "门店提成")
		nEndCount += 1
	}

	title = append(title, "备注")

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

	categoryMap, err := GetAllCategories()
	if err != nil {
		// 处理错误
		logger.Error("GetAllCategories err:", logger.Field("err", err))
	}

	var row []interface{}
	nAmount := 0.0
	nExcelStartRow := 0
	for i := 0; i < len(list); i++ {
		var saleType string
		if list[i].RetailType == RetailTypeSale {
			saleType = "零售销售"
		} else if list[i].RetailType == RetailTypeRejected {
			saleType = "零售退货"
		} else {
			logger.Error("订单类型异常")
			return "", errors.New("RetailMarginDataExport, 订单类型异常:" + list[i].RetailType)
		}

		orderFlag := false
		salesMan1 := ""
		salesMan2 := ""
		// 先判断商品数量，确定要写几行数据
		for rowId := 0; rowId < len(list[i].Commodities); rowId++ {
			if list[i].RetailType == RetailTypeSale {
				nAmount = list[i].Commodities[rowId].Amount
			} else if list[i].RetailType == RetailTypeRejected {
				nAmount = list[i].Commodities[rowId].RejectedAmount
				//list[i].CashierList = "" // 目前零售退货订单暂时不展示各个方式的付款金额
			}

			// 用户id
			var userId string
			if list[i].Uid != 0 {
				userId = strconv.Itoa(list[i].Uid)
			} else {
				userId = ""
			}

			// 审核时间
			var auditTime, auditDate string
			if list[i].AuditTime != nil {
				auditTime = list[i].AuditTime.Format(ExcelTimeFormat)
				auditDate = list[i].AuditTime.Format(DateTimeFormat) // Extract date only
			} else {
				auditTime = ""
				auditDate = ""
			}

			// 商品分类
			categoryID := list[i].Commodities[rowId].ErpCategoryId
			categoryLevels := GetCategoryLevelsFromMap(categoryID, categoryMap)

			isIMEIType := "是"
			if list[i].Commodities[rowId].IMEIType == 1 {
				isIMEIType = "否"
			}

			strPresentType := "非赠送"
			if list[i].Commodities[rowId].PresentType == 2 {
				strPresentType = "赠送"
			}

			// 组合支付相关信息
			var cashiers []ErpOrderCashier
			err := json.Unmarshal([]byte(list[i].CashierList), &cashiers)
			if err != nil {
				logger.Error("unmarshal err:", logger.Field("err", err))
			}

			var cashierDataList []ErpOrderCashier
			for _, value := range sysCashierList {
				var orderCashier ErpOrderCashier
				orderCashier.CashierId = value.ID
				orderCashier.Name = value.Name
				for _, item := range cashiers {
					if value.ID == item.CashierId {
						if list[i].RetailType == RetailTypeRejected {
							orderCashier.Amount = -item.Amount
						} else {
							orderCashier.Amount = item.Amount
						}
					} else {
						continue
					}
				}
				cashierDataList = append(cashierDataList, orderCashier)
			}
			//for _, item := range cashiers {
			//	switch item.CashierId {
			//	case 1:
			//		cashierData.ScanAmount = item.Amount
			//	case 2:
			//		cashierData.CashAmount = item.Amount
			//	case 3:
			//		cashierData.PosAmount = item.Amount
			//	case 4:
			//		cashierData.StoreVmAmount = item.Amount
			//	default:
			//		cashierData.OtherAmount += item.Amount
			//	}
			//}

			// 单个订单的汇总数据只记录一次
			if !orderFlag {
				orderFlag = true
				nSalesProfitPer := 0.0
				nStaffProfitPer := 0.0
				nSalesmanPer := 0.0
				if len(list[i].Salesman) > 0 {
					salesMan1 = list[i].Salesman[0].Name
					if len(list[i].Salesman) == 2 {
						salesMan2 = list[i].Salesman[1].Name
					}
					nSalesProfitPer = math.Round(list[i].Salesman[0].SalesProfitPer*100) / 100
					nStaffProfitPer = math.Round(list[i].Salesman[0].StaffProfitPer*100) / 100
					nSalesmanPer = math.Round(list[i].Salesman[0].SalesmanPer*100) / 100
				}
				row = []interface{}{
					list[i].BillSn,
					saleType,
					userId,
					list[i].Tel,
					auditDate,
					auditTime,
					list[i].StoreName,
					list[i].BankTrxNo,
					salesMan1,                  //销售员1
					salesMan2,                  //销售员2
					categoryLevels.Level1.Name, // 一级分类
					categoryLevels.Level2.Name, // 二级分类
					categoryLevels.Level3.Name, // 三级分类
					list[i].Commodities[rowId].ErpCommodityName,
					list[i].Commodities[rowId].ErpSupplierName, //供应商
					isIMEIType,
					list[i].Commodities[rowId].IMEI,
					strPresentType,
					list[i].Commodities[rowId].Count,
					list[i].Commodities[rowId].RetailPrice,
					list[i].Commodities[rowId].SalePrice,
					list[i].Commodities[rowId].SaleDiscount,
					list[i].Commodities[rowId].MemberDiscount,
					nAmount,
					//list[i].Commodities[rowId].WholesalePrice,
					//list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
					//list[i].Commodities[rowId].SalesProfit,
					//list[i].Commodities[rowId].StaffProfit,

					//list[i].TotalRetailPrice,
					//list[i].TotalDiscount,
					//list[i].TotalAmount,
					//cashierData.ScanAmount,    // 扫码付
					//cashierData.CashAmount,    // 现金收款
					//cashierData.PosAmount,     // pos机收款
					//cashierData.StoreVmAmount, // 商场积分抵扣
					//cashierData.OtherAmount,   // 其他付款方式

					//list[i].TotalSalesProfit,
					//list[i].TotalStaffProfit,
					//nSalesProfitPer, // 销售毛利提成
					//nStaffProfitPer, // 员工毛利提成
					//nSalesmanPer,    // 销售员提成
					//list[i].StorePer,

					//list[i].Commodities[rowId].Remark,
				}

				// 控制是否导出
				if flag1 { // 采购单价
					row = append(row, list[i].Commodities[rowId].WholesalePrice)
				}
				if flag2 { // 员工成本价
					row = append(row, list[i].Commodities[rowId].WholesalePrice+list[i].Commodities[rowId].StaffCostPrice)
				}
				if flag3 { // 销售毛利
					row = append(row, list[i].Commodities[rowId].SalesProfit)
				}
				if flag4 { // 员工毛利
					row = append(row, list[i].Commodities[rowId].StaffProfit)
				}

				row = append(row, list[i].TotalRetailPrice)
				row = append(row, list[i].TotalDiscount)
				row = append(row, list[i].TotalAmount)
				//row = append(row, cashierData.ScanAmount)
				//row = append(row, cashierData.CashAmount)
				//row = append(row, cashierData.PosAmount)
				//row = append(row, cashierData.StoreVmAmount)
				//row = append(row, cashierData.OtherAmount)

				for _, value := range cashierDataList {
					row = append(row, value.Amount)
				}

				if flag5 { // 订单总销售毛利
					row = append(row, list[i].TotalSalesProfit)
				}
				if flag6 { // 订单总员工毛利
					row = append(row, list[i].TotalStaffProfit)
				}
				if flag7 { // 销售毛利提成
					row = append(row, nSalesProfitPer)
				}
				if flag8 { // 员工毛利提成
					row = append(row, nStaffProfitPer)
				}
				if flag9 { // 销售员提成
					row = append(row, nSalesmanPer)
				}
				if flag10 { // 门店提成
					row = append(row, list[i].StorePer)
				}

				row = append(row, list[i].Commodities[rowId].Remark)
			} else {
				if len(list[i].Salesman) == 2 && rowId == 1 {
					row = []interface{}{
						list[i].BillSn,
						saleType,
						userId,
						list[i].Tel,
						auditDate,
						auditTime,
						list[i].StoreName,
						list[i].BankTrxNo,
						salesMan1,                  //销售员1
						salesMan2,                  //销售员2
						categoryLevels.Level1.Name, // 一级分类
						categoryLevels.Level2.Name, // 二级分类
						categoryLevels.Level3.Name, // 三级分类
						list[i].Commodities[rowId].ErpCommodityName,
						list[i].Commodities[rowId].ErpSupplierName, //供应商
						isIMEIType,
						list[i].Commodities[rowId].IMEI,
						strPresentType,
						list[i].Commodities[rowId].Count,
						list[i].Commodities[rowId].RetailPrice,
						list[i].Commodities[rowId].SalePrice,
						list[i].Commodities[rowId].SaleDiscount,
						list[i].Commodities[rowId].MemberDiscount,
						nAmount,

						//list[i].Commodities[rowId].WholesalePrice,
						//list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
						//list[i].Commodities[rowId].SalesProfit,
						//list[i].Commodities[rowId].StaffProfit,

						//"",
						//"",
						//"",
						//"",
						//"",
						//"",
						//"",
						//"",

						//"",
						//"",
						//math.Round(list[i].Salesman[1].SalesProfitPer*100) / 100, // 销售毛利提成
						//math.Round(list[i].Salesman[1].StaffProfitPer*100) / 100, // 员工毛利提成
						//math.Round(list[i].Salesman[1].SalesmanPer*100) / 100,    // 销售员提成
						//"",

						//"",
					}
					// 控制是否导出
					if flag1 { // 采购单价
						row = append(row, list[i].Commodities[rowId].WholesalePrice)
					}
					if flag2 { // 员工成本价
						row = append(row, list[i].Commodities[rowId].WholesalePrice+list[i].Commodities[rowId].StaffCostPrice)
					}
					if flag3 { // 销售毛利
						row = append(row, list[i].Commodities[rowId].SalesProfit)
					}
					if flag4 { // 员工毛利
						row = append(row, list[i].Commodities[rowId].StaffProfit)
					}

					row = append(row, "")
					row = append(row, "")
					row = append(row, "")

					for _, value := range sysCashierList {
						fmt.Println("cashier name:", value.Name)
						row = append(row, "")
					}
					//row = append(row, "")
					//row = append(row, "")
					//row = append(row, "")
					//row = append(row, "")
					//row = append(row, "")

					if flag5 { // 订单总销售毛利
						row = append(row, "")
					}
					if flag6 { // 订单总员工毛利
						row = append(row, "")
					}
					if flag7 { // 销售毛利提成
						row = append(row, math.Round(list[i].Salesman[1].SalesProfitPer*100)/100)
					}
					if flag8 { // 员工毛利提成
						row = append(row, math.Round(list[i].Salesman[1].StaffProfitPer*100)/100)
					}
					if flag9 { // 销售员提成
						row = append(row, math.Round(list[i].Salesman[1].SalesmanPer*100)/100)
					}
					if flag10 { // 门店提成
						row = append(row, "")
					}

					row = append(row, "")
				} else {
					row = []interface{}{
						list[i].BillSn,
						saleType,
						userId,
						list[i].Tel,
						auditDate,
						auditTime,
						list[i].StoreName,
						list[i].BankTrxNo,
						salesMan1,                  //销售员1
						salesMan2,                  //销售员2
						categoryLevels.Level1.Name, // 一级分类
						categoryLevels.Level2.Name, // 二级分类
						categoryLevels.Level3.Name, // 三级分类
						list[i].Commodities[rowId].ErpCommodityName,
						list[i].Commodities[rowId].ErpSupplierName, //供应商
						isIMEIType,
						list[i].Commodities[rowId].IMEI,
						strPresentType,
						list[i].Commodities[rowId].Count,
						list[i].Commodities[rowId].RetailPrice,
						list[i].Commodities[rowId].SalePrice,
						list[i].Commodities[rowId].SaleDiscount,
						list[i].Commodities[rowId].MemberDiscount,
						nAmount,

						//list[i].Commodities[rowId].WholesalePrice,
						//list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
						//list[i].Commodities[rowId].SalesProfit,
						//list[i].Commodities[rowId].StaffProfit,

						//"",
						//"",
						//"",
						//"",
						//"",
						//"",
						//"",
						//"",

						//"",
						//"",
						//"", // 销售毛利提成
						//"", // 员工毛利提成
						//"", // 销售员提成
						//"",

						//"",
					}
					// 控制是否导出
					if flag1 { // 采购单价
						row = append(row, list[i].Commodities[rowId].WholesalePrice)
					}
					if flag2 { // 员工成本价
						row = append(row, list[i].Commodities[rowId].WholesalePrice+list[i].Commodities[rowId].StaffCostPrice)
					}
					if flag3 { // 销售毛利
						row = append(row, list[i].Commodities[rowId].SalesProfit)
					}
					if flag4 { // 员工毛利
						row = append(row, list[i].Commodities[rowId].StaffProfit)
					}

					row = append(row, "")
					row = append(row, "")
					row = append(row, "")

					for _, value := range sysCashierList {
						fmt.Println("cashier name:", value.Name)
						row = append(row, "")
					}
					//row = append(row, "")
					//row = append(row, "")
					//row = append(row, "")
					//row = append(row, "")
					//row = append(row, "")

					if flag5 { // 订单总销售毛利
						row = append(row, "")
					}
					if flag6 { // 订单总员工毛利
						row = append(row, "")
					}
					if flag7 { // 销售毛利提成
						row = append(row, "")
					}
					if flag8 { // 员工毛利提成
						row = append(row, "")
					}
					if flag9 { // 销售员提成
						row = append(row, "")
					}
					if flag10 { // 门店提成
						row = append(row, "")
					}

					row = append(row, list[i].Commodities[rowId].Remark)
				}
			}

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

			//if len(list[i].Commodities) == 1 && len(list[i].Salesman) == 2 {
			//	row = []interface{}{
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		list[i].Salesman[1].Name, //销售员
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//		"",
			//
			//		//"",
			//		//"",
			//		//"",
			//		//"",
			//
			//		//"",
			//		//"",
			//		//"",
			//		//"",
			//		//"",
			//		//"",
			//		//"",
			//		//"",
			//
			//		//"",
			//		//"",
			//		//math.Round(list[i].Salesman[1].SalesProfitPer*100) / 100, // 销售毛利提成
			//		//math.Round(list[i].Salesman[1].StaffProfitPer*100) / 100, // 员工毛利提成
			//		//math.Round(list[i].Salesman[1].SalesmanPer*100) / 100,    // 销售员提成
			//		//"",
			//
			//		//"",
			//	}
			//	// 控制是否导出
			//	if flag1 { // 采购单价
			//		row = append(row, "")
			//	}
			//	if flag2 { // 员工成本价
			//		row = append(row, "")
			//	}
			//	if flag3 { // 销售毛利
			//		row = append(row, "")
			//	}
			//	if flag4 { // 员工毛利
			//		row = append(row, "")
			//	}
			//
			//	row = append(row, "")
			//	row = append(row, "")
			//	row = append(row, "")
			//	row = append(row, "")
			//	row = append(row, "")
			//	row = append(row, "")
			//	row = append(row, "")
			//	row = append(row, "")
			//
			//	if flag5 { // 订单总销售毛利
			//		row = append(row, "")
			//	}
			//	if flag6 { // 订单总员工毛利
			//		row = append(row, "")
			//	}
			//	if flag7 { // 销售毛利提成
			//		row = append(row, math.Round(list[i].Salesman[1].SalesProfitPer*100)/100)
			//	}
			//	if flag8 { // 员工毛利提成
			//		row = append(row, math.Round(list[i].Salesman[1].StaffProfitPer*100)/100)
			//	}
			//	if flag9 { // 销售员提成
			//		row = append(row, math.Round(list[i].Salesman[1].SalesmanPer*100)/100)
			//	}
			//	if flag10 { // 门店提成
			//		row = append(row, "")
			//	}
			//
			//	row = append(row, "")
			//
			//	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(len(list)), 10)
	end := []interface{}{totalData, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
		sumData.Count,
		sumData.RetailPrice,
		sumData.SalePrice,
		sumData.SaleDiscount,
		sumData.MemberDiscount,
		sumData.Amount,

		//sumData.WholesalePrice,
		//sumData.StaffPrice,
		//sumData.SalesProfit,
		//sumData.StaffProfit,

		//sumData.TotalRetailPrice,
		//sumData.TotalDiscount,
		//sumData.TotalAmount,
		//sumData.ScanAmount,    // 扫码付
		//sumData.CashAmount,    // 现金收款
		//sumData.PosAmount,     // pos机收款
		//sumData.StoreVmAmount, // 商场积分抵扣
		//sumData.OtherAmount,   // 其他付款方式

		//sumData.TotalSalesProfit,
		//sumData.TotalStaffProfit,
		//sumData.TotalSalesProfitPer, // 销售毛利提成
		//sumData.TotalStaffProfitPer, // 员工毛利提成
		//sumData.SalesmanPer,         // 销售员提成
		//sumData.StorePer,

		//""
	}

	// 控制是否导出
	if flag1 { // 采购单价
		end = append(end, sumData.WholesalePrice)
	}
	if flag2 { // 员工成本价
		end = append(end, sumData.StaffPrice)
	}
	if flag3 { // 销售毛利
		end = append(end, sumData.SalesProfit)
	}
	if flag4 { // 员工毛利
		end = append(end, sumData.StaffProfit)
	}

	end = append(end, sumData.TotalRetailPrice)
	end = append(end, sumData.TotalDiscount)
	end = append(end, sumData.TotalAmount)

	for _, value := range sumData.TotalCashierData {
		end = append(end, value.Amount)
	}
	//end = append(end, sumData.ScanAmount)
	//end = append(end, sumData.CashAmount)
	//end = append(end, sumData.PosAmount)
	//end = append(end, sumData.StoreVmAmount)
	//end = append(end, sumData.OtherAmount)

	if flag5 { // 订单总销售毛利
		end = append(end, sumData.TotalSalesProfit)
	}
	if flag6 { // 订单总员工毛利
		end = append(end, sumData.TotalStaffProfit)
	}
	if flag7 { // 销售毛利提成
		end = append(end, sumData.TotalSalesProfitPer)
	}
	if flag8 { // 员工毛利提成
		end = append(end, sumData.TotalStaffProfitPer)
	}
	if flag9 { // 销售员提成
		end = append(end, sumData.SalesmanPer)
	}
	if flag10 { // 门店提成
		end = append(end, sumData.StorePer)
	}

	end = append(end, "")

	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"}}`)
	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 := getEndRow(nEndCount, nExcelStartRow)
	fmt.Println(endRow)
	//endRow := fmt.Sprintf("AL%d", nExcelStartRow+2)
	// 应用样式到整个表格
	_ = file.SetCellStyle("Sheet1", "A1", endRow, style)

	// 设置单元格的样式: 居中、加边框、自动换行
	//style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true}}`)
	style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
	"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}]}`)

	//需要自动换行的列
	endRow2 := fmt.Sprintf("AI%d", nExcelStartRow+2)
	endRow3 := fmt.Sprintf("AJ%d", nExcelStartRow+2)
	endRow4 := fmt.Sprintf("AK%d", nExcelStartRow+2)
	_ = file.SetCellStyle("Sheet1", "A1", "AN1", style1)
	_ = file.SetCellStyle("Sheet1", "AL2", endRow2, style1)
	_ = file.SetCellStyle("Sheet1", "AJ2", endRow3, style1)
	_ = file.SetCellStyle("Sheet1", "AK2", endRow4, style1)

	// 设置单元格大小
	file.SetColWidth("Sheet1", "A", "A", 15)
	file.SetColWidth("Sheet1", "D", "D", 15)
	file.SetColWidth("Sheet1", "E", "E", 12)
	file.SetColWidth("Sheet1", "F", "F", 18)
	file.SetColWidth("Sheet1", "G", "G", 25)
	file.SetColWidth("Sheet1", "H", "H", 25)

	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 getEndRow(nEndCount, nExcelStartRow int) string {
	// Excel列是26进制的，列A为1，B为2，... Z为26，AA为27，以此类推
	columnIndex := 28 + nEndCount // "AH" 是第33列

	// 计算Excel列标
	columnLetter := ""
	for columnIndex > 0 {
		// 获取当前列的字母，并且列标从1开始，所以要减去1
		columnLetter = string(rune((columnIndex-1)%26+'A')) + columnLetter
		columnIndex = (columnIndex - 1) / 26
	}

	// 生成最终的单元格位置
	endRow := fmt.Sprintf("%s%d", columnLetter, nExcelStartRow+2)
	return endRow
}

// 生成Excel列名
func getExcelColumnName(index int) string {
	columnName := ""
	for index >= 0 {
		columnName = string(rune(index%26+'A')) + columnName
		index = index/26 - 1
	}
	return columnName
}

// RetailDetailByJoin 联表查询扫描参数
type RetailDetailByJoin struct {
	ErpOrderCommodity
	ErpOrder
}

// 联表查询
func queryRetailDetailByJoin(req *ErpOrderRetailDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

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

	qs := orm.Eloquent.Debug().Table("erp_order_commodity").
		Select("erp_order_commodity.*, erp_order.*").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")

	es := orm.Eloquent.Debug().Table("erp_order_commodity").
		Select("erp_order_commodity.*, erp_order.*").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")

	orderSumQs := orm.Eloquent.Table("erp_order_commodity AS oc").Select("oc.*, eo.*").
		Joins("JOIN erp_order AS eo ON oc.erp_order_id = eo.id")

	rejectedOrderSumQs := orm.Eloquent.Table("erp_order_commodity AS oc").Select("oc.*, eo.*").
		Joins("JOIN erp_order AS eo ON oc.erp_order_id = eo.id")

	if len(req.ErpCategoryId) != 0 { // 商品分类
		categoryList, err := TransformErpCategoryIds(req.ErpCategoryId)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("erp_order_commodity.erp_category_id in ?", categoryList)
		es = es.Where("erp_order_commodity.erp_category_id in ?", categoryList)
		orderSumQs = orderSumQs.Where("oc.erp_category_id in ?", categoryList)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.erp_category_id in ?", categoryList)
	}
	if req.ErpCommodityName != "" { // 商品名称
		qs = qs.Where("erp_order_commodity.erp_commodity_name = ?", req.ErpCommodityName)
		es = es.Where("erp_order_commodity.erp_commodity_name = ?", req.ErpCommodityName)
		orderSumQs = orderSumQs.Where("oc.erp_commodity_name = ?", req.ErpCommodityName)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.erp_commodity_name = ?", req.ErpCommodityName)
	}
	if req.RetailType != "" { // 销售类型
		qs = qs.Where("erp_order.retail_type=?", req.RetailType)
		es = es.Where("erp_order.retail_type=?", req.RetailType)
		orderSumQs = orderSumQs.Where("eo.retail_type=?", req.RetailType)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.retail_type=?", req.RetailType)
	}
	if req.Uid != 0 { // 用户ID
		qs = qs.Where("erp_order.uid=?", req.Uid)
		es = es.Where("erp_order.uid=?", req.Uid)
		orderSumQs = orderSumQs.Where("eo.uid=?", req.Uid)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.uid=?", req.Uid)
	}
	if req.Tel != "" { // 用户手机号
		qs = qs.Where("erp_order.tel=?", req.Tel)
		es = es.Where("erp_order.tel=?", req.Tel)
		orderSumQs = orderSumQs.Where("eo.tel=?", req.Tel)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.tel=?", req.Tel)
	}
	if len(req.StoreId) != 0 { // 门店ID
		qs = qs.Where("erp_order.store_id in ?", req.StoreId)
		es = es.Where("erp_order.store_id in ?", req.StoreId)
		orderSumQs = orderSumQs.Where("eo.store_id in ?", req.StoreId)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id in ?", req.StoreId)
	}
	if req.IMEI != "" { // 串码
		qs = qs.Where("erp_order_commodity.imei=?", req.IMEI)
		es = es.Where("erp_order_commodity.imei=?", req.IMEI)
		orderSumQs = orderSumQs.Where("oc.imei=?", req.IMEI)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.imei=?", req.IMEI)
	}
	// 非管理员才判断所属门店
	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("erp_order.store_id = ?", storeList[0])
				es = es.Where("erp_order.store_id = ?", storeList[0])
				orderSumQs = orderSumQs.Where("eo.store_id = ?", storeList[0])
				rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id = ?", storeList[0])
			} else {
				qs = qs.Where("erp_order.store_id IN (?)", storeList)
				es = es.Where("erp_order.store_id IN (?)", storeList)
				orderSumQs = orderSumQs.Where("eo.store_id IN (?)", storeList)
				rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id IN (?)", storeList)
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}
	if req.Salesman != 0 { // 销售员
		qs = qs.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
		es = es.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
		orderSumQs = orderSumQs.Where("JSON_CONTAINS(eo.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
		rejectedOrderSumQs = rejectedOrderSumQs.Where("JSON_CONTAINS(eo.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
	}
	if req.StartTime != "" { // 审核开始时间
		parse, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Errorf("err:", err)
		}
		qs = qs.Where("erp_order.audit_time > ?", parse)
		es = es.Where("erp_order.audit_time > ?", parse)
		orderSumQs = orderSumQs.Where("eo.audit_time > ?", parse)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.audit_time > ?", parse)
	}
	if req.EndTime != "" { // 审核结束时间
		parse, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Errorf("err:", err)
		}
		//parse = parse.AddDate(0, 0, 1)
		qs = qs.Where("erp_order.audit_time < ?", parse)
		es = es.Where("erp_order.audit_time < ?", parse)
		orderSumQs = orderSumQs.Where("eo.audit_time < ?", parse)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.audit_time < ?", parse)
	}
	if showConfig.ShowAll == "OFF" {
		qs = qs.Where("erp_order.is_print = ? or erp_order.retail_type = ?", HavePrinted, RetailTypeRejected)
		es = es.Where("erp_order.is_print = ? or erp_order.retail_type = ?", HavePrinted, RetailTypeRejected)
		orderSumQs = orderSumQs.Where("eo.is_print = ? or eo.retail_type = ?", HavePrinted, RetailTypeRejected)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.is_print = ? or eo.retail_type = ?", HavePrinted, RetailTypeRejected)
	}
	qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	es.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	orderSumQs.Where("eo.pay_status = ? or (eo.retail_type = ? and eo.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	rejectedOrderSumQs.Where("eo.pay_status = ? or (eo.retail_type = ? and eo.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)

	// 销售订单的汇总数据
	var sumData RetailDetailTotalData
	sumData, err = getRetailDetailTotalDataJoinErpOrderSale(orderSumQs, RetailTypeSale)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单的汇总数据
	var rejectedSumData RetailDetailTotalData
	rejectedSumData, err = getRetailDetailTotalDataJoinErpOrderRejected(rejectedOrderSumQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的销售数据
	sumData = subtractRetailData(sumData, rejectedSumData)

	// 销售订单提成汇总
	var totalPerData TotalPerData
	totalPerQs := qs
	totalPerData, err = getTotalPerData(totalPerQs, RetailTypeSale)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单提成汇总
	var rejectedTotalPerData TotalPerData
	rejectedTotalPerQs := qs
	rejectedTotalPerData, err = getTotalPerData(rejectedTotalPerQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的提成数据
	totalPerData = subtractTotalPerData(totalPerData, rejectedTotalPerData)

	//// 销售订单支持汇总
	//var cashier TotalCashierData
	//cashierQs := qs
	//cashier, err = getTotalCashierData(cashierQs, RetailTypeSale)
	//if err != nil {
	//	logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
	//	return resp, err
	//}
	//
	//// 支付方式筛选
	//if req.CashierId != 0 {
	//	var tempCashier TotalCashierData
	//	switch req.CashierId {
	//	case 1:
	//		tempCashier.ScanAmount = cashier.ScanAmount
	//	case 2:
	//		tempCashier.CashAmount = cashier.CashAmount
	//	case 3:
	//		tempCashier.PosAmount = cashier.PosAmount
	//	case 4:
	//		tempCashier.StoreVmAmount = cashier.StoreVmAmount
	//	default:
	//		tempCashier = cashier
	//	}
	//	cashier = tempCashier
	//}
	//
	//// 退货订单支付汇总：目前零售退货订单暂时不展示各个方式的付款金额
	//var rejectedCashier TotalCashierData
	//rejectedCashierQs := qs
	//rejectedCashier, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected)
	//if err != nil {
	//	logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
	//	return resp, err
	//}
	//// 计算销售订单和退货订单汇总后的支付数据
	//cashier = subtractCashierData(cashier, rejectedCashier)
	//
	//// 处理汇总数据，四舍五入保留2位小数
	//roundValues(&sumData, &totalPerData, &cashier)

	// 销售订单支付汇总
	var cashierData []ErpOrderCashier
	cashierQs := qs
	cashierData, err = getTotalCashierData(cashierQs, RetailTypeSale)
	if err != nil {
		logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
		return resp, err
	}

	// 支付方式筛选
	if req.CashierId != 0 {
		var filteredData []ErpOrderCashier
		for _, cashier := range cashierData {
			if cashier.CashierId == req.CashierId {
				filteredData = append(filteredData, cashier)
			}
		}
		cashierData = filteredData
	}

	// 退货订单支付汇总：目前零售退货订单暂时不展示各个方式的付款金额
	var rejectedCashierData []ErpOrderCashier
	rejectedCashierQs := qs
	rejectedCashierData, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
		return resp, err
	}

	// 计算销售订单和退货订单汇总后的支付数据
	cashierData = subtractCashierData(cashierData, rejectedCashierData)

	// 处理汇总数据，四舍五入保留2位小数
	roundValues(&sumData, &totalPerData)

	sumData.TotalSalesProfit = 0 // 订单总销售毛利
	sumData.TotalStaffProfit = 0 // 订单总员工毛利
	sumData.TotalRetailPrice = 0 // 订单总指导零售价
	sumData.TotalDiscount = 0    // 订单总优惠
	sumData.TotalAmount = 0      // 订单实收金额
	sumData.StorePer = 0         // 门店提成
	sumData.TotalCashierData = nil

	//sumData.ScanAmount = cashier.ScanAmount
	//sumData.CashAmount = cashier.CashAmount
	//sumData.PosAmount = cashier.PosAmount
	//sumData.StoreVmAmount = cashier.StoreVmAmount
	//sumData.OtherAmount = cashier.OtherAmount

	RoundRetailDetailTotalData(&sumData)

	var result []RetailDetailByJoin

	if req.IsExport == 1 { //导出excel
		err = qs.Order("erp_order.audit_time DESC").Find(&result).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}

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

		orders := packData(result)
		erpOrderSetBankTrxNo(orders)
		fileUrl, err := retailDetailExport(orders, sumData, c)
		if err != nil {
			logger.Error("retailDetailExport err:", logger.Field("err", err))
			return resp, err
		}
		resp.ExportUrl = fileUrl
	} else {
		//err = qs.Order("erp_order.audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&result).Error
		err = qs.Order("erp_order.audit_time DESC").Find(&result).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}

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

		orders := packData(result)
		erpOrderListSetCashier(orders)
		erpOrderListSetSalesman(orders)
		erpOrderSetBankTrxNo(orders)
		pagedOrders := paginate(orders, page, req.PageSize)

		resp.List = pagedOrders

		//跟之前保持一致
		resp.Total = len(orders)
		resp.PageIndex = page + 1
		resp.PageSize = req.PageSize
		resp.SumData = sumData
	}

	return resp, nil
}

// 分页函数
func paginate(orders []ErpOrder, page int, pageSize int) []ErpOrder {
	start := page * pageSize
	end := start + pageSize

	if start >= len(orders) {
		return []ErpOrder{}
	}

	if end > len(orders) {
		end = len(orders)
	}

	return orders[start:end]
}

// 组合数据
func packData(result []RetailDetailByJoin) []ErpOrder {
	var orders []ErpOrder
	orderIdMap := make(map[uint32]ErpOrder)
	for _, item := range result {
		var order ErpOrder
		var commodity ErpOrderCommodity

		// 判断是否有重复数据
		if len(orderIdMap) != 0 && orderIdMap[item.ErpOrderId].BillSn != "" {
			order = orderIdMap[item.ErpOrderId]
		} else {
			// 订单数据
			order.CreatedAt = item.ErpOrderCommodity.CreatedAt
			order.ID = item.ErpOrderId
			order.BillSn = item.BillSn
			order.RetailType = item.RetailType
			order.Uid = item.Uid
			order.Tel = item.Tel
			order.StoreId = item.StoreId
			order.StoreName = item.StoreName
			order.MakerId = item.MakerId
			order.MakerName = item.MakerName
			order.MakerTime = item.MakerTime
			order.AuditorId = item.AuditorId
			order.AuditorName = item.AuditorName
			order.AuditTime = item.AuditTime
			order.CashierList = item.CashierList
			order.SalesmanList = item.SalesmanList
			order.MemberType = item.MemberType
			order.State = item.State
			order.TotalRetailPrice = item.TotalRetailPrice
			order.TotalAmount = item.TotalAmount
			order.TotalCount = item.TotalCount
			order.TotalSalesProfit = item.TotalSalesProfit
			order.TotalStaffProfit = item.TotalStaffProfit
			order.VmCount = item.VmCount
			order.SaleOrderId = item.SaleOrderId
			order.PayStatus = item.PayStatus
			order.IsPrint = item.IsPrint
			order.PrintCount = item.PrintCount
			order.InvoiceCode = item.InvoiceCode
			order.InvoiceNumber = item.InvoiceNumber
			order.RejectedTotalAmount = item.RejectedTotalAmount
			order.RejectedTotalCount = item.RejectedTotalCount

			if order.RetailType == RetailTypeRejected { // 退货订单，金额需要转换为负值
				order.TotalRetailPrice = -math.Abs(order.TotalRetailPrice)
				order.TotalAmount = -math.Abs(order.TotalAmount)
				order.TotalCount = -int32(math.Abs(float64(order.TotalCount)))
				order.TotalSalesProfit = -order.TotalSalesProfit
				order.TotalStaffProfit = -order.TotalStaffProfit
				order.TotalDiscount = -math.Abs(order.TotalDiscount)
				order.VmCount = -uint32(math.Abs(float64(order.VmCount)))
				order.StorePer = -math.Abs(order.StorePer)
			}
		}

		if order.RetailType == RetailTypeRejected { // 退货订单，金额需要转换为负值
			item.Count = -item.Count
			item.RetailPrice = -item.RetailPrice
			item.SalePrice = -item.SalePrice
			item.Amount = -item.Amount
			item.SaleDiscount = -item.SaleDiscount
			item.MemberDiscount = -item.MemberDiscount
			item.VmDiscount = -item.VmDiscount
			item.ReceivedAmount = -item.ReceivedAmount
			item.RejectedAmount = -item.RejectedAmount
			item.SalesProfit = -item.SalesProfit
			item.StaffProfit = -item.StaffProfit
			item.StaffCostPrice = -item.StaffCostPrice
			item.WholesalePrice = -item.WholesalePrice
		}
		// 订单商品数据
		commodity.CreatedAt = item.ErpOrderCommodity.CreatedAt
		commodity.ErpOrderId = item.ErpOrderId
		commodity.ErpCategoryId = item.ErpCategoryId
		commodity.ErpCategoryName = item.ErpCategoryName
		commodity.ErpCommodityId = item.ErpCommodityId
		commodity.ErpCommodityName = item.ErpCommodityName
		commodity.IMEIType = item.IMEIType
		commodity.IMEI = item.IMEI
		commodity.PresentType = item.PresentType
		commodity.RetailPrice = item.RetailPrice
		commodity.SalePrice = item.SalePrice
		commodity.Count = item.Count
		commodity.SaleDiscount = item.SaleDiscount
		commodity.MemberDiscount = item.MemberDiscount
		commodity.VmDiscount = item.VmDiscount
		commodity.Amount = item.Amount
		commodity.ReceivedAmount = item.ReceivedAmount
		commodity.Remark = item.Remark
		commodity.RejectedPrice = item.RejectedPrice
		commodity.RejectedCount = item.RejectedCount
		commodity.RejectedAmount = item.RejectedAmount
		commodity.RejectedOrderCommodityId = item.RejectedOrderCommodityId
		commodity.StaffCostPrice = item.StaffCostPrice
		commodity.WholesalePrice = item.WholesalePrice
		commodity.ErpSupplierId = item.ErpSupplierId
		commodity.ErpSupplierName = item.ErpSupplierName
		commodity.SalesProfit = item.SalesProfit
		commodity.StaffProfit = item.StaffProfit
		commodity.StaffPrice = item.WholesalePrice + item.StaffCostPrice

		// 若商品为非串码（IMEIType==1），则尝试合并同一订单中相同 ErpCommodityId 的记录
		if commodity.IMEIType == 1 {
			merged := false
			for idx, exist := range order.Commodities {
				// 合并条件：同为非串码且 ErpCommodityId 相同
				if exist.IMEIType == 1 && exist.ErpCommodityId == commodity.ErpCommodityId &&
					exist.SalePrice == commodity.SalePrice {
					order.Commodities[idx].Count += commodity.Count
					order.Commodities[idx].SaleDiscount += commodity.SaleDiscount
					order.Commodities[idx].MemberDiscount += commodity.MemberDiscount
					order.Commodities[idx].VmDiscount += commodity.VmDiscount
					order.Commodities[idx].Amount += commodity.Amount
					order.Commodities[idx].ReceivedAmount += commodity.ReceivedAmount
					order.Commodities[idx].RejectedCount += commodity.RejectedCount
					order.Commodities[idx].RejectedAmount += commodity.RejectedAmount
					order.Commodities[idx].SalesProfit += commodity.SalesProfit
					order.Commodities[idx].StaffProfit += commodity.StaffProfit
					order.Commodities[idx].StaffCostPrice += commodity.StaffCostPrice
					order.Commodities[idx].WholesalePrice += commodity.WholesalePrice
					//order.Commodities[idx].RetailPrice += commodity.RetailPrice
					//order.Commodities[idx].SalePrice += commodity.SalePrice
					// 重新计算员工价格
					order.Commodities[idx].StaffPrice = order.Commodities[idx].WholesalePrice + order.Commodities[idx].StaffCostPrice
					merged = true
					break
				}
			}
			if !merged {
				order.Commodities = append(order.Commodities, commodity)
			}
		} else {
			// 串码商品不合并，直接追加
			order.Commodities = append(order.Commodities, commodity)
		}
		orderIdMap[item.ErpOrderId] = order
	}

	for _, order := range orderIdMap {
		for i := range order.Commodities {
			if order.Commodities[i].IMEIType == 1 {
				order.Commodities[i].WholesalePrice = tools.RoundToTwoDecimalPlaces(order.Commodities[i].WholesalePrice)
				order.Commodities[i].StaffPrice = tools.RoundToTwoDecimalPlaces(order.Commodities[i].WholesalePrice + order.Commodities[i].StaffCostPrice)
			}
		}
		orders = append(orders, order)
	}

	// 根据AuditTime进行降序排序
	sort.SliceStable(orders, func(i, j int) bool {
		// 若其中一个 AuditTime 为空，则按其他字段排序或认为空时间最小
		if orders[i].AuditTime == nil {
			return false
		}
		if orders[j].AuditTime == nil {
			return true
		}
		return orders[i].AuditTime.After(*orders[j].AuditTime)
	})

	return orders
}

// 普通单表查询，然后补充收款数据和商品数据
func queryRetailDetailCommon(req *ErpOrderRetailDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

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

	qs := orm.Eloquent.Table("erp_order")
	totalPerQs := orm.Eloquent.Table("erp_order")
	if showConfig.ShowAll == "OFF" {
		qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
		totalPerQs = totalPerQs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
	}
	if req.BillSn != "" { // 订单编号
		qs = qs.Where("bill_sn=?", req.BillSn)
		totalPerQs = totalPerQs.Where("bill_sn=?", req.BillSn)
	} else {
		if req.RetailType != "" { // 销售类型
			qs = qs.Where("retail_type=?", req.RetailType)
			totalPerQs = totalPerQs.Where("retail_type=?", req.RetailType)
		}
		if req.Uid != 0 { // 用户ID
			qs = qs.Where("erp_order.uid=?", req.Uid)
			totalPerQs = totalPerQs.Where("erp_order.uid=?", req.Uid)
		}
		if req.Tel != "" { // 用户手机号
			qs = qs.Where("tel=?", req.Tel)
			totalPerQs = totalPerQs.Where("tel=?", req.Tel)
		}
		if len(req.StoreId) != 0 { // 门店ID
			qs = qs.Where("store_id in ?", req.StoreId)
			totalPerQs = totalPerQs.Where("store_id in ?", req.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])
					totalPerQs = totalPerQs.Where("store_id = ?", storeList[0])
				} else {
					qs = qs.Where("store_id IN (?)", storeList)
					totalPerQs = totalPerQs.Where("store_id IN (?)", storeList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
		if tools.GetRoleName(c) == "shopper" {
			qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, tools.GetUserId(c)))
			totalPerQs = totalPerQs.Where("erp_order_sales.uid = ?", tools.GetUserId(c))
		} else {
			if req.Salesman != 0 { // 销售员
				qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
				totalPerQs = totalPerQs.Where("erp_order_sales.uid = ?", req.Salesman)
			}
		}

		if req.CashierId != 0 { // 支付方式
			qs = qs.Where("JSON_CONTAINS(cashier_list, ?)", fmt.Sprintf(`{"cashier_id":%d}`, req.CashierId))
			//qs = qs.Where("retail_type=?", RetailTypeSale)
			//totalPerQs = totalPerQs.Where("erp_order_pay_way.cashier_id = ?", req.CashierId)
		}
		if req.StartTime != "" { // 审核开始时间
			parse, err := time.Parse(QueryTimeFormat, req.StartTime)
			if err != nil {
				logger.Errorf("err:", err)
			}
			qs = qs.Where("audit_time > ?", parse)
			totalPerQs = totalPerQs.Where("audit_time > ?", parse)
		}
		if req.EndTime != "" { // 审核结束时间
			parse, err := time.Parse(QueryTimeFormat, req.EndTime)
			if err != nil {
				logger.Errorf("err:", err)
			}
			//parse = parse.AddDate(0, 0, 1)
			qs = qs.Where("audit_time < ?", parse)
			totalPerQs = totalPerQs.Where("audit_time < ?", parse)
		}
	}
	qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	totalPerQs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	es := qs
	rejectedTotalPerQs := totalPerQs

	// 销售订单的汇总数据
	orderSumQs := qs
	var sumData RetailDetailTotalData
	sumData, err = getRetailDetailTotalDataSale(orderSumQs, RetailTypeSale)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单的汇总数据
	var rejectedSumData RetailDetailTotalData
	rejectedOrderSumQs := qs
	rejectedSumData, err = getRetailDetailTotalDataRejected(rejectedOrderSumQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的销售数据
	sumData = subtractRetailData(sumData, rejectedSumData)

	// 销售订单提成汇总
	var totalPerData TotalPerData
	totalPerData, err = getTotalPerData(totalPerQs, RetailTypeSale)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单提成汇总
	var rejectedTotalPerData TotalPerData
	rejectedTotalPerData, err = getTotalPerData(rejectedTotalPerQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的提成数据
	totalPerData = subtractTotalPerData(totalPerData, rejectedTotalPerData)

	//// 销售订单支付汇总
	//var cashier TotalCashierData
	//cashierQs := qs
	//cashier, err = getTotalCashierData(cashierQs, RetailTypeSale)
	//if err != nil {
	//	logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
	//	return resp, err
	//}
	//
	//// 支付方式筛选
	//if req.CashierId != 0 {
	//	var tempCashier TotalCashierData
	//	switch req.CashierId {
	//	case 1:
	//		tempCashier.ScanAmount = cashier.ScanAmount
	//	case 2:
	//		tempCashier.CashAmount = cashier.CashAmount
	//	case 3:
	//		tempCashier.PosAmount = cashier.PosAmount
	//	case 4:
	//		tempCashier.StoreVmAmount = cashier.StoreVmAmount
	//	default:
	//		tempCashier = cashier
	//	}
	//	cashier = tempCashier
	//}
	//
	//// 退货订单支付汇总：目前零售退货订单暂时不展示各个方式的付款金额
	//var rejectedCashier TotalCashierData
	//rejectedCashierQs := qs
	//rejectedCashier, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected)
	//if err != nil {
	//	logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
	//	return resp, err
	//}
	//// 计算销售订单和退货订单汇总后的支付数据
	//cashier = subtractCashierData(cashier, rejectedCashier)
	//
	//// 处理汇总数据，四舍五入保留2位小数
	//roundValues(&sumData, &totalPerData, &cashier)

	// 销售订单支付汇总
	var cashierData []ErpOrderCashier
	cashierQs := qs
	cashierData, err = getTotalCashierData(cashierQs, RetailTypeSale)
	if err != nil {
		logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
		return resp, err
	}

	//// 支付方式筛选
	//if req.CashierId != 0 {
	//	var filteredData []ErpOrderCashier
	//	for _, cashier := range cashierData {
	//		if cashier.CashierId == req.CashierId {
	//			filteredData = append(filteredData, cashier)
	//		}
	//	}
	//	cashierData = filteredData
	//}

	// 退货订单支付汇总：目前零售退货订单暂时不展示各个方式的付款金额
	var rejectedCashierData []ErpOrderCashier
	rejectedCashierQs := qs
	rejectedCashierData, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
		return resp, err
	}

	// 计算销售订单和退货订单汇总后的支付数据
	cashierData = subtractCashierData(cashierData, rejectedCashierData)

	// 处理汇总数据，四舍五入保留2位小数
	roundValues(&sumData, &totalPerData)

	sumData.TotalSalesProfitPer = totalPerData.TotalSalesProfitPer
	sumData.TotalStaffProfitPer = totalPerData.TotalStaffProfitPer
	sumData.SalesmanPer = totalPerData.SalesmanPer
	sumData.TotalCashierData = cashierData
	RoundRetailDetailTotalData(&sumData)

	if req.IsExport == 1 { // 导出excel
		var orders []ErpOrder
		err = qs.Order("audit_time DESC").Find(&orders).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}
		// 进行批量处理
		var wg sync.WaitGroup
		wg.Add(2)

		go func() {
			defer wg.Done()
			ErpOrderRetailDetailSetCommodityAI(orders) // 商品信息处理
		}()

		go func() {
			defer wg.Done()
			erpOrderSetBankTrxNoAI(orders) // 银行交易号处理
		}()

		wg.Wait() // 等待所有处理完成

		fileUrl, err := retailDetailExport(orders, sumData, c)
		if err != nil {
			logger.Error("retailDetailExport err:", logger.Field("err", err))
			return resp, err
		}
		resp.ExportUrl = fileUrl
	} else {
		var count int64
		err = es.Count(&count).Error
		if err != nil {
			logger.Error("count err:", logger.Field("err", err))
			return resp, err
		}

		var orders []ErpOrder
		err = qs.Order("audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}

		// 添加付款、销售员、商品信息
		ErpOrderRetailDetailSetCommodity(orders)
		erpOrderListSetSalesman(orders)
		erpOrderListSetCashier(orders)
		erpOrderSetBankTrxNo(orders)
		//erpOrderListSetSalesmanByRetailDetail(req.Salesman, orders)

		resp.List = orders

		//跟之前保持一致
		resp.Total = int(count)
		resp.PageIndex = page + 1
		resp.PageSize = req.PageSize
		resp.SumData = sumData
	}

	return resp, nil
}

// 四舍五入保留2位小数
func roundValues(data *RetailDetailTotalData, totalPerData *TotalPerData) {
	roundMap := map[*float64]*float64{
		&data.StorePer:                    &data.StorePer,
		&totalPerData.TotalSalesProfitPer: &totalPerData.TotalSalesProfitPer,
		&totalPerData.TotalStaffProfitPer: &totalPerData.TotalStaffProfitPer,
		&totalPerData.SalesmanPer:         &totalPerData.SalesmanPer,
	}

	for original, rounded := range roundMap {
		*rounded = tools.RoundToTwoDecimalPlaces(*original)
	}
}

//// 四舍五入保留2位小数
//func roundValues(data *RetailDetailTotalData, totalPerData *TotalPerData, cashier *TotalCashierData) {
//	roundMap := map[*float64]*float64{
//		&data.StorePer:                    &data.StorePer,
//		&totalPerData.TotalSalesProfitPer: &totalPerData.TotalSalesProfitPer,
//		&totalPerData.TotalStaffProfitPer: &totalPerData.TotalStaffProfitPer,
//		&totalPerData.SalesmanPer:         &totalPerData.SalesmanPer,
//		&cashier.ScanAmount:               &cashier.ScanAmount,
//		&cashier.CashAmount:               &cashier.CashAmount,
//		&cashier.PosAmount:                &cashier.PosAmount,
//		&cashier.StoreVmAmount:            &cashier.StoreVmAmount,
//		&cashier.OtherAmount:              &cashier.OtherAmount,
//	}
//
//	for original, rounded := range roundMap {
//		*rounded = tools.RoundToTwoDecimalPlaces(*original)
//	}
//}

// RoundRetailDetailTotalData 将 RetailDetailTotalData 中所有 float64 字段保留两位小数
func RoundRetailDetailTotalData(data *RetailDetailTotalData) {
	data.RetailPrice = tools.RoundToTwoDecimalPlaces(data.RetailPrice)
	data.SalePrice = tools.RoundToTwoDecimalPlaces(data.SalePrice)
	data.SaleDiscount = tools.RoundToTwoDecimalPlaces(data.SaleDiscount)
	data.MemberDiscount = tools.RoundToTwoDecimalPlaces(data.MemberDiscount)
	data.VmDiscount = tools.RoundToTwoDecimalPlaces(data.VmDiscount)
	data.CouponDiscount = tools.RoundToTwoDecimalPlaces(data.CouponDiscount)
	data.Amount = tools.RoundToTwoDecimalPlaces(data.Amount)
	data.WholesalePrice = tools.RoundToTwoDecimalPlaces(data.WholesalePrice)
	data.StaffPrice = tools.RoundToTwoDecimalPlaces(data.StaffPrice)
	data.SalesProfit = tools.RoundToTwoDecimalPlaces(data.SalesProfit)
	data.StaffProfit = tools.RoundToTwoDecimalPlaces(data.StaffProfit)
	data.TotalRetailPrice = tools.RoundToTwoDecimalPlaces(data.TotalRetailPrice)
	data.TotalDiscount = tools.RoundToTwoDecimalPlaces(data.TotalDiscount)
	data.TotalAmount = tools.RoundToTwoDecimalPlaces(data.TotalAmount)
	data.TotalSalesProfit = tools.RoundToTwoDecimalPlaces(data.TotalSalesProfit)
	data.TotalStaffProfit = tools.RoundToTwoDecimalPlaces(data.TotalStaffProfit)
	data.StorePer = tools.RoundToTwoDecimalPlaces(data.StorePer)

	// 处理TotalCashierData中的float64
	//data.ScanAmount = tools.RoundToTwoDecimalPlaces(data.ScanAmount)
	//data.CashAmount = tools.RoundToTwoDecimalPlaces(data.CashAmount)
	//data.PosAmount = tools.RoundToTwoDecimalPlaces(data.PosAmount)
	//data.StoreVmAmount = tools.RoundToTwoDecimalPlaces(data.StoreVmAmount)
	//data.OtherAmount = tools.RoundToTwoDecimalPlaces(data.OtherAmount)

	for i, value := range data.TotalCashierData {
		data.TotalCashierData[i].Amount = tools.RoundToTwoDecimalPlaces(value.Amount)
	}

	// 处理TotalPerData中的float64
	data.TotalSalesProfitPer = tools.RoundToTwoDecimalPlaces(data.TotalSalesProfitPer)
	data.TotalStaffProfitPer = tools.RoundToTwoDecimalPlaces(data.TotalStaffProfitPer)
	data.SalesmanPer = tools.RoundToTwoDecimalPlaces(data.SalesmanPer)
}

// 查询零售订单的汇总数据
func getRetailDetailTotalDataSale(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
	var sumData RetailDetailTotalData

	err := qs.Debug().
		Select("SUM(cs.count) as count, "+
			"SUM(cs.retail_price) as retail_price, "+
			"SUM(cs.sale_price) as sale_price, "+
			"SUM(cs.sale_discount) as sale_discount, "+
			"SUM(cs.member_discount) as member_discount, "+
			"SUM(cs.coupon_discount) as coupon_discount, "+
			"SUM(cs.amount) as Amount, "+
			"SUM(cs.wholesale_price) as wholesale_price, "+
			"(SUM(cs.wholesale_price) + SUM(cs.staff_cost_price)) as staff_price, "+
			"(SUM(cs.amount) - SUM(cs.wholesale_price)) as sales_profit, "+
			"(SUM(cs.amount) - SUM(cs.wholesale_price) - SUM(cs.staff_cost_price)) as staff_profit, "+
			"SUM(erp_order.total_retail_price) as total_retail_price, "+
			"(SUM(erp_order.total_retail_price) - SUM(erp_order.total_amount)) as total_discount, "+
			"SUM(erp_order.total_amount) as total_amount, "+
			"SUM(erp_order.total_sales_profit) as total_sales_profit, "+
			"SUM(erp_order.total_staff_profit) as total_staff_profit, "+
			"SUM(erp_order.store_per) as store_per").
		Joins("JOIN (SELECT erp_order_id, "+
			"SUM(count) as count, "+
			"SUM(retail_price) as retail_price, "+
			"SUM(sale_price) as sale_price, "+
			"SUM(sale_discount) as sale_discount, "+
			"SUM(member_discount) as member_discount, "+
			"SUM(coupon_discount) as coupon_discount, "+
			"SUM(amount) as amount, "+
			"SUM(wholesale_price) as wholesale_price, "+
			"SUM(staff_cost_price) as staff_cost_price "+
			"FROM erp_order_commodity "+
			"GROUP BY erp_order_id) as cs ON cs.erp_order_id = erp_order.id").
		Where("erp_order.retail_type = ?", retailType).
		Scan(&sumData).Error

	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return sumData, err
	}
	return sumData, nil
}

// 查询零售退货订单的汇总数据
func getRetailDetailTotalDataRejected(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
	var sumData RetailDetailTotalData

	err := qs.Debug().
		Select("SUM(cs.count) as count, "+
			"SUM(cs.retail_price) as retail_price, "+
			"SUM(cs.sale_price) as sale_price, "+
			"SUM(cs.sale_discount) as sale_discount, "+
			"SUM(cs.member_discount) as member_discount, "+
			"SUM(cs.coupon_discount) as coupon_discount, "+
			"SUM(cs.amount) as Amount, "+
			"SUM(cs.wholesale_price) as wholesale_price, "+
			"(SUM(cs.wholesale_price) + SUM(cs.staff_cost_price)) as staff_price, "+
			"(SUM(cs.amount) - SUM(cs.wholesale_price)) as sales_profit, "+
			"(SUM(cs.amount) - SUM(cs.wholesale_price) - SUM(cs.staff_cost_price)) as staff_profit, "+
			"SUM(erp_order.total_retail_price) as total_retail_price, "+
			"(SUM(erp_order.total_retail_price) - SUM(erp_order.total_amount)) as total_discount, "+
			"SUM(erp_order.total_amount) as total_amount, "+
			"SUM(erp_order.total_sales_profit) as total_sales_profit, "+
			"SUM(erp_order.total_staff_profit) as total_staff_profit, "+
			"SUM(erp_order.store_per) as store_per").
		Joins("JOIN (SELECT erp_order_id, "+
			"SUM(count) as count, "+
			"SUM(retail_price) as retail_price, "+
			"SUM(sale_price) as sale_price, "+
			"SUM(sale_discount) as sale_discount, "+
			"SUM(member_discount) as member_discount, "+
			"SUM(coupon_discount) as coupon_discount, "+
			"SUM(rejected_amount) as amount, "+
			"SUM(wholesale_price) as wholesale_price, "+
			"SUM(staff_cost_price) as staff_cost_price "+
			"FROM erp_order_commodity "+
			"GROUP BY erp_order_id) as cs ON cs.erp_order_id = erp_order.id").
		Where("erp_order.retail_type = ?", retailType).
		Scan(&sumData).Error

	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return sumData, err
	}
	return sumData, nil
}

// 查询零售订单的汇总数据
func getRetailDetailTotalDataJoinErpOrderSale(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
	var sumData RetailDetailTotalData
	qs = qs.Where("eo.retail_type = ?", retailType) // 添加额外的条件
	err := qs.Debug().Select("SUM(oc.count) as count, " +
		"SUM(oc.retail_price) as retail_price, " +
		"SUM(oc.sale_price) as sale_price, " +
		"SUM(oc.sale_discount) as sale_discount, " +
		"SUM(oc.member_discount) as member_discount, " +
		"SUM(oc.amount) as Amount, " +
		"SUM(oc.wholesale_price) as wholesale_price, " +
		"(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) as staff_price, " +
		"(SUM(oc.Amount) - SUM(oc.wholesale_price)) as sales_profit, " +
		"(SUM(oc.Amount) - SUM(oc.wholesale_price) - SUM(oc.staff_cost_price)) as staff_profit").
		Scan(&sumData).Error
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return sumData, err
	}
	return sumData, nil
}

// 查询零售订单的汇总数据
func getRetailDetailTotalDataJoinErpOrderRejected(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
	var sumData RetailDetailTotalData
	qs = qs.Where("eo.retail_type = ?", retailType) // 添加额外的条件
	err := qs.Debug().Select("SUM(oc.count) as count, " +
		"SUM(oc.retail_price) as retail_price, " +
		"SUM(oc.sale_price) as sale_price, " +
		"SUM(oc.sale_discount) as sale_discount, " +
		"SUM(oc.member_discount) as member_discount, " +
		"SUM(oc.rejected_amount) as Amount, " +
		"SUM(oc.wholesale_price) as wholesale_price, " +
		"(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) as staff_price, " +
		"SUM(oc.sales_profit) as sales_profit, " +
		"SUM(oc.staff_profit) as staff_profit").
		Scan(&sumData).Error
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return sumData, err
	}
	return sumData, nil
}

// 查询零售订单的提成汇总数据
func getTotalPerData(qs *gorm.DB, retailType string) (TotalPerData, error) {
	var totalPerData TotalPerData
	err := qs.Debug().Select("SUM(erp_order_sales.sales_profit_per) as total_sales_profit_per, "+
		"SUM(erp_order_sales.staff_profit_per) as total_staff_profit_per, "+
		"SUM(erp_order_sales.salesman_per) as salesman_per").
		Joins("JOIN erp_order_sales ON erp_order_sales.erp_order_id = erp_order.id and erp_order.retail_type = ?", retailType).
		Scan(&totalPerData).Error
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return totalPerData, err
	}
	return totalPerData, nil
}

//// 查询零售订单的支付汇总数据
//func getTotalCashierData(qs *gorm.DB, retailType string) (TotalCashierData, error) {
//	var cashier TotalCashierData
//	err := qs.Debug().Select(
//		"SUM(CASE WHEN erp_order_pay_way.cashier_id = 1 THEN erp_order_pay_way.amount ELSE 0 END) AS scan_amount,"+
//			"SUM(CASE WHEN erp_order_pay_way.cashier_id = 2 THEN erp_order_pay_way.amount ELSE 0 END) AS cash_amount,"+
//			"SUM(CASE WHEN erp_order_pay_way.cashier_id = 3 THEN erp_order_pay_way.amount ELSE 0 END) AS pos_amount,"+
//			"SUM(CASE WHEN erp_order_pay_way.cashier_id = 4 THEN erp_order_pay_way.amount ELSE 0 END) AS store_vm_amount,"+
//			"SUM(CASE WHEN erp_order_pay_way.cashier_id not in (1,2,3,4) THEN erp_order_pay_way.amount ELSE 0 END) AS other_amount").
//		Joins("JOIN erp_order_pay_way ON erp_order_pay_way.erp_order_id = erp_order.id  and erp_order.retail_type = ?", retailType).
//		Scan(&cashier).Error
//	if err != nil {
//		logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
//		return cashier, err
//	}
//	return cashier, nil
//}

// 查询零售订单的支付汇总数据
func getTotalCashierData(qs *gorm.DB, retailType string) ([]ErpOrderCashier, error) {
	var results []ErpOrderCashier
	err := qs.Debug().
		Select("erp_order_pay_way.cashier_id AS cashier_id, erp_cashier.name AS name, SUM(erp_order_pay_way.amount) AS amount").
		Joins("JOIN erp_order_pay_way ON erp_order_pay_way.erp_order_id = erp_order.id AND erp_order.retail_type = ?", retailType).
		Joins("JOIN erp_cashier ON erp_cashier.id = erp_order_pay_way.cashier_id").
		Group("erp_order_pay_way.cashier_id, erp_cashier.name").
		Scan(&results).Error
	if err != nil {
		logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
		return nil, err
	}

	// 查询所有支付方式
	var sysCashierList []ErpCashier
	err = orm.Eloquent.Table("erp_cashier").Order("id ASC").Find(&sysCashierList).Error
	if err != nil {
		return nil, err
	}

	var resp []ErpOrderCashier
	for _, value := range sysCashierList {
		var data ErpOrderCashier
		data.CashierId = value.ID
		data.Name = value.Name
		for _, item := range results {
			if value.ID == item.CashierId {
				data.Amount = item.Amount
			} else {
				continue
			}
		}
		resp = append(resp, data)
	}

	return resp, nil
}

// 计算销售订单和退货订单汇总后的销售数据
func subtractRetailData(sumData, rejectedSumData RetailDetailTotalData) RetailDetailTotalData {
	result := RetailDetailTotalData{
		Count:            sumData.Count - rejectedSumData.Count,
		RetailPrice:      sumData.RetailPrice - rejectedSumData.RetailPrice,
		SalePrice:        sumData.SalePrice - rejectedSumData.SalePrice,
		SaleDiscount:     sumData.SaleDiscount - rejectedSumData.SaleDiscount,
		MemberDiscount:   sumData.MemberDiscount - rejectedSumData.MemberDiscount,
		VmDiscount:       sumData.VmDiscount - rejectedSumData.VmDiscount,
		Amount:           sumData.Amount - rejectedSumData.Amount,
		WholesalePrice:   sumData.WholesalePrice - rejectedSumData.WholesalePrice,
		StaffPrice:       sumData.StaffPrice - rejectedSumData.StaffPrice,
		SalesProfit:      sumData.SalesProfit - rejectedSumData.SalesProfit,
		StaffProfit:      sumData.StaffProfit - rejectedSumData.StaffProfit,
		TotalRetailPrice: sumData.TotalRetailPrice - rejectedSumData.TotalRetailPrice,
		TotalDiscount:    sumData.TotalDiscount - rejectedSumData.TotalDiscount,
		TotalAmount:      sumData.TotalAmount - rejectedSumData.TotalAmount,
		TotalSalesProfit: sumData.TotalSalesProfit - rejectedSumData.TotalSalesProfit,
		TotalStaffProfit: sumData.TotalStaffProfit - rejectedSumData.TotalStaffProfit,
		StorePer:         sumData.StorePer - rejectedSumData.StorePer,
		CouponDiscount:   sumData.CouponDiscount - rejectedSumData.CouponDiscount,
	}
	//if sumData.TotalSalesProfit != 0 {
	//	result.TotalSalesProfit = sumData.TotalSalesProfit - rejectedSumData.TotalSalesProfit
	//} else {
	//	result.TotalSalesProfit = rejectedSumData.TotalSalesProfit
	//}
	//if sumData.TotalStaffProfit != 0 {
	//	result.TotalStaffProfit = sumData.TotalStaffProfit - rejectedSumData.TotalStaffProfit
	//} else {
	//	result.TotalStaffProfit = rejectedSumData.TotalStaffProfit
	//}

	return result
}

// 计算销售订单和退货订单汇总后的提成数据
func subtractTotalPerData(totalPerData, rejectedTotalPerData TotalPerData) TotalPerData {
	result := TotalPerData{
		TotalSalesProfitPer: totalPerData.TotalSalesProfitPer - rejectedTotalPerData.TotalSalesProfitPer,
		TotalStaffProfitPer: totalPerData.TotalStaffProfitPer - rejectedTotalPerData.TotalStaffProfitPer,
		SalesmanPer:         totalPerData.SalesmanPer - rejectedTotalPerData.SalesmanPer,
	}
	return result
}

//// 计算销售订单和退货订单汇总后的支付数据
//func subtractCashierData(cashier, rejectedCashier TotalCashierData) TotalCashierData {
//	result := TotalCashierData{
//		ScanAmount:    cashier.ScanAmount - rejectedCashier.ScanAmount,
//		CashAmount:    cashier.CashAmount - rejectedCashier.CashAmount,
//		PosAmount:     cashier.PosAmount - rejectedCashier.PosAmount,
//		StoreVmAmount: cashier.StoreVmAmount - rejectedCashier.StoreVmAmount,
//		OtherAmount:   cashier.OtherAmount - rejectedCashier.OtherAmount,
//	}
//	return result
//}

// subtractCashierData 计算销售订单和退货订单汇总后的支付数据
func subtractCashierData(cashierData, rejectedCashierData []ErpOrderCashier) []ErpOrderCashier {
	// 将退货数据转换为 map 便于查找
	rejectedMap := make(map[uint32]float64)
	for _, rejected := range rejectedCashierData {
		rejectedMap[rejected.CashierId] = rejected.Amount
	}

	// 减去退货数据的金额
	var result []ErpOrderCashier
	for _, cashier := range cashierData {
		adjustedAmount := cashier.Amount - rejectedMap[cashier.CashierId]
		//// 如果金额为负数则视为零
		//if adjustedAmount < 0 {
		//	adjustedAmount = 0
		//}
		result = append(result, ErpOrderCashier{
			CashierId: cashier.CashierId,
			Name:      cashier.Name,
			Amount:    adjustedAmount,
		})
	}

	return result
}

// QueryReceiptData 查询小票数据
func QueryReceiptData(req *ErpOrderDeleteReq, c *gin.Context) (*ErpOrderReceiptDataResp, error) {
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		logger.Errorf("err:%#v", err)
		return nil, err
	}

	var orders []ErpOrder
	err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orders).Error
	if err != nil {
		logger.Error("erp_order find err:", logger.Field("err", err))
		return nil, err
	}

	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		// 校验入参门店是否包含在用户所有门店中，是否过期
		if !CheckUserStore(orders[0].StoreId, sysUser) {
			return nil, errors.New("操作失败：您没有该门店权限")
		}
	}

	// add 2024-12-25 方便领取厂家激励；操作路径：开单不审核，然后打印小票
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员" ||
		tools.GetRoleName(c) == "manager" || tools.GetRoleName(c) == "经理" ||
		tools.GetRoleName(c) == "yunying" || tools.GetRoleName(c) == "运营") {
		if orders[0].PayStatus != HavePaid {
			logger.Error("订单未支付")
			return nil, errors.New("该订单未支付，不支持打印小票")
		}
	}

	// 添加付款、销售员、商品信息
	erpOrderListSetCommodity(orders)
	erpOrderListSetCashier(orders)
	erpOrderListSetSalesman(orders)

	// 查询门店信息
	storeInfo, err := GetStore(orders[0].StoreId)
	if err != nil {
		logger.Error("QueryReceiptData GetStore err:", logger.Field("err", err))
		return nil, err
	}

	// 记录打印信息
	if orders[0].IsPrint != HavePrinted {
		err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Updates(map[string]interface{}{
			"is_print": HavePrinted,
		}).Error
		if err != nil {
			return nil, err
		}
	}

	err = orm.Eloquent.Model(&ErpOrder{}).
		Where("bill_sn = ? ", req.BillSn).
		UpdateColumn("print_count", gorm.Expr("print_count + ?", 1)).Error
	if err != nil {
		return nil, err
	}

	order := orders[0]
	var salesName string
	if len(order.Salesman) != 0 {
		// 遍历销售员信息，拼接名称
		var names []string
		for _, item := range order.Salesman {
			names = append(names, item.Name)
		}
		salesName = strings.Join(names, "，") // 使用中文逗号拼接
	}

	resp := new(ErpOrderReceiptDataResp)
	resp.StoreName = order.StoreName
	resp.Barcode = order.BillSn
	resp.OddNum = order.BillSn
	resp.Time = orders[0].UpdatedAt
	resp.CollectS = salesName

	if order.StoreId == 29 { // 大运哈曼店才打印商品串码
		resp.IsShowImei = 1
	}

	var categoryList []uint32
	if sysUser.CooperativeBusinessId == 1 { // 迪为特殊处理
		// 获取任天堂游戏的子分类
		categoryList, _ = GetSubcategoryIds(4)
	}

	var totalCouponAmount float64
	commodityMap := make(map[string]TableData, 0)
	for i, item := range order.Commodities {
		var tableData TableData
		if Contains(categoryList, item.ErpCategoryId) {
			category, err := GetCategoryById(4)
			if err != nil {
				tableData.Name = "任天堂游戏"
			} else {
				tableData.Name = category.Name
			}
		} else {
			tableData.Name = item.ErpCommodityName
		}
		tableData.SL = uint32(item.Count)
		tableData.DJ = item.RetailPrice
		tableData.JE = float64(item.Count) * item.RetailPrice
		tableData.IMEI = item.IMEI

		key := fmt.Sprintf("commodity_%d", i)
		commodityMap[key] = tableData

		resp.TotalAmount += item.SaleDiscount
		resp.IntegrationAmount += item.VmDiscount

		if order.MemberType != ErpOrderMemberTypeGeneral {
			resp.MembersAmount += item.MemberDiscount
		}
		totalCouponAmount += item.CouponDiscount
	}

	resp.ChandiseObj = commodityMap
	resp.TotalRetailP = order.TotalRetailPrice
	resp.TotalNum = uint32(order.TotalCount)
	resp.ToDealWith = order.TotalAmount
	resp.CouponAmount = totalCouponAmount

	cashierMap := make(map[string]ErpOrderCashier, 0)
	for i, item := range order.Cashiers {
		key := fmt.Sprintf("payment_%d", i)
		cashierMap[key] = item
	}

	resp.ModeOfPayment = cashierMap
	resp.ActualPayment = order.TotalAmount
	resp.Tel = order.Tel
	if order.MemberType != ErpOrderMemberTypeGeneral {
		resp.Uid = order.Uid
	}
	resp.StoreTel = storeInfo.Tel
	resp.StoreAddress = storeInfo.Address

	return resp, nil
}

// CreateErpOrder 创建零售订单
func CreateErpOrder(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) {
	for i, _ := range req.ErpOrderCommodities {
		req.ErpOrderCommodities[i].ID = 0
	}
	// 校验订单数据
	erpOrder, err := checkOrderData(req, c)
	if err != nil {
		return nil, err
	}
	// 四舍五入
	tools.RoundFloatFields(req)

	begin := orm.Eloquent.Begin()
	if req.Tel != "" {
		// 0-创建用户信息
		userInfo, err := GetUserInfoByTel(req.Tel)
		if err != nil {
			logger.Error("checkOrderData GetUserInfoByTel err:", logger.Field("err", err))
			return nil, errors.New("操作失败:" + err.Error())
		}

		if userInfo.Uid == 0 {
			user := UserInfo{
				Uid:                   uint32(erpOrder.Uid),
				Tel:                   req.Tel,
				StoreId:               uint64(req.StoreId),
				UserType:              UserTypeConsumer,    // 用户
				OpenMemberLevel:       MemberLevelConsumer, // 普通用户
				MemberLevel:           MemberLevelConsumer, // 普通用户
				CooperativeBusinessId: 1,                   // 合作商默认为1
			}
			err = begin.Create(&user).Error
			if err != nil {
				begin.Rollback()
				logger.Error("create user err:", logger.Field("err", err))
				return nil, errors.New("操作失败:" + err.Error())
			}
		}
	}

	// 记录用户会员类型
	if erpOrder.Uid != 0 {
		erpOrder.UserType, _ = GetUserType(erpOrder.Uid)
	}

	// 1-创建零售订单
	err = begin.Create(erpOrder).Error
	if err != nil {
		begin.Rollback()
		logger.Error("create erp_order err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	// 销售信息添加零售订单id
	for i, _ := range req.Salesman {
		req.Salesman[i].ErpOrderId = erpOrder.ID
	}
	// 2-创建销售员信息记录
	err = begin.Create(&req.Salesman).Error
	if err != nil {
		begin.Rollback()
		logger.Error("Create erp_order_sales err")
		return nil, errors.New("操作失败:" + err.Error())
	}

	// 支付方式添加零售订单id
	var orderPayWay ErpOrderPayWay
	var orderPayWayList []ErpOrderPayWay
	for _, item := range req.Cashiers {
		orderPayWay.ErpOrderId = erpOrder.ID
		orderPayWay.CashierId = item.CashierId
		orderPayWay.Name = item.Name
		orderPayWay.Amount = item.Amount
		orderPayWayList = append(orderPayWayList, orderPayWay)
	}
	// 3-创建支付方式记录
	err = begin.Create(&orderPayWayList).Error
	if err != nil {
		begin.Rollback()
		logger.Error("Create erp_order_pay_way err")
		return nil, errors.New("操作失败:" + err.Error())
	}

	// 订单商品表信息添加零售订单id
	for i, _ := range req.ErpOrderCommodities {
		req.ErpOrderCommodities[i].ErpOrderId = erpOrder.ID
	}

	// 4-创建商品订单信息
	err = begin.Create(&req.ErpOrderCommodities).Error
	if err != nil {
		begin.Rollback()
		logger.Error("Create erp_order_commodity err")
		return nil, errors.New("操作失败:" + err.Error())
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("commit err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	erpOrder.Commodities = req.ErpOrderCommodities
	erpOrder.Cashiers = req.Cashiers
	erpOrder.Salesman = req.Salesman

	return erpOrder, nil
}

// EditErpOrder 编辑订单
func EditErpOrder(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) {
	var orderInfo ErpOrder
	err := orm.Eloquent.Table("erp_order").Where("bill_sn=?", req.BillSn).Find(&orderInfo).Error
	if err != nil {
		logger.Error("query erp_order err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	if orderInfo.State != ErpOrderStateUnAudit {
		logger.Error("EditErpOrder err:", logger.Field("err", err))
		return nil, errors.New("订单状态不是待审核，操作失败")
	}

	// 校验订单数据
	erpOrder, err := checkOrderData(req, c)
	if err != nil {
		return nil, err
	}

	erpOrder.ID = orderInfo.ID
	erpOrder.BillSn = orderInfo.BillSn // 编辑的订单单据号不能改变
	begin := orm.Eloquent.Begin()
	// 1-更新零售订单
	//err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).Updates(erpOrder).Error
	err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).Omit("created_at").Save(&erpOrder).Error
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_order err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	// 2-更新零售订单商品信息
	err = updateCommodityData(begin, orderInfo.ID, req)
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_order_commodity err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	// 3-更新销售员信息记录
	err = updateSalesData(begin, orderInfo.ID, req)
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_order_sales err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	// 4-更新支付方式记录
	err = updatePayWayData(begin, orderInfo.ID, req)
	if err != nil {
		begin.Rollback()
		logger.Error("update erp_order_pay_way err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	err = begin.Commit().Error
	if err != nil {
		begin.Rollback()
		logger.Error("commit err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	erpOrder.Commodities = req.ErpOrderCommodities
	erpOrder.Cashiers = req.Cashiers
	erpOrder.Salesman = req.Salesman

	return erpOrder, nil
}

// CheckUserStore 校验用户门店是否包含在门店数据中且未过期
func CheckUserStore(userStoreId uint32, sysUser *SysUser) bool {
	// 解析门店数据
	var stores []StoreInfo
	if err := json.Unmarshal([]byte(sysUser.StoreData), &stores); err != nil {
		return false
	}

	// 查找用户门店并检查是否过期
	for _, store := range stores {
		if store.StoreID == int(userStoreId) {
			expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
			if err != nil {
				return false
			}
			expireTime = expireTime.Add(24*time.Hour - time.Second)
			// 如果过期时间在当前时间之后，则未过期
			if expireTime.After(time.Now()) {
				return true
			}
			return false
		}
	}

	// 没有找到对应的门店
	return false
}

// AuthUserStore 校验是否有某个门店的权限
func AuthUserStore(c *gin.Context, storeId uint32) error {
	// 非管理员才判断所属门店
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return err
		}

		// 校验入参门店是否包含在用户所有门店中，是否过期
		if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
			if !CheckUserStore(storeId, sysUser) {
				return errors.New("操作失败：您没有该门店权限")
			}
		}
	}

	return nil
}

// HasPermission 校验角色权限：以下角色支持零售开单修改零售价 < 商品最低零售价
func HasPermission(c *gin.Context) bool {
	// 获取用户角色
	roleName := tools.GetRoleName(c)

	// 允许的角色列表
	allowedRoles := map[string]bool{
		"manager": true, "经理": true,
		"cg": true, "采购": true,
		"yunying": true, "运营": true,
		"admin": true, "系统管理员": true,
	}

	// 检查用户角色是否在允许列表中
	if _, ok := allowedRoles[roleName]; !ok {
		return false
	}

	return true
}

// checkOrderData 校验订单数据
func checkOrderData(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) {
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		return nil, errors.New("操作失败:" + err.Error())
	}
	// 校验入参门店是否包含在用户所有门店中，是否过期
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		if !CheckUserStore(req.StoreId, sysUser) {
			return nil, errors.New("操作失败：您没有该门店权限")
		}
	}

	var rejectedOrderSaleId uint32
	if req.RetailType == RetailTypeSale {
		// 校验商品是否有库存,是否是对应门店库存商品
		err = CheckOrderCommodityStock(req)
		if err != nil {
			return nil, err
		}
	} else { // 零售退货单，需校验退货商品是否是本门店售卖商品，同一个退货单中只能添加同一销售订单的商品
		rejectedOrderSaleId, err = checkRejectedOrderRule(req)
		if err != nil {
			return nil, err
		}
	}

	jCashier, err := json.Marshal(req.Cashiers)
	if err != nil {
		logger.Error("cashiers marshal err:", logger.Field("err", err))
		return nil, errors.New("操作失败:" + err.Error())
	}

	var userUid uint32
	if req.Tel != "" {
		// 通过手机号查询用户id，如果没有，则新建一个用户id
		userInfo, err := GetUserInfoByTel(req.Tel)
		if err != nil {
			logger.Error("checkOrderData GetUserInfoByTel err:", logger.Field("err", err))
			return nil, errors.New("操作失败:" + err.Error())
		}

		if userInfo.Uid == 0 {
			userUid = CreateUid() // 没有用户则新建
		} else {
			userUid = userInfo.Uid
		}
	}

	erpOrder := &ErpOrder{
		BillSn:           NewErpBillSn(),
		RetailType:       req.RetailType,
		Uid:              int(userUid),
		Tel:              req.Tel,
		StoreId:          req.StoreId,
		StoreName:        req.StoreName,
		MakerId:          uint32(sysUser.UserId),
		MakerName:        sysUser.NickName,
		MakerTime:        time.Now(),
		CashierList:      string(jCashier),
		MemberType:       req.MemberType,
		State:            ErpOrderStateUnAudit,
		PayStatus:        NoCreatePayOrder,
		IsPrint:          NoPrint, // 未打印
		PrintCount:       0,       // 打印次数
		TotalRetailPrice: req.TotalRetailPrice,
		VmCount:          req.VmAmount,
	}

	if req.RetailType == RetailTypeRejected {
		erpOrder.SaleOrderId = rejectedOrderSaleId
	}

	commodityMap := make(map[uint32]ErpStockCommodity)
	imeiCommodityMap := make(map[string]ErpStockCommodity)
	if req.RetailType == RetailTypeSale { // 零售订单，查商品表信息
		commodityIds := make([]uint32, 0, len(req.ErpOrderCommodities)) // 非串码商品的商品id列表
		imeiList := make([]string, 0, len(req.ErpOrderCommodities))     // 串码商品的串码列表
		for i, _ := range req.ErpOrderCommodities {
			if req.ErpOrderCommodities[i].IMEIType == 1 { // 非串码商品
				commodityIds = append(commodityIds, req.ErpOrderCommodities[i].ErpCommodityId)
			} else { // 串码商品
				imeiList = append(imeiList, req.ErpOrderCommodities[i].IMEI)
			}
		}

		// 商品的相关价格以库存表为准，商品表的价格除了最低零售价，其他只是参考
		// 串码商品直接查询；非串码商品查询库存时间最久的商品
		var commodities []ErpStockCommodity
		if len(imeiList) != 0 {
			err := orm.Eloquent.Table("erp_stock_commodity").Where("imei IN (?) and state = ? "+
				"and store_id = ?", imeiList, InStock, req.StoreId).
				Find(&commodities).Error
			if err != nil {
				logger.Error("get commodities err:", logger.Field("err", err))
				return nil, errors.New("操作失败:" + err.Error())
			}

			for i, _ := range commodities { // 串码
				imeiCommodityMap[commodities[i].IMEI] = commodities[i]
			}
		}

		if len(commodityIds) != 0 {
			commodities = nil
			err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id IN (?) and state = ? "+
				"and store_id = ?", commodityIds, InStock, req.StoreId).
				Find(&commodities).Error
			if err != nil {
				logger.Error("get commodities err:", logger.Field("err", err))
				return nil, errors.New("操作失败:" + err.Error())
			}

			for _, commodity := range commodities { // 非串码
				v, ok := commodityMap[commodity.ErpCommodityId]
				if !ok { // 没有则直接添加
					commodityMap[commodity.ErpCommodityId] = commodity
				} else {
					// 已有则比较非串码的入库时间，添加入库时间最早的商品
					if commodity.FirstStockTime.Before(v.FirstStockTime) {
						commodityMap[commodity.ErpCommodityId] = commodity
					}
				}
			}
		}

		// 更新用户信息表，添加首次零售订单时间
		if req.Tel != "" {
			SetUserInfo(req.Tel)
		}
	}

	bCheckFlag := false
	// 校验商品相关金额是否符合要求
	var respErpOrderCommodities []ErpOrderCommodity
	for i, _ := range req.ErpOrderCommodities {
		if req.RetailType == RetailTypeRejected { // 零售退货订单
			if req.ErpOrderCommodities[i].RejectedPrice > req.ErpOrderCommodities[i].Amount { // 退货单价不能大于实际零售价
				logger.Error("rejected price gt retail price ")
				return nil, errors.New("退货单价大于实际零售价")
			}
			if int32(req.ErpOrderCommodities[i].RejectedCount) > req.ErpOrderCommodities[i].Count { // 退货数量不能大于销售数量
				logger.Error("rejected count gt retail count ")
				return nil, errors.New("退货数量大于销售数量")
			}

			// 更新订单表总退款金额和数量 备注：2024-03-12 订单表没有退款金额的字段，默认都使用订单金额字段，根据订单类型判断是零售或退款
			//erpOrder.RejectedTotalAmount += req.ErpOrderCommodities[i].RejectedAmount
			//erpOrder.RejectedTotalCount += req.ErpOrderCommodities[i].RejectedCount
			erpOrder.TotalAmount += req.ErpOrderCommodities[i].RejectedAmount
			erpOrder.TotalCount += int32(req.ErpOrderCommodities[i].Count)

			// 订单总优惠
			erpOrder.TotalDiscount += req.ErpOrderCommodities[i].MemberDiscount + req.ErpOrderCommodities[i].SaleDiscount

			// 销售毛利：实际退货金额-采购金额（需要先取负值，然后再计算），结果等同于：采购金额-实际退货金额
			salesProfit := req.ErpOrderCommodities[i].RejectedAmount - req.ErpOrderCommodities[i].WholesalePrice*float64(req.ErpOrderCommodities[i].Count)

			// 员工毛利
			StaffProfit := salesProfit - req.ErpOrderCommodities[i].StaffCostPrice*float64(req.ErpOrderCommodities[i].Count)

			req.ErpOrderCommodities[i].SalesProfit = salesProfit // 销售毛利
			req.ErpOrderCommodities[i].StaffProfit = StaffProfit // 员工毛利
			erpOrder.TotalSalesProfit += salesProfit
			erpOrder.TotalStaffProfit += StaffProfit

			// 单个商品的销售毛利
			req.ErpOrderCommodities[i].SalesProfit = salesProfit / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品的员工毛利
			req.ErpOrderCommodities[i].StaffProfit = StaffProfit / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品的零售优惠
			req.ErpOrderCommodities[i].SaleDiscount = req.ErpOrderCommodities[i].SaleDiscount / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品的会员优惠
			req.ErpOrderCommodities[i].MemberDiscount = req.ErpOrderCommodities[i].MemberDiscount / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品实收金额
			req.ErpOrderCommodities[i].ReceivedAmount = req.ErpOrderCommodities[i].ReceivedAmount / float64(req.ErpOrderCommodities[i].Count)
			//// 单个商品退货金额
			//req.ErpOrderCommodities[i].RejectedAmount = req.ErpOrderCommodities[i].RejectedAmount / float64(req.ErpOrderCommodities[i].Count)

			for j := 0; j < int(req.ErpOrderCommodities[i].RejectedCount); j++ {
				stockIdList, _ := stringToIntArray(req.ErpOrderCommodities[i].ErpStockCommodityID)
				temp := req.ErpOrderCommodities[i]
				temp.RejectedAmount = req.ErpOrderCommodities[i].RejectedAmount / float64(req.ErpOrderCommodities[i].RejectedCount)
				temp.Count = 1
				temp.RejectedCount = 1
				if len(stockIdList) > j {
					temp.ErpStockCommodityID = fmt.Sprintf("%d", stockIdList[j])
				}
				respErpOrderCommodities = append(respErpOrderCommodities, temp)
			}
		} else if req.RetailType == RetailTypeSale { // 零售订单
			// 校验是否使用优惠券，如果使用判断是否符合规则
			if req.ErpOrderCommodities[i].CouponID != 0 {
				// 判断优惠券抵扣金额是否正确
				var userCoupon UserCoupon
				err = orm.Eloquent.Table("user_coupon").Where("id = ?", req.ErpOrderCommodities[i].CouponID).
					Find(&userCoupon).Error
				if err != nil || err == RecordNotFound {
					return nil, errors.New("操作失败，未查询到优惠券信息：" + err.Error())
				}

				var coupon Coupon
				err = orm.Eloquent.Table("coupon").Where("id = ?", userCoupon.CouponId).Find(&coupon).Error
				if err != nil || err == RecordNotFound {
					return nil, errors.New("操作失败，未查询到优惠券信息：" + err.Error())
				}

				switch userCoupon.State {
				case 2: // 已使用
					return nil, errors.New(fmt.Sprintf("操作失败：优惠券[%s]已使用，请重新选择",
						coupon.Name))
				case 3: // 已过期
					return nil, errors.New(fmt.Sprintf("操作失败：优惠券[%s]已过期，请重新选择",
						coupon.Name))
				}

				if userCoupon.Value/100 != uint32(req.ErpOrderCommodities[i].CouponDiscount) {
					return nil, errors.New("操作失败：当前抵扣金额与优惠券金额不符")
				}

				// 判断优惠券可用商品分类是否跟当前商品分类是否符合
				if !(CheckCouponCategory(userCoupon.CategoryNumber, req.ErpOrderCommodities[i].ErpCategoryId)) {
					return nil, errors.New(fmt.Sprintf("操作失败：当前商品[%s]与优惠券可用商品不符",
						req.ErpOrderCommodities[i].ErpCommodityName))
				}
			}

			var v ErpStockCommodity
			var ok bool
			if req.ErpOrderCommodities[i].IMEIType == 1 { // 非串码商品
				v, ok = commodityMap[req.ErpOrderCommodities[i].ErpCommodityId]
				if !ok {
					return nil, errors.New("遍历商品信息报错")
				}
			} else { // 串码商品
				v, ok = imeiCommodityMap[req.ErpOrderCommodities[i].IMEI]
				if !ok {
					return nil, errors.New("遍历商品信息报错")
				}
			}

			// 赠送类型商品进行校验，最低零售价为0才能赠送
			if req.ErpOrderCommodities[i].PresentType == 2 && v.MinRetailPrice != 0 {
				logger.Error("PresentType is 2, MinRetailPrice no equal 0")
				return nil, errors.New("赠送商品最低零售价不为0，不符合赠送条件，请检查")
			}
			if req.ErpOrderCommodities[i].SalePrice < v.MinRetailPrice { //零售价不能低于最低零售价
				if !HasPermission(c) {
					logger.Error("SalePrice less than MinRetailPrice")
					return nil, errors.New("零售价不能低于最低零售价，请检查")
				}
			}
			if req.ErpOrderCommodities[i].PresentType == 1 &&
				req.ErpOrderCommodities[i].CouponDiscount < req.ErpOrderCommodities[i].Amount { // 有非赠送商品
				bCheckFlag = true
			}

			req.ErpOrderCommodities[i].ErpCommodityId = v.ErpCommodityId     // 商品id
			req.ErpOrderCommodities[i].ErpCommodityName = v.ErpCommodityName // 商品名称
			req.ErpOrderCommodities[i].ErpCategoryId = v.ErpCategoryId       // 分类id
			req.ErpOrderCommodities[i].ErpCategoryName = v.ErpCategoryName   // 分类名称
			req.ErpOrderCommodities[i].ErpSupplierId = v.ErpSupplierId       // 供应商id
			req.ErpOrderCommodities[i].ErpSupplierName = v.ErpSupplierName   // 供应商名称
			req.ErpOrderCommodities[i].RetailPrice = v.RetailPrice           // 指导零售价
			req.ErpOrderCommodities[i].StaffCostPrice = v.StaffCostPrice     // 员工成本价加价
			req.ErpOrderCommodities[i].WholesalePrice = v.WholesalePrice     // 指导采购价

			// 销售毛利 备注：产品说有亏本销售的情况，不用判断毛利是否<0
			salesProfit := req.ErpOrderCommodities[i].ReceivedAmount -
				req.ErpOrderCommodities[i].WholesalePrice*float64(req.ErpOrderCommodities[i].Count)
			// 员工毛利
			StaffProfit := salesProfit - req.ErpOrderCommodities[i].StaffCostPrice*float64(req.ErpOrderCommodities[i].Count)
			// 单个商品的销售毛利
			req.ErpOrderCommodities[i].SalesProfit = salesProfit / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品的员工毛利
			req.ErpOrderCommodities[i].StaffProfit = StaffProfit / float64(req.ErpOrderCommodities[i].Count)

			// 订单总销售毛利
			erpOrder.TotalSalesProfit += salesProfit
			// 订单总员工毛利
			erpOrder.TotalStaffProfit += StaffProfit
			// 更新订单表总金额和数量
			erpOrder.TotalAmount += req.ErpOrderCommodities[i].ReceivedAmount
			erpOrder.TotalCount += int32(req.ErpOrderCommodities[i].Count)

			// 单个商品的零售优惠
			req.ErpOrderCommodities[i].SaleDiscount = req.ErpOrderCommodities[i].SaleDiscount / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品的会员优惠
			req.ErpOrderCommodities[i].MemberDiscount = req.ErpOrderCommodities[i].MemberDiscount / float64(req.ErpOrderCommodities[i].Count)
			// 单个商品实收金额
			req.ErpOrderCommodities[i].ReceivedAmount = req.ErpOrderCommodities[i].ReceivedAmount / float64(req.ErpOrderCommodities[i].Count)

			if req.ErpOrderCommodities[i].Amount == 0 &&
				req.ErpOrderCommodities[i].CouponDiscount > req.ErpOrderCommodities[i].SalePrice { // 实际零售金额为0且使用了优惠券
				req.ErpOrderCommodities[i].MemberDiscount = 0
				req.ErpOrderCommodities[i].SaleDiscount = 0
				req.ErpOrderCommodities[i].CouponDiscount = req.ErpOrderCommodities[i].SalePrice
			}

			for j := 0; j < int(req.ErpOrderCommodities[i].Count); j++ {
				temp := req.ErpOrderCommodities[i]
				temp.Count = 1
				respErpOrderCommodities = append(respErpOrderCommodities, temp)
			}
		}
	}

	if erpOrder.TotalAmount == 0 && bCheckFlag {
		return nil, errors.New("订单包含非赠送商品，实收金额不能为0")
	}

	req.ErpOrderCommodities = respErpOrderCommodities
	tools.RoundFloatFields(erpOrder)

	// 判断线上支付金额是否>0
	if req.RetailType == RetailTypeSale {
		erpOrder.TotalAmount = erpOrder.TotalAmount - float64(erpOrder.VmCount/100)
		onlinePayFlag := false
		onlinePayAmount := erpOrder.TotalAmount
		var nWaitPayAmount float64
		for _, item := range req.Cashiers {
			if item.CashierId == 1 { // 线上支付
				onlinePayFlag = true
			} else {
				onlinePayAmount -= item.Amount
			}
			nWaitPayAmount += item.Amount
		}
		if onlinePayFlag && onlinePayAmount <= 0 { // 线上支付且金额小于0则报错
			logger.Error("线上支付金额小于0")
			return nil, errors.New("扫码付金额需>0")
		}
		if nWaitPayAmount > erpOrder.TotalAmount { // 收款金额大于订单金额
			logger.Error("收款金额大于订单金额")
			return nil, errors.New("收款金额大于订单金额")
		}
		if nWaitPayAmount < erpOrder.TotalAmount { // 收款金额小于订单金额
			logger.Error("收款金额小于订单金额")
			return nil, errors.New("收款金额小于订单金额")
		}
	}

	// 添加销售员相关信息
	jSalesman, err := req.GetSalesmanList()
	if err != nil {
		return nil, errors.New("操作失败:" + err.Error())
	}
	erpOrder.SalesmanList = jSalesman

	// 添加门店提成
	store, err := GetStore(req.StoreId)
	if err != nil {
		return nil, errors.New("操作失败:" + err.Error())
	}
	erpOrder.StorePer = erpOrder.TotalStaffProfit * (store.SalesCommRate / 100)
	erpOrder.StorePer = math.Round(erpOrder.StorePer*100) / 100

	// 订单总优惠
	if req.RetailType == RetailTypeSale {
		erpOrder.TotalDiscount = math.Round((erpOrder.TotalRetailPrice-erpOrder.TotalAmount)*100) / 100
	}

	return erpOrder, nil
}

// CheckOrderCommodityStock 校验商品是否有库存
func CheckOrderCommodityStock(req *ErpOrderCreateReq) error {
	if len(req.ErpOrderCommodities) != 0 {
		// 统计串码和非串码商品信息
		commodityMap := make(map[uint32]uint32)     // 记录非串码商品id及其数量
		imeiCommodityMap := make(map[uint32]string) // 记录串码商品id及其串码
		commodityNameMap := make(map[uint32]string) // 记录商品名称
		for _, commodity := range req.ErpOrderCommodities {
			if commodity.IMEIType == 1 {
				_, ok := commodityMap[commodity.ErpCommodityId]
				if !ok { // 没有则直接添加
					commodityMap[commodity.ErpCommodityId] = uint32(commodity.Count)
				} else {
					commodityMap[commodity.ErpCommodityId] += uint32(commodity.Count)
				}
				commodityNameMap[commodity.ErpCommodityId] = commodity.ErpCommodityName
			} else {
				imeiCommodityMap[commodity.ErpCommodityId] = commodity.IMEI
				commodityNameMap[commodity.ErpCommodityId] = commodity.ErpCommodityName
			}
		}

		// 查询库存表，确认是否有库存
		if len(commodityMap) != 0 { // 查询非串码商品库存
			var count int64
			for commodityId, nCount := range commodityMap {
				err := orm.Eloquent.Table("erp_stock_commodity").
					Where("erp_commodity_id = ? and store_id = ? and state = ? and imei_type = ?",
						commodityId, req.StoreId, InStock, NoIMEICommodity).
					Count(&count).Error
				if err != nil {
					return err
				}

				if count < int64(nCount) {
					// 获取商品名称
					return errors.New("商品" + "[" + commodityNameMap[commodityId] + "]库存不足")
				}
			}
		}

		if len(imeiCommodityMap) != 0 { // 查询串码商品库存
			for commodityId, imei := range imeiCommodityMap {
				var imeiStockCommodity ErpStockCommodity
				err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", imei, InStock).
					Find(&imeiStockCommodity).Error
				if err != nil {
					return err
				}
				if imeiStockCommodity.ID == 0 {
					// 获取商品名称
					return errors.New("商品" + "[" + commodityNameMap[commodityId] + "]库存不足")
				}

				if imeiStockCommodity.StoreId != req.StoreId {
					return errors.New(commodityNameMap[commodityId] + "商品非所选门店库存，请检查")
				}
			}
		}

	} else {
		return errors.New("该零售订单未添加商品")
	}

	return nil
}

// 退货校验
// （1）校验退货商品销售时的手机号与当前填写的手机号是否相同，不匹配报错：所退商品的历史订单手机号与当前不符。
// （2）校验商品是否是当前用户购买
// （3）校验退货商品是否是本门店售卖商品
// （4）同一个退货单中只能添加同一销售订单的商品
func checkRejectedOrderRule(req *ErpOrderCreateReq) (uint32, error) {
	if req.RetailType != RetailTypeRejected {
		return 0, errors.New("订单类型有误，非退货订单")
	}

	if len(req.ErpOrderCommodities) == 0 {
		return 0, errors.New("未添加退货商品")
	}

	var salesId uint32
	rejectOrderSalesMap := make(map[string]bool)
	for _, item := range req.ErpOrderCommodities {
		// 查询退货商品之前的销售情况
		if item.IMEIType == NoIMEICommodity {
			var saleOrderId uint32
			if req.Tel != "" { //非串码商品，且手机号不为空才校验
				var commodities []ErpOrderCommodity
				err := orm.Eloquent.Table("erp_order_commodity").
					Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id ").
					Where("erp_order_commodity.erp_commodity_id = ? and erp_order.store_id = ? "+
						"and erp_order.retail_type = ? and erp_order.pay_status = ? and erp_order.tel = ?",
						item.ErpCommodityId, req.StoreId, RetailTypeSale, HavePaid, req.Tel).
					Find(&commodities).Order("audit_time DESC").Error
				if err != nil {
					logger.Error("query erp_order_commodity err:", logger.Field("err", err))
					return 0, errors.New("操作失败:" + err.Error())
				}

				if len(commodities) == 0 {
					return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售情况", item.ErpCommodityName))
				}

				saleOrderId = commodities[0].ErpOrderId
			} else {
				saleOrderId = item.ErpOrderId
			}

			var orderInfo ErpOrder
			err := orm.Eloquent.Table("erp_order").Where("id = ?", saleOrderId).
				Find(&orderInfo).Error
			if err != nil {
				logger.Error("query erp_order err:", logger.Field("err", err))
				return 0, errors.New("操作失败:" + err.Error())
			}
			if orderInfo.BillSn == "" {
				return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售订单", item.ErpCommodityName))
			}

			rejectOrderSalesMap[orderInfo.BillSn] = true
			if len(rejectOrderSalesMap) > 1 {
				return 0, errors.New("只可添加相同零售订单的商品")
			}
			salesId = orderInfo.ID

		} else { // 串码商品
			if item.IMEI == "" {
				return 0, errors.New("退货商品串码为空")
			}
			var commodities []ErpOrderCommodity
			err := orm.Eloquent.Table("erp_order_commodity").
				Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id ").
				Where("erp_order_commodity.imei = ? and erp_order.retail_type = ? and erp_order.pay_status = ?",
					item.IMEI, RetailTypeSale, HavePaid).
				Order("erp_order_id DESC").Find(&commodities).Error
			if err != nil {
				logger.Error("query erp_order_commodity err:", logger.Field("err", err))
				return 0, errors.New("操作失败:" + err.Error())
			}

			if len(commodities) == 0 {
				return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售情况", item.ErpCommodityName))
			}

			var orderInfo ErpOrder
			err = orm.Eloquent.Table("erp_order").Where("id = ?", commodities[0].ErpOrderId).
				Find(&orderInfo).Error
			if err != nil {
				logger.Error("query erp_order err:", logger.Field("err", err))
				return 0, errors.New("操作失败:" + err.Error())
			}
			if orderInfo.BillSn == "" {
				return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售订单", item.ErpCommodityName))
			}

			if orderInfo.Tel != req.Tel {
				return 0, errors.New(fmt.Sprintf("所退商品[%s]的历史订单手机号与当前不符", item.ErpCommodityName))
			}

			if orderInfo.StoreId != req.StoreId {
				return 0, errors.New(fmt.Sprintf("[%s]非当前门店所售商品，需前往对应门店退货", item.ErpCommodityName))
			}

			rejectOrderSalesMap[orderInfo.BillSn] = true
			if len(rejectOrderSalesMap) > 1 {
				return 0, errors.New("只可添加相同零售订单的商品")
			}
			salesId = orderInfo.ID
		}
	}

	return salesId, nil
}

// updateCommodityData 更新订单商品信息
func updateCommodityData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
	// 查询现有的零售订单信息
	var commodities []ErpOrderCommodity
	err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", orderId).Find(&commodities).Error
	if err != nil {
		logger.Error("query erp_order_commodity err:", logger.Field("err", err))
		return errors.New("操作失败:" + err.Error())
	}

	// 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.ErpOrderCommodities {
		req.ErpOrderCommodities[i].ID = 0
		if req.ErpOrderCommodities[i].ErpOrderId == 0 || req.ErpOrderCommodities[i].ErpOrderId != orderId { //发现前端有时会没传，后端打补丁
			req.ErpOrderCommodities[i].ErpOrderId = orderId
		}
	}

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

	return nil
}

// updateSalesData 更新订单销售员信息
func updateSalesData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
	// 查询现有的零售订单销售员信息
	var orderSales []ErpOrderSales
	err := orm.Eloquent.Table("erp_order_sales").Where("erp_order_id = ?", orderId).Find(&orderSales).Error
	if err != nil {
		logger.Error("query erp_order_sales err:", logger.Field("err", err))
		return errors.New("操作失败:" + err.Error())
	}

	// 1-删除所有的零售订单支付方式
	if len(orderSales) != 0 {
		err = gdb.Delete(&orderSales).Error
		if err != nil {
			logger.Error("更新订单销售员信息-删除 error")
			return errors.New("操作失败:" + err.Error())
		}
	}

	var newOrderSales []ErpOrderSales
	for _, reqSales := range req.Salesman {
		reqSales.ID = 0
		if reqSales.ErpOrderId == 0 {
			reqSales.ErpOrderId = orderId
		}
		newOrderSales = append(newOrderSales, reqSales)
	}

	// 2-新增所有的零售订单支付方式
	if len(newOrderSales) != 0 {
		err = gdb.Create(&newOrderSales).Error
		if err != nil {
			logger.Error("更新订单销售员信息-新增 error")
			return errors.New("操作失败:" + err.Error())
		}
	}

	return nil
}

// updatePayWayData 更新零售订单支付方式记录表
func updatePayWayData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
	// 查询现有的零售订单销售员信息
	var orderPayWay []ErpOrderPayWay
	err := orm.Eloquent.Table("erp_order_pay_way").Where("erp_order_id = ?", orderId).Find(&orderPayWay).Error
	if err != nil {
		logger.Error("query erp_order_sales err:", logger.Field("err", err))
		return errors.New("操作失败:" + err.Error())
	}

	// 1-删除所有的零售订单支付方式
	if len(orderPayWay) != 0 {
		err = gdb.Delete(&orderPayWay).Error
		if err != nil {
			logger.Error("更新零售订单支付方式-删除 error")
			return errors.New("操作失败:" + err.Error())
		}
	}

	var newOrderPayWay []ErpOrderPayWay
	for _, reqPayWay := range req.Cashiers {
		payWay := ErpOrderPayWay{
			ErpOrderId: orderId,
			CashierId:  reqPayWay.CashierId,
			Name:       reqPayWay.Name,
			Amount:     reqPayWay.Amount,
		}
		if payWay.ErpOrderId == 0 {
			payWay.ErpOrderId = orderId
		}
		newOrderPayWay = append(newOrderPayWay, payWay)
	}

	// 2-新增所有的零售订单支付方式
	if len(newOrderPayWay) != 0 {
		err = gdb.Create(&newOrderPayWay).Error
		if err != nil {
			logger.Error("更新零售订单支付方式-新增 error")
			return errors.New("操作失败:" + err.Error())
		}
	}

	return nil
}

// ErpOrderDailyReportReq 经营日报表入参
type ErpOrderDailyReportReq struct {
	StartTime string `json:"start_time"` // 开始时间
	EndTime   string `json:"end_time"`   // 结束时间
	PageIndex int    `json:"pageIndex"`  // 页码
	PageSize  int    `json:"pageSize"`   // 页面条数
}

// ErpOrderDailyReportResp 经营日报表出参
type ErpOrderDailyReportResp struct {
	Total            int           `json:"total"`              // 总条数（总订单数）
	PageIndex        int           `json:"pageIndex"`          // 页码
	PageSize         int           `json:"pageSize"`           // 每页展示条数
	TotalCount       int32         `json:"total_count"`        // 合计总销售数量
	TotalAmount      float64       `json:"total_amount"`       // 合计总金额
	TotalSalesProfit float64       `json:"total_sales_profit"` // 合计总毛利（销售毛利；店员看员工毛利）
	List             []DailyReport `json:"list"`               // 零售明细
}

// DailyReport 经营日报表
type DailyReport struct {
	StoreId          uint32              `json:"store_id"`           // 门店ID
	StoreName        string              `json:"store_name"`         // 门店名称
	StoreAmount      float64             `json:"store_amount"`       // 门店销售金额
	StoreSalesProfit float64             `json:"store_sales_profit"` // 门店销售毛利（销售毛利；店员看员工毛利）
	CategorySales    []CategorySalesData `json:"category_sales"`     // 各分类的销售数据
}

// CategorySalesData 门店分类销售数据
type CategorySalesData struct {
	CategoryID        uint32  `json:"category_id"`         // 一级分类ID
	CategoryName      string  `json:"category_name"`       // 一级分类名称
	SaleTitle         string  `json:"sale_title"`          // 金额标题 (例如: "主机金额")
	TotalSaleAmount   float64 `json:"total_sale_amount"`   // 销售金额
	CostTitle         string  `json:"cost_title"`          // 成本标题 (例如: "主机成本")
	TotalCostAmount   float64 `json:"total_cost_amount"`   // 销售成本
	ProfitTitle       string  `json:"profit_title"`        // 毛利标题 (例如: "主机毛利")
	TotalProfitAmount float64 `json:"total_profit_amount"` // 销售利润
}

// QueryOrderDailyReport 生成经营日报表
func QueryOrderDailyReport(req *ErpOrderDailyReportReq, c *gin.Context) (*ErpOrderDailyReportResp, error) {
	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

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

	// 查询用户所属门店
	var storeList []uint32
	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		return nil, err
	}

	roleName := tools.GetRoleName(c)
	if !(roleName == "admin" || roleName == "系统管理员") {
		// 返回sysUser未过期的门店id列表
		storeList = GetValidStoreIDs(sysUser.StoreData)
	} else {
		storeList, err = GetAllStoreIdsByCooperativeBusinessId(sysUser.CooperativeBusinessId)
		if err != nil {
			return nil, errors.New("用户未绑定门店")
		}
	}
	if len(storeList) == 0 {
		return nil, errors.New("用户未绑定门店")
	}

	// 判断是否为店长和店员的账户，店长或员工展示员工成本和员工毛利
	showFlag := false
	if roleName == "store-manager" || roleName == "shopper" {
		showFlag = true
	}

	storeMap, err := GetAllStoreData()
	if err != nil {
		return nil, err
	}

	// 查询所有门店和分类的零售信息
	var sumData []RetailDetailSumData
	if roleName == "shopper" { //店员只查询自己的业绩
		sumData, err = getSalesmanSumDataByStoreAndCategory(req, c)
	} else {
		sumData, err = getSumDataByStoreAndCategory(req)
	}
	if err != nil {
		return nil, err
	}

	var nTotalAmount, nTotalSalesProfit float64
	var nTotalCount int32
	var storeDataList []DailyReport
	for _, store := range storeList {
		var categoryDataList []CategorySalesData
		var nStoreAmount, nStoreSalesProfit float64

		// 判断门店名称中是否包含"哈曼"
		displayCategories := getDisplayCategories(storeMap[store].Name)

		for _, item := range sumData {
			// 仅当门店ID匹配且分类ID在展示分类中时，才添加分类数据
			if item.StoreId == store && containsCategory(displayCategories, item.ErpCategoryId) {
				nTotalAmount += item.Amount
				nStoreAmount += item.Amount
				nTotalCount += item.Count

				if showFlag { // 员工毛利
					nTotalSalesProfit += item.StaffProfit
					nStoreSalesProfit += item.StaffProfit
				} else { // 销售毛利
					nTotalSalesProfit += item.SalesProfit
					nStoreSalesProfit += item.SalesProfit
				}

				// 处理单个分类数据
				categoryData := processCategoryData(item, showFlag)
				categoryDataList = append(categoryDataList, categoryData)
			}
		}

		// 如果分类数据不足4个，补充缺失的分类，金额为0
		categoryDataList = appendMissingCategories(categoryDataList, displayCategories)

		// 排序分类数据列表
		sort.Slice(categoryDataList, func(i, j int) bool {
			return categoryDataList[i].CategoryID < categoryDataList[j].CategoryID
		})

		// 构建门店数据
		storeData := DailyReport{
			StoreId:          store,
			StoreName:        storeMap[store].Name,
			StoreAmount:      tools.RoundToTwoDecimalPlaces(nStoreAmount),
			StoreSalesProfit: tools.RoundToTwoDecimalPlaces(nStoreSalesProfit),
			CategorySales:    categoryDataList,
		}
		storeDataList = append(storeDataList, storeData)
	}

	sort.Slice(storeDataList, func(i, j int) bool {
		return storeDataList[i].StoreAmount > storeDataList[j].StoreAmount
	})

	// 计算分页所需的切片索引
	startIndex := page * req.PageSize
	endIndex := (page + 1) * req.PageSize
	if endIndex > len(storeDataList) {
		endIndex = len(storeDataList)
	}
	resp.List = storeDataList[startIndex:endIndex]
	resp.Total = len(storeDataList)
	resp.PageIndex = req.PageIndex
	resp.PageSize = req.PageSize
	resp.TotalCount = nTotalCount
	resp.TotalAmount = tools.RoundToTwoDecimalPlaces(nTotalAmount)
	resp.TotalSalesProfit = tools.RoundToTwoDecimalPlaces(nTotalSalesProfit)

	return resp, nil
}

// 获取分类展示列表
func getDisplayCategories(storeName string) []uint32 {
	if strings.Contains(storeName, "哈曼") {
		return []uint32{27, 34} // 如果包含"哈曼"，只显示分类27和34
	}
	return []uint32{1, 4, 7, 13} // 否则显示分类1、4、7、13
}

// 处理单个分类数据
func processCategoryData(item RetailDetailSumData, flag bool) CategorySalesData {
	var categoryName string
	switch item.ErpCategoryId {
	case 1:
		categoryName = "主机"
	case 4:
		categoryName = "游戏"
	case 7:
		categoryName = "配件"
	case 13:
		categoryName = "周边"
	default:
		categoryName = item.ErpCategoryName
	}

	var saleData CategorySalesData
	saleData.CategoryID = item.ErpCategoryId
	saleData.CategoryName = item.ErpCategoryName
	saleData.SaleTitle = categoryName + "销售金额"
	saleData.TotalSaleAmount = tools.RoundToTwoDecimalPlaces(item.Amount)

	if flag { // 店长或员工展示员工成本和员工毛利
		saleData.CostTitle = categoryName + "销售成本"
		saleData.TotalCostAmount = tools.RoundToTwoDecimalPlaces(item.StaffPrice)
		saleData.ProfitTitle = categoryName + "销售利润"
		saleData.TotalProfitAmount = tools.RoundToTwoDecimalPlaces(item.StaffProfit)
	} else {
		saleData.CostTitle = categoryName + "销售成本"
		saleData.TotalCostAmount = tools.RoundToTwoDecimalPlaces(item.WholesalePrice)
		saleData.ProfitTitle = categoryName + "销售利润"
		saleData.TotalProfitAmount = tools.RoundToTwoDecimalPlaces(item.SalesProfit)
	}

	return saleData
}

// 补充缺失的分类数据
func appendMissingCategories(categoryDataList []CategorySalesData, displayCategories []uint32) []CategorySalesData {
	for _, categoryId := range displayCategories {
		if !containsCategorySalesData(categoryDataList, categoryId) {
			var categoryName string
			switch categoryId {
			case 1:
				categoryName = "主机"
			case 4:
				categoryName = "游戏"
			case 7:
				categoryName = "配件"
			case 13:
				categoryName = "周边"
			case 27:
				categoryName = "哈曼卡顿"
			case 34:
				categoryName = "JBL"
			}

			categoryDataList = append(categoryDataList, CategorySalesData{
				CategoryID:        categoryId,
				CategoryName:      categoryName,
				SaleTitle:         categoryName + "销售金额",
				TotalSaleAmount:   0, // 补充分类金额为0
				CostTitle:         categoryName + "销售成本",
				TotalCostAmount:   0, // 补充分类成本为0
				ProfitTitle:       categoryName + "销售利润",
				TotalProfitAmount: 0, // 补充分类利润为0
			})
		}
	}
	return categoryDataList
}

// RetailDetailSumData 零售明细相关金额汇总
type RetailDetailSumData struct {
	StoreId          uint32  `json:"store_id" gorm:"index"`        // 门店id
	StoreName        string  `json:"store_name"`                   // 门店名称
	ErpCategoryId    uint32  `json:"erp_category_id" gorm:"index"` // 分类id
	ErpCategoryName  string  `json:"erp_category_name"`            // 分类名称
	Count            int32   `json:"count"`                        // 销售数量
	RetailPrice      float64 `json:"retail_price"`                 // 指导零售价
	SalePrice        float64 `json:"sale_price"`                   // 零售价
	SaleDiscount     float64 `json:"sale_discount"`                // 零售优惠
	MemberDiscount   float64 `json:"member_discount"`              // 会员优惠
	VmDiscount       float64 `json:"vm_discount"`                  // 会员积分抵扣
	CouponDiscount   float64 `json:"coupon_discount"`              // 优惠券抵扣
	Amount           float64 `json:"amount"`                       // 实际零售价
	WholesalePrice   float64 `json:"wholesale_price"`              // 采购单价
	StaffPrice       float64 `json:"staff_price"`                  // 员工成本价
	SalesProfit      float64 `json:"sales_profit"`                 // 销售毛利
	StaffProfit      float64 `json:"staff_profit"`                 // 员工毛利
	TotalRetailPrice float64 `json:"total_retail_price"`           // 订单总指导零售价
	TotalDiscount    float64 `json:"total_discount"`               // 订单总优惠：订单所有商品零售优惠+会员优惠+会员积分抵扣之和
	TotalAmount      float64 `json:"total_amount"`                 // 订单实收金额
	TotalCashierData
	TotalSalesProfit float64 `json:"total_sales_profit"` // 订单总销售毛利
	TotalStaffProfit float64 `json:"total_staff_profit"` // 订单总员工毛利
	TotalPerData
	StorePer float64 `json:"store_per"` // 门店提成
}

// 查询零售和退货订单的汇总并直接做减法，增加时间筛选条件
func getSumDataByStoreAndCategory(req *ErpOrderDailyReportReq) ([]RetailDetailSumData, error) {
	var result []RetailDetailSumData

	// 解析开始时间
	startTimeCondition := ""
	if req.StartTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Errorf("开始时间解析错误: %v", err)
			return result, err
		}
		startTimeCondition = fmt.Sprintf("AND eo.audit_time > '%s'", parse.Format(QueryTimeFormat))
	}

	// 解析结束时间
	endTimeCondition := ""
	if req.EndTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Errorf("结束时间解析错误: %v", err)
			return result, err
		}
		endTimeCondition = fmt.Sprintf("AND eo.audit_time < '%s'", parse.Format(QueryTimeFormat))
	}

	// 获取所有1级分类
	firstCategories, err := GetAllFirstCategories()
	if err != nil {
		logger.Error("获取一级分类错误", logger.Field("err", err))
		return result, err
	}

	// 获取所有一级分类对应的子分类IDs
	categorySubIds := make(map[uint32][]uint32)
	for _, category := range firstCategories {
		subCategoryIDs, err := GetSubcategoryIds(category.ID)
		if err != nil {
			logger.Error("获取子分类ID错误", logger.Field("err", err), logger.Field("categoryID", category.ID))
			return result, err
		}
		categorySubIds[category.ID] = subCategoryIDs
	}

	err = orm.Eloquent.Raw(fmt.Sprintf(`
		SELECT 
			retail.store_id,
			retail.store_name,
			retail.erp_category_id,
			retail.erp_category_name,
			COALESCE(retail.count, 0) - COALESCE(rejected.count, 0) AS count,
			COALESCE(retail.retail_price, 0) - COALESCE(rejected.retail_price, 0) AS retail_price,
			COALESCE(retail.sale_price, 0) - COALESCE(rejected.sale_price, 0) AS sale_price,
			COALESCE(retail.sale_discount, 0) - COALESCE(rejected.sale_discount, 0) AS sale_discount,
			COALESCE(retail.member_discount, 0) - COALESCE(rejected.member_discount, 0) AS member_discount,
			COALESCE(retail.amount, 0) - COALESCE(rejected.amount, 0) AS amount,
			COALESCE(retail.wholesale_price, 0) - COALESCE(rejected.wholesale_price, 0) AS wholesale_price,
			COALESCE(retail.staff_price, 0) - COALESCE(rejected.staff_price, 0) AS staff_price,
			COALESCE(retail.sales_profit, 0) - COALESCE(rejected.sales_profit, 0) AS sales_profit,
			COALESCE(retail.staff_profit, 0) - COALESCE(rejected.staff_profit, 0) AS staff_profit,
			COALESCE(retail.total_amount, 0) - COALESCE(rejected.total_amount, 0) AS total_amount,
			COALESCE(retail.total_sales_profit, 0) - COALESCE(rejected.total_sales_profit, 0) AS total_sales_profit,
			COALESCE(retail.total_staff_profit, 0) - COALESCE(rejected.total_staff_profit, 0) AS total_staff_profit
		FROM (
			SELECT eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name,
				SUM(oc.count) AS count,
				SUM(oc.retail_price) AS retail_price,
				SUM(oc.sale_price) AS sale_price,
				SUM(oc.sale_discount) AS sale_discount,
				SUM(oc.member_discount) AS member_discount,
				SUM(oc.amount) AS amount,
				SUM(oc.wholesale_price) AS wholesale_price,
				(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) AS staff_price,
				(SUM(oc.amount) - SUM(oc.wholesale_price)) AS sales_profit,
				(SUM(oc.amount) - SUM(oc.wholesale_price) - SUM(oc.staff_cost_price)) AS staff_profit,
				SUM(eo.total_amount) as total_amount, 
			    SUM(eo.total_sales_profit) as total_sales_profit, 
			    SUM(eo.total_staff_profit) as total_staff_profit
			FROM erp_order eo
			JOIN erp_order_commodity oc ON eo.id = oc.erp_order_id
			WHERE eo.retail_type = ? %s %s
			GROUP BY eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name
		) AS retail
		LEFT JOIN (
			SELECT eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name,
				SUM(oc.count) AS count,
				SUM(oc.retail_price) AS retail_price,
				SUM(oc.sale_price) AS sale_price,
				SUM(oc.sale_discount) AS sale_discount,
				SUM(oc.member_discount) AS member_discount,
				SUM(oc.rejected_amount) AS amount,
				SUM(oc.wholesale_price) AS wholesale_price,
				(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) AS staff_price,
				SUM(oc.sales_profit) AS sales_profit,
				SUM(oc.staff_profit) AS staff_profit,
                SUM(eo.total_amount) as total_amount, 
			    SUM(eo.total_sales_profit) as total_sales_profit, 
			    SUM(eo.total_staff_profit) as total_staff_profit
			FROM erp_order eo
			JOIN erp_order_commodity oc ON eo.id = oc.erp_order_id
			WHERE eo.retail_type = ? %s %s
			GROUP BY eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name
		) AS rejected ON retail.store_id = rejected.store_id AND retail.erp_category_id = rejected.erp_category_id
	`, startTimeCondition, endTimeCondition, startTimeCondition, endTimeCondition), RetailTypeSale, RetailTypeRejected).Scan(&result).Error

	if err != nil {
		logger.Error("query data with subtraction err:", logger.Field("err", err))
		return result, err
	}

	// 合并子分类数据（根据门店ID和父分类合并，并累加金额）
	mergedResult := make(map[string]RetailDetailSumData)

	for i := range result {
		for parentID, subCategories := range categorySubIds {
			if containsCategory(subCategories, result[i].ErpCategoryId) {
				key := fmt.Sprintf("%d-%d", result[i].StoreId, parentID)

				if existing, exists := mergedResult[key]; exists {
					existing.Count += result[i].Count
					existing.RetailPrice += result[i].RetailPrice
					existing.SalePrice += result[i].SalePrice
					existing.SaleDiscount += result[i].SaleDiscount
					existing.MemberDiscount += result[i].MemberDiscount
					existing.Amount += result[i].Amount
					existing.WholesalePrice += result[i].WholesalePrice
					existing.StaffPrice += result[i].StaffPrice
					existing.SalesProfit += result[i].SalesProfit
					existing.StaffProfit += result[i].StaffProfit
					mergedResult[key] = existing
				} else {
					result[i].ErpCategoryId = parentID
					//result[i].ErpCategoryName = getCategoryNameByCategoryID(parentID)
					mergedResult[key] = result[i]
				}
				break
			}
		}
	}

	// 转换合并结果为切片
	finalResult := make([]RetailDetailSumData, 0, len(mergedResult))
	for _, v := range mergedResult {
		finalResult = append(finalResult, v)
	}

	return finalResult, nil
}

func getSalesmanSumDataByStoreAndCategory(req *ErpOrderDailyReportReq, c *gin.Context) ([]RetailDetailSumData, error) {
	var result []RetailDetailSumData

	// 解析开始时间
	startTimeCondition := ""
	if req.StartTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Errorf("开始时间解析错误: %v", err)
			return result, err
		}
		startTimeCondition = fmt.Sprintf("AND eo.audit_time > '%s'", parse.Format(QueryTimeFormat))
	}

	// 解析结束时间
	endTimeCondition := ""
	if req.EndTime != "" {
		parse, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Errorf("结束时间解析错误: %v", err)
			return result, err
		}
		endTimeCondition = fmt.Sprintf("AND eo.audit_time < '%s'", parse.Format(QueryTimeFormat))
	}

	// 销售员条件
	salesmanCondition := fmt.Sprintf("AND JSON_CONTAINS(eo.salesman_list, '%s')", fmt.Sprintf(`{"userId":%d}`, tools.GetUserId(c)))

	// 获取所有1级分类
	firstCategories, err := GetAllFirstCategories()
	if err != nil {
		logger.Error("获取一级分类错误", logger.Field("err", err))
		return result, err
	}

	// 获取所有一级分类对应的子分类IDs
	categorySubIds := make(map[uint32][]uint32)
	for _, category := range firstCategories {
		subCategoryIDs, err := GetSubcategoryIds(category.ID)
		if err != nil {
			logger.Error("获取子分类ID错误", logger.Field("err", err), logger.Field("categoryID", category.ID))
			return result, err
		}
		categorySubIds[category.ID] = subCategoryIDs
	}

	err = orm.Eloquent.Raw(fmt.Sprintf(`
		SELECT 
			retail.store_id,
			retail.store_name,
			retail.erp_category_id,
			retail.erp_category_name,
			COALESCE(retail.count, 0) - COALESCE(rejected.count, 0) AS count,
			COALESCE(retail.retail_price, 0) - COALESCE(rejected.retail_price, 0) AS retail_price,
			COALESCE(retail.sale_price, 0) - COALESCE(rejected.sale_price, 0) AS sale_price,
			COALESCE(retail.sale_discount, 0) - COALESCE(rejected.sale_discount, 0) AS sale_discount,
			COALESCE(retail.member_discount, 0) - COALESCE(rejected.member_discount, 0) AS member_discount,
			COALESCE(retail.amount, 0) - COALESCE(rejected.amount, 0) AS amount,
			COALESCE(retail.wholesale_price, 0) - COALESCE(rejected.wholesale_price, 0) AS wholesale_price,
			COALESCE(retail.staff_price, 0) - COALESCE(rejected.staff_price, 0) AS staff_price,
			COALESCE(retail.sales_profit, 0) - COALESCE(rejected.sales_profit, 0) AS sales_profit,
			COALESCE(retail.staff_profit, 0) - COALESCE(rejected.staff_profit, 0) AS staff_profit,
			COALESCE(retail.total_amount, 0) - COALESCE(rejected.total_amount, 0) AS total_amount,
			COALESCE(retail.total_sales_profit, 0) - COALESCE(rejected.total_sales_profit, 0) AS total_sales_profit,
			COALESCE(retail.total_staff_profit, 0) - COALESCE(rejected.total_staff_profit, 0) AS total_staff_profit
		FROM (
			SELECT eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name,
				SUM(oc.count) AS count,
				SUM(oc.retail_price) AS retail_price,
				SUM(oc.sale_price) AS sale_price,
				SUM(oc.sale_discount) AS sale_discount,
				SUM(oc.member_discount) AS member_discount,
				SUM(oc.amount) AS amount,
				SUM(oc.wholesale_price) AS wholesale_price,
				(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) AS staff_price,
				(SUM(oc.amount) - SUM(oc.wholesale_price)) AS sales_profit,
				(SUM(oc.amount) - SUM(oc.wholesale_price) - SUM(oc.staff_cost_price)) AS staff_profit,
				SUM(eo.total_amount) as total_amount, 
			    SUM(eo.total_sales_profit) as total_sales_profit, 
			    SUM(eo.total_staff_profit) as total_staff_profit
			FROM erp_order eo
			JOIN erp_order_commodity oc ON eo.id = oc.erp_order_id
			WHERE eo.retail_type = ? %s %s %s
			GROUP BY eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name
		) AS retail
		LEFT JOIN (
			SELECT eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name,
				SUM(oc.count) AS count,
				SUM(oc.retail_price) AS retail_price,
				SUM(oc.sale_price) AS sale_price,
				SUM(oc.sale_discount) AS sale_discount,
				SUM(oc.member_discount) AS member_discount,
				SUM(oc.rejected_amount) AS amount,
				SUM(oc.wholesale_price) AS wholesale_price,
				(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) AS staff_price,
				SUM(oc.sales_profit) AS sales_profit,
				SUM(oc.staff_profit) AS staff_profit,
                SUM(eo.total_amount) as total_amount, 
			    SUM(eo.total_sales_profit) as total_sales_profit, 
			    SUM(eo.total_staff_profit) as total_staff_profit
			FROM erp_order eo
			JOIN erp_order_commodity oc ON eo.id = oc.erp_order_id
			WHERE eo.retail_type = ? %s %s %s
			GROUP BY eo.store_id, eo.store_name, oc.erp_category_id, oc.erp_category_name
		) AS rejected ON retail.store_id = rejected.store_id AND retail.erp_category_id = rejected.erp_category_id
	`, startTimeCondition, endTimeCondition, salesmanCondition, startTimeCondition, endTimeCondition, salesmanCondition), RetailTypeSale, RetailTypeRejected).Scan(&result).Error

	if err != nil {
		logger.Error("query data with subtraction err:", logger.Field("err", err))
		return result, err
	}

	// 合并子分类数据（根据门店ID和父分类合并，并累加金额）
	mergedResult := make(map[string]RetailDetailSumData)

	for i := range result {
		for parentID, subCategories := range categorySubIds {
			if containsCategory(subCategories, result[i].ErpCategoryId) {
				key := fmt.Sprintf("%d-%d", result[i].StoreId, parentID)

				if existing, exists := mergedResult[key]; exists {
					existing.Count += result[i].Count
					existing.RetailPrice += result[i].RetailPrice
					existing.SalePrice += result[i].SalePrice
					existing.SaleDiscount += result[i].SaleDiscount
					existing.MemberDiscount += result[i].MemberDiscount
					existing.Amount += result[i].Amount
					existing.WholesalePrice += result[i].WholesalePrice
					existing.StaffPrice += result[i].StaffPrice
					existing.SalesProfit += result[i].SalesProfit
					existing.StaffProfit += result[i].StaffProfit
					mergedResult[key] = existing
				} else {
					result[i].ErpCategoryId = parentID
					//result[i].ErpCategoryName = getCategoryNameByCategoryID(parentID)
					mergedResult[key] = result[i]
				}
				break
			}
		}
	}

	// 转换合并结果为切片
	finalResult := make([]RetailDetailSumData, 0, len(mergedResult))
	for _, v := range mergedResult {
		finalResult = append(finalResult, v)
	}

	return finalResult, nil
}

// containsCategory 检查分类ID是否在子分类IDs列表中
func containsCategory(subCategoryIds []uint32, categoryId uint32) bool {
	for _, id := range subCategoryIds {
		if id == categoryId {
			return true
		}
	}
	return false
}

// 辅助函数，用于检查分类是否已经存在于categoryDataList中
func containsCategorySalesData(categoryDataList []CategorySalesData, categoryId uint32) bool {
	for _, category := range categoryDataList {
		if category.CategoryID == categoryId {
			return true
		}
	}
	return false
}

// ErpOrderSaleDetailReq 销售明细汇总入参
type ErpOrderSaleDetailReq struct {
	BillSn           string   `json:"bill_sn"`            // 单据编号
	RetailType       string   `json:"retail_type"`        // 销售类型：sale 零售销售； rejected 零售退货
	UserType         []uint32 `json:"user_type"`          // 会员类别：0-未注册 1-普通会员 2-黄金会员 4-白金会员 5-黑金会员 6-尊享会员 7-黄金&尊享 8-白金&尊享 9-黑金&尊享
	Uid              int      `json:"uid"`                // 用户ID
	Tel              string   `json:"tel"`                // 客户手机号
	StoreId          []uint32 `json:"store_id"`           // 门店ID
	ErpCategoryId    []uint32 `json:"erp_category_id"`    // 分类id
	ErpCommodityName string   `json:"erp_commodity_name"` // 商品名称
	Salesman         uint32   `json:"salesman"`           // 销售人员ID
	IMEI             string   `json:"imei"`               // 串码
	StartTime        string   `json:"start_time"`         // 开始时间
	EndTime          string   `json:"end_time"`           // 结束时间
	BankTrxNo        string   `json:"bank_trx_no"`        // 银联流水号
	PageIndex        int      `json:"pageIndex"`          // 页码
	PageSize         int      `json:"pageSize"`           // 页面条数
	IsExport         uint32   `json:"is_export"`          // 1-导出
}

// QuerySaleDetail 查询销售明细
func QuerySaleDetail(req *ErpOrderSaleDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
	resp := &ErpOrderRetailDetailResp{}

	// 通过银行流水号查询
	if req.BankTrxNo != "" {
		var orderPayWay ErpOrderRecord
		err := orm.Eloquent.Table("erp_order_record").Where("bank_trx_no = ? and status = ?",
			req.BankTrxNo, PayOk).Find(&orderPayWay).Error
		if err != nil {
			logger.Error("query erp_order_record err:", logger.Field("err", err))
			return nil, err
		}
		req.BillSn = orderPayWay.BillSn
	}

	var err error
	if (len(req.ErpCategoryId) != 0 || req.ErpCommodityName != "" || req.IMEI != "") && req.BillSn == "" { // 商品分类or商品名称不为空且订单编号为空
		// 联表查询
		resp, err = querySaleDetailByJoin(req, c)
	} else {
		// 普通单表查询，然后补充收款数据和商品数据
		resp, err = querySaleDetailCommon(req, c)
	}
	if err != nil {
		logger.Error("queryRetailDetailCommon err")
		return nil, err
	}

	return resp, nil
}

// 联表查询
func querySaleDetailByJoin(req *ErpOrderSaleDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

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

	qs := orm.Eloquent.Debug().Table("erp_order_commodity").
		Select("erp_order_commodity.*, erp_order.*").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")

	es := orm.Eloquent.Debug().Table("erp_order_commodity").
		Select("erp_order_commodity.*, erp_order.*").
		Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")

	orderSumQs := orm.Eloquent.Table("erp_order_commodity AS oc").Select("oc.*, eo.*").
		Joins("JOIN erp_order AS eo ON oc.erp_order_id = eo.id")

	rejectedOrderSumQs := orm.Eloquent.Table("erp_order_commodity AS oc").Select("oc.*, eo.*").
		Joins("JOIN erp_order AS eo ON oc.erp_order_id = eo.id")

	if len(req.ErpCategoryId) != 0 { // 商品分类
		categoryList, err := TransformErpCategoryIds(req.ErpCategoryId)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("erp_order_commodity.erp_category_id in ?", categoryList)
		es = es.Where("erp_order_commodity.erp_category_id in ?", categoryList)
		orderSumQs = orderSumQs.Where("oc.erp_category_id in ?", categoryList)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.erp_category_id in ?", categoryList)
	}
	if req.ErpCommodityName != "" { // 商品名称
		qs = qs.Where("erp_order_commodity.erp_commodity_name = ?", req.ErpCommodityName)
		es = es.Where("erp_order_commodity.erp_commodity_name = ?", req.ErpCommodityName)
		orderSumQs = orderSumQs.Where("oc.erp_commodity_name = ?", req.ErpCommodityName)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.erp_commodity_name = ?", req.ErpCommodityName)
	}
	if req.RetailType != "" { // 销售类型
		qs = qs.Where("erp_order.retail_type=?", req.RetailType)
		es = es.Where("erp_order.retail_type=?", req.RetailType)
		orderSumQs = orderSumQs.Where("eo.retail_type=?", req.RetailType)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.retail_type=?", req.RetailType)
	}
	if req.Uid != 0 { // 用户ID
		qs = qs.Where("erp_order.uid=?", req.Uid)
		es = es.Where("erp_order.uid=?", req.Uid)
		orderSumQs = orderSumQs.Where("eo.uid=?", req.Uid)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.uid=?", req.Uid)
	}
	if len(req.UserType) != 0 { // 会员类别
		qs = qs.Where("user_type in ?", req.UserType)
		es = es.Where("user_type in ?", req.UserType)
		orderSumQs = orderSumQs.Where("user_type in ?", req.UserType)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("user_type in ?", req.UserType)
	}
	if req.Tel != "" { // 用户手机号
		qs = qs.Where("erp_order.tel=?", req.Tel)
		es = es.Where("erp_order.tel=?", req.Tel)
		orderSumQs = orderSumQs.Where("eo.tel=?", req.Tel)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.tel=?", req.Tel)
	}
	if len(req.StoreId) != 0 { // 门店ID
		qs = qs.Where("erp_order.store_id in ?", req.StoreId)
		es = es.Where("erp_order.store_id in ?", req.StoreId)
		orderSumQs = orderSumQs.Where("eo.store_id in ?", req.StoreId)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id in ?", req.StoreId)
	}
	if req.IMEI != "" { // 串码
		qs = qs.Where("erp_order_commodity.imei=?", req.IMEI)
		es = es.Where("erp_order_commodity.imei=?", req.IMEI)
		orderSumQs = orderSumQs.Where("oc.imei=?", req.IMEI)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.imei=?", req.IMEI)
	}
	// 非管理员才判断所属门店
	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("erp_order.store_id = ?", storeList[0])
				es = es.Where("erp_order.store_id = ?", storeList[0])
				orderSumQs = orderSumQs.Where("eo.store_id = ?", storeList[0])
				rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id = ?", storeList[0])
			} else {
				qs = qs.Where("erp_order.store_id IN (?)", storeList)
				es = es.Where("erp_order.store_id IN (?)", storeList)
				orderSumQs = orderSumQs.Where("eo.store_id IN (?)", storeList)
				rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id IN (?)", storeList)
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}
	if req.Salesman != 0 { // 销售员
		qs = qs.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
		es = es.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
		orderSumQs = orderSumQs.Where("JSON_CONTAINS(eo.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
		rejectedOrderSumQs = rejectedOrderSumQs.Where("JSON_CONTAINS(eo.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
	}
	if req.StartTime != "" { // 审核开始时间
		parse, err := time.Parse(QueryTimeFormat, req.StartTime)
		if err != nil {
			logger.Errorf("err:", err)
		}
		qs = qs.Where("erp_order.audit_time > ?", parse)
		es = es.Where("erp_order.audit_time > ?", parse)
		orderSumQs = orderSumQs.Where("eo.audit_time > ?", parse)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.audit_time > ?", parse)
	}
	if req.EndTime != "" { // 审核结束时间
		parse, err := time.Parse(QueryTimeFormat, req.EndTime)
		if err != nil {
			logger.Errorf("err:", err)
		}
		//parse = parse.AddDate(0, 0, 1)
		qs = qs.Where("erp_order.audit_time < ?", parse)
		es = es.Where("erp_order.audit_time < ?", parse)
		orderSumQs = orderSumQs.Where("eo.audit_time < ?", parse)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.audit_time < ?", parse)
	}
	if showConfig.ShowAll == "OFF" {
		qs = qs.Where("erp_order.is_print = ? or erp_order.retail_type = ?", HavePrinted, RetailTypeRejected)
		es = es.Where("erp_order.is_print = ? or erp_order.retail_type = ?", HavePrinted, RetailTypeRejected)
		orderSumQs = orderSumQs.Where("eo.is_print = ? or eo.retail_type = ?", HavePrinted, RetailTypeRejected)
		rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.is_print = ? or eo.retail_type = ?", HavePrinted, RetailTypeRejected)
	}
	qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	es.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	orderSumQs.Where("eo.pay_status = ? or (eo.retail_type = ? and eo.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	rejectedOrderSumQs.Where("eo.pay_status = ? or (eo.retail_type = ? and eo.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)

	// 销售订单的汇总数据
	var sumData RetailDetailTotalData
	sumData, err = getRetailDetailTotalDataJoinErpOrderSale(orderSumQs, RetailTypeSale)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单的汇总数据
	var rejectedSumData RetailDetailTotalData
	rejectedSumData, err = getRetailDetailTotalDataJoinErpOrderRejected(rejectedOrderSumQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的销售数据
	sumData = subtractRetailData(sumData, rejectedSumData)

	// 销售订单提成汇总
	var totalPerData TotalPerData
	totalPerQs := qs
	totalPerData, err = getTotalPerData(totalPerQs, RetailTypeSale)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单提成汇总
	var rejectedTotalPerData TotalPerData
	rejectedTotalPerQs := qs
	rejectedTotalPerData, err = getTotalPerData(rejectedTotalPerQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的提成数据
	totalPerData = subtractTotalPerData(totalPerData, rejectedTotalPerData)

	// 处理汇总数据，四舍五入保留2位小数
	saleDetailRoundValues(&sumData, &totalPerData)

	sumData.TotalSalesProfit = 0 // 订单总销售毛利
	sumData.TotalStaffProfit = 0 // 订单总员工毛利
	sumData.TotalRetailPrice = 0 // 订单总指导零售价
	sumData.TotalDiscount = 0    // 订单总优惠
	sumData.TotalAmount = 0      // 订单实收金额
	sumData.StorePer = 0         // 门店提成
	sumData.TotalCashierData = nil

	//sumData.ScanAmount = 0
	//sumData.CashAmount = 0
	//sumData.PosAmount = 0
	//sumData.StoreVmAmount = 0
	//sumData.OtherAmount = 0
	RoundRetailDetailTotalData(&sumData)

	var result []RetailDetailByJoin

	if req.IsExport == 1 { //导出excel
		err = qs.Order("erp_order.audit_time DESC").Find(&result).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}

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

		orders := packData(result)
		erpOrderSetBankTrxNo(orders)
		fileUrl, err := saleDetailExport(orders, sumData, c)
		if err != nil {
			logger.Error("retailDetailExport err:", logger.Field("err", err))
			return resp, err
		}
		resp.ExportUrl = fileUrl
	} else {
		//err = qs.Order("erp_order.audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&result).Error
		err = qs.Order("erp_order.audit_time DESC").Find(&result).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}

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

		orders := packData(result)

		erpOrderListSetSalesman(orders)
		erpOrderSetBankTrxNo(orders)
		pagedOrders := paginate(orders, page, req.PageSize)

		resp.List = pagedOrders

		//跟之前保持一致
		resp.Total = len(orders)
		resp.PageIndex = page + 1
		resp.PageSize = req.PageSize
		resp.SumData = sumData
	}

	return resp, nil
}

// 普通单表查询，然后补充收款数据和商品数据
func querySaleDetailCommon(req *ErpOrderSaleDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
	showConfig, err := GetErpOrderShowConfig()
	if err != nil {
		logger.Errorf("List err:", err)
		showConfig.ShowAll = "ON"
	}

	page := req.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if req.PageSize == 0 {
		req.PageSize = 10
	}

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

	qs := orm.Eloquent.Table("erp_order")
	totalPerQs := orm.Eloquent.Table("erp_order")
	if showConfig.ShowAll == "OFF" {
		qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
		totalPerQs = totalPerQs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
	}
	if req.BillSn != "" { // 订单编号
		qs = qs.Where("bill_sn=?", req.BillSn)
		totalPerQs = totalPerQs.Where("bill_sn=?", req.BillSn)
	} else {
		if req.RetailType != "" { // 销售类型
			qs = qs.Where("retail_type=?", req.RetailType)
			totalPerQs = totalPerQs.Where("retail_type=?", req.RetailType)
		}
		if req.Uid != 0 { // 用户ID
			qs = qs.Where("erp_order.uid=?", req.Uid)
			totalPerQs = totalPerQs.Where("erp_order.uid=?", req.Uid)
		}
		if req.Tel != "" { // 用户手机号
			qs = qs.Where("tel=?", req.Tel)
			totalPerQs = totalPerQs.Where("tel=?", req.Tel)
		}
		if len(req.StoreId) != 0 { // 门店ID
			qs = qs.Where("store_id in ?", req.StoreId)
			totalPerQs = totalPerQs.Where("store_id in ?", req.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])
					totalPerQs = totalPerQs.Where("store_id = ?", storeList[0])
				} else {
					qs = qs.Where("store_id IN (?)", storeList)
					totalPerQs = totalPerQs.Where("store_id IN (?)", storeList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
		if req.Salesman != 0 { // 销售员
			qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
			totalPerQs = totalPerQs.Where("erp_order_sales.uid = ?", req.Salesman)
		}
		if req.StartTime != "" { // 审核开始时间
			parse, err := time.Parse(QueryTimeFormat, req.StartTime)
			if err != nil {
				logger.Errorf("err:", err)
			}
			qs = qs.Where("audit_time > ?", parse)
			totalPerQs = totalPerQs.Where("audit_time > ?", parse)
		}
		if req.EndTime != "" { // 审核结束时间
			parse, err := time.Parse(QueryTimeFormat, req.EndTime)
			if err != nil {
				logger.Errorf("err:", err)
			}
			//parse = parse.AddDate(0, 0, 1)
			qs = qs.Where("audit_time < ?", parse)
			totalPerQs = totalPerQs.Where("audit_time < ?", parse)
		}
		if len(req.UserType) != 0 {
			qs = qs.Where("user_type in ?", req.UserType)
			totalPerQs = totalPerQs.Where("user_type in ?", req.UserType)
		}
	}
	qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	totalPerQs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
		HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
	es := qs
	rejectedTotalPerQs := totalPerQs

	// 销售订单的汇总数据
	orderSumQs := qs
	var sumData RetailDetailTotalData
	sumData, err = getRetailDetailTotalDataSale(orderSumQs, RetailTypeSale)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单的汇总数据
	var rejectedSumData RetailDetailTotalData
	rejectedOrderSumQs := qs
	rejectedSumData, err = getRetailDetailTotalDataRejected(rejectedOrderSumQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的销售数据
	sumData = subtractRetailData(sumData, rejectedSumData)

	// 销售订单提成汇总
	var totalPerData TotalPerData
	totalPerData, err = getTotalPerData(totalPerQs, RetailTypeSale)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 退货订单提成汇总
	var rejectedTotalPerData TotalPerData
	rejectedTotalPerData, err = getTotalPerData(rejectedTotalPerQs, RetailTypeRejected)
	if err != nil {
		logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
		return resp, err
	}
	// 计算销售订单和退货订单汇总后的提成数据
	totalPerData = subtractTotalPerData(totalPerData, rejectedTotalPerData)

	// 处理汇总数据，四舍五入保留2位小数
	saleDetailRoundValues(&sumData, &totalPerData)
	sumData.TotalSalesProfitPer = totalPerData.TotalSalesProfitPer
	sumData.TotalStaffProfitPer = totalPerData.TotalStaffProfitPer
	sumData.SalesmanPer = totalPerData.SalesmanPer
	RoundRetailDetailTotalData(&sumData)

	if req.IsExport == 1 { // 导出excel
		var orders []ErpOrder
		err = qs.Order("audit_time DESC").Find(&orders).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}
		// 进行批量处理
		var wg sync.WaitGroup
		wg.Add(2)

		go func() {
			defer wg.Done()
			ErpOrderRetailDetailSetCommodityAI(orders) // 商品信息处理
		}()

		go func() {
			defer wg.Done()
			erpOrderSetBankTrxNoAI(orders) // 银行交易号处理
		}()

		wg.Wait() // 等待所有处理完成

		fileUrl, err := saleDetailExport(orders, sumData, c)
		if err != nil {
			logger.Error("retailDetailExport err:", logger.Field("err", err))
			return resp, err
		}
		resp.ExportUrl = fileUrl
	} else {
		var count int64
		err = es.Count(&count).Error
		if err != nil {
			logger.Error("count err:", logger.Field("err", err))
			return resp, err
		}

		var orders []ErpOrder
		err = qs.Order("audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
		if err != nil && err != RecordNotFound {
			logger.Error("erp commodity list err:", logger.Field("err", err))
			return resp, err
		}

		// 添加付款、销售员、商品信息
		ErpOrderRetailDetailSetCommodity(orders)
		erpOrderListSetSalesman(orders)
		erpOrderSetBankTrxNo(orders)

		resp.List = orders

		//跟之前保持一致
		resp.Total = int(count)
		resp.PageIndex = page + 1
		resp.PageSize = req.PageSize
		resp.SumData = sumData
	}

	return resp, nil
}

// 四舍五入保留2位小数
func saleDetailRoundValues(data *RetailDetailTotalData, totalPerData *TotalPerData) {
	roundMap := map[*float64]*float64{
		&data.StorePer:                    &data.StorePer,
		&totalPerData.TotalSalesProfitPer: &totalPerData.TotalSalesProfitPer,
		&totalPerData.TotalStaffProfitPer: &totalPerData.TotalStaffProfitPer,
		&totalPerData.SalesmanPer:         &totalPerData.SalesmanPer,
	}

	for original, rounded := range roundMap {
		*rounded = tools.RoundToTwoDecimalPlaces(*original)
	}
}

// 导出销售明细报表excel
func saleDetailExport(list []ErpOrder, sumData RetailDetailTotalData, 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)

	title := []interface{}{"订单编号", "订单类型", "店铺", "会员类别", "用户ID", "日期", "审核时间", "销售员1", "销售员2",
		"一级分类", "二级分类", "三级分类", "商品名称", "供应商", "商品串码", "是否赠送", "销售数量", "指导价", "零售价", "零售优惠",
		"会员优惠", "销售金额", "采购单价", "员工成本", "销售毛利", "员工毛利", "银联流水", "联系电话", "备注"}

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

	categoryMap, err := GetAllCategories()
	if err != nil {
		// 处理错误
		logger.Error("GetAllCategories err:", logger.Field("err", err))
	}

	var row []interface{}
	nAmount := 0.0
	nExcelStartRow := 0
	for i := 0; i < len(list); i++ {
		var saleType string
		if list[i].RetailType == RetailTypeSale {
			saleType = "零售销售"
		} else if list[i].RetailType == RetailTypeRejected {
			saleType = "零售退货"
		} else {
			logger.Error("订单类型异常")
			return "", errors.New("RetailMarginDataExport, 订单类型异常:" + list[i].RetailType)
		}

		var salesMan1, salesMan2 string
		// 先判断商品数量，确定要写几行数据
		for rowId := 0; rowId < len(list[i].Commodities); rowId++ {
			if list[i].RetailType == RetailTypeSale {
				nAmount = list[i].Commodities[rowId].Amount
			} else if list[i].RetailType == RetailTypeRejected {
				nAmount = list[i].Commodities[rowId].RejectedAmount
				list[i].CashierList = "" // 目前零售退货订单暂时不展示各个方式的付款金额
			}

			// 用户id，会员类别
			var userId, userType string
			if list[i].Uid != 0 {
				userId = strconv.Itoa(list[i].Uid)
				userType = GetUserTypeString(list[i].UserType)
			} else {
				userId = ""
			}

			// 审核时间
			var auditTime, auditDate string
			if list[i].AuditTime != nil {
				auditTime = list[i].AuditTime.Format(ExcelTimeFormat)
				auditDate = list[i].AuditTime.Format(DateTimeFormat) // Extract date only
			} else {
				auditTime = ""
				auditDate = ""
			}

			// 商品分类
			categoryID := list[i].Commodities[rowId].ErpCategoryId
			categoryLevels := GetCategoryLevelsFromMap(categoryID, categoryMap)

			// 是否赠送
			strPresentType := "非赠送"
			if list[i].Commodities[rowId].PresentType == 2 {
				strPresentType = "赠送"
			}

			if len(list[i].Salesman) > 0 {
				salesMan1 = list[i].Salesman[0].Name
				if len(list[i].Salesman) == 2 {
					salesMan2 = list[i].Salesman[1].Name
				}
			}
			row = []interface{}{
				list[i].BillSn,             // 订单编号
				saleType,                   // 订单类型
				list[i].StoreName,          // 店铺
				userType,                   // 会员类别
				userId,                     // 用户ID
				auditDate,                  // 日期
				auditTime,                  // 审核时间
				salesMan1,                  // 销售员1
				salesMan2,                  // 销售员2
				categoryLevels.Level1.Name, // 一级分类
				categoryLevels.Level2.Name, // 二级分类
				categoryLevels.Level3.Name, // 三级分类
				list[i].Commodities[rowId].ErpCommodityName, // 商品名称
				list[i].Commodities[rowId].ErpSupplierName,  // 供应商
				list[i].Commodities[rowId].IMEI,             // 商品串码
				strPresentType,                              // 是否赠送
				list[i].Commodities[rowId].Count,            // 销售数量
				list[i].Commodities[rowId].RetailPrice,      // 指导价
				list[i].Commodities[rowId].SalePrice,        // 零售价
				list[i].Commodities[rowId].SaleDiscount,     // 零售优惠
				list[i].Commodities[rowId].MemberDiscount,   // 会员优惠
				nAmount, // 销售金额
				list[i].Commodities[rowId].WholesalePrice,                                             // 采购单价
				list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice, // 员工成本
				list[i].Commodities[rowId].SalesProfit,                                                // 销售毛利
				list[i].Commodities[rowId].StaffProfit,                                                // 员工毛利
				list[i].BankTrxNo,                                                                     // 银联流水
				list[i].Tel,                                                                           // 联系电话
				list[i].Commodities[rowId].Remark,                                                     // 备注
			}

			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(len(list)), 10)
	end := []interface{}{totalData, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
		sumData.Count,
		sumData.RetailPrice,
		sumData.SalePrice,
		sumData.SaleDiscount,
		sumData.MemberDiscount,
		sumData.Amount,
		"",
	}

	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}]}`)

	endRow := fmt.Sprintf("AC"+"%d", nExcelStartRow+2)

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

	// 设置单元格大小
	file.SetColWidth("Sheet1", "A", "A", 15)
	file.SetColWidth("Sheet1", "C", "C", 25)
	file.SetColWidth("Sheet1", "D", "D", 19)
	file.SetColWidth("Sheet1", "F", "F", 15)
	file.SetColWidth("Sheet1", "G", "G", 19)
	file.SetColWidth("Sheet1", "M", "M", 25)
	file.SetColWidth("Sheet1", "O", "O", 18)
	file.SetColWidth("Sheet1", "AA", "AA", 30)
	file.SetColWidth("Sheet1", "AB", "AB", 15)

	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
}

// UpdateSwitchUserCoupon
// 针对购买switch1老主机的用户，如果有录入手机号且开通了会员，则自动发放"500元尊享会员开通优惠券"
// 针对购买switch2新主机的用户，如果有录入手机号且开通了会员，则自动发放"300元尊享会员开通优惠券"
func UpdateSwitchUserCoupon(orderId uint32, uid int, retailType string) error {
	if uid == 0 || orderId == 0 {
		return errors.New("参数不能为空")
	}

	// 判断是否是会员
	userInfo, err := GetUserInfoByUid(uint32(uid))
	if err != nil {
		logger.Error("获取用户信息失败:", logger.Field("err", err))
		return err
	}

	if userInfo.Uid == 0 {
		logger.Errorf("未查询到用户信息,uid:", uid)
		return errors.New("未查询到用户信息")
	}

	// 判断是否购买了switch1主机
	var commodity []ErpOrderCommodity
	err = orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", orderId).Find(&commodity).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf("查询订单商品失败: %w", err)
		return fmt.Errorf("查询订单商品失败: %w", err)
	}

	buySwitch1, buySwitch2 := false, false
	for _, item := range commodity {
		if item.ErpCategoryId == Switch2CategoryId2 { // 判断是否购买了switch2主机
			buySwitch2 = true
			break
		} else if item.ErpCategoryId == Switch1CategoryId1 || item.ErpCategoryId == Switch1CategoryId2 { // 判断是否购买了switch1主机
			buySwitch1 = true
			break
		}
	}
	if !buySwitch1 && !buySwitch2 {
		logger.Info("订单未包含Switch主机", logger.Field("orderId", orderId))
		return nil
	}

	if retailType == RetailTypeRejected { // 退货订单
		// 查询并删除已发放的活动优惠券（state = 1）
		err = orm.Eloquent.Table("user_coupon").
			Where("uid = ? AND activity_type = ? AND state = 1", userInfo.Uid, SwitchActivityType).
			Delete(nil).Error
		if err != nil {
			logger.Error("删除用户已发放的活动优惠券失败", logger.Field("err", err), logger.Field("uid", userInfo.Uid))
			return err
		}

		return nil
	}

	// 已是尊享会员不发券
	if IsValidPrivilegeMember(userInfo.Uid) {
		logger.Info("用户已是尊享会员", logger.Field("uid", userInfo.Uid))
		return nil
	}

	// 确定目标优惠券面值与活动ID
	var targetActivityId int
	var targetValue uint32

	switch {
	case buySwitch1 && buySwitch2:
		targetActivityId = Switch2ActivityId
		targetValue = 30000
	case buySwitch1:
		targetActivityId = Switch1ActivityId
		targetValue = 50000
	case buySwitch2:
		targetActivityId = Switch2ActivityId
		targetValue = 30000
	}

	// 查询已发放优惠券（state = 1）
	var existingCoupons []UserCoupon
	err = orm.Eloquent.Table("user_coupon").
		Where("uid = ? AND activity_type = ? AND state = 1", uid, SwitchActivityType).
		Find(&existingCoupons).Error
	if err != nil {
		logger.Error("查询已发放优惠券失败", logger.Field("err", err))
		return err
	}

	// 多张券处理逻辑
	if len(existingCoupons) > 0 {
		// 判断是否有比目标券面值小的旧券
		var smallerCoupons []UserCoupon
		var greaterOrEqualCoupons []UserCoupon
		for _, c := range existingCoupons {
			if c.Value < targetValue {
				smallerCoupons = append(smallerCoupons, c)
			} else {
				greaterOrEqualCoupons = append(greaterOrEqualCoupons, c)
			}
		}

		if len(smallerCoupons) > 0 {
			// 保留最小的一张更新有效期，删除其他券
			minCoupon := smallerCoupons[0]
			for _, c := range smallerCoupons {
				if c.Value < minCoupon.Value {
					minCoupon = c
				}
			}

			// 更新最小券有效期
			err = orm.Eloquent.Model(&UserCoupon{}).
				Where("id = ?", minCoupon.ID).
				Update("active_end", time.Now().AddDate(0, 1, 0)).Error
			if err != nil {
				logger.Error("更新优惠券有效期失败", logger.Field("err", err))
			}

			// 删除其余所有券（除保留那张）
			var deleteIds []uint32
			for _, c := range existingCoupons {
				if c.ID != minCoupon.ID {
					deleteIds = append(deleteIds, c.ID)
				}
			}
			if len(deleteIds) > 0 {
				err = orm.Eloquent.Table("user_coupon").
					Where("id IN ?", deleteIds).
					Delete(nil).Error
				if err != nil {
					logger.Error("删除多余旧券失败", logger.Field("err", err))
				}
			}
			return nil // 不再发新券
		}

		// 所有旧券面值 >= 当前目标，全部删除，继续发新券
		err = orm.Eloquent.Table("user_coupon").
			Where("uid = ? AND activity_type = ? AND state = 1", uid, SwitchActivityType).
			Delete(nil).Error
		if err != nil {
			logger.Error("删除旧优惠券失败", logger.Field("err", err))
			return err
		}
	}

	// 发放优惠券
	var coupons []Coupon
	err = orm.Eloquent.Debug().Table("coupon").Where("activity_id = ?", targetActivityId).Find(&coupons).Error
	if err != nil {
		logger.Error("查询优惠券失败:", logger.Field("err", err))
		return err
	}

	for i, _ := range coupons {
		couponCode, err := utils.GenerateRandomNumber19()
		if err != nil {
			logger.Error("生成优惠码失败:", logger.Field("err", err))
			continue
		}
		userCoupon := &UserCoupon{
			Uid:              userInfo.Uid,
			CouponId:         coupons[i].ID,
			CouponType:       coupons[i].CouponType,
			ActivityType:     coupons[i].ActivityType,
			ActivityId:       coupons[i].ActivityId,
			Value:            coupons[i].Value,
			State:            1,
			ActiveStart:      time.Now(),
			ActiveEnd:        time.Now().AddDate(0, 1, 0),
			UseTime:          time.Time{},
			MemberLevel:      coupons[i].MemberLevel,
			Approach:         0,
			PromotionalSales: 0,
			RedeemCode:       "",
			CategoryNumber:   coupons[i].CategoryNumber,
			Code:             couponCode,
		}

		err = orm.Eloquent.Create(userCoupon).Error
		if err != nil {
			logger.Errorf("user coupon err:", err)
			continue
		}
	}

	return nil
}
