固化七月迭代审计治理进展以隔离线上热修
Constraint: 切换 main 前必须保存当前七月分支全部项目进展,套餐生效提案仅属于 Iteration/7-11。 Rejected: 将七月套餐修复直接移植到 main | 两个分支的可靠投递架构不同。 Confidence: medium Scope-risk: broad Directive: 不得将本提交整体 cherry-pick 到 main;main 套餐热修必须基于其纯 Asynq 代码独立实施。 Tested: git diff --check;openspec validate fix-package-activation-starvation --strict。 Not-tested: 按用户要求未运行自动化测试;go build ./... 因当前审计改造中的 Enterprise 模型字面量和 role.recordFailure 参数类型错误未通过。
This commit is contained in:
@@ -77,3 +77,13 @@ func recordDisabledCarrierCallback(
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// completeResolvedCarrierCallback 在回调已精确解析卡后补充真实本地资源ID。
|
||||
func completeResolvedCarrierCallback(ctx context.Context, repository *integrationlog.Repository, integrationID, result string, stateChanged bool, reason string, cardID uint) error {
|
||||
resourceID := strconv.FormatUint(uint64(cardID), 10)
|
||||
_, err := repository.Complete(ctx, integrationID, integrationlog.Completion{
|
||||
Result: result, HTTPStatus: fiber.StatusOK, StateChanged: stateChanged, ResourceID: &resourceID,
|
||||
ResponseSummary: map[string]any{"reason": reason},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ func (h *CMCCRealnameHandler) process(ctx context.Context, body []byte, contentT
|
||||
h.logger.Warn("移动实名事实已应用但提前完成观测序列失败", zap.Uint("card_id", card.ID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
return h.complete(ctx, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用")
|
||||
return completeResolvedCarrierCallback(ctx, h.integration, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用", card.ID)
|
||||
}
|
||||
|
||||
func (h *CMCCRealnameHandler) recordConflict(ctx context.Context, body []byte, contentType, baseKey string, translated carriercallback.CMCCRealnameTranslation, requestID *string) error {
|
||||
|
||||
@@ -141,7 +141,7 @@ func (h *CTCCRealnameHandler) process(ctx context.Context, body []byte, contentT
|
||||
h.logger.Warn("电信实名事实已应用但提前完成观测序列失败", zap.Uint("card_id", card.ID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
return h.complete(ctx, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用")
|
||||
return completeResolvedCarrierCallback(ctx, h.integration, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用", card.ID)
|
||||
}
|
||||
|
||||
func (h *CTCCRealnameHandler) failPending(ctx context.Context, integrationID string, original error) error {
|
||||
|
||||
@@ -114,7 +114,7 @@ func (h *CUCCRealnameHandler) process(ctx context.Context, body []byte, contentT
|
||||
h.logger.Warn("联通实名事实已应用但提前完成观测序列失败", zap.Uint("card_id", card.ID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
return h.complete(ctx, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用")
|
||||
return completeResolvedCarrierCallback(ctx, h.integration, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用", card.ID)
|
||||
}
|
||||
|
||||
func (h *CUCCRealnameHandler) recordConflict(ctx context.Context, body []byte, contentType, baseKey string, translated carriercallback.CUCCRealnameTranslation, requestID *string) error {
|
||||
|
||||
@@ -93,7 +93,7 @@ func (h *CUCCRealnameRemovalHandler) process(ctx context.Context, body []byte, c
|
||||
if len(cards) > 1 {
|
||||
return h.complete(ctx, log.IntegrationID, constants.IntegrationResultConflict, "精确列匹配多张卡")
|
||||
}
|
||||
return h.complete(ctx, log.IntegrationID, constants.IntegrationResultIgnored, "解除实名仅留痕,不修改本地实名事实")
|
||||
return completeResolvedCarrierCallback(ctx, h.integration, log.IntegrationID, constants.IntegrationResultIgnored, false, "解除实名仅留痕,不修改本地实名事实", cards[0].ID)
|
||||
}
|
||||
|
||||
func (h *CUCCRealnameRemovalHandler) recordConflict(ctx context.Context, body []byte, contentType, baseKey string, translated carriercallback.CUCCRealnameRemovalTranslation, requestID *string) error {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
rechargeOrderSvc "github.com/break/junhong_cmp_fiber/internal/service/recharge_order"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/alipay"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/auditcontext"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/fuiou"
|
||||
@@ -112,6 +113,7 @@ func (h *PaymentHandler) WechatPayCallback(c *fiber.Ctx) error {
|
||||
)
|
||||
return errors.New(errors.CodeWechatCallbackInvalid, "微信支付服务未配置")
|
||||
}
|
||||
ctx = paymentCallbackContext(ctx, constants.IntegrationProviderWechatPay)
|
||||
|
||||
switch cfg.ProviderType {
|
||||
case model.ProviderTypeWechatV2:
|
||||
@@ -218,7 +220,9 @@ func (h *PaymentHandler) confirmAgentRechargePayment(ctx context.Context, callba
|
||||
if h.agentPaymentConfirm == nil || h.integration == nil {
|
||||
return errors.New(errors.CodeInternalError, "代理充值支付回调能力未配置")
|
||||
}
|
||||
resourceID, correlationID := callback.PaymentNo, callback.PaymentNo
|
||||
resourceKey, correlationID := callback.PaymentNo, callback.PaymentNo
|
||||
ctx = auditcontext.With(ctx, auditcontext.Context{CorrelationID: correlationID})
|
||||
linkage := auditcontext.From(ctx)
|
||||
idempotencyKey := callback.TransactionID
|
||||
if idempotencyKey == "" {
|
||||
idempotencyKey = callback.PaymentNo
|
||||
@@ -226,7 +230,7 @@ func (h *PaymentHandler) confirmAgentRechargePayment(ctx context.Context, callba
|
||||
log, _, err := h.integration.RecordInbound(ctx, integrationlog.InboundAttempt{
|
||||
IdempotencyKey: idempotencyKey, Provider: callback.Provider,
|
||||
Operation: constants.IntegrationOperationPaymentCallback, ExternalID: callback.TransactionID,
|
||||
ResourceType: constants.IntegrationResourceTypeAgentRechargePayment, ResourceID: &resourceID,
|
||||
ResourceType: constants.IntegrationResourceTypeAgentRechargePayment, ResourceKey: &resourceKey,
|
||||
RawPayload: callback.RawPayload, ContentType: callback.ContentType,
|
||||
RequestID: pkgmiddleware.GetRequestIDFromContext(ctx), CorrelationID: &correlationID,
|
||||
})
|
||||
@@ -236,20 +240,27 @@ func (h *PaymentHandler) confirmAgentRechargePayment(ctx context.Context, callba
|
||||
result, confirmErr := h.agentPaymentConfirm.Execute(ctx, agentrechargeApp.ConfirmOnlinePaymentCommand{
|
||||
PaymentNo: callback.PaymentNo, PaymentMethod: callback.PaymentMethod, ConfigID: callback.ConfigID,
|
||||
MerchantIdentity: callback.MerchantIdentity, ThirdPartyTradeNo: callback.TransactionID,
|
||||
Amount: callback.Amount, PaidAt: callback.PaidAt, CorrelationID: correlationID,
|
||||
Amount: callback.Amount, PaidAt: callback.PaidAt, RequestID: linkage.RequestID,
|
||||
CorrelationID: correlationID, ParentEventID: linkage.ParentEventID,
|
||||
})
|
||||
if confirmErr != nil {
|
||||
h.logger.Error("代理充值支付确认失败",
|
||||
zap.String("integration_id", log.IntegrationID),
|
||||
zap.String("payment_no", callback.PaymentNo),
|
||||
zap.Error(confirmErr),
|
||||
)
|
||||
h.completePaymentCallbackLog(ctx, log, integrationlog.Completion{
|
||||
Result: constants.IntegrationResultFailed, ProviderMessage: confirmErr.Error(),
|
||||
Result: constants.IntegrationResultFailed, SafeProviderMessage: "代理充值支付确认失败",
|
||||
ResponseSummary: map[string]any{"confirmed": false},
|
||||
})
|
||||
return confirmErr
|
||||
}
|
||||
if log.Result == constants.IntegrationResultPending {
|
||||
resolvedResourceID := strconv.FormatUint(uint64(result.PaymentID), 10)
|
||||
_, err = h.integration.Complete(ctx, log.IntegrationID, integrationlog.Completion{
|
||||
Result: constants.IntegrationResultSuccess, ProviderCode: "SUCCESS",
|
||||
ResponseSummary: map[string]any{"confirmed": true, "already_confirmed": result.AlreadyConfirmed},
|
||||
StateChanged: !result.AlreadyConfirmed,
|
||||
StateChanged: !result.AlreadyConfirmed, ResourceID: &resolvedResourceID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -305,6 +316,7 @@ func (h *PaymentHandler) AlipayCallback(c *fiber.Ctx) error {
|
||||
)
|
||||
return errors.New(errors.CodeWechatCallbackInvalid, "支付配置不可用")
|
||||
}
|
||||
ctx = paymentCallbackContext(ctx, constants.IntegrationProviderAlipay)
|
||||
|
||||
// 使用支付宝公钥验签(DecodeNotification 内部完成签名校验)
|
||||
notification, err := alipay.DecodeNotification(ctx, cfg, values)
|
||||
@@ -513,6 +525,7 @@ func (h *PaymentHandler) FuiouPayCallback(c *fiber.Ctx) error {
|
||||
)
|
||||
return c.Send(fuiou.BuildNotifyFailResponse("payment config unavailable"))
|
||||
}
|
||||
ctx = paymentCallbackContext(ctx, model.ProviderTypeFuiou)
|
||||
if cfg.ProviderType != model.ProviderTypeFuiou ||
|
||||
strings.TrimSpace(preNotify.InsCd) != strings.TrimSpace(cfg.FyInsCd) ||
|
||||
strings.TrimSpace(preNotify.MchntCd) != strings.TrimSpace(cfg.FyMchntCd) {
|
||||
@@ -604,6 +617,13 @@ func (h *PaymentHandler) FuiouPayCallback(c *fiber.Ctx) error {
|
||||
return c.Send(fuiou.BuildNotifySuccessResponse())
|
||||
}
|
||||
|
||||
func paymentCallbackContext(ctx context.Context, provider string) context.Context {
|
||||
return auditcontext.With(ctx, auditcontext.Context{
|
||||
ActorKind: constants.AuditActorExternalSystem, ActorID: provider,
|
||||
ActorName: provider, Source: constants.AuditSourceCallback,
|
||||
})
|
||||
}
|
||||
|
||||
// fuiouCallbackPayload 提取富友回调载荷,兼容 body、form req 和 query req 三种来源。
|
||||
func fuiouCallbackPayload(c *fiber.Ctx) ([]byte, string) {
|
||||
if req := strings.TrimSpace(c.FormValue("req")); req != "" {
|
||||
|
||||
Reference in New Issue
Block a user