七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
This commit is contained in:
163
internal/service/asset_package_batch_order/service.go
Normal file
163
internal/service/asset_package_batch_order/service.go
Normal file
@@ -0,0 +1,163 @@
|
||||
// Package asset_package_batch_order 提供单列 CSV 资产套餐批量订购任务能力。
|
||||
package asset_package_batch_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/asynctask"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/queue"
|
||||
)
|
||||
|
||||
// Service 资产套餐批量订购任务服务。
|
||||
type Service struct {
|
||||
taskStore *postgres.AssetPackageBatchOrderTaskStore
|
||||
packageStore *postgres.PackageStore
|
||||
queueClient *queue.Client
|
||||
}
|
||||
|
||||
// New 创建资产套餐批量订购任务服务。
|
||||
func New(taskStore *postgres.AssetPackageBatchOrderTaskStore, packageStore *postgres.PackageStore, queueClient *queue.Client) *Service {
|
||||
return &Service{taskStore: taskStore, packageStore: packageStore, queueClient: queueClient}
|
||||
}
|
||||
|
||||
// TaskPayload 批量订购 Worker 结构化载荷。
|
||||
type TaskPayload struct {
|
||||
TaskID uint `json:"task_id"`
|
||||
}
|
||||
|
||||
// Create 创建批量订购任务。
|
||||
func (s *Service) Create(ctx context.Context, req *dto.CreateAssetPackageBatchOrderRequest) (*dto.AssetPackageBatchOrderTaskResponse, error) {
|
||||
if !strings.EqualFold(filepath.Ext(req.FileKey), ".csv") {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "批量订购文件必须为CSV格式")
|
||||
}
|
||||
if !strings.HasPrefix(req.FileKey, constants.AssetPackageBatchOrderStoragePrefix+"/") {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "批量订购文件Key不属于指定上传目录")
|
||||
}
|
||||
if err := validatePaymentParameters(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userID := middleware.GetUserIDFromContext(ctx)
|
||||
if userID == 0 {
|
||||
return nil, errors.New(errors.CodeUnauthorized)
|
||||
}
|
||||
pkg, err := s.packageStore.GetByID(ctx, req.PackageID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeNotFound, "套餐不存在")
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐失败")
|
||||
}
|
||||
task := &model.AssetPackageBatchOrderTask{
|
||||
TaskNo: s.taskStore.GenerateTaskNo(), PackageID: pkg.ID,
|
||||
PackageCode: pkg.PackageCode, PackageName: pkg.PackageName,
|
||||
PaymentMethod: req.PaymentMethod, FileName: filepath.Base(req.FileKey), StorageKey: req.FileKey,
|
||||
VoucherKeys: model.StringJSONBArray(req.VoucherKeys), Status: asynctask.StatusPending,
|
||||
ResultItems: model.AssetPackageBatchOrderResultItems{}, Creator: userID, Updater: userID,
|
||||
CreatorUserType: middleware.GetUserTypeFromContext(ctx), CreatorShopID: middleware.GetShopIDFromContext(ctx),
|
||||
CreatorName: middleware.GetUsernameFromContext(ctx),
|
||||
}
|
||||
if err := s.taskStore.Create(ctx, task); err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "创建批量订购任务失败")
|
||||
}
|
||||
var enqueueErr error
|
||||
if s.queueClient == nil {
|
||||
enqueueErr = errors.New(errors.CodeTaskQueueError, "批量订购任务队列未配置")
|
||||
} else {
|
||||
enqueueErr = s.queueClient.EnqueueTask(ctx, constants.TaskTypeAssetPackageBatchOrder, TaskPayload{TaskID: task.ID},
|
||||
asynq.Queue(constants.QueueForTaskType(constants.TaskTypeAssetPackageBatchOrder)),
|
||||
asynq.Timeout(constants.AssetPackageBatchOrderTaskTimeout))
|
||||
}
|
||||
if enqueueErr != nil {
|
||||
message := "批量订购任务入队失败"
|
||||
_ = s.taskStore.MarkFailed(ctx, task.ID, message)
|
||||
task.Status, task.ErrorMessage = asynctask.StatusFailed, message
|
||||
now := time.Now()
|
||||
task.CompletedAt = &now
|
||||
}
|
||||
return toResponse(task), nil
|
||||
}
|
||||
|
||||
// List 分页查询批量订购任务。
|
||||
func (s *Service) List(ctx context.Context, req *dto.ListAssetPackageBatchOrderRequest) (*dto.AssetPackageBatchOrderTaskListResponse, error) {
|
||||
if req.Page <= 0 {
|
||||
req.Page = constants.DefaultPage
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = constants.DefaultPageSize
|
||||
}
|
||||
tasks, total, err := s.taskStore.List(ctx, &store.QueryOptions{Page: req.Page, PageSize: req.PageSize}, req.Status)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询批量订购任务失败")
|
||||
}
|
||||
items := make([]*dto.AssetPackageBatchOrderTaskResponse, 0, len(tasks))
|
||||
for _, task := range tasks {
|
||||
items = append(items, toResponse(task))
|
||||
}
|
||||
return &dto.AssetPackageBatchOrderTaskListResponse{Total: total, Page: req.Page, PageSize: req.PageSize, Items: items}, nil
|
||||
}
|
||||
|
||||
// GetByID 查询批量订购任务及逐行结果。
|
||||
func (s *Service) GetByID(ctx context.Context, id uint) (*dto.AssetPackageBatchOrderTaskDetailResponse, error) {
|
||||
task, err := s.taskStore.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeNotFound, "批量订购任务不存在")
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询批量订购任务失败")
|
||||
}
|
||||
items := make([]dto.AssetPackageBatchOrderResultItemResponse, 0, len(task.ResultItems))
|
||||
for _, item := range task.ResultItems {
|
||||
items = append(items, dto.AssetPackageBatchOrderResultItemResponse{
|
||||
Line: item.Line, AssetIdentifier: item.AssetIdentifier, Status: item.Status,
|
||||
StatusName: constants.GetAssetPackageBatchOrderItemStatusName(item.Status),
|
||||
OrderID: item.OrderID, OrderNo: item.OrderNo, Amount: item.Amount, Reason: item.Reason,
|
||||
})
|
||||
}
|
||||
return &dto.AssetPackageBatchOrderTaskDetailResponse{AssetPackageBatchOrderTaskResponse: *toResponse(task), Items: items}, nil
|
||||
}
|
||||
|
||||
func validatePaymentParameters(req *dto.CreateAssetPackageBatchOrderRequest) error {
|
||||
if req.PaymentMethod == model.PaymentMethodWallet && len(req.VoucherKeys) > 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "钱包支付不能提交线下凭证")
|
||||
}
|
||||
if req.PaymentMethod == model.PaymentMethodOffline && len(req.VoucherKeys) == 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "线下支付必须提交至少一个凭证")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toResponse(task *model.AssetPackageBatchOrderTask) *dto.AssetPackageBatchOrderTaskResponse {
|
||||
response := &dto.AssetPackageBatchOrderTaskResponse{
|
||||
ID: task.ID, TaskNo: task.TaskNo, PackageID: task.PackageID, PackageCode: task.PackageCode,
|
||||
PackageName: task.PackageName, PaymentMethod: task.PaymentMethod, FileName: task.FileName,
|
||||
VoucherKeys: []string(task.VoucherKeys), Status: task.Status, StatusName: asynctask.StatusName(task.Status),
|
||||
TotalCount: task.TotalCount, SuccessCount: task.SuccessCount, FailCount: task.FailCount,
|
||||
ErrorMessage: task.ErrorMessage, CreatorName: task.CreatorName,
|
||||
CreatedAt: task.CreatedAt.Format(time.RFC3339), UpdatedAt: task.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
if response.VoucherKeys == nil {
|
||||
response.VoucherKeys = []string{}
|
||||
}
|
||||
if task.StartedAt != nil {
|
||||
value := task.StartedAt.Format(time.RFC3339)
|
||||
response.StartedAt = &value
|
||||
}
|
||||
if task.CompletedAt != nil {
|
||||
value := task.CompletedAt.Format(time.RFC3339)
|
||||
response.CompletedAt = &value
|
||||
}
|
||||
return response
|
||||
}
|
||||
Reference in New Issue
Block a user