chore: 初始开源发布
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
package iot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/iot/simcardbatch/addpackage"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func (s *sIotTSimCardBindPkg) PrepareInput(ctx context.Context, in *model.TSimCardBindPkgAddPackageInputPrepareParam) (*model.TSimCardBindPkgAddPackageInputPrepareRes, error) {
|
||||
if in == nil {
|
||||
in = &model.TSimCardBindPkgAddPackageInputPrepareParam{}
|
||||
}
|
||||
result, err := addpackage.NewCardSubmitter().PrepareInput(ctx, in.Input, addpackage.SubmitOptions{
|
||||
PackageCode: in.PackageCode,
|
||||
Remark: in.Remark,
|
||||
EffectiveMode: in.EffectiveMode,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimCardBindPkgAddPackageInputPrepareRes)(addPackagePrepareRes(result)), nil
|
||||
}
|
||||
|
||||
func (s *sIotTSimCardBindPkg) PrepareResult(ctx context.Context, batchNo string) (*model.TSimCardBindPkgAddPackagePrepareResultRes, error) {
|
||||
res, err := loadAddPackagePrepareResult(ctx, batchNo, consts.BatchTypeCardAddPackage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimCardBindPkgAddPackagePrepareResultRes)(res), nil
|
||||
}
|
||||
|
||||
func (s *sIotTSimCardBindPkg) ConfirmBatch(ctx context.Context, in *model.TSimCardBindPkgAddPackageBatchConfirmParam) (*model.TSimCardBindPkgAddPackageBatchConfirmRes, error) {
|
||||
res, err := confirmAddPackageBatch(ctx, (*model.TSimAddPackageBatchConfirmParam)(in), consts.BatchTypeCardAddPackage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimCardBindPkgAddPackageBatchConfirmRes)(res), nil
|
||||
}
|
||||
|
||||
func (s *sIotTSimPoolBindPackage) PrepareInput(ctx context.Context, in *model.TSimPoolBindPackageAddPackageInputPrepareParam) (*model.TSimPoolBindPackageAddPackageInputPrepareRes, error) {
|
||||
if in == nil {
|
||||
in = &model.TSimPoolBindPackageAddPackageInputPrepareParam{}
|
||||
}
|
||||
result, err := addpackage.NewPoolSubmitter().PrepareInput(ctx, in.Input, addpackage.SubmitOptions{
|
||||
PackageCode: in.PackageCode,
|
||||
Remark: in.Remark,
|
||||
EffectiveMode: in.EffectiveMode,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimPoolBindPackageAddPackageInputPrepareRes)(addPackagePrepareRes(result)), nil
|
||||
}
|
||||
|
||||
func (s *sIotTSimPoolBindPackage) PrepareResult(ctx context.Context, batchNo string) (*model.TSimPoolBindPackageAddPackagePrepareResultRes, error) {
|
||||
res, err := loadAddPackagePrepareResult(ctx, batchNo, consts.BatchTypePoolAddPackage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimPoolBindPackageAddPackagePrepareResultRes)(res), nil
|
||||
}
|
||||
|
||||
func (s *sIotTSimPoolBindPackage) ConfirmBatch(ctx context.Context, in *model.TSimPoolBindPackageAddPackageBatchConfirmParam) (*model.TSimPoolBindPackageAddPackageBatchConfirmRes, error) {
|
||||
res, err := confirmAddPackageBatch(ctx, (*model.TSimAddPackageBatchConfirmParam)(in), consts.BatchTypePoolAddPackage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimPoolBindPackageAddPackageBatchConfirmRes)(res), nil
|
||||
}
|
||||
|
||||
func addPackagePrepareRes(result *addpackage.SubmitResult) *model.TSimAddPackagePrepareRes {
|
||||
res := &model.TSimAddPackagePrepareRes{
|
||||
BatchType: consts.BatchTypePrepare,
|
||||
BatchAsyncStatus: consts.BatchAsyncStatusPending,
|
||||
RunResult: consts.BatchRunResultPending,
|
||||
Status: "pending",
|
||||
}
|
||||
if result == nil {
|
||||
return res
|
||||
}
|
||||
res.BatchNo = result.BatchNo
|
||||
res.BatchType = result.BatchType
|
||||
res.TargetBatchType = result.TargetBatchType
|
||||
res.Total = result.Total
|
||||
res.ValidCount = result.ValidCount
|
||||
res.FailCount = result.FailCount
|
||||
return res
|
||||
}
|
||||
|
||||
func confirmAddPackageBatch(ctx context.Context, in *model.TSimAddPackageBatchConfirmParam, targetBatchType int) (*model.TSimAddPackageBatchConfirmRes, error) {
|
||||
if in == nil {
|
||||
in = &model.TSimAddPackageBatchConfirmParam{}
|
||||
}
|
||||
in.BatchNo = strings.TrimSpace(in.BatchNo)
|
||||
if in.BatchNo == "" {
|
||||
return nil, gerror.New("批次号不能为空")
|
||||
}
|
||||
if targetBatchType != consts.BatchTypeCardAddPackage && targetBatchType != consts.BatchTypePoolAddPackage {
|
||||
return nil, gerror.New("加油包目标批次类型不正确")
|
||||
}
|
||||
effectiveMode, err := addpackage.NormalizeEffectiveMode(in.EffectiveMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paymentMode, offlineContractCompleted, err := normalizeAddPackagePaymentMode(ctx, in.PaymentMode, in.OfflineContractCompleted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var converted *addpackage.AsyncConfirmResult
|
||||
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
var convertErr error
|
||||
converted, convertErr = addpackage.ConvertPrepareToAsync(ctx, tx, &addpackage.AsyncConfirmInput{
|
||||
BatchNo: in.BatchNo,
|
||||
TargetBatchType: targetBatchType,
|
||||
PackageCode: in.PackageCode,
|
||||
Remark: in.Remark,
|
||||
PaymentMode: paymentMode,
|
||||
OfflineContractCompleted: offlineContractCompleted,
|
||||
EffectiveMode: effectiveMode,
|
||||
Operator: currentOperator(ctx),
|
||||
})
|
||||
return convertErr
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if converted == nil {
|
||||
return nil, gerror.New("加油包确认结果为空")
|
||||
}
|
||||
publishPendingExecute(ctx, converted.BatchNo, converted.BatchType, contexts.GetTenantId(ctx))
|
||||
return &model.TSimAddPackageBatchConfirmRes{
|
||||
BatchNo: converted.BatchNo,
|
||||
BatchType: converted.BatchType,
|
||||
BatchAsyncStatus: converted.BatchAsyncStatus,
|
||||
PackageCode: strings.TrimSpace(in.PackageCode),
|
||||
EffectiveMode: effectiveMode,
|
||||
Status: "pending",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadAddPackagePrepareResult(ctx context.Context, batchNo string, targetBatchType int) (*model.TSimAddPackagePrepareResultRes, error) {
|
||||
batchNo = strings.TrimSpace(batchNo)
|
||||
if batchNo == "" {
|
||||
return nil, gerror.New("批次号不能为空")
|
||||
}
|
||||
columns := dao.BatchMain.Columns()
|
||||
batch := &entity.BatchMain{}
|
||||
if err := dao.BatchMain.Ctx(ctx).
|
||||
Where(columns.BatchNo, batchNo).
|
||||
Where(columns.TenantId, contexts.GetTenantId(ctx)).
|
||||
Where(columns.CreatedDept, contexts.GetDeptId(ctx)).
|
||||
Scan(batch); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询加油包预处理批次失败")
|
||||
}
|
||||
if batch.Id == 0 {
|
||||
return nil, gerror.New("加油包预处理批次不存在或不可见")
|
||||
}
|
||||
if !isAddPackagePrepareOrTarget(batch, targetBatchType) {
|
||||
return nil, gerror.New("批次类型不匹配")
|
||||
}
|
||||
|
||||
asyncStatus, runResult, status := prepareRuntimeStatus(batch.BatchAsyncStatus, batch.RunResult)
|
||||
res := &model.TSimAddPackagePrepareResultRes{
|
||||
BatchNo: batch.BatchNo,
|
||||
BatchType: batch.BatchType,
|
||||
TargetBatchType: targetBatchType,
|
||||
Status: status,
|
||||
BatchAsyncStatus: asyncStatus,
|
||||
RunResult: runResult,
|
||||
Total: batch.TotalCount,
|
||||
ValidCount: batch.ValidCount,
|
||||
SuccessCount: batch.SuccessCount,
|
||||
FailCount: batch.FailCount,
|
||||
FailReason: strings.TrimSpace(batch.FailReason),
|
||||
StartTime: batch.StartTime,
|
||||
EndTime: batch.EndTime,
|
||||
}
|
||||
fillAddPackagePrepareFields(res, batch.BatchInfo)
|
||||
if res.Quantity <= 0 {
|
||||
res.Quantity = firstPositive(batch.SuccessCount, batch.ValidCount, batch.TotalCount)
|
||||
}
|
||||
if res.TotalAmount <= 0 && res.UnitPrice > 0 && res.Quantity > 0 {
|
||||
res.TotalAmount = roundAmount(res.UnitPrice * float64(res.Quantity))
|
||||
}
|
||||
fillAddPackagePaymentView(ctx, res)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func isAddPackagePrepareOrTarget(batch *entity.BatchMain, targetBatchType int) bool {
|
||||
if batch == nil {
|
||||
return false
|
||||
}
|
||||
if targetBatchType != consts.BatchTypeCardAddPackage && targetBatchType != consts.BatchTypePoolAddPackage {
|
||||
return false
|
||||
}
|
||||
if batch.BatchInfo != nil && batch.BatchInfo.Get("targetBatchType").Int() == targetBatchType {
|
||||
return true
|
||||
}
|
||||
return batch.BatchType == targetBatchType
|
||||
}
|
||||
|
||||
func prepareRuntimeStatus(asyncStatusValue int, runResultValue int) (int, int, string) {
|
||||
asyncStatus := consts.BatchAsyncStatusPending
|
||||
runResult := consts.BatchRunResultPending
|
||||
status := "pending"
|
||||
switch {
|
||||
case asyncStatusValue == consts.BatchAsyncStatusProcessing || runResultValue == consts.BatchRunResultRunning:
|
||||
asyncStatus = consts.BatchAsyncStatusProcessing
|
||||
runResult = consts.BatchRunResultRunning
|
||||
status = "processing"
|
||||
case asyncStatusValue == consts.BatchAsyncStatusSuccess && runResultValue == consts.BatchRunResultSuccess:
|
||||
asyncStatus = consts.BatchAsyncStatusSuccess
|
||||
runResult = consts.BatchRunResultSuccess
|
||||
status = "success"
|
||||
case asyncStatusValue == consts.BatchAsyncStatusFailed || runResultValue == consts.BatchRunResultFailed:
|
||||
asyncStatus = consts.BatchAsyncStatusFailed
|
||||
runResult = consts.BatchRunResultFailed
|
||||
status = "failed"
|
||||
case asyncStatusValue == consts.BatchAsyncStatusPartialSuccess || runResultValue == consts.BatchRunResultPartialSuccess:
|
||||
asyncStatus = consts.BatchAsyncStatusFailed
|
||||
runResult = consts.BatchRunResultFailed
|
||||
status = "failed"
|
||||
}
|
||||
return asyncStatus, runResult, status
|
||||
}
|
||||
|
||||
func fillAddPackagePrepareFields(res *model.TSimAddPackagePrepareResultRes, info *gjson.Json) {
|
||||
if res == nil || info == nil {
|
||||
return
|
||||
}
|
||||
res.PackageCode = jsonString(info, "packageCode", "priceSnapshot.packageCode")
|
||||
res.PackageName = jsonString(info, "packageName", "priceSnapshot.packageName")
|
||||
res.FlowMb = roundAmount(jsonFloat64(info, "flowMb", "priceSnapshot.flowMb"))
|
||||
res.UnitPrice = roundAmount(jsonFloat64(info, "unitPrice", "priceSnapshot.unitPrice"))
|
||||
res.TotalAmount = roundAmount(jsonFloat64(info, "totalAmount"))
|
||||
res.Quantity = jsonInt(info, "quantity")
|
||||
res.EffectiveMode = jsonString(info, "effectiveMode")
|
||||
if res.EffectiveMode == "" {
|
||||
res.EffectiveMode = addpackage.EffectiveModeCurrentMonth
|
||||
}
|
||||
res.EffectiveModeText = jsonString(info, "effectiveModeText")
|
||||
if res.EffectiveModeText == "" {
|
||||
res.EffectiveModeText = addpackage.EffectiveModeText(res.EffectiveMode)
|
||||
}
|
||||
res.EffectiveTime = jsonString(info, "effectiveTime")
|
||||
res.ExpectedExpireTime = jsonString(info, "expectedExpireTime")
|
||||
res.PaymentAccounts = addPackagePaymentAccountsFromInfo(info)
|
||||
res.AvailablePackages = addPackagePackageOptionsFromInfo(info)
|
||||
res.Snapshot = info
|
||||
}
|
||||
|
||||
func addPackagePaymentAccountsFromInfo(info *gjson.Json) []*model.TSimAddPackagePaymentAccountModel {
|
||||
value := jsonField(info, "paymentAccounts")
|
||||
if value == nil || value.IsNil() {
|
||||
return nil
|
||||
}
|
||||
var accounts []*model.TSimAddPackagePaymentAccountModel
|
||||
if err := gconv.Structs(value.Interfaces(), &accounts); err != nil {
|
||||
return nil
|
||||
}
|
||||
return accounts
|
||||
}
|
||||
|
||||
func addPackagePackageOptionsFromInfo(info *gjson.Json) []*model.TSimAddPackageOptionModel {
|
||||
value := jsonField(info, "availablePackages", "packageOptions")
|
||||
if value == nil || value.IsNil() {
|
||||
return nil
|
||||
}
|
||||
var options []*model.TSimAddPackageOptionModel
|
||||
if err := gconv.Structs(value.Interfaces(), &options); err != nil {
|
||||
return nil
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func fillAddPackagePaymentView(ctx context.Context, res *model.TSimAddPackagePrepareResultRes) {
|
||||
if res == nil {
|
||||
return
|
||||
}
|
||||
isTop, _, err := service.AgentDept().IsTopDept(ctx)
|
||||
if err == nil {
|
||||
res.IsTopDept = isTop
|
||||
res.DefaultPaymentMode = addPackageDefaultPaymentMode(isTop)
|
||||
}
|
||||
balance, err := queryAddPackageAvailableBalance(ctx, contexts.GetDeptId(ctx))
|
||||
if err == nil {
|
||||
res.AvailableBalance = balance
|
||||
}
|
||||
}
|
||||
|
||||
func firstPositive(values ...int) int {
|
||||
for _, value := range values {
|
||||
if value > 0 {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user