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>
79 lines
3.2 KiB
Go
79 lines
3.2 KiB
Go
package packagesilence
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// ExchangeHook 是换货流程中的沉默期与出库时间接缝(技术方案 §9、§17.3.2)。
|
||
type ExchangeHook struct {
|
||
setter *Setter
|
||
outbound *OutboundRecorder
|
||
}
|
||
|
||
// NewExchangeHook 创建换货接缝。
|
||
func NewExchangeHook(setter *Setter, outbound *OutboundRecorder) *ExchangeHook {
|
||
return &ExchangeHook{setter: setter, outbound: outbound}
|
||
}
|
||
|
||
// OnUsagesMigratedInTx 换货迁移套餐记录后写沉默期流水(exchange):沉默期字段随记录迁移,不重新起算,截止时间不变;
|
||
// 过期记录仍为过期,可在新资产上延期。
|
||
func (h *ExchangeHook) OnUsagesMigratedInTx(ctx context.Context, tx *gorm.DB, order *model.ExchangeOrder, usageIDs []uint) error {
|
||
if h == nil || len(usageIDs) == 0 {
|
||
return nil
|
||
}
|
||
var usages []model.PackageUsage
|
||
if err := tx.WithContext(ctx).Where("id IN ? AND silence_status IS NOT NULL", usageIDs).Find(&usages).Error; err != nil {
|
||
return errors.Wrap(errors.CodeDatabaseError, err, "查询迁移的沉默期套餐记录失败")
|
||
}
|
||
var writer = h.setter.audit
|
||
for index := range usages {
|
||
usage := &usages[index]
|
||
exchangeID := order.ID
|
||
if err := writeRecord(ctx, tx, writer, recordInput{
|
||
Usage: usage, EventType: constants.SilenceRecordEventExchange, Trigger: constants.SilenceTriggerExchange,
|
||
BeforeStatus: copyStringPtr(usage.SilenceStatus), BeforeDeadline: copyTimePtr(usage.SilenceDeadlineAt),
|
||
ExchangeID: &exchangeID, ExchangeNo: order.ExchangeNo, Reason: "换货迁移套餐记录,沉默期随套餐迁移、不重新起算",
|
||
Extra: map[string]any{
|
||
"old_asset_type": order.OldAssetType, "old_asset_id": order.OldAssetID,
|
||
"new_asset_type": order.NewAssetType, "new_asset_id": order.NewAssetID,
|
||
},
|
||
AuditAction: constants.AuditActionUsageSilenceMigratedOnExchange, AuditSummary: "换货迁移套餐沉默期",
|
||
}); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// OnNewAssetInTx 换货完成时为新资产写出库时间(换货完成时间)与 exchange 出库记录;已有出库时间的不覆盖。
|
||
func (h *ExchangeHook) OnNewAssetInTx(ctx context.Context, tx *gorm.DB, assetType string, assetID uint, order *model.ExchangeOrder, completedAt time.Time) error {
|
||
if h == nil || h.outbound == nil {
|
||
return nil
|
||
}
|
||
return h.outbound.RecordForExchangeInTx(ctx, tx, normalizeOutboundAssetType(assetType), assetID, order.ID, order.ExchangeNo, completedAt)
|
||
}
|
||
|
||
// OnOldAssetRenewedInTx 旧资产换货回库、世代 +1 的同一事务内清空出库时间并结束旧世代出库记录。
|
||
func (h *ExchangeHook) OnOldAssetRenewedInTx(ctx context.Context, tx *gorm.DB, assetType string, assetID uint, oldGeneration int, at time.Time) error {
|
||
if h == nil || h.outbound == nil {
|
||
return nil
|
||
}
|
||
return h.outbound.EndGenerationInTx(ctx, tx, normalizeOutboundAssetType(assetType), assetID, oldGeneration, at)
|
||
}
|
||
|
||
func normalizeOutboundAssetType(assetType string) string {
|
||
switch assetType {
|
||
case "card", constants.OutboundAssetTypeIotCard:
|
||
return constants.OutboundAssetTypeIotCard
|
||
default:
|
||
return constants.OutboundAssetTypeDevice
|
||
}
|
||
}
|