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>
146 lines
6.7 KiB
Go
146 lines
6.7 KiB
Go
package packagesilence
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/break/junhong_cmp_fiber/internal/application/refundchannel"
|
|
"github.com/break/junhong_cmp_fiber/internal/infrastructure/audit"
|
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
|
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
|
)
|
|
|
|
func refundTarget(order *model.PackageSilenceExtensionOrder, payment *model.Payment, config *model.WechatConfig, providerType, refundNo string, amount int64) refundchannel.Target {
|
|
target := refundchannel.Target{
|
|
RefundNo: refundNo, OrderID: order.ID, OrderNo: order.OrderNo, ProviderType: providerType, Config: config,
|
|
PaymentNo: payment.PaymentNo, ChannelTradeNo: payment.ThirdPartyTradeNo, PaidAt: payment.PaidAt,
|
|
PaidAmount: payment.Amount, RefundAmount: amount, FrozenActualReceivedAmount: amount, ChannelRefundRequestNo: refundNo,
|
|
}
|
|
if providerType == model.ProviderTypeFuiou {
|
|
target.ChannelOrderType = "WECHAT"
|
|
}
|
|
return target
|
|
}
|
|
|
|
func orderAuditInput(usage *model.PackageUsage, order *model.PackageSilenceExtensionOrder, before, summary string) audit.SilenceAuditInput {
|
|
return audit.SilenceAuditInput{
|
|
ActionCode: constants.AuditActionUsageSilenceExtensionOrderState, Summary: summary, Usage: usage,
|
|
BeforeData: map[string]any{"order_status": before},
|
|
AfterData: map[string]any{"order_status": order.Status},
|
|
Metadata: map[string]any{
|
|
"order_no": order.OrderNo, "batch_id": order.BatchID, "source": order.Source, "payment_method": order.PaymentMethod,
|
|
"months": order.Months, "extension_days": order.ExtensionDays, "amount": order.Amount,
|
|
"paid_payment_id": order.PaidPaymentID, "exception_code": order.ExceptionCode,
|
|
"offline_trade_no": order.OfflineTradeNo, "approval_instance_id": order.ApprovalInstanceID,
|
|
"before_deadline_at": order.BeforeDeadlineAt, "expected_deadline_at": order.ExpectedDeadlineAt,
|
|
},
|
|
}
|
|
}
|
|
|
|
func auditInputForException(usage *model.PackageUsage, extension *model.PackageSilenceExtension, code, text string) audit.SilenceAuditInput {
|
|
return audit.SilenceAuditInput{
|
|
ActionCode: constants.AuditActionUsageSilenceExtensionException, Summary: "沉默期延期执行异常:" + text, Usage: usage,
|
|
AfterData: map[string]any{"extension_status": extension.Status},
|
|
Metadata: map[string]any{
|
|
"batch_id": extension.BatchID, "extension_id": extension.ID, "extension_type": extension.ExtensionType,
|
|
"months": extension.Months, "extension_days": extension.ExtensionDays, "amount": extension.Amount,
|
|
"extension_order_id": extension.ExtensionOrderID, "failure_code": code,
|
|
},
|
|
}
|
|
}
|
|
|
|
// orderResponse 构造延期订单响应:支付方式、收款商户、交易流水号取已支付或已退款支付单快照;待支付时返回支付内容。
|
|
func (s *ExtensionService) orderResponse(ctx context.Context, order *model.PackageSilenceExtensionOrder, includeQR bool) (*dto.SilenceExtensionOrderResponse, error) {
|
|
resp := OrderDTO(order)
|
|
var payments []model.Payment
|
|
if order.PaymentMethod != model.PaymentByOffline {
|
|
if err := s.db.WithContext(ctx).Where("order_type = ? AND order_id = ?", constants.PaymentOrderTypeSilenceExtension, order.ID).
|
|
Order("id DESC").Find(&payments).Error; err != nil {
|
|
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询延期支付单失败")
|
|
}
|
|
}
|
|
for index := range payments {
|
|
payment := &payments[index]
|
|
if order.PaidPaymentID != nil && payment.ID == *order.PaidPaymentID {
|
|
resp.PaymentMerchantName = payment.MerchantNameSnapshot
|
|
resp.ThirdPartyTradeNo = payment.ThirdPartyTradeNo
|
|
resp.PaymentNo = payment.PaymentNo
|
|
}
|
|
if includeQR && order.Status == constants.SilenceOrderStatusPendingPayment && payment.Status == model.PaymentRecordStatusPending && resp.QRContent == "" {
|
|
resp.QRContent = payment.QRContent
|
|
resp.PaymentNo = payment.PaymentNo
|
|
}
|
|
}
|
|
var batch model.PackageSilenceExtensionBatch
|
|
if err := s.db.WithContext(ctx).Select("id", "batch_no").Where("id = ?", order.BatchID).First(&batch).Error; err == nil {
|
|
resp.BatchNo = batch.BatchNo
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// OrderDTO 构造延期订单基础响应(不含支付单快照)。
|
|
func OrderDTO(order *model.PackageSilenceExtensionOrder) *dto.SilenceExtensionOrderResponse {
|
|
resp := &dto.SilenceExtensionOrderResponse{
|
|
ID: order.ID, OrderNo: order.OrderNo, PackageUsageID: order.PackageUsageID, PackageID: order.PackageID,
|
|
PackageName: order.PackageNameSnapshot, AssetType: order.AssetType, AssetID: order.AssetID,
|
|
AssetIdentifier: order.AssetIdentifierSnapshot, ShopID: order.ShopID, CustomerID: order.CustomerID,
|
|
Source: order.Source, SourceName: orderSourceName(order.Source), InputDays: order.InputDays, Months: order.Months,
|
|
ExtensionDays: order.ExtensionDays, UnitPrice: order.UnitPrice, Amount: order.Amount, PolicyName: order.PolicyNameSnapshot,
|
|
BeforeDeadlineAt: order.BeforeDeadlineAt, ExpectedDeadlineAt: order.ExpectedDeadlineAt, Status: order.Status,
|
|
StatusName: OrderStatusName(order.Status), PaymentMethod: order.PaymentMethod,
|
|
PaymentVoucherKeys: []string(order.PaymentVoucherKeys), EvidenceRefs: []string(order.EvidenceRefs),
|
|
ApprovalRequired: order.ApprovalRequired, ApprovalInstanceID: order.ApprovalInstanceID, PaidAmount: order.PaidAmount,
|
|
PaidAt: order.PaidAt, ExpireAt: order.ExpireAt, CompletedAt: order.CompletedAt, ExceptionCode: order.ExceptionCode,
|
|
ExceptionSummary: order.ExceptionSummary, RefundAmount: order.RefundAmount, RefundedAt: order.RefundedAt,
|
|
CreatedBy: order.CreatedBy, CreatedAt: order.CreatedAt,
|
|
}
|
|
if order.OfflinePaymentMethodName != nil {
|
|
resp.OfflinePaymentMethodName = *order.OfflinePaymentMethodName
|
|
}
|
|
if order.OfflineTradeNo != nil {
|
|
resp.OfflineTradeNo = *order.OfflineTradeNo
|
|
}
|
|
if order.RefundNo != nil {
|
|
resp.RefundNo = *order.RefundNo
|
|
}
|
|
return resp
|
|
}
|
|
|
|
// OrderStatusName 返回延期订单状态名称。
|
|
func OrderStatusName(status string) string {
|
|
switch status {
|
|
case constants.SilenceOrderStatusPendingPayment:
|
|
return "待支付"
|
|
case constants.SilenceOrderStatusPendingApproval:
|
|
return "待审批"
|
|
case constants.SilenceOrderStatusRejected:
|
|
return "已驳回"
|
|
case constants.SilenceOrderStatusPaid:
|
|
return "已支付"
|
|
case constants.SilenceOrderStatusCompleted:
|
|
return "已延期"
|
|
case constants.SilenceOrderStatusClosed:
|
|
return "已关闭"
|
|
case constants.SilenceOrderStatusException:
|
|
return "执行异常"
|
|
case constants.SilenceOrderStatusRefunded:
|
|
return "已退款"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func orderSourceName(source string) string {
|
|
switch source {
|
|
case constants.SilenceOrderSourceClient:
|
|
return "客户 H5 下单"
|
|
case constants.SilenceOrderSourceAdmin:
|
|
return "后台二维码"
|
|
case constants.SilenceOrderSourceOffline:
|
|
return "线下登记"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|