补充一些通知
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m7s

This commit is contained in:
2026-07-28 15:50:12 +08:00
parent 9303af3d46
commit 1fee19feeb
12 changed files with 151 additions and 27 deletions

View File

@@ -18,7 +18,7 @@ import (
var shanghaiLocation = time.FixedZone("Asia/Shanghai", 8*60*60)
// ReminderPublisher 将临期节点事实转换为个人客户通知 Outbox。
// ReminderPublisher 将临期节点事实转换为店铺和个人客户通知 Outbox。
type ReminderPublisher struct {
db *gorm.DB
outbox *outbox.Repository
@@ -34,7 +34,7 @@ type recipientRow struct {
CustomerID uint
}
// Publish 批量解析资产关联个人客户,并在同一事务内幂等追加通知事件。
// Publish 批量解析资产关联个人客户,并在同一事务内幂等追加店铺和个人通知事件。
func (p *ReminderPublisher) Publish(ctx context.Context, candidates []dto.ExpiringAssetItem) error {
if p == nil || p.db == nil || p.outbox == nil {
return errors.New(errors.CodeInternalError, "套餐临期通知 Publisher 未配置")
@@ -49,6 +49,11 @@ func (p *ReminderPublisher) Publish(ctx context.Context, candidates []dto.Expiri
continue
}
key := recipientKey(candidate.AssetType, candidate.AssetID)
if candidate.ShopID != nil {
if err := p.appendShopNotification(ctx, tx, candidate, *candidate.ShopID); err != nil {
return err
}
}
for customerID := range recipients[key] {
if err := p.appendNotification(ctx, tx, candidate, customerID); err != nil {
return err
@@ -59,6 +64,35 @@ func (p *ReminderPublisher) Publish(ctx context.Context, candidates []dto.Expiri
})
}
// appendShopNotification 按资产所属店铺写入一条动态接收人通知事件。
func (p *ReminderPublisher) appendShopNotification(ctx context.Context, tx *gorm.DB, candidate dto.ExpiringAssetItem, shopID uint) error {
node := *candidate.DaysUntilFinalExpiry
expiryDate := candidate.EstimatedFinalExpiresAt.In(shanghaiLocation).Format("20060102")
assetCode := "c"
if candidate.AssetType == constants.AssetTypeDevice {
assetCode = "d"
}
eventID := fmt.Sprintf("pex:%s:%d:%s:%d:shop:%d", assetCode, candidate.AssetID, expiryDate, node, shopID)
assetID := strconv.FormatUint(uint64(candidate.AssetID), 10)
shopIDText := strconv.FormatUint(uint64(shopID), 10)
_, err := p.outbox.AppendIdempotent(ctx, tx, outbox.Envelope{
EventID: eventID, EventType: constants.OutboxEventTypeAdminDynamicNotification,
PayloadVersion: constants.NotificationPayloadVersionV1,
AggregateType: "package_expiry", AggregateID: strconv.FormatUint(uint64(candidate.PackageUsageID), 10),
ResourceType: candidate.AssetType, ResourceID: assetID, BusinessKey: eventID,
Payload: notificationapp.AdminDynamicPayload{
TargetKind: constants.NotificationTargetKindShop, TargetID: shopID,
NotificationType: constants.NotificationTypePackageExpiring, TemplateData: map[string]string{},
RefType: constants.NotificationRefTypeExpiringAsset, RefID: shopIDText,
ExpiresAt: candidate.EstimatedFinalExpiresAt,
},
})
if err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "写入店铺套餐临期通知事件失败")
}
return nil
}
func (p *ReminderPublisher) loadRecipients(ctx context.Context, candidates []dto.ExpiringAssetItem) (map[string]map[uint]struct{}, error) {
cardIDs := make([]uint, 0)
deviceIDs := make([]uint, 0)