Files
hfb_sys/backend/internal/modules/adminfinance/service.go
T

138 lines
3.7 KiB
Go

package adminfinance
import (
"context"
"errors"
"net/url"
"strings"
"unicode/utf8"
"hfb_sys/backend/internal/auditlog"
)
var (
ErrDependencyUnavailable = errors.New("dependency unavailable")
ErrInvalidManualDisbursement = errors.New("invalid manual disbursement")
ErrManualDisbursementNotFound = errors.New("manual disbursement not found")
ErrManualDisbursementNotPaid = errors.New("manual disbursement is not paid")
)
type Service struct {
repo *Repository
}
func NewService(repo *Repository) *Service {
return &Service{repo: repo}
}
func (s *Service) Dashboard(ctx context.Context, query DashboardQuery) (*DashboardDTO, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable
}
return s.repo.Dashboard(ctx, query)
}
func (s *Service) Details(ctx context.Context, query DetailQuery) (*PaginatedResult, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable
}
if query.Page < 1 {
query.Page = 1
}
if query.PageSize < 1 {
query.PageSize = 20
}
if query.PageSize > 100 {
query.PageSize = 100
}
return s.repo.Details(ctx, query)
}
func (s *Service) Disbursements(ctx context.Context, query DisbursementQuery) (*DisbursementListDTO, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable
}
if query.Page < 1 {
query.Page = 1
}
if query.PageSize < 1 {
query.PageSize = 20
}
if query.PageSize > 100 {
query.PageSize = 100
}
return s.repo.Disbursements(ctx, query)
}
func (s *Service) CreateManualDisbursement(
ctx context.Context,
req CreateManualDisbursementRequest,
adminID uint64,
meta auditlog.Meta,
) (*ManualDisbursementDTO, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable
}
req.Category = strings.TrimSpace(req.Category)
req.CustomCategoryName = strings.TrimSpace(req.CustomCategoryName)
req.PayeeName = strings.TrimSpace(req.PayeeName)
req.Remark = strings.TrimSpace(req.Remark)
req.VoucherURL = strings.TrimSpace(req.VoucherURL)
if !validManualDisbursementCategory(req.Category) ||
!validManualDisbursementCustomCategoryName(req.Category, req.CustomCategoryName) ||
utf8.RuneCountInString(req.PayeeName) < 1 || utf8.RuneCountInString(req.PayeeName) > 100 ||
req.AmountCent <= 0 || req.PaidAt.IsZero() ||
utf8.RuneCountInString(req.Remark) < 1 || utf8.RuneCountInString(req.Remark) > 500 ||
!validManualVoucherURL(req.VoucherURL) {
return nil, ErrInvalidManualDisbursement
}
return s.repo.CreateManualDisbursement(ctx, req, adminID, meta)
}
func (s *Service) VoidManualDisbursement(
ctx context.Context,
id uint64,
reason string,
adminID uint64,
meta auditlog.Meta,
) (*ManualDisbursementDTO, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable
}
reason = strings.TrimSpace(reason)
if id == 0 || utf8.RuneCountInString(reason) < 1 || utf8.RuneCountInString(reason) > 255 {
return nil, ErrInvalidManualDisbursement
}
return s.repo.VoidManualDisbursement(ctx, id, reason, adminID, meta)
}
func validManualDisbursementCategory(category string) bool {
switch category {
case "user_compensation", "seller_supplement", "operating_expense", "channel_fee", "duoduo_deposit_refund", "other", "custom":
return true
default:
return false
}
}
func validManualDisbursementCustomCategoryName(category, name string) bool {
if category != "custom" {
return name == ""
}
return utf8.RuneCountInString(name) >= 1 && utf8.RuneCountInString(name) <= 50
}
func validManualVoucherURL(raw string) bool {
if raw == "" {
return true
}
if len(raw) > 500 {
return false
}
parsed, err := url.Parse(raw)
if err != nil || parsed.IsAbs() || parsed.Path != "/api/files/object" {
return false
}
return strings.HasPrefix(parsed.Query().Get("key"), "manual-disbursement/")
}