fix: 富友订单支持退款,0 元退款不强制客户收款材料映射
- decideRefundMethods 将 fuiou 与 wechat、alipay 按线上支付处理,修复富友订单报"该订单的支付方式不支持退款" - 客户收款信息退款仅在金额大于 0 时强制映射并提交客户收款信息与凭证;0 元退款允许客户收款信息为空 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/hex"
|
||||
stdErrors "errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -332,6 +333,7 @@ func RequiredSceneFields(businessType string) []RequiredSceneField {
|
||||
}
|
||||
|
||||
// RequiredRefundFields 返回退款提交固定与条件必需字段;快照方式编码缺失或未知时由表单构建拒绝。
|
||||
// 客户收款信息退款要求客户收款信息与凭证必须映射并提交;0 元退款不退钱,两者不强制。
|
||||
func RequiredRefundFields(snapshot map[string]any) []RequiredSceneField {
|
||||
methodCode, ok := snapshot[constants.ApprovalFieldRefundMethodCode].(string)
|
||||
methodCode = strings.TrimSpace(methodCode)
|
||||
@@ -339,12 +341,22 @@ func RequiredRefundFields(snapshot map[string]any) []RequiredSceneField {
|
||||
return []RequiredSceneField{{Code: constants.ApprovalFieldRefundMethodCode, Name: "退款方式编码"}}
|
||||
}
|
||||
result := []RequiredSceneField{{Code: constants.ApprovalFieldRefundMethod, Name: "退款方式", RequiredMapping: true}}
|
||||
if methodCode == constants.RefundMethodCustomerAccount {
|
||||
if methodCode == constants.RefundMethodCustomerAccount && !isZeroAmountRefund(snapshot) {
|
||||
result = append(result, RequiredSceneField{Code: constants.ApprovalFieldCustomerAccountInfo, Name: "客户收款信息"}, RequiredSceneField{Code: constants.ApprovalFieldCustomerVoucherKey, Name: "客户收款凭证"})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// isZeroAmountRefund 判断快照中的申请退款金额是否为 0;金额缺失或无法解析时按非 0 处理,保持强制校验。
|
||||
func isZeroAmountRefund(snapshot map[string]any) bool {
|
||||
raw, ok := snapshot[constants.ApprovalFieldRequestedRefundAmount].(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
amount, err := strconv.ParseFloat(strings.TrimSpace(raw), 64)
|
||||
return err == nil && amount == 0
|
||||
}
|
||||
|
||||
// approvalBusinessTypes 返回全部已登记审批业务场景,供只读字段汇总复用。
|
||||
func approvalBusinessTypes() []string {
|
||||
return []string{
|
||||
|
||||
@@ -101,7 +101,7 @@ func buildApprovalForm(ctx context.Context, businessType string, applicationID,
|
||||
attachmentCount := 0
|
||||
for _, mapping := range mappings {
|
||||
raw, exists := lookupSnapshotValue(snapshot, mapping.BusinessField)
|
||||
if !exists || raw == nil || isEmptyFileValue(mapping, raw) {
|
||||
if !exists || raw == nil || isEmptyFileValue(mapping, raw) || isEmptyCustomerAccountInfo(mapping, raw) {
|
||||
if requiredControls[mapping.ControlID] {
|
||||
return approvalFormBuildResult{}, errors.New(errors.CodeInvalidStatus, "审批业务快照缺少模板必填字段: "+mapping.BusinessField)
|
||||
}
|
||||
@@ -142,6 +142,15 @@ func isEmptyFileValue(mapping dto.WeComControlMappingItem, raw any) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// isEmptyCustomerAccountInfo 判断客户收款信息是否为空文本;只有 0 元退款可能为空,按未填写处理,由模板必填规则决定是否拦截。
|
||||
func isEmptyCustomerAccountInfo(mapping dto.WeComControlMappingItem, raw any) bool {
|
||||
if strings.TrimSpace(mapping.BusinessField) != constants.ApprovalFieldCustomerAccountInfo {
|
||||
return false
|
||||
}
|
||||
value, ok := raw.(string)
|
||||
return ok && strings.TrimSpace(value) == ""
|
||||
}
|
||||
|
||||
// lookupSnapshotValue 支持用点分路径读取嵌套业务快照,避免模板映射绑定具体 DTO。
|
||||
func lookupSnapshotValue(snapshot map[string]any, path string) (any, bool) {
|
||||
segments := strings.Split(strings.TrimSpace(path), ".")
|
||||
|
||||
@@ -45,7 +45,8 @@ func (s *Service) decideRefundMethods(ctx context.Context, order *model.Order) (
|
||||
|
||||
decision := &refundMethodDecision{}
|
||||
switch order.PaymentMethod {
|
||||
case model.PaymentMethodWechat, model.PaymentMethodAlipay:
|
||||
// 富友是微信支付的上游通道,套餐订单回调写入 fuiou,按线上支付处理。
|
||||
case model.PaymentMethodWechat, model.PaymentMethodAlipay, model.ProviderTypeFuiou:
|
||||
payment, err := s.loadPaidPackagePayment(ctx, order.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user