80 lines
3.5 KiB
Go
80 lines
3.5 KiB
Go
package wallet
|
||
|
||
import (
|
||
"context"
|
||
"strings"
|
||
|
||
"hyapp/pkg/appcode"
|
||
"hyapp/pkg/xerr"
|
||
"hyapp/services/wallet-service/internal/domain/ledger"
|
||
)
|
||
|
||
// FreezeSalaryWithdrawal 把工资从可用余额冻结到提现审核池;提交申请前必须先由 gateway 完成身份校验。
|
||
func (s *Service) FreezeSalaryWithdrawal(ctx context.Context, command ledger.SalaryWithdrawalCommand) (ledger.SalaryWithdrawalReceipt, error) {
|
||
if err := normalizeSalaryWithdrawalCommand(&command, false); err != nil {
|
||
return ledger.SalaryWithdrawalReceipt{}, err
|
||
}
|
||
if command.Reason == "" {
|
||
command.Reason = "salary withdrawal freeze"
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.SalaryWithdrawalReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
return s.repository.FreezeSalaryWithdrawal(ctx, command)
|
||
}
|
||
|
||
// SettleSalaryWithdrawal 在财务审核通过后扣减冻结金额;它只动 frozen,不再次扣 available。
|
||
func (s *Service) SettleSalaryWithdrawal(ctx context.Context, command ledger.SalaryWithdrawalCommand) (ledger.SalaryWithdrawalReceipt, error) {
|
||
if err := normalizeSalaryWithdrawalCommand(&command, true); err != nil {
|
||
return ledger.SalaryWithdrawalReceipt{}, err
|
||
}
|
||
if command.Reason == "" {
|
||
command.Reason = "salary withdrawal approved"
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.SalaryWithdrawalReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
return s.repository.SettleSalaryWithdrawal(ctx, command)
|
||
}
|
||
|
||
// ReleaseSalaryWithdrawal 在审核拒绝或申请创建失败时把冻结工资返还到可用余额。
|
||
func (s *Service) ReleaseSalaryWithdrawal(ctx context.Context, command ledger.SalaryWithdrawalCommand) (ledger.SalaryWithdrawalReceipt, error) {
|
||
if err := normalizeSalaryWithdrawalCommand(&command, false); err != nil {
|
||
return ledger.SalaryWithdrawalReceipt{}, err
|
||
}
|
||
if command.Reason == "" {
|
||
command.Reason = "salary withdrawal released"
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.SalaryWithdrawalReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
return s.repository.ReleaseSalaryWithdrawal(ctx, command)
|
||
}
|
||
|
||
func normalizeSalaryWithdrawalCommand(command *ledger.SalaryWithdrawalCommand, requireOperator bool) error {
|
||
if command == nil || command.CommandID == "" || command.UserID <= 0 || command.SalaryUSDMinor <= 0 {
|
||
return xerr.New(xerr.InvalidArgument, "salary withdrawal command is incomplete")
|
||
}
|
||
if requireOperator && command.OperatorUserID <= 0 {
|
||
return xerr.New(xerr.InvalidArgument, "operator_user_id is required")
|
||
}
|
||
command.SalaryAssetType = strings.ToUpper(strings.TrimSpace(command.SalaryAssetType))
|
||
if !ledger.ValidSalaryAssetType(command.SalaryAssetType) {
|
||
return xerr.New(xerr.InvalidArgument, "salary_asset_type is invalid")
|
||
}
|
||
command.CommandID = strings.TrimSpace(command.CommandID)
|
||
command.Reason = strings.TrimSpace(command.Reason)
|
||
command.WithdrawalRef = strings.TrimSpace(command.WithdrawalRef)
|
||
command.WithdrawalApplicationID = strings.TrimSpace(command.WithdrawalApplicationID)
|
||
if len(command.CommandID) > 128 || len(command.Reason) > 512 || len(command.WithdrawalRef) > 128 || len(command.WithdrawalApplicationID) > 64 {
|
||
return xerr.New(xerr.InvalidArgument, "salary withdrawal text fields are too long")
|
||
}
|
||
return nil
|
||
}
|