- Add ExportOrder RPC method to camel_oil API and service interfaces - Implement service logic to query orders and generate Excel file with order data - Include card number and password fields in order export - Create HTTP handler to stream Excel file with proper headers for download - Handle token status update on frequent error ban (oneDay case) - Fix order processing query to filter by status and pay status correctly - Add new error code for one-day ban in camel_oil_api and handle in client logic - Update order model and response to include card number and password - Remove redundant logging of SendCaptcha request data in camel_oil_api client - Add access control checks on ExportOrder endpoint for authorized users only
199 lines
6.5 KiB
Go
199 lines
6.5 KiB
Go
package camel_oil
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"kami/utility/utils"
|
||
|
||
"github.com/gogf/gf/v2/database/gdb"
|
||
"github.com/gogf/gf/v2/os/glog"
|
||
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/shopspring/decimal"
|
||
|
||
v1 "kami/api/camel_oil/v1"
|
||
"kami/internal/consts"
|
||
"kami/internal/dao"
|
||
"kami/internal/model/do"
|
||
"kami/internal/model/entity"
|
||
"kami/utility/config"
|
||
)
|
||
|
||
// ====================================================================================
|
||
// 订单管理相关方法
|
||
// ====================================================================================
|
||
|
||
// UpdateOrderStatus 更新订单状态并记录历史
|
||
func (s *sCamelOil) UpdateOrderStatus(ctx context.Context, orderId int64, newStatus consts.CamelOilOrderStatus, operationType consts.CamelOilOrderChangeType, rawData string, description string) (err error) {
|
||
m := dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1())
|
||
|
||
// 获取当前订单信息
|
||
var order *entity.V1CamelOilOrder
|
||
err = m.Where(dao.V1CamelOilOrder.Columns().Id, orderId).Scan(&order)
|
||
if err != nil {
|
||
return gerror.Wrap(err, "查询订单失败")
|
||
}
|
||
|
||
if order == nil {
|
||
return gerror.New("订单不存在")
|
||
}
|
||
|
||
oldStatus := consts.CamelOilOrderStatus(order.Status)
|
||
|
||
// 如果状态没有变化,则不更新
|
||
if oldStatus == newStatus {
|
||
return nil
|
||
}
|
||
|
||
// 更新订单状态
|
||
_, err = m.Where(dao.V1CamelOilOrder.Columns().Id, orderId).Update(&do.V1CamelOilOrder{
|
||
Status: int(newStatus),
|
||
})
|
||
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新订单状态失败")
|
||
}
|
||
|
||
// 记录订单变更历史
|
||
_ = s.RecordOrderHistory(ctx, order.OrderNo, operationType, rawData, description)
|
||
|
||
g.Log().Infof(ctx, "订单状态更新成功,订单号=%s, 原状态=%d, 新状态=%d", order.OrderNo, oldStatus, newStatus)
|
||
|
||
return nil
|
||
}
|
||
|
||
// SubmitOrder 提交订单并返回支付宝支付链接
|
||
func (s *sCamelOil) SubmitOrder(ctx context.Context, req *v1.SubmitOrderReq) (res *v1.SubmitOrderRes, err error) {
|
||
var order *entity.V1CamelOilOrder
|
||
_ = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).Where(dao.V1CamelOilOrder.Columns().MerchantOrderId, req.MerchantOrderId).Scan(&order)
|
||
if order != nil {
|
||
if order.Status != int(consts.CamelOilOrderStatusPending) {
|
||
return nil, gerror.New("订单已失效")
|
||
}
|
||
return &v1.SubmitOrderRes{
|
||
OrderNo: order.OrderNo,
|
||
AlipayUrl: order.AlipayUrl,
|
||
Amount: req.Amount,
|
||
CreatedAt: order.CreatedAt,
|
||
}, nil
|
||
}
|
||
|
||
orderId := fmt.Sprintf("CO%s", utils.GenerateRandomUUID())
|
||
prefetchOrder, err := s.MatchPrefetchOrder(ctx, orderId, req.Amount)
|
||
if prefetchOrder == nil {
|
||
prefetchOrder, err = s.PrefetchOrderConcurrently(ctx, req.Amount)
|
||
if err != nil || prefetchOrder == nil {
|
||
return nil, gerror.Wrap(err, "拉取订单失败")
|
||
}
|
||
}
|
||
|
||
// 2. 创建空订单记录
|
||
_, err = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).Insert(&do.V1CamelOilOrder{
|
||
OrderNo: orderId,
|
||
MerchantOrderId: req.MerchantOrderId,
|
||
Amount: decimal.NewFromFloat(req.Amount),
|
||
Status: consts.CamelOilOrderStatusPending, // 1=待支付
|
||
PayStatus: consts.CamelOilPaymentStatusUnpaid, // 0=未支付
|
||
NotifyStatus: consts.CamelOilCallbackStatusPending, // 0=未回调
|
||
NotifyCount: 0,
|
||
AccountId: prefetchOrder.AccountId,
|
||
AccountName: prefetchOrder.AccountName,
|
||
PlatformOrderNo: prefetchOrder.PlatformOrderNo,
|
||
AlipayUrl: prefetchOrder.AlipayUrl,
|
||
Attach: req.Attach,
|
||
})
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "更新订单失败")
|
||
}
|
||
|
||
// 更新账号使用记录
|
||
_, _ = dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, prefetchOrder.AccountId).
|
||
Increment(dao.V1CamelOilAccount.Columns().DailyOrderCount, 1)
|
||
|
||
_, _ = dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, prefetchOrder.AccountId).
|
||
Increment(dao.V1CamelOilAccount.Columns().TotalOrderCount, 1)
|
||
|
||
glog.Infof(ctx, "订单提交成功: 订单号=%s", orderId)
|
||
|
||
res = &v1.SubmitOrderRes{
|
||
OrderNo: orderId,
|
||
AlipayUrl: prefetchOrder.AlipayUrl,
|
||
Amount: req.Amount,
|
||
CreatedAt: gtime.Now(),
|
||
}
|
||
|
||
return res, nil
|
||
}
|
||
|
||
// ====================================================================================
|
||
// 卡密填写相关方法
|
||
// ====================================================================================
|
||
|
||
// FillOrderCard 填写订单卡密和卡号
|
||
func (s *sCamelOil) fillOrderCard(ctx context.Context, orderNo string, cardNumber string, cardPassword string) error {
|
||
// 1. 查询订单信息
|
||
var order *entity.V1CamelOilOrder
|
||
err := dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilOrder.Columns().OrderNo, orderNo).
|
||
Scan(&order)
|
||
if err != nil {
|
||
return gerror.Wrap(err, "查询订单失败")
|
||
}
|
||
if order == nil {
|
||
return gerror.New("订单不存在")
|
||
}
|
||
|
||
// 2. 更新卡密和卡号
|
||
_, err = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilOrder.Columns().OrderNo, orderNo).
|
||
Update(&do.V1CamelOilOrder{
|
||
CardPassword: cardPassword,
|
||
CardNumber: cardNumber,
|
||
PaidAt: gtime.Now(),
|
||
PayStatus: consts.CamelOilPaymentStatusPaid,
|
||
})
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新卡密失败")
|
||
}
|
||
|
||
// 3. 记录操作历史
|
||
remark := fmt.Sprintf("填写卡密和卡号")
|
||
_, err = dao.V1CamelOilOrderHistory.Ctx(ctx).DB(config.GetDatabaseV1()).Data(&do.V1CamelOilOrderHistory{
|
||
OrderNo: orderNo,
|
||
ChangeType: consts.CamelOilOrderChangeTypeFillCard,
|
||
AccountId: order.AccountId,
|
||
AccountName: order.AccountName,
|
||
Remark: remark,
|
||
}).Insert()
|
||
if err != nil {
|
||
g.Log().Errorf(ctx, "记录订单历史失败:%v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// IncrementAccountOrderCount 增加账户订单计数(支付成功时调用)
|
||
func (s *sCamelOil) IncrementAccountOrderCount(ctx context.Context, accountId int64) error {
|
||
if accountId <= 0 {
|
||
return gerror.New("账户ID无效")
|
||
}
|
||
|
||
// 增加日订单计数
|
||
_, err := dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).
|
||
Where(dao.V1CamelOilAccount.Columns().Id, accountId).
|
||
Update(gdb.Map{
|
||
dao.V1CamelOilAccount.Columns().DailyOrderCount: gdb.Counter{Field: dao.V1CamelOilAccount.Columns().DailyOrderCount, Value: 1},
|
||
dao.V1CamelOilAccount.Columns().TotalOrderCount: gdb.Counter{Field: dao.V1CamelOilAccount.Columns().TotalOrderCount, Value: 1},
|
||
})
|
||
if err != nil {
|
||
return gerror.Wrap(err, "增加账户日订单计数失败")
|
||
}
|
||
|
||
glog.Infof(ctx, "账户订单计数增加成功,账户ID=%d", accountId)
|
||
return nil
|
||
}
|