package refundOrderSer import ( "context" "errors" "fmt" "stat/api/proto" "stat/models/rechargemod" "stat/models/refundOrderMod" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) // 只回填付款成功的订单。status=3 为付款成功,与 models/rechargemod/stat.go 中 // 各统计口径一致;付款失败(status=2)的订单不存在退款场景。 const rechargeStatusSuccess = 3 // List 退款订单查询,支持 appId / userId / cid / channelName / districtCode 任意组合 func List(ctx context.Context, req *proto.RefundOrderListReq) (*proto.RefundOrderListResp, error) { resp := &proto.RefundOrderListResp{ Total: 0, List: make(refundOrderMod.RefundOrderList, 0), } filter := bson.M{} if req.AppId != nil { filter[refundOrderMod.FN.RefundOrder.AppId] = *req.AppId } if req.UserId != nil { filter[refundOrderMod.FN.RefundOrder.UserId] = *req.UserId } if req.CID != nil && *req.CID != "" { filter[refundOrderMod.FN.RefundOrder.CID] = *req.CID } if req.ChannelName != nil && *req.ChannelName != "" { filter[refundOrderMod.FN.RefundOrder.ChannelName] = *req.ChannelName } if req.DistrictCode != nil && *req.DistrictCode != "" { filter[refundOrderMod.FN.RefundOrder.DistrictCode] = *req.DistrictCode } total, err := refundOrderMod.CountRefundOrders(ctx, filter) if err != nil { return nil, err } opt := &options.FindOptions{} opt.SetSort(bson.D{{Key: refundOrderMod.FN.RefundOrder.CreatedAt, Value: -1}}) opt.SetSkip((req.PageNum - 1) * req.PageSize) opt.SetLimit(req.PageSize) list, err := refundOrderMod.FindManyRefundOrders(ctx, filter, opt) if err != nil { return nil, err } resp.Total = total resp.List = list return resp, nil } // Add 按单个 cid 回填 func Add(ctx context.Context, req *proto.AddRefundOrderReq) (*proto.AddRefundOrderResp, error) { return addByCids(ctx, []string{req.CID}) } // BatchAdd 按多个 cid 批量回填 func BatchAdd(ctx context.Context, req *proto.BatchAddRefundOrderReq) (*proto.AddRefundOrderResp, error) { return addByCids(ctx, req.CIDs) } // addByCids 逐个 cid 查询 log_recharge 的成功订单,按 (appId, orderId) 判重后落库。 // 单个 cid 失败不影响其余 cid,错误直接返回由调用方决定。 func addByCids(ctx context.Context, cids []string) (*proto.AddRefundOrderResp, error) { resp := &proto.AddRefundOrderResp{ Details: make([]proto.RefundCidStat, 0, len(cids)), } seen := make(map[string]bool, len(cids)) // 同一次请求里 cid 去重 for _, cid := range cids { if cid == "" || seen[cid] { continue } seen[cid] = true stat, err := addOneCid(ctx, cid) if err != nil { return nil, fmt.Errorf("回填渠道[%s]失败: %w", cid, err) } resp.Matched += stat.Matched resp.Inserted += stat.Inserted resp.Skipped += stat.Skipped resp.Details = append(resp.Details, *stat) } return resp, nil } func addOneCid(ctx context.Context, cid string) (*proto.RefundCidStat, error) { stat := &proto.RefundCidStat{CID: cid} // cid 唯一标识一笔订单,只回填付款成功的那条 src, err := rechargemod.FindOneRecharge(ctx, bson.M{ "cid": cid, "status": rechargeStatusSuccess, }) if err != nil { if errors.Is(err, mongo.ErrNoDocuments) { return stat, nil // 该 cid 没有对应的成功订单,matched 记 0,不算失败 } return nil, err } stat.Matched = 1 // 按 (appId, orderId) 判重,已存在则跳过 exist, err := refundOrderMod.FindOneRefundOrder(ctx, bson.M{ refundOrderMod.FN.RefundOrder.AppId: src.AppId, refundOrderMod.FN.RefundOrder.OrderId: src.OrderId, }) if err != nil { return nil, err } if exist != nil && !exist.ID.IsZero() { stat.Skipped = 1 return stat, nil } doc := &refundOrderMod.RefundOrder{ AppId: src.AppId, CID: src.CID, DistrictCode: src.DistrictCode, Money: src.Money, OrderId: src.OrderId, UserId: src.UserId, Type: src.Type, ChannelName: src.ChannelName, CreatedAt: src.CreatedAt, } if err := refundOrderMod.InsertOneRefundOrder(ctx, doc); err != nil { // 并发下两个请求可能同时通过上面的判重检查,由唯一索引兜底。 // 撞上即视为重复添加,与"重复跳过不报错"的口径一致。 if refundOrderMod.IsDuplicateKey(err) { stat.Skipped = 1 return stat, nil } return nil, err } stat.Inserted = 1 return stat, nil } // Del 按 _id 删除单条 func Del(ctx context.Context, req *proto.DelRefundOrderReq) error { oid, err := primitive.ObjectIDFromHex(req.Id) if err != nil { return fmt.Errorf("id 格式错误: %w", err) } count, err := refundOrderMod.DelOneRefundOrder(ctx, bson.M{ refundOrderMod.FN.RefundOrder.ID: oid, }) if err != nil { return err } if count == 0 { return fmt.Errorf("记录不存在") } return nil }