bindbox-game/internal/service/user/shipping_groups.go
Zuncle c7cd3c21e5 feat(shipping): 发货订单超过48小时不允许撤销
- 在cancel_shipping.go中添加48小时限制检查
- 在shipping_groups.go中返回created_at字段供前端判断
- 超过48小时的订单撤销时提示'需要撤销发货请联系客服'
2026-03-17 18:11:00 +08:00

146 lines
3.9 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"strconv"
"time"
)
// ProductInfo 商品简要信息
type ProductInfo struct {
ID int64 `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
Price int64 `json:"price"`
}
type ShipmentGroup struct {
ExpressCode string `json:"express_code"`
ExpressNo string `json:"express_no"`
BatchNo string `json:"batch_no"`
Status int32 `json:"status"`
Count int64 `json:"count"`
ShippedAt *time.Time `json:"shipped_at,omitempty"`
ReceivedAt *time.Time `json:"received_at,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"` // 发货申请创建时间用于前端判断48小时撤销限制
InventoryIDs []int64 `json:"inventory_ids"`
ProductIDs []int64 `json:"product_ids"`
Products []ProductInfo `json:"products"`
}
func (s *service) ListUserShipmentGroups(ctx context.Context, userID int64, page, pageSize int) (items []*ShipmentGroup, total int64, err error) {
q := s.readDB.ShippingRecords.WithContext(ctx).ReadDB().Where(
s.readDB.ShippingRecords.UserID.Eq(userID),
s.readDB.ShippingRecords.Status.Neq(5), // Exclude cancelled records
)
total, err = q.Count()
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
rows, err := q.Order(s.readDB.ShippingRecords.UpdatedAt.Desc(), s.readDB.ShippingRecords.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
type acc struct {
status int32
shippedAt *time.Time
receivedAt *time.Time
createdAt *time.Time // 最早的创建时间
inv []int64
pid []int64
}
m := make(map[string]*acc)
meta := make(map[string]struct{ code, no, batch string })
order := make([]string, 0) // 保持顺序
for _, r := range rows {
// 分组优先级:运单号 > 批次号 > 记录ID
key := ""
if r.ExpressNo != "" {
// 有运单号,按运单号分组
key = "E|" + r.ExpressCode + "|" + r.ExpressNo
} else if r.BatchNo != "" {
// 无运单号但有批次号,按批次号分组
key = "B|" + r.BatchNo
} else {
// 无运单号也无批次号按记录ID独立
key = "_" + strconv.FormatInt(r.ID, 10)
}
if _, ok := m[key]; !ok {
m[key] = &acc{}
meta[key] = struct{ code, no, batch string }{r.ExpressCode, r.ExpressNo, r.BatchNo}
order = append(order, key)
}
a := m[key]
if a.status == 0 || r.Status >= a.status {
a.status = r.Status
}
if !r.ShippedAt.IsZero() {
t := r.ShippedAt
a.shippedAt = &t
}
if !r.ReceivedAt.IsZero() {
t := r.ReceivedAt
a.receivedAt = &t
}
// 记录最早的创建时间
if !r.CreatedAt.IsZero() {
if a.createdAt == nil || r.CreatedAt.Before(*a.createdAt) {
t := r.CreatedAt
a.createdAt = &t
}
}
a.inv = append(a.inv, r.InventoryID)
if r.ProductID > 0 {
a.pid = append(a.pid, r.ProductID)
}
}
items = make([]*ShipmentGroup, 0, len(m))
for _, k := range order {
a := m[k]
md := meta[k]
c := int64(len(a.inv))
// 获取商品详情(去重)
pidSet := make(map[int64]struct{})
for _, pid := range a.pid {
pidSet[pid] = struct{}{}
}
products := make([]ProductInfo, 0, len(pidSet))
for pid := range pidSet {
if prod, _ := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.Eq(pid)).First(); prod != nil {
products = append(products, ProductInfo{
ID: prod.ID,
Name: prod.Name,
Image: prod.ImagesJSON,
Price: prod.Price,
})
}
}
items = append(items, &ShipmentGroup{
ExpressCode: md.code,
ExpressNo: md.no,
BatchNo: md.batch,
Status: a.status,
Count: c,
ShippedAt: a.shippedAt,
ReceivedAt: a.receivedAt,
CreatedAt: a.createdAt,
InventoryIDs: a.inv,
ProductIDs: a.pid,
Products: products,
})
}
return items, total, nil
}