119 lines
4.7 KiB
Go
119 lines
4.7 KiB
Go
package financewithdrawal
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"hyapp-admin-server/internal/model"
|
||
"hyapp-admin-server/internal/repository"
|
||
)
|
||
|
||
type markdownSender interface {
|
||
SendMarkdown(ctx context.Context, title string, text string) error
|
||
}
|
||
|
||
// ReviewPendingNotifier 只通知“当前待谁处理”,不参与提现创建、冻结或审核事务。
|
||
type ReviewPendingNotifier interface {
|
||
NotifyReviewPending(ctx context.Context, application model.UserWithdrawalApplication, stage repository.WithdrawalApplicationReviewStage) error
|
||
}
|
||
|
||
type dingTalkReviewPendingNotifier struct {
|
||
sender markdownSender
|
||
}
|
||
|
||
func NewDingTalkReviewPendingNotifier(sender markdownSender) ReviewPendingNotifier {
|
||
if sender == nil {
|
||
return nil
|
||
}
|
||
return &dingTalkReviewPendingNotifier{sender: sender}
|
||
}
|
||
|
||
func (n *dingTalkReviewPendingNotifier) NotifyReviewPending(ctx context.Context, application model.UserWithdrawalApplication, stage repository.WithdrawalApplicationReviewStage) error {
|
||
if n == nil || n.sender == nil {
|
||
return nil
|
||
}
|
||
title, text := withdrawalReviewPendingMarkdown(application, stage)
|
||
return n.sender.SendMarkdown(ctx, title, text)
|
||
}
|
||
|
||
func withdrawalReviewPendingMarkdown(application model.UserWithdrawalApplication, stage repository.WithdrawalApplicationReviewStage) (string, string) {
|
||
stageName := "运营审核阶段"
|
||
pageURL := "https://admin-acc.global-interaction.com/finance/?view=withdrawalOperations"
|
||
if stage == repository.WithdrawalApplicationReviewStageFinance {
|
||
stageName = "财务审核阶段"
|
||
pageURL = "https://admin-acc.global-interaction.com/finance/?view=withdrawalFinance"
|
||
}
|
||
title := fmt.Sprintf("用户提现待处理【%s】", stageName)
|
||
lines := []string{
|
||
fmt.Sprintf("### 用户提现待处理【%s】", stageName),
|
||
"",
|
||
fmt.Sprintf("- 当前阶段:**%s**", stageName),
|
||
fmt.Sprintf("- 申请ID:%d", application.ID),
|
||
fmt.Sprintf("- APP:%s", withdrawalMarkdownValue(application.AppCode)),
|
||
fmt.Sprintf("- 来源系统:%s", withdrawalMarkdownValue(application.SourceSystem)),
|
||
fmt.Sprintf("- 来源单号:%s", withdrawalMarkdownValue(application.SourceApplicationID)),
|
||
fmt.Sprintf("- 用户ID:%s", withdrawalMarkdownValue(application.UserID)),
|
||
fmt.Sprintf("- 申请金额:$ %s", withdrawalMarkdownValue(application.WithdrawAmount)),
|
||
fmt.Sprintf("- 提现方式:%s", withdrawalMarkdownValue(application.WithdrawMethod)),
|
||
fmt.Sprintf("- 提现地址:%s", withdrawalMarkdownValue(application.WithdrawAddress)),
|
||
fmt.Sprintf("- 申请时间:%s", formatWithdrawalNotifyMillis(application.CreatedAtMS)),
|
||
}
|
||
if hasWithdrawalPayoutSnapshot(application) {
|
||
// 协作通知展示来源申请时的不可变快照,财务不应在审核时按当前费率重算。
|
||
lines = append(lines,
|
||
fmt.Sprintf("- 手续费:$ %s(费率 %s%%)", withdrawalOptionalMarkdownValue(application.ServiceCharge), withdrawalOptionalMarkdownValue(application.ServiceChargeRatio)),
|
||
fmt.Sprintf("- 实际打款金额:$ %s", withdrawalOptionalMarkdownValue(application.ActualAmount)),
|
||
)
|
||
}
|
||
if stage == repository.WithdrawalApplicationReviewStageFinance {
|
||
// 财务提醒保留运营审核快照,接收人无需先打开后台就能确认这是一张已完成初审的申请。
|
||
lines = append(lines,
|
||
fmt.Sprintf("- 运营审核人:%s", withdrawalMarkdownValue(application.OperationsReviewerName)),
|
||
fmt.Sprintf("- 运营审核备注:%s", withdrawalMarkdownValue(application.OperationsAuditRemark)),
|
||
fmt.Sprintf("- 运营通过时间:%s", formatWithdrawalNotifyMillis(int64Value(application.OperationsReviewedAtMS))),
|
||
)
|
||
}
|
||
lines = append(lines, "- 后台地址:"+pageURL)
|
||
return title, strings.Join(lines, "\n")
|
||
}
|
||
|
||
func hasWithdrawalPayoutSnapshot(application model.UserWithdrawalApplication) bool {
|
||
return application.ServiceChargeRatio != nil || application.ServiceCharge != nil || application.ActualAmount != nil || application.ActualAmountMinor != nil
|
||
}
|
||
|
||
func withdrawalOptionalMarkdownValue(value *string) string {
|
||
if value == nil {
|
||
return "-"
|
||
}
|
||
return withdrawalMarkdownValue(*value)
|
||
}
|
||
|
||
func formatWithdrawalNotifyMillis(value int64) string {
|
||
if value <= 0 {
|
||
return "-"
|
||
}
|
||
// 协作消息按运营团队使用的北京时间展示;接口和数据库仍以 Unix 毫秒 UTC 事实为准。
|
||
return time.UnixMilli(value).In(time.FixedZone("UTC+8", 8*60*60)).Format("2006-01-02 15:04:05")
|
||
}
|
||
|
||
func int64Value(value *int64) int64 {
|
||
if value == nil {
|
||
return 0
|
||
}
|
||
return *value
|
||
}
|
||
|
||
func withdrawalMarkdownValue(value string) string {
|
||
value = strings.TrimSpace(value)
|
||
if value == "" {
|
||
return "-"
|
||
}
|
||
runes := []rune(value)
|
||
if len(runes) > 240 {
|
||
value = string(runes[:240]) + "..."
|
||
}
|
||
return strings.NewReplacer("\r", " ", "\n", " ", "\t", " ").Replace(value)
|
||
}
|