Files
kami_backend/internal/logic/camel_oil/order.go
danial 85b552eec3 feat(camel_oil): add order export to Excel functionality
- 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
2025-12-11 20:13:52 +08:00

199 lines
6.5 KiB
Go
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 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
}