package models import ( "errors" "fmt" "github.com/xuri/excelize/v2" orm "go-admin/common/global" "go-admin/logger" "go-admin/tools/config" "gorm.io/gorm" "math/rand" "strings" "sync" "time" ) const ( ErpPurchaseOrderUnAudit = 1 // 待审核 ErpPurchaseOrderWaitInventory = 2 // 待入库 ErpPurchaseOrderWaitReject = 3 // 待退货 ErpPurchaseOrderFinished = 4 // 已完成 ErpPurchaseOrderEnd = 5 // 已终止 ErpPurchaseOrderInInventory = 6 // 入库中,部分入库 ErpPurchaseOrderInReject = 7 // 退货中,部分退货 ErpProcureOrder = "procure" // 采购入库订单 ErpRejectOrder = "reject" // 采购退货订单 ErpDemandStateWait = 1 // 待采购 ErpDemandStateFinish = 2 // 完成采购 ) // ErpPurchaseOrder 采购订单表 type ErpPurchaseOrder struct { Model SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号 PurchaseType string `json:"purchase_type"` // 类型:procure-采购 reject-退货 StoreId uint32 `json:"store_id" gorm:"index"` // 门店id StoreName string `json:"store_name"` // 门店名称 ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称 HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id HandlerName string `json:"handler_name"` // 经手人名称 MakerTime time.Time `json:"maker_time"` // 制单时间 MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id MakerName string `json:"maker_name"` // 制单人名称 AuditTime time.Time `json:"audit_time"` // 审核时间 AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id AuditorName string `json:"auditor_name"` // 审核人名称 State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 RejectedPurchaseOrderId uint32 `json:"rejected_purchase_order_id"` // 退货采购订单id ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式/收款方式id ErpCashierName string `json:"erp_cashier_name"` // 付款方式/收款方式名称 AccountHolder string `json:"account_holder"` // 收款人 OpeningBank string `json:"opening_bank"` // 开户行 BankAccount string `json:"bank_account"` // 银行卡号 DeliveryTime string `json:"delivery_time"` // 交货日期,如:2024-02-23 DeliveryAddress string `json:"delivery_address"` // 交货地址 Remark string `json:"remark"` // 备注 Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"` } // ErpPurchaseCommodity 采购订单商品表 type ErpPurchaseCommodity struct { Model ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 采购订单id ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei"` // 商品串码 RetailPrice uint32 `json:"retail_price"` // 指导零售价 Count uint32 `json:"count"` // 计划采购数量 Price float64 `json:"price"` // 计划采购单价 Amount float64 `json:"amount"` // 计划采购金额 Remark string `json:"remark"` // 备注 RejectedPrice float64 `json:"rejected_price"` // 计划退货单价 RejectedCount uint32 `json:"rejected_count"` // 计划退货数量 RejectedAmount float64 `json:"rejected_amount"` // 计划退货金额 InventoryCount int32 `json:"inventory_count"` // 入库数量(=执行数量) ExecutionCount uint32 `json:"execute_count" gorm:"-"` // 执行数量 ExecutionPrice float64 `json:"execute_price" gorm:"-"` // 平均采购单价 ExecutionEmployeePrice float64 `json:"execute_employee_price" gorm:"-"` // 平均员工成本价 ExecutionAmount float64 `json:"execute_amount" gorm:"-"` // 执行金额 } // ErpPurchaseInventory 采购入库执行信息 type ErpPurchaseInventory struct { Model ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id ErpPurchaseCommodityId uint32 `json:"erp_purchase_commodity_id" gorm:"index"` // 采购订单商品表id PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号 ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei"` // 商品串码 Count uint32 `json:"count"` // 执行数量 ImplementationPrice float64 `json:"implementation_price"` // 执行单价 Amount float64 `json:"amount"` // 执行金额 EmployeePrice float64 `json:"employee_price"` // 员工成本价 } type ErpPurchaseCreateReq struct { PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号 StoreId uint32 `json:"store_id"` // 门店id DeliveryAddress string `json:"delivery_address"` // 交货地址 HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id HandlerName string `json:"handler_name"` // 经手人名称 ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式 AccountHolder string `json:"account_holder"` // 收款人 OpeningBank string `json:"opening_bank" ` // 开户行 BankAccount string `json:"bank_account" ` // 银行卡号 DeliveryTime string `json:"delivery_time" ` // 交货日期 Remark string `json:"remark"` // 备注 ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodities" binding:"required"` // 采购商品信息 } type ErpPurchaseEditReq struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号 StoreId uint32 `json:"store_id" binding:"required"` // 门店id DeliveryAddress string `json:"delivery_address" binding:"required"` // 交货地址 HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id HandlerName string `json:"handler_name"` // 经手人名称 ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 供应商id ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式 AccountHolder string `json:"account_holder"` // 收款人 OpeningBank string `json:"opening_bank" validate:"required"` // 开户行 BankAccount string `json:"bank_account" validate:"required"` // 银行卡号 DeliveryTime string `json:"delivery_time" binding:"required"` // 交货日期 Remark string `json:"remark"` // 备注 ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodities" binding:"required"` // 采购商品信息 } type ErpPurchaseOrderListReq struct { SerialNumber string `json:"serial_number"` // 单据编号 PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货 StoreId uint32 `json:"store_id"` // 门店id ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 State uint32 `json:"state"` // 状态:1-待审核 2-待入库 3-待退货 4-已完成 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } type ErpPurchaseOrderListResp struct { List []ErpPurchaseOrder `json:"list"` Total int `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } type ErpPurchaseDetailReq struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id } // ErpPurchaseInventoryReq 入库(退货)入参;执行(入库/退货)入参 type ErpPurchaseInventoryReq struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息 } // ErpPurchaseAuditReq 审核采购订单入参 type ErpPurchaseAuditReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核 } // ErpPurchaseTerminateReq 终止采购入参 type ErpPurchaseTerminateReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 Remark string `json:"remark" binding:"required"` // 备注 } // ErpPurchaseExecuteResp 执行(入库/退货)出参 type ErpPurchaseExecuteResp struct { List []ExecuteData `json:"list"` Total int `json:"total"` // 总条数 } type ExecuteData struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei"` // 商品串码 Count uint32 `json:"count"` // 数量 ImplementationPrice float64 `json:"implementation_price"` // 执行单价 EmployeePrice float64 `json:"employee_price"` // 员工成本价 } type ErpPurchaseDemand struct { Model ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 ErpCommodityName string `json:"erp_commodity_name" gorm:"index"` // 商品名称 StoreId uint32 `json:"store_id"` // 门店id StoreName string `json:"store_name"` // 门店名称 Count uint32 `json:"count"` // 需采购数量 State uint32 `json:"state"` // 1-待采购 2-已采购 MakerId uint32 `json:"maker_id"` // 制单人id PurchaserId uint32 `json:"purchaser_id"` // 采购人id FinishTime *time.Time `json:"finish_time"` // 完成采购时间 Remark string `json:"remark"` // 备注 } type ErpPurchaseDemandRecord struct { Model ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id StoreId uint32 `json:"store_id" binding:"required"` // 门店id StoreName string `json:"store_name" binding:"required"` // 门店名称 Count uint32 `json:"count"` // 数量 MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id State uint32 `json:"state"` // 1-待采购 2-已采购 } type GetErpPurchaseDemandReq struct { ErpCategoryId uint32 `json:"erp_category_id"` // 商品分类id ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 HideFlag string `json:"hide_flag"` // 隐藏标记(默认关闭):ON-开启,隐藏无采购需求的商品,OFF-关闭,展示所有 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示数据条数 IsExport uint32 `json:"is_export"` // 1-导出 } type DemandData struct { ErpCommodityID uint32 `json:"erp_commodity_id"` // 商品id ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id ErpCategoryName string `json:"erp_category_name"` // 商品分类名称 RetailPrice uint32 `json:"retail_price"` // 指导零售价 LastWholesalePrice float64 `json:"last_wholesale_price"` // 最近采购价 TotalCount uint32 `json:"total_count"` // 需采购总数量 TotalAmount float64 `json:"total_amount"` // 需采购总金额 Remark string `json:"remark"` // 备注 StoreList []struct { StoreID uint32 `json:"store_id"` // 门店id StoreName string `json:"store_name"` // 门店名称 LastMonthSales uint32 `json:"last_month_sales"` // 上月销售数 StockCount uint32 `json:"stock_count"` // 库存数量 NeedCount uint32 `json:"need_count"` // 需采购数 } `json:"store_list"` } type GetErpPurchaseDemandResp struct { List []DemandData `json:"list"` Total int64 `json:"total"` // 数据总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 ExportUrl string `json:"export_url"` // 文件路径 } type CreateErpPurchaseDemandReq struct { ErpCommodityID uint32 `json:"erp_commodity_id"` // 商品id ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 Remark string `json:"remark"` // 备注 List []struct { StoreID uint32 `json:"store_id"` // 门店id StoreName string `json:"store_name"` // 门店名称 NeedCount uint32 `json:"need_count"` // 需采购数 } `json:"list"` } type FinishErpPurchaseDemandReq struct { ErpCommodityID uint32 `json:"erp_commodity_id" binding:"required"` // 商品id } func (m *ErpPurchaseOrderListReq) List() (*ErpPurchaseOrderListResp, error) { resp := &ErpPurchaseOrderListResp{ PageIndex: m.PageIndex, PageSize: m.PageSize, } page := m.PageIndex - 1 if page < 0 { page = 0 } if m.PageSize == 0 { m.PageSize = 10 } qs := orm.Eloquent.Table("erp_purchase_order") if m.SerialNumber != "" { qs = qs.Where("serial_number=?", m.SerialNumber) } else { if m.PurchaseType != "" { qs = qs.Where("purchase_type=?", m.PurchaseType) } if m.StoreId != 0 { qs = qs.Where("store_id=?", m.StoreId) } if m.ErpSupplierId != 0 { qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId) } if m.State != 0 { qs = qs.Where("state=?", m.State) } if m.AuditTimeStart != "" { parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) if err != nil { logger.Errorf("erpPurchaseOrderList err:", err) return nil, err } qs = qs.Where("audit_time > ?", parse) } if m.AuditTimeEnd != "" { parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd) if err != nil { logger.Errorf("erpPurchaseOrderList err:", err) return nil, err } parse = parse.AddDate(0, 0, 1) qs = qs.Where("audit_time < ?", parse) } } var count int64 err := qs.Count(&count).Error if err != nil { logger.Error("count err:", logger.Field("err", err)) return resp, err } resp.Total = int(count) var orders []ErpPurchaseOrder err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error if err != nil && err != RecordNotFound { logger.Error("erp commodity list err:", logger.Field("err", err)) return resp, err } resp.List = orders return resp, nil } // NewErpPurchaseSn 生成采购订单号 func NewErpPurchaseSn() 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_purchase_order WHERE serial_number='%s'", sn)) if err != nil { logger.Error("exist sn err") } if !exist { return sn } max++ } } func ErpPurchaseCommodityListPerfectInfo(purchaseCommodities []ErpPurchaseCommodity) error { commodityIds := make([]uint32, 0, len(purchaseCommodities)) for i, _ := range purchaseCommodities { commodityIds = append(commodityIds, purchaseCommodities[i].ID) } commodityMap, err := GetErpCommodityMap(commodityIds) if err != nil { logger.Error("purchase commodities err:", logger.Field("err", err)) return err } for i, _ := range purchaseCommodities { v, ok := commodityMap[purchaseCommodities[i].ErpCommodityId] if ok { purchaseCommodities[i].CommoditySerialNumber = v.SerialNumber purchaseCommodities[i].IMEIType = v.IMEIType //purchaseCommodities[i].IMEI = v.IMEI purchaseCommodities[i].ErpCommodityName = v.Name if purchaseCommodities[i].Count != 0 { purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price } if purchaseCommodities[i].RejectedCount != 0 { purchaseCommodities[i].RejectedAmount = float64(purchaseCommodities[i].RejectedCount) * purchaseCommodities[i].RejectedPrice } } } return nil } // IdInit 添加商户和供应商信息 func (m *ErpPurchaseOrder) IdInit() error { if m.StoreId != 0 { store, err := GetStore(m.StoreId) if err != nil { logger.Error("get store err:", logger.Field("err", err)) return err } m.StoreName = store.Name } if m.ErpSupplierId != 0 { supplier, err := GetErpSupplier(m.ErpSupplierId) if err != nil { logger.Error("get supplier err:", logger.Field("err", err)) return err } m.ErpSupplierName = supplier.Name } if m.ErpCashierId != 0 { cashier, err := GetAccountDetail(int(m.ErpCashierId)) if err != nil { logger.Error("get cashier err:", logger.Field("err", err)) return err } m.ErpCashierName = cashier.Name } return nil } // GetPurchaseInventorySn 生成入库编号 func GetPurchaseInventorySn() string { count := 0 for { if count > 5 { return "" } nowTime := time.Now() sn := nowTime.Format("060102") sn += fmt.Sprintf("%d", nowTime.Unix()%100) rand.Seed(nowTime.UnixNano()) sn += fmt.Sprintf("%d", rand.Int31n(100)) exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_inventory WHERE serial_number='%s'", sn)) if err != nil { logger.Error("sn err:", logger.Field("err", err)) count++ continue } if err == nil && !exist { return sn } return "" } } // CreateErpPurchaseOrder 新增采购订单 func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) { var err error nowTime := time.Now() purchaseOrder := &ErpPurchaseOrder{} if req.PurchaseType == ErpProcureOrder { // 采购入库订单 purchaseOrder = &ErpPurchaseOrder{ SerialNumber: "cgr" + NewErpPurchaseSn(), PurchaseType: req.PurchaseType, StoreId: req.StoreId, ErpSupplierId: req.ErpSupplierId, MakerTime: nowTime, HandlerId: req.HandlerId, HandlerName: req.HandlerName, MakerId: uint32(sysUser.UserId), MakerName: sysUser.NickName, State: ErpPurchaseOrderUnAudit, // 1-待审核 ErpCashierId: req.ErpCashierId, AccountHolder: req.AccountHolder, OpeningBank: req.OpeningBank, BankAccount: req.BankAccount, DeliveryTime: req.DeliveryTime, DeliveryAddress: req.DeliveryAddress, Remark: req.Remark, } err = purchaseOrder.IdInit() } else if req.PurchaseType == ErpRejectOrder { // 采购退货订单 if req.PurchaseOrderSn == "" { return nil, errors.New("新建失败:采购退货订单号为空") } var erpPurchaseOrder ErpPurchaseOrder err = orm.Eloquent.Table("erp_purchase_order").Where("serial_number=?", req.PurchaseOrderSn).Find(&erpPurchaseOrder).Error if err != nil { logger.Error("purchase order err:", logger.Field("err", err)) return nil, err } purchaseOrder = &ErpPurchaseOrder{ SerialNumber: "cgt" + NewErpPurchaseSn(), PurchaseType: req.PurchaseType, StoreId: erpPurchaseOrder.StoreId, ErpSupplierId: erpPurchaseOrder.ErpSupplierId, MakerTime: nowTime, HandlerId: req.HandlerId, HandlerName: req.HandlerName, MakerId: uint32(sysUser.UserId), MakerName: sysUser.NickName, State: ErpPurchaseOrderUnAudit, // 1-待审核 ErpCashierId: req.ErpCashierId, Remark: req.Remark, } err = purchaseOrder.IdInit() } else { logger.Errorf("purchase_type err:", req.PurchaseType) return nil, errors.New("操作失败:采购类型有误") } if err != nil { logger.Error("info err:", logger.Field("err", err)) return nil, err } err = ErpPurchaseCommodityListPerfectInfo(req.ErpPurchaseCommodities) if err != nil { logger.Error("info err:", logger.Field("err", err)) return nil, err } begin := orm.Eloquent.Begin() err = begin.Create(purchaseOrder).Error if err != nil { begin.Rollback() logger.Error("create purchase order err:", logger.Field("err", err)) return nil, err } for i, _ := range req.ErpPurchaseCommodities { req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = purchaseOrder.ID req.ErpPurchaseCommodities[i].InventoryCount = 0 // todo 数量待核实 err = begin.Create(&req.ErpPurchaseCommodities[i]).Error if err != nil { begin.Rollback() logger.Error("create purchase commodity err:", logger.Field("err", err)) return nil, err } } err = begin.Commit().Error if err != nil { begin.Rollback() logger.Error("commit purchase commodity err:", logger.Field("err", err)) return nil, err } return purchaseOrder, nil } // EditErpPurchaseOrder 编辑采购订单 func EditErpPurchaseOrder(req *ErpPurchaseEditReq, sysUser *SysUser) (*ErpPurchaseOrder, error) { // 查询订单信息 var purchaseOrder ErpPurchaseOrder err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error if err != nil { logger.Error("purchase order err:", logger.Field("err", err)) return nil, err } if purchaseOrder.State != ErpPurchaseOrderUnAudit { // 只有待审核的订单才能编辑 return nil, errors.New("订单不是待审核状态") } begin := orm.Eloquent.Begin() // 1-更新采购订单信息 purchaseOrder.StoreId = req.StoreId purchaseOrder.ErpSupplierId = req.ErpSupplierId purchaseOrder.HandlerId = req.HandlerId purchaseOrder.HandlerName = req.HandlerName purchaseOrder.MakerId = uint32(sysUser.UserId) purchaseOrder.MakerName = sysUser.NickName purchaseOrder.ErpCashierId = req.ErpCashierId purchaseOrder.AccountHolder = req.AccountHolder purchaseOrder.OpeningBank = req.OpeningBank purchaseOrder.BankAccount = req.BankAccount purchaseOrder.DeliveryTime = req.DeliveryTime purchaseOrder.DeliveryAddress = req.DeliveryAddress purchaseOrder.Remark = req.Remark err = purchaseOrder.IdInit() if err != nil { logger.Error("purchase IdInit err:", logger.Field("err", err)) return nil, err } err = begin.Model(&ErpPurchaseOrder{}).Where("id = ?", req.ErpPurchaseOrderId).Updates(purchaseOrder).Error if err != nil { begin.Rollback() logger.Error("update erp_order err:", logger.Field("err", err)) return nil, err } // 2-更新采购订单商品表 err = updatePurchaseCommodityData(begin, req.ErpPurchaseOrderId, req) if err != nil { begin.Rollback() logger.Error("update erp_purchase_commodity err:", logger.Field("err", err)) return nil, err } err = begin.Commit().Error if err != nil { begin.Rollback() logger.Error("commit err:", logger.Field("err", err)) return nil, err } return &purchaseOrder, nil } // updatePurchaseCommodityData 更新采购订单商品信息 func updatePurchaseCommodityData(gdb *gorm.DB, orderId uint32, req *ErpPurchaseEditReq) error { // 查询现有的零售订单信息 var commodities []ErpPurchaseCommodity err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error if err != nil { logger.Error("query erp_purchase_commodity err:", logger.Field("err", err)) return err } var newCommodities []ErpPurchaseCommodity var deletedCommodities []ErpPurchaseCommodity var matchingCommodities []ErpPurchaseCommodity // 找到新增的商品 for i, reqCommodity := range req.ErpPurchaseCommodities { // 订单商品表信息添加零售订单id req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = orderId var found bool for _, dbCommodity := range commodities { if reqCommodity.ErpCommodityId == dbCommodity.ErpCommodityId { found = true break } } if !found { newCommodities = append(newCommodities, reqCommodity) } } // 找到删除的商品 for _, dbCommodity := range commodities { var found bool for _, reqCommodity := range req.ErpPurchaseCommodities { if reqCommodity.ID == dbCommodity.ID { found = true // 找到匹配的商品,加入匹配列表 matchingCommodities = append(matchingCommodities, reqCommodity) break } } if !found { deletedCommodities = append(deletedCommodities, dbCommodity) } } // 2-更新商品订单信息-更新 for _, commodity := range matchingCommodities { if err := gdb.Model(&ErpPurchaseCommodity{}).Where("id = ?", commodity.ID).Updates(commodity).Error; err != nil { logger.Error("更新商品订单信息-更新 error") return errors.New("操作失败:" + err.Error()) } } // 2-更新商品订单信息-新增 if len(newCommodities) != 0 { err = gdb.Create(&newCommodities).Error if err != nil { logger.Error("更新商品订单信息-新增 error") return errors.New("操作失败:" + err.Error()) } } //2-更新商品订单信息-删除 if len(deletedCommodities) != 0 { err = gdb.Delete(&deletedCommodities).Error if err != nil { logger.Error("更新商品订单信息-删除 error") return errors.New("操作失败:" + err.Error()) } } return nil } // InventoryErpPurchase 采购订单入库 func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { err := checkPurchaseInventory(req) if err != nil { logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err)) return err } begin := orm.Eloquent.Begin() for _, v := range req.Inventories { v.SerialNumber = GetPurchaseInventorySn() // 更新采购商品表的执行数量 // todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息,可能采购价不同,需要区分入库的是哪一条(已修改) err = begin.Model(&ErpPurchaseCommodity{}). Where("id = ?", v.ErpPurchaseCommodityId). UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error if err != nil { begin.Rollback() logger.Error("update inventory count err:", logger.Field("err", err)) return err } // 新建采购入库记录 err = begin.Create(&v).Error if err != nil { begin.Rollback() logger.Error("create erp inventory commodity err:", logger.Field("err", err)) return err } } // 查询采购订单信息 var purchaseOrder ErpPurchaseOrder err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error if err != nil { logger.Error("purchase order err:", logger.Field("err", err)) return err } // 更新库存信息表 if purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单 err = InventoryErpPurchaseUpdateStock(begin, req, purchaseOrder) } else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单 err = InventoryErpPurchaseUpdateRejectStock(begin, req, purchaseOrder) } else { return errors.New("订单类型有误") } if err != nil { begin.Rollback() logger.Error("update stock err:", logger.Field("err", err)) return err } err = begin.Commit().Error if err != nil { begin.Rollback() logger.Error("commit err:", logger.Field("err", err)) return err } return nil } // InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息 func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error { // 遍历采购入库商品信息 var stockList []ErpStockCommodity for _, v := range req.Inventories { commodityInfo, err := GetCommodity(v.ErpCommodityId) if err != nil { logger.Errorf("GetCommodity err:", err) return err } exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d", purchaseOrder.StoreId, v.ErpCommodityId)) if err != nil { logger.Errorf("exist err:", err) return err } if exist { err = gdb.Exec(fmt.Sprintf( "UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;", v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error if err != nil { logger.Errorf("update stock err:", err) return err } } else { stock := &ErpStock{ StoreId: purchaseOrder.StoreId, StoreName: purchaseOrder.StoreName, ErpCommodityId: v.ErpCommodityId, ErpCommodityName: v.ErpCommodityName, ErpCategoryId: commodityInfo.ErpCategoryId, ErpCategoryName: commodityInfo.ErpCategoryName, CommoditySerialNumber: v.CommoditySerialNumber, IMEIType: v.IMEIType, RetailPrice: commodityInfo.RetailPrice, MinRetailPrice: commodityInfo.MinRetailPrice, Count: v.Count, DispatchCount: 0, } err = gdb.Create(stock).Error if err != nil { logger.Errorf("create stock err:", err) return err } } nowTime := time.Now() stockCommodity := ErpStockCommodity{ StoreId: purchaseOrder.StoreId, StoreName: purchaseOrder.StoreName, ErpCommodityId: v.ErpCommodityId, ErpCommodityName: v.ErpCommodityName, CommoditySerialNumber: v.CommoditySerialNumber, ErpCategoryId: commodityInfo.ErpCategoryId, ErpCategoryName: commodityInfo.ErpCategoryName, ErpSupplierId: purchaseOrder.ErpSupplierId, ErpSupplierName: purchaseOrder.ErpSupplierName, StaffCostPrice: uint32(v.EmployeePrice - v.ImplementationPrice), WholesalePrice: uint32(v.ImplementationPrice), State: 1, StorageType: 1, FirstStockTime: nowTime, StockTime: nowTime, Count: v.Count, ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码 IMEIType: v.IMEIType, IMEI: v.IMEI, Remark: "", MemberDiscount: commodityInfo.MemberDiscount, MinRetailPrice: commodityInfo.MinRetailPrice, RetailPrice: commodityInfo.RetailPrice, } stockList = append(stockList, stockCommodity) } err := gdb.Debug().Create(&stockList).Error if err != nil { logger.Errorf("create stock commodity err:", err) return err } return nil } // InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息 func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error { for i, _ := range req.Inventories { if req.Inventories[i].IMEIType == 2 { // 串码商品 if req.Inventories[i].IMEI == "" { return errors.New("串码为空") } // 判断该串码商品是否已经销售 var stockCommodityInfo ErpStockCommodity err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[i].IMEI). Find(&stockCommodityInfo).Error if err != nil { logger.Error("Inventory RejectStock query commodities err:", logger.Field("err", err)) return err } if stockCommodityInfo.State == SoldOut { return fmt.Errorf("商品[%s]已经消息,不能退货", stockCommodityInfo.ErpCommodityName) } else if stockCommodityInfo.State == OnSale { return fmt.Errorf("商品[%s]在销售锁定中,不能退货", stockCommodityInfo.ErpCommodityName) } err = gdb.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[i].IMEI). Update("state", PurchaseReturn).Error // 状态更新为采购退货 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", purchaseOrder.StoreId, req.Inventories[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } } else { // 非串码商品 var stockCommodity []ErpStockCommodity // 通过门店id,商品id,查找状态为1-在库的非串码商品 err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ "and state = ? and imei_type = ?", req.Inventories[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1). Order("id DESC").Find(&stockCommodity).Error if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } if stockCommodity == nil { return errors.New("RetailTypeRejected find no stock commodity") } err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). Update("state", PurchaseReturn).Error // 状态更新为采购退货 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", purchaseOrder.StoreId, req.Inventories[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } } } return nil } // 校验入参数据,执行数量是否超过总数;串码商品的串码是否重复 func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error { // 查询现有的零售订单信息 var commodities []ErpPurchaseCommodity err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", req.ErpPurchaseOrderId).Find(&commodities).Error if err != nil { logger.Error("query erp_purchase_commodity err:", logger.Field("err", err)) return err } countMap := make(map[uint32]uint32) for _, inventory := range req.Inventories { countMap[inventory.ErpCommodityId] += inventory.Count // 如果该商品是串码商品,判断其串码是否会重复 if inventory.IMEI != "" { exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET(%s, imei) > 0", inventory.IMEI)) if err != nil { logger.Error("exist sn err") } if exist { return fmt.Errorf("串码重复[%s]", inventory.IMEI) } } } // 入库的商品信息有误,不在之前的商品列表中 for commodityID := range countMap { found := false for _, commodity := range commodities { if commodity.ErpCommodityId == commodityID { found = true break } } if !found { return fmt.Errorf("商品编号[%d]不属于该采购订单", commodityID) } } // 本次入库的数量超出该商品未入库数量 for _, commodity := range commodities { if inventoryCount, ok := countMap[commodity.ErpCommodityId]; ok { if req.PurchaseType == ErpProcureOrder { if commodity.Count-uint32(commodity.InventoryCount) < inventoryCount { return fmt.Errorf("本次入库商品[%s]数量[%d]超出该商品未入库数量[%d]", commodity.ErpCommodityName, inventoryCount, int32(commodity.Count)-commodity.InventoryCount) } } else if req.PurchaseType == ErpRejectOrder { if commodity.RejectedCount-uint32(commodity.InventoryCount) < inventoryCount { return fmt.Errorf("本次退货商品[%s]数量[%d]超出该商品未退货数量[%d]", commodity.ErpCommodityName, inventoryCount, int32(commodity.Count)-commodity.InventoryCount) } } } } return nil } // ExecuteErpPurchase 执行(入库/退货) func ExecuteErpPurchase(req *ErpPurchaseInventoryReq) (*ErpPurchaseExecuteResp, error) { err := checkPurchaseInventory(req) if err != nil { logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err)) return nil, err } resp := &ErpPurchaseExecuteResp{ List: make([]ExecuteData, 0), } for _, inventory := range req.Inventories { if inventory.IMEIType == 2 { // 如果是串码商品,根据 Count 拆分成对应数量的数据 for i := 0; i < int(inventory.Count); i++ { imei := "" // 默认退货单执行时不需要串码 if inventory.PurchaseType == ErpProcureOrder { // 采购单 // 调用函数B生成商品串码 imei, err = generateIMEI(inventory.ErpCommodityId) if err != nil { return nil, err } } // 将拆分后的商品信息添加到执行响应中 resp.List = append(resp.List, ExecuteData{ ErpPurchaseOrderId: inventory.ErpPurchaseOrderId, ErpCommodityId: inventory.ErpCommodityId, ErpCommodityName: inventory.ErpCommodityName, CommoditySerialNumber: inventory.CommoditySerialNumber, IMEIType: inventory.IMEIType, IMEI: imei, Count: 1, ImplementationPrice: inventory.ImplementationPrice, EmployeePrice: inventory.EmployeePrice, }) } } else if inventory.IMEIType == 1 { // 如果是非串码商品,只需拆分为1条数据 resp.List = append(resp.List, ExecuteData{ ErpPurchaseOrderId: inventory.ErpPurchaseOrderId, ErpCommodityId: inventory.ErpCommodityId, ErpCommodityName: inventory.ErpCommodityName, CommoditySerialNumber: inventory.CommoditySerialNumber, IMEIType: inventory.IMEIType, IMEI: "", Count: inventory.Count, ImplementationPrice: inventory.ImplementationPrice, EmployeePrice: inventory.EmployeePrice, }) } } resp.Total = len(resp.List) return resp, nil } // 生成串码 func generateIMEI(commodityId uint32) (string, error) { commodity, err := GetCommodity(commodityId) if err != nil { return "", err } return GenerateSerialCode(commodity.ErpCategoryId) } // CreateErpPurchaseDemand 创建采购需求单 func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error { var demandInfo ErpPurchaseDemand var demandList []ErpPurchaseDemand demandInfo.ErpCommodityId = req.ErpCommodityID demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber demandInfo.ErpCommodityName = req.ErpCommodityName demandInfo.Remark = req.Remark demandInfo.State = ErpDemandStateWait // 待采购 for _, v := range req.List { demandInfo.StoreId = v.StoreID demandInfo.StoreName = v.StoreName demandInfo.Count = v.NeedCount demandInfo.MakerId = uint32(sysUser.UserId) demandList = append(demandList, demandInfo) } begin := orm.Eloquent.Begin() // 查询当前表格,有记录则更新,没有则插入新记录 for _, v := range demandList { var demand ErpPurchaseDemand err := orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? and store_id = ? and state = 1", v.ErpCommodityId, v.StoreId).Find(&demand).Error if err != nil { logger.Error("query erp_purchase_demand err:", logger.Field("err", err)) return err } if demand.StoreId != 0 { // 有记录 if demand.Count == v.Count { // 值没变则不更新 continue } else { err = begin.Model(&ErpPurchaseDemand{}).Where("erp_commodity_id = ? and store_id = ? and state = 1", v.ErpCommodityId, v.StoreId).Updates(v).Error if err != nil { begin.Rollback() logger.Error("update erp_order err:", logger.Field("err", err)) return err } } } else { // 无记录,新建 err = begin.Create(&v).Error if err != nil { logger.Error("query erp_purchase_demand err:", logger.Field("err", err)) return err } } } err := begin.Commit().Error if err != nil { begin.Rollback() logger.Error("commit err:", logger.Field("err", err)) return err } return nil } // FinishErpPurchaseDemand 完成采购需求 func FinishErpPurchaseDemand(req *FinishErpPurchaseDemandReq, sysUser *SysUser) error { exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_demand WHERE erp_commodity_id='%d'", req.ErpCommodityID)) if err != nil { logger.Error("exist sn err") } if !exist { return fmt.Errorf("商品编号[%d]的商品不在采购需求单中", req.ErpCommodityID) } // 批量更新状态 err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=?", req.ErpCommodityID). Updates(map[string]interface{}{ "state": ErpDemandStateFinish, "finish_time": time.Now(), "purchaser_id": sysUser.UserId, }).Error if err != nil { logger.Error("update err:", logger.Field("err", err)) return err } return nil } //// GetErpPurchaseDemand 获取采购需求 //func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { // resp := &GetErpPurchaseDemandResp{ // 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_commodity") // if req.ErpCategoryId != 0 { // qs = qs.Where("erp_category_id=?", req.ErpCategoryId) // } // // var commodities []ErpCommodity // err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error // if err != nil && err != RecordNotFound { // //logger.Error("erp commodity list err:", err) // return resp, err // } // // // 组合数据 // resp, err = convertToDemandResp(commodities) // // return resp, nil //} // //func convertToDemandResp(commodities []ErpCommodity) (*GetErpPurchaseDemandResp, error) { // resp := new(GetErpPurchaseDemandResp) // var demandData DemandData // var demandList []DemandData // // // 查询所有在线门店信息 // var stores []Store // err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error // if err != nil { // logger.Error("stores err:", logger.Field("err", err)) // return nil, err // } // // demandData.List = make([]struct { // StoreID uint32 `json:"store_id"` // StoreName string `json:"store_name"` // LastMonthSales uint32 `json:"last_month_sales"` // StockCount uint32 `json:"stock_count"` // NeedCount uint32 `json:"need_count"` // }, len(stores)) // // var totalCount uint32 // 总需采购数量 // // // 遍历所有商品 // for _, v := range commodities { // // 初始化 NeedCount 为 0 // var totalNeedCount uint32 // // for i, store := range stores { // demandData.List[i].StoreID = store.ID // demandData.List[i].StoreName = store.Name // // // 初始化 NeedCount 为 0 // demandData.List[i].NeedCount = 0 // // // 设置商品相关信息 // demandData.ErpCommodityID = v.ID // demandData.ErpCommoditySerialNumber = v.SerialNumber // demandData.ErpCommodityName = v.Name // demandData.ErpCategoryID = v.ErpCategoryId // demandData.ErpCategoryName = v.ErpCategoryName // demandData.RetailPrice = v.RetailPrice // // 最近采购价 // demandData.LastWholesalePrice, _ = GetCommodityLastWholesalePrice(v.ID) // // // 查询采购需求单 // var demand []ErpPurchaseDemand // err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", // v.ID, store.ID).Find(&demand).Error // if err != nil { // logger.Error("query erp_purchase_demand err:", logger.Field("err", err)) // return nil, err // } // // if len(demand) > 0 { // totalNeedCount += demand[0].Count // demandData.List[i].NeedCount = demand[0].Count // } // // // 查询某个门店某个商品的库存情况 // demandData.List[i].StockCount, _ = GetCommodityStockByStoreId(v.ID, store.ID) // // 查询某个门店某件商品的上月销售数量 // demandData.List[i].LastMonthSales, _ = GetCommodityLastMonthSalesByStoreId(v.ID, store.ID) // } // totalCount += totalNeedCount // demandData.TotalCount = totalCount // demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice // demandList = append(demandList, demandData) // } // resp.List = demandList // // return resp, nil //} // //// GetCommodityStockByStoreId 查询某个门店某个商品的库存情况 //func GetCommodityStockByStoreId(commodityId, storeId uint32) (uint32, error) { // var count int64 // err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? and state = 1", // commodityId, storeId).Count(&count).Error // if err != nil { // logger.Error("GetCommodityStockByStoreId count err:", logger.Field("err", err)) // return 0, err // } // // return uint32(count), nil //} // //// GetCommodityLastMonthSalesByStoreId 查询某个门店某件商品的上月销售数量 //func GetCommodityLastMonthSalesByStoreId(commodityId, storeId uint32) (uint32, error) { // var lastMonthSales uint32 // // // 获取当前时间 // now := time.Now() // year, month, _ := now.Date() // firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) // lastDay := firstDay.AddDate(0, 1, -1) // // // 执行查询 // err := orm.Eloquent.Model(&ErpOrderCommodity{}). // Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). // Select("SUM(erp_order_commodity.count) AS last_month_sales"). // Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ // "AND erp_order_commodity.created_at BETWEEN ? AND ?", // HavePaid, commodityId, storeId, firstDay, lastDay). // Scan(&lastMonthSales).Error // if err != nil { // logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err)) // return 0, err // } // // return lastMonthSales, nil //} // //// GetCommodityLastWholesalePrice 查询某个商品的最近采购价 //func GetCommodityLastWholesalePrice(commodityId uint32) (float64, error) { // var implementationPrice float64 // // // 执行查询 // err := orm.Eloquent.Table("erp_purchase_inventory"). // Select("implementation_price"). // Where("erp_commodity_id = ? AND purchase_type = ?", 167, "procure"). // Order("created_at DESC"). // Limit(1). // Scan(&implementationPrice).Error // if err != nil { // logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err)) // return 0, err // } // // return implementationPrice, nil //} // 222222222 //// GetErpPurchaseDemand 获取采购需求 //func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { // resp := &GetErpPurchaseDemandResp{ // 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_commodity") // if req.ErpCategoryId != 0 { // qs = qs.Where("erp_category_id=?", req.ErpCategoryId) // } // // var commodities []ErpCommodity // err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error // if err != nil && err != RecordNotFound { // return resp, err // } // // // 批量查询门店信息 // stores, err := GetOnlineStores() // if err != nil { // return nil, err // } // // // 批量查询商品信息 // demandDataList := make([]DemandData, 0, len(commodities)) // for _, v := range commodities { // demandData, err := convertToDemandData(v, stores) // if err != nil { // return nil, err // } // demandDataList = append(demandDataList, demandData) // } // // resp.List = demandDataList // // return resp, nil //} // //// convertToDemandData 将商品转换为采购需求数据 //func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { // demandData := DemandData{ // ErpCommodityID: commodity.ID, // ErpCommoditySerialNumber: commodity.SerialNumber, // ErpCommodityName: commodity.Name, // ErpCategoryID: commodity.ErpCategoryId, // ErpCategoryName: commodity.ErpCategoryName, // RetailPrice: commodity.RetailPrice, // } // // // 批量查询最近采购价 // lastWholesalePrices, err := GetCommodityLastWholesalePrices(commodity.ID) // if err != nil { // return DemandData{}, err // } // // for i, store := range stores { // demandData.List = append(demandData.List, struct { // StoreID uint32 `json:"store_id"` // StoreName string `json:"store_name"` // LastMonthSales uint32 `json:"last_month_sales"` // StockCount uint32 `json:"stock_count"` // NeedCount uint32 `json:"need_count"` // }{ // StoreID: store.ID, // StoreName: store.Name, // }) // // // 批量查询库存情况 // stockCounts, err := GetCommodityStocksByStoreID(commodity.ID, store.ID) // if err != nil { // return DemandData{}, err // } // demandData.List[i].StockCount = stockCounts[store.ID] // // // 批量查询上月销售数量 // lastMonthSales, err := GetCommodityLastMonthSales(commodity.ID, store.ID) // if err != nil { // return DemandData{}, err // } // demandData.List[i].LastMonthSales = lastMonthSales // // // 设置最近采购价 // demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID] // } // // return demandData, nil //} // //// GetCommodityLastWholesalePrices 批量查询商品的最近采购价 //func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { // // 查询最近采购价 // var prices []struct { // CommodityID uint32 // Price float64 // } // err := orm.Eloquent.Table("erp_purchase_inventory"). // Select("erp_commodity_id, implementation_price AS price"). // Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure"). // Group("erp_commodity_id"). // Order("created_at DESC"). // Find(&prices).Error // if err != nil { // return nil, err // } // // // 构建结果 // result := make(map[uint32]float64) // for _, p := range prices { // result[p.CommodityID] = p.Price // } // return result, nil //} // //// GetCommodityStocksByStoreID 批量查询商品的库存情况 //func GetCommodityStocksByStoreID(commodityID, storeID uint32) (map[uint32]uint32, error) { // // 查询库存情况 // var stocks []struct { // StoreID uint32 // CommodityID uint32 // StockCount uint32 // } // err := orm.Eloquent.Table("erp_stock_commodity"). // Select("store_id, erp_commodity_id, COUNT(*) AS stock_count"). // Where("erp_commodity_id IN (?) AND store_id = ? AND state = 1", commodityID, storeID). // Group("store_id, erp_commodity_id"). // Find(&stocks).Error // if err != nil { // return nil, err // } // // // 构建结果 // result := make(map[uint32]uint32) // for _, s := range stocks { // result[s.StoreID] = s.StockCount // } // return result, nil //} // //// GetCommodityLastMonthSales 批量查询商品的上月销售数量 //func GetCommodityLastMonthSales(commodityID, storeID uint32) (uint32, error) { // // 获取上个月的时间范围 // firstDay, lastDay := GetLastMonthRange() // // // 查询上月销售数量 // var lastMonthSales struct { // Sales uint32 // } // err := orm.Eloquent.Table("erp_order_commodity"). // Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). // Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ // "AND erp_order_commodity.created_at BETWEEN ? AND ?", // HavePaid, commodityID, storeID, firstDay, lastDay). // Select("SUM(erp_order_commodity.count) AS sales"). // Scan(&lastMonthSales).Error // if err != nil { // return 0, err // } // // return lastMonthSales.Sales, nil //} // //// GetLastMonthRange 获取上个月的时间范围 //func GetLastMonthRange() (time.Time, time.Time) { // now := time.Now() // year, month, _ := now.Date() // firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) // lastDay := firstDay.AddDate(0, 1, -1) // return firstDay, lastDay //} // //// GetOnlineStores 查询所有在线门店信息 //func GetOnlineStores() ([]Store, error) { // var stores []Store // err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error // if err != nil { // return nil, err // } // return stores, nil //} // 3333 //// GetErpPurchaseDemand 获取采购需求 //func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { // resp := &GetErpPurchaseDemandResp{ // 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_commodity") // if req.ErpCategoryId != 0 { // qs = qs.Where("erp_category_id=?", req.ErpCategoryId) // } // // var commodities []ErpCommodity // err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error // if err != nil && err != RecordNotFound { // return resp, err // } // // // 批量查询门店信息 // stores, err := GetOnlineStores() // if err != nil { // return nil, err // } // // // 并行查询需求数据 // var wg sync.WaitGroup // demandDataList := make([]DemandData, len(commodities)) // // for i, v := range commodities { // wg.Add(1) // go func(index int, commodity ErpCommodity) { // defer wg.Done() // demandData, err := convertToDemandData(commodity, stores) // if err != nil { // // Handle error // return // } // demandDataList[index] = demandData // }(i, v) // } // // wg.Wait() // // resp.List = demandDataList // // return resp, nil //} // //// convertToDemandData 将商品转换为采购需求数据 //func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { // demandData := DemandData{ // ErpCommodityID: commodity.ID, // ErpCommoditySerialNumber: commodity.SerialNumber, // ErpCommodityName: commodity.Name, // ErpCategoryID: commodity.ErpCategoryId, // ErpCategoryName: commodity.ErpCategoryName, // RetailPrice: commodity.RetailPrice, // } // // // 并行查询最近采购价、库存情况、上月销售数量 // var wg sync.WaitGroup // wg.Add(3) // // var lastWholesalePrices map[uint32]float64 // var stockCounts map[uint32]uint32 // var lastMonthSales uint32 // var err1, err2, err3 error // // go func() { // defer wg.Done() // lastWholesalePrices, err1 = GetCommodityLastWholesalePrices(commodity.ID) // }() // // go func() { // defer wg.Done() // stockCounts, err2 = GetCommodityStocksByStoreID(commodity.ID, stores) // }() // // go func() { // defer wg.Done() // lastMonthSales, err3 = GetCommodityLastMonthSales(commodity.ID, stores) // }() // // wg.Wait() // // if err1 != nil || err2 != nil || err3 != nil { // // Handle error // return DemandData{}, err1 // } // // // 构建需求数据 // demandData.List = make([]struct { // StoreID uint32 `json:"store_id"` // StoreName string `json:"store_name"` // LastMonthSales uint32 `json:"last_month_sales"` // StockCount uint32 `json:"stock_count"` // NeedCount uint32 `json:"need_count"` // }, len(stores)) // // for i, store := range stores { // demandData.List[i].StoreID = store.ID // demandData.List[i].StoreName = store.Name // // demandData.List[i].StockCount = stockCounts[store.ID] // demandData.List[i].LastMonthSales = lastMonthSales // // // 设置最近采购价 // demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID] // } // // return demandData, nil //} // //// GetCommodityLastWholesalePrices 批量查询商品的最近采购价 //func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { // // 查询最近采购价 // var prices []struct { // CommodityID uint32 // Price float64 // } // err := orm.Eloquent.Table("erp_purchase_inventory"). // Select("erp_commodity_id, implementation_price AS price"). // Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure"). // Group("erp_commodity_id"). // Order("created_at DESC"). // Find(&prices).Error // if err != nil { // return nil, err // } // // // 构建结果 // result := make(map[uint32]float64) // for _, p := range prices { // result[p.CommodityID] = p.Price // } // return result, nil //} // //// GetCommodityStocksByStoreID 批量查询商品的库存情况 //func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) { // // 并行查询库存情况 // var wg sync.WaitGroup // wg.Add(len(stores)) // // result := make(map[uint32]uint32) // // for _, store := range stores { // go func(storeID uint32) { // defer wg.Done() // // 查询库存情况 // var stockCount int64 // err := orm.Eloquent.Table("erp_stock_commodity"). // Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID). // Count(&stockCount).Error // if err != nil { // // Handle error // return // } // result[storeID] = uint32(stockCount) // }(store.ID) // } // // wg.Wait() // // return result, nil //} // //// GetCommodityLastMonthSales 批量查询商品的上月销售数量 //func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) { // // 获取上个月的时间范围 // firstDay, lastDay := GetLastMonthRange() // // // 并行查询上月销售数量 // var wg sync.WaitGroup // wg.Add(len(stores)) // // var totalSales uint32 // var mu sync.Mutex // 用于保护 totalSales 的并发访问 // // for _, store := range stores { // go func(storeID uint32) { // defer wg.Done() // // 查询上月销售数量 // var sales uint32 // err := orm.Eloquent.Table("erp_order_commodity"). // Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). // Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ // "AND erp_order_commodity.created_at BETWEEN ? AND ?", // HavePaid, commodityID, storeID, firstDay, lastDay). // Select("SUM(erp_order_commodity.count) AS sales"). // Scan(&sales).Error // if err != nil { // // Handle error // return // } // // // 累加销售数量 // mu.Lock() // totalSales += sales // mu.Unlock() // }(store.ID) // } // // wg.Wait() // // return totalSales, nil //} // //// GetLastMonthRange 获取上个月的时间范围 //func GetLastMonthRange() (time.Time, time.Time) { // now := time.Now() // year, month, _ := now.Date() // firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) // lastDay := firstDay.AddDate(0, 1, -1) // return firstDay, lastDay //} // //// GetOnlineStores 查询所有在线门店信息 //func GetOnlineStores() ([]Store, error) { // var stores []Store // err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error // if err != nil { // return nil, err // } // return stores, nil //} // GetErpPurchaseDemand 获取采购需求 func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { var err error resp := new(GetErpPurchaseDemandResp) if req.HideFlag == "ON" { // 隐藏无采购需求的商品 resp, err = getErpPurchaseDemandHide(req) } else { // 展示所有 resp, err = getErpPurchaseDemandAll(req) } if err != nil { return nil, err } return resp, nil } // 展示所有采购需求 func getErpPurchaseDemandAll(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { page := req.PageIndex - 1 if page < 0 { page = 0 } if req.PageSize == 0 { req.PageSize = 10 } resp := &GetErpPurchaseDemandResp{ PageIndex: page + 1, PageSize: req.PageSize, } qs := orm.Eloquent.Debug().Table("erp_commodity") if req.ErpCategoryId != 0 { qs = qs.Where("erp_category_id=?", req.ErpCategoryId) } if req.ErpCommoditySerialNumber != "" { qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber) } if req.ErpCommodityName != "" { qs = qs.Where("name=?", req.ErpCommodityName) } var count int64 if err := qs.Count(&count).Error; err != nil { logger.Error("count err:", logger.Field("err", err)) return resp, err } var commodities []ErpCommodity if req.IsExport == 1 { // 导出excel err := qs.Order("id DESC").Find(&commodities).Error if err != nil && err != RecordNotFound { return resp, err } } else { err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error if err != nil && err != RecordNotFound { return resp, err } } // 批量查询门店信息 stores, err := GetOnlineStores() if err != nil { return nil, err } // 并行查询需求数据 var wg sync.WaitGroup demandDataList := make([]DemandData, len(commodities)) for i, v := range commodities { wg.Add(1) go func(index int, commodity ErpCommodity) { defer wg.Done() demandData, err := convertToDemandData(commodity, stores) if err != nil { // Handle error return } demandDataList[index] = demandData }(i, v) } wg.Wait() if req.IsExport == 1 { // 导出excel if len(demandDataList) == 0 { return nil, errors.New("未查询到数据") } resp.ExportUrl, err = demandDataExport(demandDataList) if err != nil { return nil, err } } else { resp.List = demandDataList resp.Total = count } return resp, nil } // 隐藏无采购需求的商品 func getErpPurchaseDemandHide(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { page := req.PageIndex - 1 if page < 0 { page = 0 } if req.PageSize == 0 { req.PageSize = 10 } resp := &GetErpPurchaseDemandResp{ PageIndex: page + 1, PageSize: req.PageSize, } // 查询采购需求单信息,筛选出有采购需求的商品id var demand []ErpPurchaseDemand err := orm.Eloquent.Table("erp_purchase_demand"). Where("state = 1").Find(&demand).Error if err != nil { return nil, err } // 用 map 存储已经出现过的 ErpCommodityId commodityIds := make(map[uint32]bool) var uniqueCommodityIds []uint32 for _, d := range demand { if _, ok := commodityIds[d.ErpCommodityId]; !ok { commodityIds[d.ErpCommodityId] = true uniqueCommodityIds = append(uniqueCommodityIds, d.ErpCommodityId) } } // 查询商品信息 qs := orm.Eloquent.Debug().Table("erp_commodity") if req.ErpCategoryId != 0 { qs = qs.Where("erp_category_id=?", req.ErpCategoryId) } if req.ErpCommoditySerialNumber != "" { qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber) } if req.ErpCommodityName != "" { qs = qs.Where("name=?", req.ErpCommodityName) } var count int64 if err := qs.Count(&count).Error; err != nil { logger.Error("count err:", logger.Field("err", err)) return resp, err } var commodities []ErpCommodity if req.IsExport == 1 { // 导出excel err := qs.Order("id DESC").Find(&commodities).Error if err != nil && err != RecordNotFound { return resp, err } } else { err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error if err != nil && err != RecordNotFound { return resp, err } } // 匹配商品id,有则继续查询返回数据,没有则不返回 var matchedCommodities []ErpCommodity for _, c := range commodities { for _, uniqueID := range uniqueCommodityIds { if c.ID == uniqueID { matchedCommodities = append(matchedCommodities, c) break // 找到匹配的商品后跳出内层循环,继续下一个商品 } } } if len(matchedCommodities) == 0 { resp.List = nil } else { // 批量查询门店信息 stores, err := GetOnlineStores() if err != nil { return nil, err } // 并行查询需求数据 var wg sync.WaitGroup demandDataList := make([]DemandData, len(matchedCommodities)) for i, v := range matchedCommodities { wg.Add(1) go func(index int, commodity ErpCommodity) { defer wg.Done() demandData, err := convertToDemandData(commodity, stores) if err != nil { // Handle error return } demandDataList[index] = demandData }(i, v) } wg.Wait() if req.IsExport == 1 { // 导出excel if len(demandDataList) == 0 { return nil, errors.New("未查询到数据") } resp.ExportUrl, err = demandDataExport(demandDataList) if err != nil { return nil, err } } else { resp.List = demandDataList resp.Total = int64(len(matchedCommodities)) } } return resp, nil } // convertToDemandData 将商品转换为采购需求数据 func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { demandData := DemandData{ ErpCommodityID: commodity.ID, ErpCommoditySerialNumber: commodity.SerialNumber, ErpCommodityName: commodity.Name, ErpCategoryID: commodity.ErpCategoryId, ErpCategoryName: commodity.ErpCategoryName, RetailPrice: commodity.RetailPrice, } // 查询采购需求单 demands, err := GetCommodityPurchaseDemands(commodity.ID, stores) if err != nil { // Handle error return DemandData{}, err } if len(demands) != 0 { demandData.Remark = demands[0].Remark } // 使用 WaitGroup 进行并行查询 var wg sync.WaitGroup wg.Add(3) var lastWholesalePrices map[uint32]float64 var stockCounts map[uint32]uint32 var lastMonthSales uint32 go func() { defer wg.Done() lastWholesalePrices, err = GetCommodityLastWholesalePrices(commodity.ID) }() go func() { defer wg.Done() stockCounts, err = GetCommodityStocksByStoreID(commodity.ID, stores) }() go func() { defer wg.Done() lastMonthSales, err = GetCommodityLastMonthSales(commodity.ID, stores) }() wg.Wait() if err != nil { // Handle error return DemandData{}, err } var totalCount uint32 // 总需采购数量 // 构建需求数据 demandData.StoreList = make([]struct { StoreID uint32 `json:"store_id"` StoreName string `json:"store_name"` LastMonthSales uint32 `json:"last_month_sales"` StockCount uint32 `json:"stock_count"` NeedCount uint32 `json:"need_count"` }, len(stores)) for i, store := range stores { demandData.StoreList[i].StoreID = store.ID demandData.StoreList[i].StoreName = store.Name demandData.StoreList[i].StockCount = stockCounts[store.ID] demandData.StoreList[i].LastMonthSales = lastMonthSales // 设置最近采购价 demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID] // 设置采购需求量 for _, demand := range demands { if demand.StoreId == store.ID { demandData.StoreList[i].NeedCount = demand.Count totalCount += demand.Count break } } } demandData.TotalCount = totalCount demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice return demandData, nil } // GetCommodityPurchaseDemands 查询商品的采购需求单 func GetCommodityPurchaseDemands(commodityID uint32, stores []Store) ([]ErpPurchaseDemand, error) { var wg sync.WaitGroup var mu sync.Mutex var demands []ErpPurchaseDemand wg.Add(len(stores)) for _, store := range stores { go func(storeID uint32) { defer wg.Done() var demand ErpPurchaseDemand err := orm.Eloquent.Table("erp_purchase_demand"). Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", commodityID, storeID). First(&demand).Error if err != nil { // Handle error return } mu.Lock() defer mu.Unlock() demands = append(demands, demand) }(store.ID) } wg.Wait() return demands, nil } // GetCommodityLastWholesalePrices 批量查询商品的最近采购价 func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { // 查询最近采购价 var prices []struct { CommodityID uint32 Price float64 } err := orm.Eloquent.Table("erp_purchase_inventory"). Select("erp_commodity_id, implementation_price AS price"). Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure"). Group("erp_commodity_id"). Order("created_at DESC"). Find(&prices).Error if err != nil { return nil, err } // 构建结果 result := make(map[uint32]float64) for _, p := range prices { result[p.CommodityID] = p.Price } return result, nil } // GetCommodityStocksByStoreID 批量查询商品的库存情况 func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) { // 并行查询库存情况 var wg sync.WaitGroup wg.Add(len(stores)) result := make(map[uint32]uint32) for _, store := range stores { go func(storeID uint32) { defer wg.Done() // 查询库存情况 var stockCount int64 err := orm.Eloquent.Table("erp_stock_commodity"). Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID). Count(&stockCount).Error if err != nil { // Handle error return } result[storeID] = uint32(stockCount) }(store.ID) } wg.Wait() return result, nil } // GetCommodityLastMonthSales 批量查询商品的上月销售数量 func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) { // 获取上个月的时间范围 firstDay, lastDay := GetLastMonthRange() // 并行查询上月销售数量 var wg sync.WaitGroup wg.Add(len(stores)) var totalSales uint32 var mu sync.Mutex // 用于保护 totalSales 的并发访问 for _, store := range stores { go func(storeID uint32) { defer wg.Done() // 查询上月销售数量 var sales uint32 err := orm.Eloquent.Table("erp_order_commodity"). Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ "AND erp_order_commodity.created_at BETWEEN ? AND ?", HavePaid, commodityID, storeID, firstDay, lastDay). Select("SUM(erp_order_commodity.count) AS sales"). Scan(&sales).Error if err != nil { // Handle error return } // 保护 totalSales 的并发访问 mu.Lock() defer mu.Unlock() totalSales += sales }(store.ID) } wg.Wait() return totalSales, nil } // GetLastMonthRange 获取上个月的时间范围 func GetLastMonthRange() (time.Time, time.Time) { now := time.Now() year, month, _ := now.Date() firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) lastDay := firstDay.AddDate(0, 1, -1) return firstDay, lastDay } // GetOnlineStores 查询所有在线门店信息 func GetOnlineStores() ([]Store, error) { var stores []Store err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error if err != nil { return nil, err } return stores, nil } type Result struct { TotalCount uint32 `gorm:"column:total_count"` AvgImplementationPrice float64 `gorm:"column:avg_implementation_price"` TotalAmount float64 `gorm:"column:total_amount"` AvgEmployeePrice float64 `gorm:"column:avg_employee_price"` } // GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价 func GetTotalsAndAveragesByCommodityID(commodityID uint32) (Result, error) { var result Result err := orm.Eloquent.Table("erp_purchase_inventory"). Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+ "SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price"). Where("erp_commodity_id = ?", commodityID). Scan(&result).Error if err != nil { return Result{}, err } return result, nil } // UpdateRetailPrice 更新指导零售价 func UpdateRetailPrice(begin *gorm.DB, commodityId, retailPrice uint32) error { // 更新商品信息表 err := begin.Table("erp_commodity").Where("id=?", commodityId). Updates(map[string]interface{}{ "retail_price": retailPrice, }).Error if err != nil { return err } // 更新库存表 err = begin.Table("erp_stock").Where("erp_commodity_id=?", commodityId). Updates(map[string]interface{}{ "retail_price": retailPrice, }).Error if err != nil { return err } // 更新库存商品表 err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", commodityId). Updates(map[string]interface{}{ "retail_price": retailPrice, }).Error if err != nil { return err } return nil } // 导出采购需求excel func demandDataExport(list []DemandData) (string, error) { file := excelize.NewFile() fSheet := "Sheet1" url := ExportUrl fileName := time.Now().Format(TimeFormat) + "采购需求" + ".xlsx" fmt.Println("url fileName:", url+fileName) // 组合标题栏第一行数据 title1 := []interface{}{"商品编号", "商品名称", "商品分类", "指导零售价", "最近采购价"} storeCount := len(list[0].StoreList) var mergeCells []string // 存储需要合并的单元格范围 for _, v := range list[0].StoreList { for i := 0; i < 3; i++ { title1 = append(title1, v.StoreName) } } for i := 0; i < storeCount; i++ { // 计算每个商户名称的起始和结束单元格 startCol, _ := excelize.ColumnNumberToName(6 + i*3) // 从第6列开始,每个商户占3列 endCol, _ := excelize.ColumnNumberToName(8 + i*3) mergeCell := startCol + "1:" + endCol + "1" mergeCells = append(mergeCells, mergeCell) } title1 = append(title1, "需采购总数量") title1 = append(title1, "需采购总金额") title1 = append(title1, "备注") // 合并单元格 for _, mergeCell := range mergeCells { startCell, endCell := splitMergeCellCoordinates(mergeCell) _ = file.MergeCell(fSheet, startCell, endCell) } // 组合标题栏第二行数据 title2 := []interface{}{"商品编号", "商品名称", "商品分类", "指导零售价", "最近采购价"} for _, _ = range list[0].StoreList { title2 = append(title2, "上月销售数") title2 = append(title2, "库存数量") title2 = append(title2, "需采购数") } title2 = append(title2, "需采购总数量") title2 = append(title2, "需采购总金额") title2 = append(title2, "备注") for i, _ := range title1 { cell, _ := excelize.CoordinatesToCellName(1+i, 1) err := file.SetCellValue(fSheet, cell, title1[i]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } for i, _ := range title2 { cell, _ := excelize.CoordinatesToCellName(1+i, 2) err := file.SetCellValue(fSheet, cell, title2[i]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } var row []interface{} nExcelStartRow := 0 for i := 0; i < len(list); i++ { row = []interface{}{ list[i].ErpCommoditySerialNumber, // 商品编号 list[i].ErpCommodityName, // 商品名称 list[i].ErpCategoryName, // 商品分类名称 list[i].RetailPrice, // 指导零售价 list[i].LastWholesalePrice, // 最近采购价 } for _, v := range list[i].StoreList { row = append(row, v.LastMonthSales) // 上月销售数 row = append(row, v.StockCount) // 库存数量 row = append(row, v.NeedCount) // 需采购数 } row = append(row, list[i].TotalCount) // 需采购总数量 row = append(row, list[i].TotalAmount) // 需采购总金额 row = append(row, list[i].Remark) // 备注 for j, _ := range row { cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3) err := file.SetCellValue(fSheet, cell, row[j]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } nExcelStartRow++ } // 合并 "需采购总数量","需采购总金额" 和 "备注" 列的单元格 strTotalCountCol, strTotalAmountCol, strRemarkCol := computeExtraColumns("E", storeCount) _ = file.MergeCell(fSheet, strTotalCountCol+"1", strTotalCountCol+"2") _ = file.MergeCell(fSheet, strTotalAmountCol+"1", strTotalAmountCol+"2") _ = file.MergeCell(fSheet, strRemarkCol+"1", strRemarkCol+"2") // 设置所有单元格的样式: 居中、加边框 style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}, "border":[{"type":"left","color":"000000","style":1}, {"type":"top","color":"000000","style":1}, {"type":"right","color":"000000","style":1}, {"type":"bottom","color":"000000","style":1}]}`) endRow := fmt.Sprintf(strRemarkCol+"%d", nExcelStartRow+2) // 应用样式到整个表格 _ = file.SetCellStyle("Sheet1", "A1", endRow, style) _ = file.MergeCell(fSheet, "A1", "A2") _ = file.MergeCell(fSheet, "B1", "B2") _ = file.MergeCell(fSheet, "C1", "C2") _ = file.MergeCell(fSheet, "D1", "D2") _ = file.MergeCell(fSheet, "E1", "E2") fmt.Println("save fileName:", config.ExportConfig.Path+fileName) if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // 根据合并单元格的字符串获取左上角和右下角的坐标 func splitMergeCellCoordinates(cell string) (string, string) { split := strings.Split(cell, ":") if len(split) != 2 { return "", "" } return split[0], split[1] } // 计算 "需采购总数量","需采购总金额" 和 "备注" 列的坐标字符串 func computeExtraColumns(startCol string, storeCount int) (string, string, string) { // "需采购总数量" 列在商户列表结束后的下一列 totalCountCol := convertColumnToLetters(convertLettersToColumn(startCol) + storeCount*3 + 1) // "需采购总金额" 列在 "需采购总数量" 列的下一列 totalAmountCol := convertColumnToLetters(convertLettersToColumn(totalCountCol) + 1) // "备注" 列在 "需采购总金额" 列的下一列 remarkCol := convertColumnToLetters(convertLettersToColumn(totalAmountCol) + 1) return totalCountCol, totalAmountCol, remarkCol } // 将列号转换为字母 func convertColumnToLetters(column int) string { var result string for column > 0 { column-- result = string('A'+column%26) + result column /= 26 } return result } // 将字母转换为列号 func convertLettersToColumn(letters string) int { result := 0 for _, letter := range letters { result *= 26 result += int(letter) - 'A' + 1 } return result }