Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Failing after 8m39s
- 迁移 000259~000265:套餐记录沉默期字段与扫描索引、套餐默认沉默期、延期政策/流水/订单/批次/明细 5 张表、默认政策与系统配置(总开关默认关闭)、企微审批白名单、卡与设备出库时间及出库记录 - 沉默期设置(订单发放、自动购包、钱包续费)、后台购买时调整(超默认值按政策免审或企微审批)、统一判定与激活闸门、排队与孤儿扫描跳过过期套餐、过期套餐禁止退款、每 10 分钟扫描 - 总开关专用接口与打开前 4 项检查;延期政策;延期资格与计费;H5 自助与后台二维码在线支付(商户池路由)、支付回调与查单恢复、线下登记、特殊/批量延期、异常重试与原路退款;沉默期审批场景与终态处理 - 换货沉默期流水与出库时间;卡/设备列表、详情、导出与出库记录接口;延期订单与即将过期套餐列表及导出;财务流水纳入延期支付 - 沉默期与出库时间回填工具 cmd/silence-backfill;前端接口变更说明 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.1 KiB
Go
80 lines
3.1 KiB
Go
package packagesilence
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
packagedomain "github.com/break/junhong_cmp_fiber/internal/domain/package"
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// PolicyMatch 是某套餐当前匹配到的延期政策及其快照;Policy 为 nil 表示未匹配到政策。
|
||
type PolicyMatch struct {
|
||
Policy *model.PackageSilenceExtensionPolicy
|
||
Snapshot *packagedomain.SilencePolicySnapshot
|
||
}
|
||
|
||
// FreeExtensionLimit 返回免费延期次数上限;未匹配到政策时按 1 次处理(技术方案 §3.6)。
|
||
func (m PolicyMatch) FreeExtensionLimit() int {
|
||
if m.Snapshot == nil {
|
||
return 1
|
||
}
|
||
return m.Snapshot.FreeExtensionLimit
|
||
}
|
||
|
||
// ExemptTypes 返回免审批场景;未匹配到政策时全部需要审批。
|
||
func (m PolicyMatch) ExemptTypes() []string {
|
||
if m.Snapshot == nil {
|
||
return nil
|
||
}
|
||
return m.Snapshot.ApprovalExemptTypes
|
||
}
|
||
|
||
// matchPolicy 按"指定套餐 > 套餐系列 > 全部套餐"匹配当前生效政策(启用且在生效期内)。
|
||
func matchPolicy(ctx context.Context, db *gorm.DB, packageID, seriesID uint, now time.Time) (PolicyMatch, error) {
|
||
policies, err := postgres.NewPackageSilencePolicyStore(db).ListEnabled(ctx)
|
||
if err != nil {
|
||
return PolicyMatch{}, errors.Wrap(errors.CodeDatabaseError, err, "查询延期政策失败")
|
||
}
|
||
candidates := make([]packagedomain.SilencePolicyCandidate, len(policies))
|
||
for index := range policies {
|
||
candidates[index] = policyCandidate(&policies[index])
|
||
}
|
||
best := packagedomain.MatchSilencePolicy(candidates, packageID, seriesID, now)
|
||
if best < 0 {
|
||
return PolicyMatch{}, nil
|
||
}
|
||
policy := policies[best]
|
||
snapshot := policySnapshot(&policy)
|
||
return PolicyMatch{Policy: &policy, Snapshot: &snapshot}, nil
|
||
}
|
||
|
||
// matchPolicyForPackage 读取套餐当前系列后匹配政策。
|
||
func matchPolicyForPackage(ctx context.Context, db *gorm.DB, packageID uint, now time.Time) (PolicyMatch, *model.Package, error) {
|
||
var pkg model.Package
|
||
if err := db.WithContext(ctx).Unscoped().Where("id = ?", packageID).First(&pkg).Error; err != nil {
|
||
return PolicyMatch{}, nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐失败")
|
||
}
|
||
match, err := matchPolicy(ctx, db, pkg.ID, pkg.SeriesID, now)
|
||
return match, &pkg, err
|
||
}
|
||
|
||
func policyCandidate(policy *model.PackageSilenceExtensionPolicy) packagedomain.SilencePolicyCandidate {
|
||
return packagedomain.SilencePolicyCandidate{
|
||
ID: policy.ID, ScopeType: policy.ScopeType, ScopeIDs: []uint(policy.ScopeIDs),
|
||
Enabled: policy.Status == 1, EffectiveFrom: policy.EffectiveFrom, EffectiveTo: policy.EffectiveTo,
|
||
}
|
||
}
|
||
|
||
func policySnapshot(policy *model.PackageSilenceExtensionPolicy) packagedomain.SilencePolicySnapshot {
|
||
return packagedomain.SilencePolicySnapshot{
|
||
PolicyID: policy.ID, Name: policy.Name, UnitPrice: policy.UnitPrice,
|
||
FreeExtensionLimit: policy.FreeExtensionLimit, PaidMaxMonths: policy.PaidMaxMonths,
|
||
SingleMaxMonths: policy.SingleMaxMonths, ApprovalExemptTypes: append([]string(nil), policy.ApprovalExemptTypes...),
|
||
}
|
||
}
|