Files
iotlcm/server/internal/logic/iot/t_sim_flow_package_info.go
T
MiFaZhan 59eb34976a 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 已说明。
2026-10-23 14:48:30 +08:00

708 lines
26 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 iot
import (
"context"
"fmt"
"math"
"strings"
"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/handler"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/hook"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/iot/packageduration"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/packagecustomer"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do"
"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/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
type sIotTSimFlowPackageInfo struct{}
func NewIotTSimFlowPackageInfo() *sIotTSimFlowPackageInfo {
return &sIotTSimFlowPackageInfo{}
}
func init() {
service.RegisterIotTSimFlowPackageInfo(NewIotTSimFlowPackageInfo())
}
func (s *sIotTSimFlowPackageInfo) 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.TSimFlowPackageInfo.Ctx(ctx), option...)
}
func (s *sIotTSimFlowPackageInfo) packageListModel(ctx context.Context) (*gdb.Model, error) {
mainTable := dao.TSimFlowPackageInfo.Table()
pcTable := dao.TPackageCustomer.Table()
pcColumns := dao.TPackageCustomer.Columns()
mod := s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false})
isTop, _, err := service.AgentDept().IsTopDept(ctx)
if err != nil {
return nil, err
}
if isTop {
return mod, nil
}
return mod.
InnerJoin(pcTable, pcTable+"."+pcColumns.PackageCode+" = "+mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageCode).
Where(pcTable+"."+pcColumns.DeptId, contexts.GetDeptId(ctx)).
Where(pcTable+"."+pcColumns.TenantId, contexts.GetTenantId(ctx)), nil
}
func (s *sIotTSimFlowPackageInfo) applyListFilter(mod *gdb.Model, mainTable string, in *model.TSimFlowPackageInfoListParam) *gdb.Model {
if in.PackageCode != "" {
mod = mod.WhereLike(mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageCode, "%"+in.PackageCode+"%")
}
if in.CategoryCode != "" {
mod = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().CategoryCode, in.CategoryCode)
}
if in.PackageType != "" {
mod = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageType, in.PackageType)
}
if in.PackageName != "" {
mod = mod.WhereLike(mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageName, "%"+in.PackageName+"%")
}
if in.Enabled != nil {
mod = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().Enabled, *in.Enabled)
}
if len(in.CreatedAt) == 2 {
mod = mod.WhereBetween(mainTable+"."+dao.TSimFlowPackageInfo.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1].EndOfDay())
}
return mod
}
func (s *sIotTSimFlowPackageInfo) buildPackageCustomer(ctx context.Context, dept *entity.SysDept, packageCode, packageName string, now *gtime.Time) do.TPackageCustomer {
userId := contexts.GetUserId(ctx)
return do.TPackageCustomer{
PackageCode: packageCode,
PackageName: packageName,
DeptId: dept.DeptId,
DeptName: dept.DeptName,
TenantId: contexts.GetTenantId(ctx),
CreatedDept: contexts.GetDeptId(ctx),
CreatedBy: userId,
CreatedAt: now,
UpdatedBy: userId,
UpdatedAt: now,
}
}
func (s *sIotTSimFlowPackageInfo) List(ctx context.Context, in *model.TSimFlowPackageInfoListParam) (list []*model.TSimFlowPackageInfoListModel, totalCount int, err error) {
mainTable := dao.TSimFlowPackageInfo.Table()
catTable := dao.TSimPackageCategory.Table()
countBaseMod, err := s.packageListModel(ctx)
if err != nil {
return nil, 0, err
}
countMod := s.applyListFilter(countBaseMod, mainTable, in)
totalCount, err = countMod.Count()
if err != nil {
err = gerror.Wrap(err, "获取SIM流量套餐管理列表失败,请稍后重试")
return
}
mod, err := s.packageListModel(ctx)
if err != nil {
return nil, 0, err
}
mod = mod.LeftJoin(catTable, mainTable+"."+dao.TSimFlowPackageInfo.Columns().CategoryCode+" = "+catTable+"."+dao.TSimPackageCategory.Columns().CategoryCode)
mod = s.applyListFilter(mod, mainTable, in)
mod = mod.FieldsPrefix(mainTable, model.TSimFlowPackageInfoListModel{})
mod = mod.Fields(catTable + "." + dao.TSimPackageCategory.Columns().CategoryName + " as categoryName")
mod = mod.Page(in.Page, in.PageSize)
mod = mod.OrderAsc(mainTable + "." + dao.TSimFlowPackageInfo.Columns().SortNo)
mod = mod.Hook(hook.MemberSummary)
if err = mod.Scan(&list); err != nil {
err = gerror.Wrap(err, "获取SIM流量套餐管理列表失败,请稍后重试")
return
}
if err = s.fillPackageListPrices(ctx, list); err != nil {
return nil, 0, err
}
normalizePackageListRows(list)
return
}
// 可配置池列表(PackageType=102)
func (s *sIotTSimFlowPackageInfo) FlowPackageList(ctx context.Context, in *model.TSimFlowPackageInfoFlowPackageListParam) (list []*model.TSimFlowPackageInfoListModel, err error) {
mainTable := dao.TSimFlowPackageInfo.Table()
mod := dao.TSimFlowPackageInfo.Ctx(ctx)
// 该接口只供流量池套餐配置弹窗使用,返回套餐编码和名称即可。
// pool_package_code 是字符串编码,旧列表模型仍为整数类型,这里不查询该字段,
// 避免编辑已有池配置时发生字符串转整数的扫描错误。
mod = mod.Fields(
mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageCode,
mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageName,
mainTable+"."+dao.TSimFlowPackageInfo.Columns().SortNo,
)
currentPoolPackageCode := ""
if in != nil {
currentPoolPackageCode = strings.TrimSpace(in.PoolPackageCode)
}
mod = applyPoolFlowPackageBaseFilter(mod, mainTable, currentPoolPackageCode)
// 根据流量套餐过滤(格式:100.000,102400.000,前边是GB后边是MB)
if in != nil && in.Flow != "" {
flow := strings.Trim(in.Flow, "\"")
parts := strings.Split(flow, ",")
if len(parts) == 2 {
flowGb := strings.TrimSpace(parts[0])
flowMb := strings.TrimSpace(parts[1])
if flowGb == "" {
mod = mod.Where(mainTable + "." + dao.TSimFlowPackageInfo.Columns().FlowGb + " IS NULL")
} else {
mod = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().FlowGb+" = ?", flowGb)
}
mod = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().FlowMb+" = ?", flowMb)
}
}
mod = mod.OrderAsc(mainTable + "." + dao.TSimFlowPackageInfo.Columns().SortNo)
mod = mod.Hook(hook.MemberSummary)
if err = mod.Scan(&list); err != nil {
err = gerror.Wrap(err, "获取SIM流量套餐管理列表失败,请稍后重试")
return
}
normalizePackageListRows(list)
return
}
// 可配置池加油包列表(PackageType=104)
func (s *sIotTSimFlowPackageInfo) FlowPackageAddList(ctx context.Context) (list []*model.TSimFlowPackageInfoListModel, err error) {
mainTable := dao.TSimFlowPackageInfo.Table()
mod := dao.TSimFlowPackageInfo.Ctx(ctx)
// 弹窗只使用套餐编码和名称,不查询字符串类型的池编码字段。
mod = mod.Fields(
mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageCode,
mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageName,
mainTable+"."+dao.TSimFlowPackageInfo.Columns().SortNo,
)
mod = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageType, "104")
mod = mod.OrderAsc(mainTable + "." + dao.TSimFlowPackageInfo.Columns().SortNo)
mod = mod.Hook(hook.MemberSummary)
if err = mod.Scan(&list); err != nil {
err = gerror.Wrap(err, "获取SIM流量套餐管理列表失败,请稍后重试")
return
}
normalizePackageListRows(list)
return
}
// GetFlowPackageOptions 获取流量套餐GB+MB组合选项
func (s *sIotTSimFlowPackageInfo) RenewablePackageOptions(ctx context.Context, in *model.TSimFlowPackageInfoRenewablePackageOptionsParam) (list []*model.TSimFlowPackageInfoListModel, err error) {
if in == nil {
in = &model.TSimFlowPackageInfoRenewablePackageOptionsParam{}
}
mainTable := dao.TSimFlowPackageInfo.Table()
columns := dao.TSimFlowPackageInfo.Columns()
mod := s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).
Fields(model.TSimFlowPackageInfoListModel{}).
Where(mainTable+"."+columns.Enabled, 1)
if packageType := strings.TrimSpace(in.PackageType); packageType != "" {
mod = mod.Where(mainTable+"."+columns.PackageType, packageType)
}
if packageCode := strings.TrimSpace(in.ExcludePackageCode); packageCode != "" {
mod = mod.WhereNot(mainTable+"."+columns.PackageCode, packageCode)
}
mod = mod.OrderAsc(mainTable + "." + columns.SortNo)
if err = mod.Scan(&list); err != nil {
return nil, gerror.Wrap(err, "获取可续费套餐候选列表失败,请稍后重试")
}
normalizePackageListRows(list)
return list, nil
}
func (s *sIotTSimFlowPackageInfo) GetFlowPackageOptions(ctx context.Context, in *model.TSimFlowPackageInfoFlowPackageOptionsParam) ([]string, error) {
var results []string
mainTable := dao.TSimFlowPackageInfo.Table()
currentPoolPackageCode := ""
if in != nil {
currentPoolPackageCode = strings.TrimSpace(in.PoolPackageCode)
}
var rows []*struct {
FlowGb string
FlowMb string
}
g.Log().Info(ctx, "获取流量套餐选项")
mod := s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).
Fields(mainTable+"."+dao.TSimFlowPackageInfo.Columns().FlowGb, mainTable+"."+dao.TSimFlowPackageInfo.Columns().FlowMb).
Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().PackageType, "102").
Distinct().
Where("(" + mainTable + "." + dao.TSimFlowPackageInfo.Columns().FlowGb + " <> '' OR " + mainTable + "." + dao.TSimFlowPackageInfo.Columns().FlowMb + " <> '')").
OrderAsc(mainTable + "." + dao.TSimFlowPackageInfo.Columns().FlowGb).
OrderAsc(mainTable + "." + dao.TSimFlowPackageInfo.Columns().FlowMb)
if currentPoolPackageCode == "" {
mod = mod.Where("(" + mainTable + "." + dao.TSimFlowPackageInfo.Columns().PoolPackageCode + " IS NULL OR " + mainTable + "." + dao.TSimFlowPackageInfo.Columns().PoolPackageCode + " = '')")
} else {
mod = mod.Where("("+mainTable+"."+dao.TSimFlowPackageInfo.Columns().PoolPackageCode+" IS NULL OR "+mainTable+"."+dao.TSimFlowPackageInfo.Columns().PoolPackageCode+" = '' OR "+mainTable+"."+dao.TSimFlowPackageInfo.Columns().PoolPackageCode+" = ?)", currentPoolPackageCode)
}
if err := mod.Scan(&rows); err != nil {
return nil, gerror.Wrap(err, "获取流量套餐选项失败")
}
for _, row := range rows {
results = append(results, row.FlowGb+","+row.FlowMb)
}
return results, nil
}
func normalizePackageListRows(list []*model.TSimFlowPackageInfoListModel) {
for _, item := range list {
if item == nil {
continue
}
if item.RenewableDurationConfig == nil {
continue
}
if normalized, normalizeErr := packageduration.NormalizeRenewableDurationConfig(item.RenewableDurationConfig); normalizeErr == nil {
item.RenewableDurationConfig = normalized
}
}
}
func (s *sIotTSimFlowPackageInfo) fillPackageListPrices(ctx context.Context, list []*model.TSimFlowPackageInfoListModel) error {
if len(list) == 0 {
return nil
}
tenantID := contexts.GetTenantId(ctx)
currentDeptID := contexts.GetDeptId(ctx)
ownerDeptID, err := loadPackagePriceParentDeptID(ctx, nil, tenantID, currentDeptID)
if err != nil {
return gerror.Wrap(err, "get package price owner department failed")
}
for _, item := range list {
if item == nil {
continue
}
salePrice, err := resolvePackageEffectiveSalePrice(
ctx,
nil,
tenantID,
ownerDeptID,
currentDeptID,
packagePriceSourceFromListModel(item),
)
if err != nil {
return gerror.Wrapf(err, "calculate effective price for package %s failed", item.PackageCode)
}
item.AgentShipmentPrice = salePrice.AgentShipmentPrice
item.TerminalSalePrice = salePrice.TerminalSalePrice
}
return nil
}
func packagePriceSourceFromListModel(pkg *model.TSimFlowPackageInfoListModel) packagePriceSource {
if pkg == nil {
return packagePriceSource{}
}
return packagePriceSource{
PackageCode: strings.TrimSpace(pkg.PackageCode),
CostPrice: pkg.CostPrice,
TerminalCost: pkg.TerminalCost,
SysDefaultRatio: pkg.SysDefaultRatio,
SysDefaultProfit: pkg.SysDefaultProfit,
SysDefaultTerminalRatio: pkg.SysDefaultTerminalRatio,
SysDefaultTerminalProfit: pkg.SysDefaultTerminalProfit,
}
}
func applyPoolFlowPackageBaseFilter(mod *gdb.Model, mainTable, currentPoolPackageCode string) *gdb.Model {
columns := dao.TSimFlowPackageInfo.Columns()
poolPackageColumn := mainTable + "." + columns.PoolPackageCode
if currentPoolPackageCode == "" {
return mod.
Where("("+poolPackageColumn+" IS NULL OR "+poolPackageColumn+" = '')").
Where(mainTable+"."+columns.PackageType, "102")
}
return mod.
Where("("+poolPackageColumn+" IS NULL OR "+poolPackageColumn+" = '' OR "+poolPackageColumn+" = ?)", currentPoolPackageCode).
Where(mainTable+"."+columns.PackageType, "102")
}
func (s *sIotTSimFlowPackageInfo) Export(ctx context.Context, in *model.TSimFlowPackageInfoListParam) (err error) {
list, totalCount, err := s.List(ctx, in)
if err != nil {
return
}
tags, err := convert.GetEntityDescTags(model.TSimFlowPackageInfoExportModel{})
if err != nil {
return
}
var (
fileName = "导出SIM流量套餐管理-" + gctx.CtxId(ctx)
sheetName = fmt.Sprintf("索引条件共%v行 共%v页 当前导出是第%v页 本页共%v行", totalCount, (totalCount+in.PageSize-1)/in.PageSize, in.Page, len(list))
exports []model.TSimFlowPackageInfoExportModel
)
if err = gconv.Scan(list, &exports); err != nil {
return
}
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
return
}
func (s *sIotTSimFlowPackageInfo) Edit(ctx context.Context, in *model.TSimFlowPackageInfoEditParam) (err error) {
if in == nil {
return gerror.New("package information cannot be empty")
}
if err = validateFlowMb(in); err != nil {
return err
}
if in.BillingMethod == nil || strings.TrimSpace(*in.BillingMethod) == "" {
billingMethod := packageduration.MonthBillingMethodValue()
in.BillingMethod = &billingMethod
}
if in.RenewableDurationConfig != nil {
in.RenewableDurationConfig, err = packageduration.NormalizeRenewableDurationConfig(in.RenewableDurationConfig)
if err != nil {
return err
}
}
packageCode := gconv.String(in.PackageCode)
normalizeFlowPackageRenewableCodes(in, packageCode)
if packageCode != "" {
uniqueMod := s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).
Where(dao.TSimFlowPackageInfo.Columns().PackageCode, packageCode)
if in.Id > 0 {
uniqueMod = uniqueMod.WhereNot(dao.TSimFlowPackageInfo.Columns().Id, in.Id)
}
count, countErr := uniqueMod.Count()
if countErr != nil {
return countErr
}
if count > 0 {
return gerror.New("套餐编码已存在")
}
}
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
now := gtime.Now()
userId := contexts.GetUserId(ctx)
if in.Id > 0 {
var oldPackage entity.TSimFlowPackageInfo
if err = s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).WherePri(in.Id).Scan(&oldPackage); err != nil {
return gerror.Wrap(err, "获取套餐信息失败,请稍后重试")
}
if oldPackage.Id == 0 {
return gerror.New("套餐不存在")
}
in.UpdatedBy = &userId
in.UpdatedAt = now
if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()).
Fields(model.TSimFlowPackageInfoUpdateFields{}).
WherePri(in.Id).
Where(dao.TSimFlowPackageInfo.Columns().TenantId, contexts.GetTenantId(ctx)).
Data(in).Update(); err != nil {
return gerror.Wrap(err, "修改SIM流量套餐管理失败,请稍后重试")
}
newPackageCode := oldPackage.PackageCode
if in.PackageCode != nil {
newPackageCode = *in.PackageCode
}
newPackageName := oldPackage.PackageName
if in.PackageName != nil {
newPackageName = *in.PackageName
}
if newPackageCode != oldPackage.PackageCode || newPackageName != oldPackage.PackageName {
updateCustomer := do.TPackageCustomer{
PackageCode: newPackageCode,
PackageName: newPackageName,
UpdatedBy: userId,
UpdatedAt: now,
}
if _, err = tx.Ctx(ctx).Model(dao.TPackageCustomer.Table()).
Where(dao.TPackageCustomer.Columns().TenantId, contexts.GetTenantId(ctx)).
Where(dao.TPackageCustomer.Columns().PackageCode, oldPackage.PackageCode).
Data(updateCustomer).Update(); err != nil {
return gerror.Wrap(err, "同步套餐客户关联失败,请稍后重试")
}
}
return nil
}
// 新增套餐
tenantId := contexts.GetTenantId(ctx)
in.TenantId = &tenantId
createdDept := contexts.GetDeptId(ctx)
in.CreatedDept = &createdDept
in.CreatedBy = &userId
in.CreatedAt = now
if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()).
Fields(model.TSimFlowPackageInfoInsertFields{}).
Data(in).Insert(); err != nil {
return gerror.Wrap(err, "新增SIM流量套餐管理失败,请稍后重试")
}
_, dept, err := service.AgentDept().IsTopDept(ctx)
if err != nil {
return err
}
packageName := gconv.String(in.PackageName)
customer := s.buildPackageCustomer(ctx, dept, packageCode, packageName, now)
if _, err = tx.Ctx(ctx).Model(dao.TPackageCustomer.Table()).Data(customer).Insert(); err != nil {
return gerror.Wrap(err, "新增套餐客户关联失败,请稍后重试")
}
return nil
})
}
func validateFlowMb(in *model.TSimFlowPackageInfoEditParam) error {
if in == nil {
return gerror.New("package information cannot be empty")
}
if in.Id <= 0 && in.FlowMb == nil {
return gerror.New("套餐流量(MB)不能为空")
}
if in.FlowMb != nil && (*in.FlowMb <= 0 || math.IsNaN(*in.FlowMb) || math.IsInf(*in.FlowMb, 0)) {
return gerror.New("套餐流量(MB)必须大于0")
}
return nil
}
func normalizeFlowPackageRenewableCodes(in *model.TSimFlowPackageInfoEditParam, packageCode string) {
if in == nil || in.RenewablePackageCodes == nil {
return
}
codes := make([]string, 0)
_ = in.RenewablePackageCodes.Scan(&codes)
in.RenewablePackageCodes = gjson.New(uniquePackageCodes(codes))
}
func uniquePackageCodes(codes []string) []string {
result := make([]string, 0, len(codes))
seen := make(map[string]struct{}, len(codes))
for _, code := range codes {
code = strings.TrimSpace(code)
if code == "" {
continue
}
if _, ok := seen[code]; ok {
continue
}
seen[code] = struct{}{}
result = append(result, code)
}
return result
}
func (s *sIotTSimFlowPackageInfo) Delete(ctx context.Context, in *model.TSimFlowPackageInfoDeleteParam) (err error) {
var packageInfo entity.TSimFlowPackageInfo
if err = s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).WherePri(in.Id).Scan(&packageInfo); err != nil {
return gerror.Wrap(err, "获取套餐信息失败,请稍后重试")
}
if packageInfo.Id == 0 {
return gerror.New("套餐不存在")
}
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()).
WherePri(in.Id).
Where(dao.TSimFlowPackageInfo.Columns().TenantId, contexts.GetTenantId(ctx)).
Unscoped().Delete(); err != nil {
return gerror.Wrap(err, "删除SIM流量套餐管理失败,请稍后重试")
}
if _, err = tx.Ctx(ctx).Model(dao.TPackageCustomer.Table()).
Where(dao.TPackageCustomer.Columns().TenantId, contexts.GetTenantId(ctx)).
Where(dao.TPackageCustomer.Columns().PackageCode, packageInfo.PackageCode).
Delete(); err != nil {
return gerror.Wrap(err, "清理套餐客户关联失败,请稍后重试")
}
return nil
})
}
func (s *sIotTSimFlowPackageInfo) View(ctx context.Context, in *model.TSimFlowPackageInfoViewParam) (res *model.TSimFlowPackageInfoViewModel, err error) {
mainTable := dao.TSimFlowPackageInfo.Table()
catTable := dao.TSimPackageCategory.Table()
mod, err := s.packageListModel(ctx)
if err != nil {
return nil, err
}
mod = mod.LeftJoin(catTable, mainTable+"."+dao.TSimFlowPackageInfo.Columns().CategoryCode+" = "+catTable+"."+dao.TSimPackageCategory.Columns().CategoryCode)
mod = mod.Fields(
mainTable+".*",
catTable+"."+dao.TSimPackageCategory.Columns().CategoryName+" as categoryName",
)
if err = mod.Where(mainTable+"."+dao.TSimFlowPackageInfo.Columns().Id, in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil {
return nil, gerror.Wrap(err, "获取SIM流量套餐管理信息失败,请稍后重试")
}
if res == nil || res.Id == 0 {
return nil, gerror.New("套餐不存在或无权限")
}
if res.RenewableDurationConfig != nil {
if normalized, normalizeErr := packageduration.NormalizeRenewableDurationConfig(res.RenewableDurationConfig); normalizeErr == nil {
res.RenewableDurationConfig = normalized
}
}
if err = s.fillPackageRelationNames(ctx, res); err != nil {
return nil, err
}
return
}
func (s *sIotTSimFlowPackageInfo) fillPackageRelationNames(ctx context.Context, res *model.TSimFlowPackageInfoViewModel) error {
if res == nil {
return nil
}
renewableCodes := packageCodesFromJSON(res.RenewablePackageCodes)
changeableCodes := packageCodesFromJSON(res.ChangeablePackageCodes)
topupCodes := packageCodesFromJSON(res.TopupPackageCodes)
allCodes := uniquePackageCodes(append(append(renewableCodes, changeableCodes...), topupCodes...))
if len(allCodes) == 0 {
return nil
}
nameMap, err := s.packageNamesByCode(ctx, res.TenantId, allCodes)
if err != nil {
return err
}
res.RenewablePackageNames = gjson.New(packageNamesForCodes(renewableCodes, nameMap))
res.ChangeablePackageNames = gjson.New(packageNamesForCodes(changeableCodes, nameMap))
res.TopupPackageNames = gjson.New(packageNamesForCodes(topupCodes, nameMap))
return nil
}
func packageCodesFromJSON(value *gjson.Json) []string {
if value == nil {
return nil
}
var codes []string
_ = value.Scan(&codes)
return uniquePackageCodes(codes)
}
func (s *sIotTSimFlowPackageInfo) packageNamesByCode(ctx context.Context, tenantId string, codes []string) (map[string]string, error) {
result := make(map[string]string, len(codes))
if len(codes) == 0 {
return result, nil
}
columns := dao.TSimFlowPackageInfo.Columns()
var packages []struct {
PackageCode string `orm:"package_code"`
PackageName string `orm:"package_name"`
}
mod := s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).
Fields(columns.PackageCode, columns.PackageName).
WhereIn(columns.PackageCode, codes)
if tenantId != "" {
mod = mod.Where(columns.TenantId, tenantId)
}
if err := mod.Scan(&packages); err != nil {
return nil, gerror.Wrap(err, "查询套餐名称失败")
}
for _, pkg := range packages {
code := strings.TrimSpace(pkg.PackageCode)
name := strings.TrimSpace(pkg.PackageName)
if code == "" || name == "" {
continue
}
result[code] = name
}
return result, nil
}
func packageNamesForCodes(codes []string, nameMap map[string]string) []string {
names := make([]string, 0, len(codes))
for _, code := range codes {
if name := strings.TrimSpace(nameMap[code]); name != "" {
names = append(names, name)
}
}
return names
}
// GetPoolPackagesByCardPackages 根据卡套餐编码列表获取对应的池套餐编码列表
func (s *sIotTSimFlowPackageInfo) GetPoolPackagesByCardPackages(ctx context.Context, cardPackageCodes []string) (poolPackageMap102 map[string]int64, poolPackageMap104 map[string]int64, err error) {
poolPackageMap102 = make(map[string]int64)
poolPackageMap104 = make(map[string]int64)
if len(cardPackageCodes) == 0 {
return
}
g.Log().Info(ctx, "GetPoolPackagesByCardPackages cardPackageCodes:", cardPackageCodes) //这些不存在 104
mod := s.Model(ctx)
mod = mod.Where(dao.TSimFlowPackageInfo.Columns().PackageCode+" IN (?)", cardPackageCodes)
// 查询 102 池套餐
mod102 := mod.Where(dao.TSimFlowPackageInfo.Columns().PackageType, 102)
var packages102 []*model.TSimFlowPackageInfoListModel
var poolPackageCodes []int64
if err = mod102.Scan(&packages102); err != nil {
return nil, nil, gerror.Wrap(err, "获取102池套餐列表失败,请稍后重试!")
}
g.Log().Info(ctx, "获取102池套餐列表:%v", packages102)
for _, pkg := range packages102 {
poolPackageMap102[pkg.PackageCode] = pkg.PoolPackageCode
poolPackageCodes = append(poolPackageCodes, pkg.PoolPackageCode)
}
// 查询 104 池套餐
mod104 := s.Model(ctx).Where(dao.TSimFlowPackageInfo.Columns().PackageType, 104).Where(dao.TSimFlowPackageInfo.Columns().PoolPackageCode+" IN (?)", poolPackageCodes)
var packages104 []*model.TSimFlowPackageInfoListModel
if err = mod104.Scan(&packages104); err != nil {
return nil, nil, gerror.Wrap(err, "获取104池套餐列表失败,请稍后重试!")
}
g.Log().Info(ctx, "GetPoolPackagesByCardPackages packages104:", packages104)
for _, pkg := range packages104 {
poolPackageMap104[pkg.PackageCode] = pkg.PoolPackageCode
}
g.Log().Info(ctx, "GetPoolPackagesByCardPackages poolPackageMap102:", poolPackageMap102)
g.Log().Info(ctx, "GetPoolPackagesByCardPackages poolPackageMap104:", poolPackageMap104)
return poolPackageMap102, poolPackageMap104, nil
}
func (s *sIotTSimFlowPackageInfo) SyncDeptPackages(ctx context.Context) (err error) {
_, dept, err := service.AgentDept().IsTopDept(ctx)
if err != nil {
return
}
return packagecustomer.PublishSync(ctx, model.PackageCustomerSyncMessage{
TenantId: contexts.GetTenantId(ctx),
DeptId: dept.DeptId,
UserId: contexts.GetUserId(ctx),
Trigger: "manual_sync",
})
}
func (s *sIotTSimFlowPackageInfo) SyncDeptPackagesByDept(ctx context.Context, tenantId string, deptId int64, userId int64) error {
return packagecustomer.SyncDeptPackagesByDept(ctx, tenantId, deptId, userId)
}