package service import ( "encoding/json" "psi/database" "psi/models" systemReq "psi/models/request" systemRes "psi/models/response" "psi/utils" "gorm.io/gorm" ) type SalesService struct{} // GetSalesOrderList 获取销售订单列表 func (s *SalesService) GetSalesOrderList(req systemReq.GetSalesOrderListRequest, creatorID int64, role int64, db ...*gorm.DB) (*systemRes.SalesOrderListResponse, error) { databaseConn := database.OptionalDB(db...) if req.Page < 1 { req.Page = 1 } if req.PageSize < 1 || req.PageSize > 100 { req.PageSize = 20 } query := databaseConn.Model(&models.SalesOrder{}).Where("sales_order.is_del = ?", 0) if role == 128 { query = query.Where("sales_order.sales_person_id = ?", creatorID) } if req.Status > 0 { query = query.Where("sales_order.status = ?", req.Status) } if req.CustomerID > 0 { query = query.Where("sales_order.customer_id = ?", req.CustomerID) } if req.WarehouseID > 0 { query = query.Where("sales_order.warehouse_id = ?", req.WarehouseID) } if req.SoNo != "" { query = query.Where("sales_order.so_no LIKE ?", "%"+req.SoNo+"%") } if req.StartDate > 0 { query = query.Where("sales_order.created_at >= ?", req.StartDate) } if req.EndDate > 0 { query = query.Where("sales_order.created_at <= ?", req.EndDate) } if req.AssociationOrderNo != "" { query = query.Where("sales_order.association_order_no LIKE ?", "%"+req.AssociationOrderNo+"%") } if req.LogisticsNo != "" { subQuery := databaseConn.Model(&models.SalesOrderItem{}). Select("sales_order_id"). Where("logistics_no LIKE ? AND is_del = 0", "%"+req.LogisticsNo+"%") query = query.Where("sales_order.id IN (?)", subQuery) } if req.ShopType > 0 { query = query.Where("sales_order.shop_type = ?", req.ShopType) } if req.LocationID > 0 { subQuery := databaseConn.Table("sales_order_item soi"). Select("DISTINCT soi.sales_order_id"). Joins("JOIN product p ON soi.product_id = p.id AND p.is_del = 0"). Joins("JOIN inventory_detail id ON p.id = id.product_id AND id.is_del = 0"). Where("id.location_id = ?", req.LocationID) query = query.Where("sales_order.id IN (?)", subQuery) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, utils.NewError("查询总数失败") } if total == 0 { return &systemRes.SalesOrderListResponse{ List: []systemRes.SalesOrderItem{}, Total: 0, Page: req.Page, PageSize: req.PageSize, }, nil } var orders []systemRes.SalesOrderWithInfo offset := (req.Page - 1) * req.PageSize if err := query.Select("sales_order.*, c.name as customer_name, w.name as warehouse_name"). Joins("LEFT JOIN customer c ON sales_order.customer_id = c.id AND c.is_del = 0"). Joins("LEFT JOIN warehouse w ON sales_order.warehouse_id = w.id AND w.is_del = 0"). Order("sales_order.created_at DESC"). Offset(offset). Limit(req.PageSize). Find(&orders).Error; err != nil { return nil, utils.NewError("查询销售订单列表失败") } // 收集订单ID用于批量查询物流单号 orderIDs := make([]int64, len(orders)) for i, order := range orders { orderIDs[i] = order.ID } type logRow struct { SalesOrderID int64 `gorm:"column:sales_order_id"` LogisticsNos string `gorm:"column:logistics_nos"` } var logRows []logRow databaseConn.Table("sales_order_item"). Select("sales_order_id, COALESCE(GROUP_CONCAT(DISTINCT logistics_no SEPARATOR ', '), '') as logistics_nos"). Where("sales_order_id IN ? AND is_del = ? AND logistics_no != ''", orderIDs, 0). Group("sales_order_id"). Scan(&logRows) logByOrderID := make(map[int64]string, len(logRows)) for _, row := range logRows { logByOrderID[row.SalesOrderID] = row.LogisticsNos } // 收集库位编码(通过 sales_order_item → product → inventory_detail → location 链路) type locRow struct { SalesOrderID int64 `gorm:"column:sales_order_id"` LocationCodes string `gorm:"column:location_codes"` } var locRows []locRow databaseConn.Table("sales_order_item"). Select("sales_order_id, COALESCE(GROUP_CONCAT(DISTINCT l.code SEPARATOR ', '), '') as location_codes"). Joins("JOIN product p ON sales_order_item.product_id = p.id AND p.is_del = 0"). Joins("JOIN inventory_detail id ON p.id = id.product_id AND id.is_del = 0"). Joins("JOIN location l ON id.location_id = l.id"). Where("sales_order_id IN ? AND sales_order_item.is_del = ?", orderIDs, 0). Group("sales_order_id"). Scan(&locRows) locByOrderID := make(map[int64]string, len(locRows)) for _, row := range locRows { locByOrderID[row.SalesOrderID] = row.LocationCodes } orderItems := make([]systemRes.SalesOrderItem, 0, len(orders)) for _, order := range orders { orderItems = append(orderItems, systemRes.ConvertSalesOrderToItem( order.SalesOrder, order.CustomerName, order.WarehouseName, logByOrderID[order.ID], locByOrderID[order.ID], )) } return &systemRes.SalesOrderListResponse{ List: orderItems, Total: total, Page: req.Page, PageSize: req.PageSize, }, nil } // GetSalesOrderDetailList 获取分页的销售订单详情列表(含明细) func (s *SalesService) GetSalesOrderDetailList(req systemReq.GetSalesOrderDetailListRequest, creatorID int64, role int64, db ...*gorm.DB) (*systemRes.SalesOrderDetailListResponse, error) { databaseConn := database.OptionalDB(db...) if req.Page < 1 { req.Page = 1 } if req.PageSize < 1 || req.PageSize > 100 { req.PageSize = 20 } query := databaseConn.Model(&models.SalesOrder{}).Where("sales_order.is_del = ?", 0) if role == 128 { query = query.Where("sales_order.sales_person_id = ?", creatorID) } //if req.Status > 0 { // query = query.Where("sales_order.status = ?", req.Status) //} //if req.CustomerID > 0 { // query = query.Where("sales_order.customer_id = ?", req.CustomerID) //} //if req.WarehouseID > 0 { // query = query.Where("sales_order.warehouse_id = ?", req.WarehouseID) //} //if req.SoNo != "" { // query = query.Where("sales_order.so_no LIKE ?", "%"+req.SoNo+"%") //} //if req.StartDate > 0 { // query = query.Where("sales_order.created_at >= ?", req.StartDate) //} //if req.EndDate > 0 { // query = query.Where("sales_order.created_at <= ?", req.EndDate) //} if req.Status > 0 { query = query.Where("sales_order.status = ?", req.Status) } if req.CustomerID > 0 { query = query.Where("sales_order.customer_id = ?", req.CustomerID) } if req.WarehouseID > 0 { query = query.Where("sales_order.warehouse_id = ?", req.WarehouseID) } if req.SoNo != "" { query = query.Where("sales_order.so_no LIKE ?", "%"+req.SoNo+"%") } if req.StartDate > 0 { query = query.Where("sales_order.created_at >= ?", req.StartDate) } if req.EndDate > 0 { query = query.Where("sales_order.created_at <= ?", req.EndDate) } if req.AssociationOrderNo != "" { query = query.Where("sales_order.association_order_no LIKE ?", "%"+req.AssociationOrderNo+"%") } if req.LogisticsNo != "" { subQuery := databaseConn.Model(&models.SalesOrderItem{}). Select("sales_order_id"). Where("logistics_no LIKE ? AND is_del = 0", "%"+req.LogisticsNo+"%") query = query.Where("sales_order.id IN (?)", subQuery) } if req.ShopType > 0 { query = query.Where("sales_order.shop_type = ?", req.ShopType) } if req.LocationID > 0 { subQuery := databaseConn.Table("sales_order_item soi"). Select("DISTINCT soi.sales_order_id"). Joins("JOIN product p ON soi.product_id = p.id AND p.is_del = 0"). Joins("JOIN inventory_detail id ON p.id = id.product_id AND id.is_del = 0"). Where("id.location_id = ?", req.LocationID) query = query.Where("sales_order.id IN (?)", subQuery) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, utils.NewError("查询总数失败") } if total == 0 { return &systemRes.SalesOrderDetailListResponse{ List: []systemRes.SalesOrderDetailResponse{}, Total: 0, Page: req.Page, PageSize: req.PageSize, }, nil } // 查询分页的销售订单 var orders []systemRes.SalesOrderWithInfo offset := (req.Page - 1) * req.PageSize if err := query.Select("sales_order.*, c.name as customer_name, w.name as warehouse_name"). Joins("LEFT JOIN customer c ON sales_order.customer_id = c.id AND c.is_del = 0"). Joins("LEFT JOIN warehouse w ON sales_order.warehouse_id = w.id AND w.is_del = 0"). Order("sales_order.created_at DESC"). Offset(offset). Limit(req.PageSize). Find(&orders).Error; err != nil { return nil, utils.NewError("查询销售订单列表失败") } // 提取订单ID列表 orderIDs := make([]int64, len(orders)) for i, order := range orders { orderIDs[i] = order.ID } // 批量查询所有订单的明细项(含商品信息) var allItems []systemRes.SalesOrderItemWithProduct if err := databaseConn.Model(&models.SalesOrderItem{}). Select("sales_order_item.*, p.name as product_name, p.barcode as product_code, p.category_id, p.sale_price as product_sale_price, c.name as category_name, p.live_image ,lt.code as location_code"). Joins("LEFT JOIN product p ON sales_order_item.product_id = p.id AND p.is_del = 0"). Joins("LEFT JOIN product_category c ON p.category_id = c.id AND c.is_del = 0"). Joins("LEFT JOIN inventory_detail de on p.id = de.product_id AND de.is_del = 0"). Joins("LEFT JOIN location lt on de.location_id = lt.id"). Where("sales_order_item.sales_order_id IN ? AND sales_order_item.is_del = ?", orderIDs, 0). Find(&allItems).Error; err != nil { return nil, utils.NewError("查询订单明细失败") } // 按订单ID分组明细项 itemMap := make(map[int64][]systemRes.SalesOrderItemWithProduct) for _, item := range allItems { itemMap[item.SalesOrderID] = append(itemMap[item.SalesOrderID], item) } // 组装响应 detailList := make([]systemRes.SalesOrderDetailResponse, 0, len(orders)) for _, order := range orders { items := itemMap[order.ID] detailItems := make([]systemRes.SalesOrderDetailItem, 0, len(items)) for _, item := range items { var imageList []string if len(item.LiveImage) > 0 { json.Unmarshal(item.LiveImage, &imageList) } detailItems = append(detailItems, systemRes.SalesOrderDetailItem{ ID: item.ID, SalesOrderID: item.SalesOrderID, ProductID: item.ProductID, ProductName: item.ProductName, ProductCode: item.ProductCode, ProductSalePrice: item.ProductSalePrice, CategoryID: item.CategoryID, CategoryName: item.CategoryName, LiveImage: imageList, Quantity: item.Quantity, AllocatedQuantity: item.AllocatedQuantity, ShippedQuantity: item.ShippedQuantity, UnitPrice: item.UnitPrice, Amount: item.Amount, ReceiverName: item.ReceiverName, ReceiverPhone: item.ReceiverPhone, ReceiverAddress: item.ReceiverAddress, LogisticsCompany: item.LogisticsCompany, LogisticsNo: item.LogisticsNo, LocationCode: item.LocationCode, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, }) } detail := systemRes.ConvertSalesOrderToDetail(order.SalesOrder, order.CustomerName, order.WarehouseName, detailItems) detailList = append(detailList, detail) } return &systemRes.SalesOrderDetailListResponse{ List: detailList, Total: total, Page: req.Page, PageSize: req.PageSize, }, nil } // GetSalesOrderDetail 获取销售订单详情 func (s *SalesService) GetSalesOrderDetail(id int64, creatorID int64, role int64, db ...*gorm.DB) (*systemRes.SalesOrderDetailResponse, error) { databaseConn := database.OptionalDB(db...) query := databaseConn.Model(&models.SalesOrder{}). Select("sales_order.*, c.name as customer_name, w.name as warehouse_name"). Joins("LEFT JOIN customer c ON sales_order.customer_id = c.id AND c.is_del = 0"). Joins("LEFT JOIN warehouse w ON sales_order.warehouse_id = w.id AND w.is_del = 0"). Where("sales_order.id = ? AND sales_order.is_del = ?", id, 0) if role == 128 { query = query.Where("sales_order.sales_person_id = ?", creatorID) } var order systemRes.SalesOrderWithInfo result := query.First(&order) if result.Error != nil { return nil, utils.NewError("销售订单不存在") } var items []systemRes.SalesOrderItemWithProduct databaseConn.Model(&models.SalesOrderItem{}). Select("sales_order_item.*, p.name as product_name, p.barcode as product_code, p.category_id,p.sale_price as product_sale_price, c.name as category_name, p.live_image, lt.code as location_code"). Joins("LEFT JOIN product p ON sales_order_item.product_id = p.id AND p.is_del = 0"). Joins("LEFT JOIN product_category c ON p.category_id = c.id AND c.is_del = 0"). Joins("LEFT JOIN inventory_detail de on p.id = de.product_id AND de.is_del = 0"). Joins("LEFT JOIN location lt on de.location_id = lt.id"). Where("sales_order_item.sales_order_id = ? AND sales_order_item.is_del = ?", order.ID, 0). Find(&items) detailItems := make([]systemRes.SalesOrderDetailItem, 0, len(items)) for _, item := range items { var imageList []string if len(item.LiveImage) > 0 { json.Unmarshal(item.LiveImage, &imageList) } detailItems = append(detailItems, systemRes.SalesOrderDetailItem{ ID: item.ID, SalesOrderID: item.SalesOrderID, ProductID: item.ProductID, ProductName: item.ProductName, ProductCode: item.ProductCode, ProductSalePrice: item.ProductSalePrice, CategoryID: item.CategoryID, CategoryName: item.CategoryName, LiveImage: imageList, Quantity: item.Quantity, AllocatedQuantity: item.AllocatedQuantity, ShippedQuantity: item.ShippedQuantity, UnitPrice: item.UnitPrice, Amount: item.Amount, ReceiverName: item.ReceiverName, ReceiverPhone: item.ReceiverPhone, ReceiverAddress: item.ReceiverAddress, LogisticsCompany: item.LogisticsCompany, LogisticsNo: item.LogisticsNo, LocationCode: item.LocationCode, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, }) } detail := systemRes.ConvertSalesOrderToDetail(order.SalesOrder, order.CustomerName, order.WarehouseName, detailItems) return &detail, nil }