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,667 @@
|
||||
// Package gen
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2026 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
// @AutoGenerate Version
|
||||
package iot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"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/library/xgorm"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/hook"
|
||||
"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"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/excel"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type sIotTSimCardBindPkg struct{}
|
||||
|
||||
func NewIotTSimCardBindPkg() *sIotTSimCardBindPkg {
|
||||
return &sIotTSimCardBindPkg{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterIotTSimCardBindPkg(NewIotTSimCardBindPkg())
|
||||
}
|
||||
|
||||
// Model 订购表ORM模型
|
||||
func (s *sIotTSimCardBindPkg) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
|
||||
if len(option) == 0 {
|
||||
option = append(option, &handler.Option{
|
||||
FilterTenant: true,
|
||||
FilterAuth: true,
|
||||
})
|
||||
}
|
||||
return handler.Model(dao.TSimCardBindPkg.Ctx(ctx), option...)
|
||||
}
|
||||
|
||||
// List 获取订购表列表
|
||||
func (s *sIotTSimCardBindPkg) List(ctx context.Context, in *model.TSimCardBindPkgListParam) (list []*model.TSimCardBindPkgListModel, totalCount int, err error) {
|
||||
mod := s.Model(ctx)
|
||||
bindPackage := dao.TSimCardBindPkg.Table()
|
||||
packageInfo := dao.TSimFlowPackageInfo.Table()
|
||||
|
||||
// 先构建 Join
|
||||
mod = mod.LeftJoin(packageInfo, bindPackage+"."+dao.TSimCardBindPkg.Columns().PackageCode+" = "+packageInfo+"."+dao.TSimFlowPackageInfo.Columns().PackageCode)
|
||||
|
||||
// 字段过滤(包含主表字段 + joined 表字段)
|
||||
mod = mod.FieldsPrefix(bindPackage, model.TSimCardBindPkgListModel{})
|
||||
mod = mod.Fields(packageInfo + ".package_name as packageName")
|
||||
mod = mod.WhereIn(dao.TSimCardBindPkg.Columns().PackageType, []int{101, 102})
|
||||
|
||||
// 查询主键ID
|
||||
if in.Id > 0 {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Columns().Id, in.Id)
|
||||
}
|
||||
// 查询ICCID
|
||||
if in.Iccid != "" {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Columns().Iccid, in.Iccid)
|
||||
}
|
||||
|
||||
// 查询订购状态 枚举
|
||||
if in.EffectiveStatus > 0 {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Columns().EffectiveStatus, in.EffectiveStatus)
|
||||
}
|
||||
// 查询类型 枚举
|
||||
if in.BusinessType != nil {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Columns().BusinessType, *in.BusinessType)
|
||||
}
|
||||
|
||||
// 查询创建时间
|
||||
if len(in.CreatedAt) == 2 {
|
||||
in.CreatedAt[1] = in.CreatedAt[1].EndOfDay()
|
||||
}
|
||||
if len(in.CreatedAt) == 2 {
|
||||
mod = mod.WhereBetween(dao.TSimCardBindPkg.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
|
||||
}
|
||||
|
||||
// 分页
|
||||
mod = mod.Page(in.Page, in.PageSize)
|
||||
|
||||
// 排序
|
||||
mod = mod.OrderDesc(dao.TSimCardBindPkg.Columns().Id)
|
||||
|
||||
// 操作人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
// 查询数据
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取订购表列表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Export 导出订购表
|
||||
func (s *sIotTSimCardBindPkg) Export(ctx context.Context, in *model.TSimCardBindPkgListParam) (err error) {
|
||||
list, totalCount, err := s.List(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
|
||||
tags, err := convert.GetEntityDescTags(model.TSimCardBindPkgExportModel{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
fileName = "导出订购表-" + gctx.CtxId(ctx)
|
||||
sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, (totalCount+in.PageSize-1)/in.PageSize, in.Page, len(list))
|
||||
exports []model.TSimCardBindPkgExportModel
|
||||
)
|
||||
|
||||
if err = gconv.Scan(list, &exports); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
||||
return
|
||||
}
|
||||
|
||||
// Edit 修改/新增订购表
|
||||
func (s *sIotTSimCardBindPkg) Edit(ctx context.Context, in *model.TSimCardBindPkgEditParam) (err error) {
|
||||
// 验证'SubscriptionNo'唯一
|
||||
if err = xgorm.IsUnique(ctx, &dao.TSimCardBindPkg, g.Map{dao.TSimCardBindPkg.Columns().SubscriptionNo: in.SubscriptionNo}, "订购记录编号已存在", in.Id); err != nil {
|
||||
return
|
||||
}
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
|
||||
|
||||
// 修改
|
||||
if in.Id > 0 {
|
||||
updatedBy := contexts.GetUserId(ctx)
|
||||
in.UpdatedBy = &updatedBy
|
||||
in.UpdatedAt = gtime.Now()
|
||||
if _, err = s.Model(ctx).
|
||||
Fields(model.TSimCardBindPkgUpdateFields{}).
|
||||
WherePri(in.Id).Data(in).Update(); err != nil {
|
||||
err = gerror.Wrap(err, "修改订购表失败,请稍后重试!")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 新增
|
||||
tenantId := contexts.GetTenantId(ctx)
|
||||
in.TenantId = &tenantId
|
||||
createdDept := contexts.GetDeptId(ctx)
|
||||
in.CreatedDept = &createdDept
|
||||
createdBy := contexts.GetUserId(ctx)
|
||||
in.CreatedBy = &createdBy
|
||||
in.CreatedAt = gtime.Now()
|
||||
if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
|
||||
Fields(model.TSimCardBindPkgInsertFields{}).
|
||||
Data(in).Insert(); err != nil {
|
||||
err = gerror.Wrap(err, "新增订购表失败,请稍后重试!")
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除订购表
|
||||
func (s *sIotTSimCardBindPkg) Delete(ctx context.Context, in *model.TSimCardBindPkgDeleteParam) (err error) {
|
||||
|
||||
if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
|
||||
err = gerror.Wrap(err, "删除订购表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// View 获取订购表指定信息
|
||||
func (s *sIotTSimCardBindPkg) View(ctx context.Context, in *model.TSimCardBindPkgViewParam) (res *model.TSimCardBindPkgViewModel, err error) {
|
||||
if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil {
|
||||
err = gerror.Wrap(err, "获取订购表信息,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AddPackagePaymentContext 获取当前组织的加油包支付上下文。
|
||||
func (s *sIotTSimCardBindPkg) AddPackagePaymentContext(ctx context.Context) (*model.TSimAddPackageOptionsRes, error) {
|
||||
return queryAddPackagePaymentContext(ctx)
|
||||
}
|
||||
|
||||
// AddPackageOptions 获取当前卡共同可订购的加油包套餐。
|
||||
func (s *sIotTSimCardBindPkg) AddPackageOptions(ctx context.Context, in *model.TSimCardAddPackageOptionsParam) (*model.TSimAddPackageOptionsRes, error) {
|
||||
if in == nil || len(in.Iccids) == 0 {
|
||||
return nil, gerror.New("ICCID不能为空")
|
||||
}
|
||||
iccids := uniqueNonEmptyStrings(in.Iccids)
|
||||
if len(iccids) == 0 {
|
||||
return nil, gerror.New("ICCID不能为空")
|
||||
}
|
||||
|
||||
cardColumns := dao.TSimCardInfo.Columns()
|
||||
var cards []struct {
|
||||
Iccid string `orm:"iccid"`
|
||||
PackageStatus int `orm:"package_status"`
|
||||
DeptId int64 `orm:"dept_id"`
|
||||
}
|
||||
if err := handler.Model(dao.TSimCardInfo.Ctx(ctx), &handler.Option{FilterTenant: true, FilterAuth: true}).
|
||||
Fields(cardColumns.Iccid, cardColumns.PackageStatus, cardColumns.TenantId, cardColumns.DeptId, cardColumns.CreatedDept, cardColumns.CreatedBy).
|
||||
WhereIn(cardColumns.Iccid, iccids).
|
||||
Scan(&cards); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询卡信息失败")
|
||||
}
|
||||
cardMap := make(map[string]int64, len(cards))
|
||||
for _, card := range cards {
|
||||
code := strings.TrimSpace(card.Iccid)
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
if card.PackageStatus != consts.PackageStatusEffective {
|
||||
return nil, gerror.Newf("ICCID %s 当前套餐未生效,不能订购加油包", code)
|
||||
}
|
||||
if card.DeptId <= 0 {
|
||||
return nil, gerror.Newf("ICCID %s 未绑定客户组织", code)
|
||||
}
|
||||
cardMap[code] = card.DeptId
|
||||
}
|
||||
for _, code := range iccids {
|
||||
if _, ok := cardMap[code]; !ok {
|
||||
return nil, gerror.Newf("ICCID %s 不存在或无权限", code)
|
||||
}
|
||||
}
|
||||
if err := ensureNoActiveCardTopupPackages(ctx, iccids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isTopDept, _, err := service.AgentDept().IsTopDept(ctx)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "判断当前组织类型失败")
|
||||
}
|
||||
availableBalance, err := queryAddPackageAvailableBalance(ctx, contexts.GetDeptId(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bindColumns := dao.TSimCardBindPkg.Columns()
|
||||
var binds []struct {
|
||||
Iccid string `orm:"iccid"`
|
||||
PackageCode string `orm:"package_code"`
|
||||
ExpectedExpireTime *gtime.Time `orm:"expected_expire_time"`
|
||||
}
|
||||
if err := handler.Model(dao.TSimCardBindPkg.Ctx(ctx), &handler.Option{FilterTenant: true, FilterAuth: true}).
|
||||
Fields(bindColumns.Iccid, bindColumns.PackageCode, bindColumns.ExpectedExpireTime, bindColumns.TenantId, bindColumns.DeptId, bindColumns.CreatedDept, bindColumns.CreatedBy).
|
||||
WhereIn(bindColumns.Iccid, iccids).
|
||||
WhereIn(bindColumns.PackageType, []int{consts.PackageTypeCard, consts.PackageTypePool}).
|
||||
Where(bindColumns.EffectiveStatus, consts.EffectiveStatusEffective).
|
||||
OrderDesc(bindColumns.ExpectedExpireTime).
|
||||
OrderDesc(bindColumns.Id).
|
||||
Scan(&binds); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询卡基础套餐失败")
|
||||
}
|
||||
baseCodes := make(map[string]string, len(iccids))
|
||||
for _, bind := range binds {
|
||||
iccid := strings.TrimSpace(bind.Iccid)
|
||||
if _, exists := baseCodes[iccid]; exists {
|
||||
continue
|
||||
}
|
||||
if bind.ExpectedExpireTime != nil && !bind.ExpectedExpireTime.After(gtime.Now()) {
|
||||
continue
|
||||
}
|
||||
baseCodes[iccid] = strings.TrimSpace(bind.PackageCode)
|
||||
}
|
||||
for _, code := range iccids {
|
||||
if baseCodes[code] == "" {
|
||||
return nil, gerror.Newf("ICCID %s 当前没有正在生效中的基础套餐", code)
|
||||
}
|
||||
}
|
||||
|
||||
packageCodes := make([]string, 0, len(baseCodes))
|
||||
for _, code := range baseCodes {
|
||||
packageCodes = append(packageCodes, code)
|
||||
}
|
||||
packageColumns := dao.TSimFlowPackageInfo.Columns()
|
||||
var packages []*entity.TSimFlowPackageInfo
|
||||
if err := handler.Model(dao.TSimFlowPackageInfo.Ctx(ctx), &handler.Option{FilterTenant: true, FilterAuth: false}).
|
||||
Fields(packageColumns.PackageCode, packageColumns.TopupPackageCodes).
|
||||
WhereIn(packageColumns.PackageCode, uniqueNonEmptyStrings(packageCodes)).
|
||||
Scan(&packages); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询基础套餐配置失败")
|
||||
}
|
||||
packageMap := make(map[string]*entity.TSimFlowPackageInfo, len(packages))
|
||||
for _, pkg := range packages {
|
||||
if pkg != nil {
|
||||
packageMap[strings.TrimSpace(pkg.PackageCode)] = pkg
|
||||
}
|
||||
}
|
||||
|
||||
var commonCodes map[string]struct{}
|
||||
for _, code := range iccids {
|
||||
base := packageMap[baseCodes[code]]
|
||||
if base == nil {
|
||||
return nil, gerror.Newf("基础套餐不存在:%s", baseCodes[code])
|
||||
}
|
||||
allowed := make(map[string]struct{})
|
||||
for _, topupCode := range packageCodesFromJSON(base.TopupPackageCodes) {
|
||||
allowed[topupCode] = struct{}{}
|
||||
}
|
||||
if len(allowed) == 0 {
|
||||
return nil, gerror.Newf("基础套餐未配置可购加油包:%s", baseCodes[code])
|
||||
}
|
||||
if commonCodes == nil {
|
||||
commonCodes = allowed
|
||||
continue
|
||||
}
|
||||
for candidate := range commonCodes {
|
||||
if _, ok := allowed[candidate]; !ok {
|
||||
delete(commonCodes, candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(commonCodes) == 0 {
|
||||
return nil, gerror.New("所选卡没有共同可购的加油包套餐")
|
||||
}
|
||||
|
||||
var addPackages []*entity.TSimFlowPackageInfo
|
||||
if err := handler.Model(dao.TSimFlowPackageInfo.Ctx(ctx), &handler.Option{FilterTenant: true, FilterAuth: false}).
|
||||
Fields(
|
||||
packageColumns.PackageCode,
|
||||
packageColumns.PackageName,
|
||||
packageColumns.FlowMb,
|
||||
packageColumns.CostPrice,
|
||||
packageColumns.TerminalCost,
|
||||
packageColumns.SysDefaultRatio,
|
||||
packageColumns.SysDefaultProfit,
|
||||
packageColumns.SysDefaultTerminalRatio,
|
||||
packageColumns.SysDefaultTerminalProfit,
|
||||
).
|
||||
WhereIn(packageColumns.PackageCode, mapKeys(commonCodes)).
|
||||
Where(packageColumns.PackageType, consts.PackageTypeCardAddPackage).
|
||||
Where(packageColumns.Enabled, 1).
|
||||
OrderAsc(packageColumns.SortNo).
|
||||
Scan(&addPackages); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询单卡加油包套餐失败")
|
||||
}
|
||||
items := make([]*model.TSimAddPackageOptionModel, 0, len(addPackages))
|
||||
for _, pkg := range addPackages {
|
||||
if pkg == nil {
|
||||
continue
|
||||
}
|
||||
var totalAmount float64
|
||||
var unitPrice float64
|
||||
priceAvailable := true
|
||||
uniformPrice := true
|
||||
paymentAccounts := make(map[int64]*model.TSimAddPackagePaymentAccountModel)
|
||||
for index, iccid := range iccids {
|
||||
customerDeptID := cardMap[iccid]
|
||||
priceOwnerDeptID, err := loadPackagePriceParentDeptID(ctx, nil, contexts.GetTenantId(ctx), customerDeptID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
salePrice, err := resolvePackageEffectiveSalePrice(
|
||||
ctx,
|
||||
nil,
|
||||
contexts.GetTenantId(ctx),
|
||||
priceOwnerDeptID,
|
||||
customerDeptID,
|
||||
packagePriceSourceFromEntity(pkg),
|
||||
)
|
||||
if err != nil {
|
||||
priceAvailable = false
|
||||
break
|
||||
}
|
||||
if index == 0 {
|
||||
unitPrice = salePrice.AgentShipmentPrice
|
||||
} else if math.Abs(unitPrice-salePrice.AgentShipmentPrice) > 0.0001 {
|
||||
uniformPrice = false
|
||||
}
|
||||
totalAmount = roundAmount(totalAmount + salePrice.AgentShipmentPrice)
|
||||
account := paymentAccounts[customerDeptID]
|
||||
if account == nil {
|
||||
balance, err := queryAddPackageAvailableBalance(ctx, customerDeptID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account = &model.TSimAddPackagePaymentAccountModel{
|
||||
PayerDeptId: customerDeptID,
|
||||
AvailableBalance: balance,
|
||||
}
|
||||
paymentAccounts[customerDeptID] = account
|
||||
}
|
||||
account.TargetCount++
|
||||
account.RequiredAmount = roundAmount(account.RequiredAmount + salePrice.AgentShipmentPrice)
|
||||
}
|
||||
paymentAccountItems := make([]*model.TSimAddPackagePaymentAccountModel, 0, len(paymentAccounts))
|
||||
for _, account := range paymentAccounts {
|
||||
account.BalanceEnough = account.AvailableBalance+0.0001 >= account.RequiredAmount
|
||||
paymentAccountItems = append(paymentAccountItems, account)
|
||||
}
|
||||
if !uniformPrice {
|
||||
unitPrice = 0
|
||||
}
|
||||
items = append(items, &model.TSimAddPackageOptionModel{
|
||||
PackageCode: strings.TrimSpace(pkg.PackageCode),
|
||||
PackageName: strings.TrimSpace(pkg.PackageName),
|
||||
FlowMb: pkg.FlowMb,
|
||||
UnitPrice: unitPrice,
|
||||
TotalAmount: totalAmount,
|
||||
PriceAvailable: priceAvailable,
|
||||
PaymentAccounts: paymentAccountItems,
|
||||
})
|
||||
}
|
||||
return &model.TSimAddPackageOptionsRes{
|
||||
Items: items,
|
||||
IsTopDept: isTopDept,
|
||||
DefaultPaymentMode: addPackageDefaultPaymentMode(isTopDept),
|
||||
AvailableBalance: availableBalance,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func uniqueNonEmptyStrings(values []string) []string {
|
||||
seen := make(map[string]struct{}, len(values))
|
||||
result := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[value]; ok {
|
||||
continue
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
result = append(result, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func mapKeys(values map[string]struct{}) []string {
|
||||
keys := make([]string, 0, len(values))
|
||||
for key := range values {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func ensureNoActiveCardTopupPackages(ctx context.Context, iccids []string) error {
|
||||
iccids = uniqueNonEmptyStrings(iccids)
|
||||
if len(iccids) == 0 {
|
||||
return nil
|
||||
}
|
||||
c := dao.TSimCardBindPkg.Columns()
|
||||
var row struct {
|
||||
Iccid string `orm:"iccid"`
|
||||
}
|
||||
if err := handler.Model(dao.TSimCardBindPkg.Ctx(ctx), &handler.Option{FilterTenant: true, FilterAuth: true}).
|
||||
Fields(c.Iccid).
|
||||
WhereIn(c.Iccid, iccids).
|
||||
Where(c.PackageType, consts.PackageTypeCardAddPackage).
|
||||
WhereIn(c.EffectiveStatus, []int{consts.EffectiveStatusPending, consts.EffectiveStatusEffective}).
|
||||
Where(fmt.Sprintf("(%s IS NULL OR %s > ?)", c.ExpectedExpireTime, c.ExpectedExpireTime), gtime.Now()).
|
||||
OrderAsc(c.Id).
|
||||
Limit(1).
|
||||
Scan(&row); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return gerror.Wrap(err, "查询未过期单卡加油包失败")
|
||||
}
|
||||
if iccid := strings.TrimSpace(row.Iccid); iccid != "" {
|
||||
return gerror.Newf("ICCID %s 存在未过期加油包,不能重复订购", iccid)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureNoActivePoolTopupPackages(ctx context.Context, poolCodes []string) error {
|
||||
poolCodes = uniqueNonEmptyStrings(poolCodes)
|
||||
if len(poolCodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
c := dao.TSimPoolBindPackage.Columns()
|
||||
var row struct {
|
||||
PoolNo string `orm:"pool_no"`
|
||||
}
|
||||
if err := handler.Model(dao.TSimPoolBindPackage.Ctx(ctx), &handler.Option{FilterTenant: true, FilterAuth: true}).
|
||||
Fields(c.PoolNo).
|
||||
WhereIn(c.PoolNo, poolCodes).
|
||||
Where(c.PackageType, consts.PackageTypePoolAddPackage).
|
||||
WhereIn(c.EffectiveStatus, []int{consts.EffectiveStatusPending, consts.EffectiveStatusEffective}).
|
||||
Where(fmt.Sprintf("(%s IS NULL OR %s > ?)", c.ExpectedExpireTime, c.ExpectedExpireTime), gtime.Now()).
|
||||
OrderAsc(c.Id).
|
||||
Limit(1).
|
||||
Scan(&row); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return gerror.Wrap(err, "查询未过期流量池加油包失败")
|
||||
}
|
||||
if poolNo := strings.TrimSpace(row.PoolNo); poolNo != "" {
|
||||
return gerror.Newf("流量池 %s 存在未过期加油包,不能重复订购", poolNo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 套餐详情查询
|
||||
func (s *sIotTSimCardBindPkg) GetPkgInfo(ctx context.Context, in *model.TSimCardBindPkgInfoParam) (list []*model.TSimCardBindPkgListModel, totalCount int, err error) {
|
||||
mod := s.Model(ctx)
|
||||
bindPackage := dao.TSimCardBindPkg.Table()
|
||||
packageInfo := dao.TSimFlowPackageInfo.Table()
|
||||
orderTable := dao.TOrder.Table()
|
||||
|
||||
// 先构建 Join
|
||||
mod = mod.LeftJoin(packageInfo, bindPackage+"."+dao.TSimCardBindPkg.Columns().PackageCode+" = "+packageInfo+"."+dao.TSimFlowPackageInfo.Columns().PackageCode)
|
||||
mod = mod.LeftJoin(orderTable, "CONVERT("+bindPackage+"."+dao.TSimCardBindPkg.Columns().OrderCode+" USING utf8mb4) = "+orderTable+"."+dao.TOrder.Columns().OrderSn)
|
||||
|
||||
// 字段过滤(包含主表字段 + joined 表字段)
|
||||
mod = mod.FieldsPrefix(bindPackage, model.TSimCardBindPkgListModel{})
|
||||
mod = mod.Fields(packageInfo + ".package_name as packageName")
|
||||
mod = mod.Fields(packageInfo + ".flow_mb as packageFlowMb")
|
||||
mod = mod.Fields(packageInfo + ".flow_gb as packageFlowGb")
|
||||
mod = mod.Fields(orderTable + ".pay_type as payType")
|
||||
mod = mod.Fields(orderTable + ".pay_status as payStatus")
|
||||
mod = mod.Fields(orderTable + ".pay_time as payTime")
|
||||
mod = mod.Fields(orderTable + ".total_amount as totalAmount")
|
||||
mod = mod.Fields(orderTable + ".paid_amount as paidAmount")
|
||||
mod = mod.Fields(orderTable + ".balance as balance")
|
||||
|
||||
// 查询ICCID
|
||||
if in.Iccid != "" {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Columns().Iccid, in.Iccid)
|
||||
}
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Columns().PackageType, 103)
|
||||
|
||||
// 分页
|
||||
mod = mod.Page(in.Page, in.PageSize)
|
||||
|
||||
// 排序
|
||||
mod = mod.OrderDesc(dao.TSimCardBindPkg.Columns().Id)
|
||||
|
||||
// 操作人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
// 查询数据
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取订购表列表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 变更套餐
|
||||
func (s *sIotTSimCardBindPkg) GetChangePkg(ctx context.Context, in *model.TSimCardBindPkgInfoParam) (list []*model.TSimCardBindPkgListModel, totalCount int, err error) {
|
||||
mod := s.Model(ctx)
|
||||
bindPackage := dao.TSimCardBindPkg.Table()
|
||||
packageInfo := dao.TSimFlowPackageInfo.Table()
|
||||
|
||||
// 构建 Join - 关联当前套餐信息(变更后)
|
||||
mod = mod.LeftJoin(packageInfo+" as curr_pkg", bindPackage+"."+dao.TSimCardBindPkg.Columns().PackageCode+" = curr_pkg."+dao.TSimFlowPackageInfo.Columns().PackageCode)
|
||||
// 构建 Join - 关联变更前套餐信息
|
||||
mod = mod.LeftJoin(packageInfo+" as prev_pkg", bindPackage+"."+dao.TSimCardBindPkg.Columns().PreviousPackageCode+" = prev_pkg."+dao.TSimFlowPackageInfo.Columns().PackageCode)
|
||||
|
||||
// 字段过滤(包含主表字段 + joined 表字段)
|
||||
mod = mod.FieldsPrefix(bindPackage, model.TSimCardBindPkgListModel{})
|
||||
mod = mod.Fields("curr_pkg.package_name as packageName")
|
||||
mod = mod.Fields("prev_pkg.package_name as previousPackageName")
|
||||
|
||||
// 查询ICCID
|
||||
mod = mod.Where(bindPackage+"."+dao.TSimCardBindPkg.Columns().Iccid, in.Iccid)
|
||||
mod = mod.Where("("+bindPackage+"."+dao.TSimCardBindPkg.Columns().BusinessType+" = ? OR "+bindPackage+"."+dao.TSimCardBindPkg.Columns().BatchNo+" LIKE ?)", consts.PackageBusinessTypeChange, "CHG%")
|
||||
// 分页
|
||||
mod = mod.Page(in.Page, in.PageSize)
|
||||
|
||||
// 排序
|
||||
mod = mod.OrderDesc(dao.TSimCardBindPkg.Columns().Id)
|
||||
|
||||
// 操作人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
// 查询数据
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取订购表列表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sIotTSimCardBindPkg) DownloadExcelTemplate(ctx context.Context) error {
|
||||
return addpackage.NewCardSubmitter().DownloadTemplate(ctx)
|
||||
}
|
||||
|
||||
func (s *sIotTSimCardBindPkg) SubmitExcel(ctx context.Context, in *model.TSimCardBindPkgAddPackageExcelSubmitParam) (*model.TSimCardBindPkgAddPackageExcelSubmitRes, error) {
|
||||
if in == nil {
|
||||
in = &model.TSimCardBindPkgAddPackageExcelSubmitParam{}
|
||||
}
|
||||
file, err := cardAddPackageUploadFile(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paymentMode, offlineContractCompleted, err := normalizeAddPackagePaymentMode(ctx, in.PaymentMode, in.OfflineContractCompleted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := addpackage.NewCardSubmitter().SubmitExcel(ctx, file, addpackage.SubmitOptions{
|
||||
PaymentMode: paymentMode,
|
||||
OfflineContractCompleted: offlineContractCompleted,
|
||||
ManualConfirm: in.ManualConfirm,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cardAddPackageSubmitRes(result), nil
|
||||
}
|
||||
|
||||
func (s *sIotTSimCardBindPkg) SubmitInput(ctx context.Context, in *model.TSimCardBindPkgAddPackageInputSubmitParam) (*model.TSimCardBindPkgAddPackageInputSubmitRes, error) {
|
||||
if in == nil {
|
||||
in = &model.TSimCardBindPkgAddPackageInputSubmitParam{}
|
||||
}
|
||||
paymentMode, offlineContractCompleted, err := normalizeAddPackagePaymentMode(ctx, in.PaymentMode, in.OfflineContractCompleted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := addpackage.NewCardSubmitter().SubmitInput(ctx, in.Input, addpackage.SubmitOptions{
|
||||
PackageCode: in.PackageCode,
|
||||
Remark: in.Remark,
|
||||
PaymentMode: paymentMode,
|
||||
OfflineContractCompleted: offlineContractCompleted,
|
||||
EffectiveMode: in.EffectiveMode,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*model.TSimCardBindPkgAddPackageInputSubmitRes)(cardAddPackageSubmitRes(result)), nil
|
||||
}
|
||||
|
||||
func cardAddPackageUploadFile(ctx context.Context) (*ghttp.UploadFile, error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
if r == nil {
|
||||
return nil, gerror.New("当前上下文不是HTTP请求")
|
||||
}
|
||||
file := r.GetUploadFile("file")
|
||||
if file == nil {
|
||||
return nil, gerror.New("请选择上传文件")
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func cardAddPackageSubmitRes(result *addpackage.SubmitResult) *model.TSimCardBindPkgAddPackageBatchSubmitRes {
|
||||
res := &model.TSimCardBindPkgAddPackageBatchSubmitRes{}
|
||||
if result == nil {
|
||||
return res
|
||||
}
|
||||
res.BatchNo = result.BatchNo
|
||||
res.BatchType = result.BatchType
|
||||
res.TargetBatchType = result.TargetBatchType
|
||||
res.BatchAsyncStatus = result.BatchAsyncStatus
|
||||
res.Total = result.Total
|
||||
res.ValidCount = result.ValidCount
|
||||
res.FailCount = result.FailCount
|
||||
return res
|
||||
}
|
||||
Reference in New Issue
Block a user