feat: payment methods
All checks were successful
Deploy / build-and-deploy (push) Successful in 1m1s
All checks were successful
Deploy / build-and-deploy (push) Successful in 1m1s
This commit is contained in:
parent
364f8dc682
commit
3de76916c9
15 changed files with 946 additions and 100 deletions
|
|
@ -10,24 +10,26 @@ import (
|
|||
)
|
||||
|
||||
type CreateExpenseDTO struct {
|
||||
SpaceID string
|
||||
UserID string
|
||||
Description string
|
||||
Amount int
|
||||
Type model.ExpenseType
|
||||
Date time.Time
|
||||
TagIDs []string
|
||||
ItemIDs []string
|
||||
SpaceID string
|
||||
UserID string
|
||||
Description string
|
||||
Amount int
|
||||
Type model.ExpenseType
|
||||
Date time.Time
|
||||
TagIDs []string
|
||||
ItemIDs []string
|
||||
PaymentMethodID *string
|
||||
}
|
||||
|
||||
type UpdateExpenseDTO struct {
|
||||
ID string
|
||||
SpaceID string
|
||||
Description string
|
||||
Amount int
|
||||
Type model.ExpenseType
|
||||
Date time.Time
|
||||
TagIDs []string
|
||||
ID string
|
||||
SpaceID string
|
||||
Description string
|
||||
Amount int
|
||||
Type model.ExpenseType
|
||||
Date time.Time
|
||||
TagIDs []string
|
||||
PaymentMethodID *string
|
||||
}
|
||||
|
||||
const ExpensesPerPage = 25
|
||||
|
|
@ -52,15 +54,16 @@ func (s *ExpenseService) CreateExpense(dto CreateExpenseDTO) (*model.Expense, er
|
|||
|
||||
now := time.Now()
|
||||
expense := &model.Expense{
|
||||
ID: uuid.NewString(),
|
||||
SpaceID: dto.SpaceID,
|
||||
CreatedBy: dto.UserID,
|
||||
Description: dto.Description,
|
||||
AmountCents: dto.Amount,
|
||||
Type: dto.Type,
|
||||
Date: dto.Date,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
ID: uuid.NewString(),
|
||||
SpaceID: dto.SpaceID,
|
||||
CreatedBy: dto.UserID,
|
||||
Description: dto.Description,
|
||||
AmountCents: dto.Amount,
|
||||
Type: dto.Type,
|
||||
Date: dto.Date,
|
||||
PaymentMethodID: dto.PaymentMethodID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
err := s.expenseRepo.Create(expense, dto.TagIDs, dto.ItemIDs)
|
||||
|
|
@ -166,6 +169,59 @@ func (s *ExpenseService) GetExpensesWithTagsForSpacePaginated(spaceID string, pa
|
|||
return result, totalPages, nil
|
||||
}
|
||||
|
||||
func (s *ExpenseService) GetExpensesWithTagsAndMethodsForSpacePaginated(spaceID string, page int) ([]*model.ExpenseWithTagsAndMethod, int, error) {
|
||||
total, err := s.expenseRepo.CountBySpaceID(spaceID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
totalPages := (total + ExpensesPerPage - 1) / ExpensesPerPage
|
||||
if totalPages < 1 {
|
||||
totalPages = 1
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if page > totalPages {
|
||||
page = totalPages
|
||||
}
|
||||
|
||||
offset := (page - 1) * ExpensesPerPage
|
||||
expenses, err := s.expenseRepo.GetBySpaceIDPaginated(spaceID, ExpensesPerPage, offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
ids := make([]string, len(expenses))
|
||||
for i, e := range expenses {
|
||||
ids[i] = e.ID
|
||||
}
|
||||
|
||||
tagsMap, err := s.expenseRepo.GetTagsByExpenseIDs(ids)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
methodsMap, err := s.expenseRepo.GetPaymentMethodsByExpenseIDs(ids)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
result := make([]*model.ExpenseWithTagsAndMethod, len(expenses))
|
||||
for i, e := range expenses {
|
||||
result[i] = &model.ExpenseWithTagsAndMethod{
|
||||
Expense: *e,
|
||||
Tags: tagsMap[e.ID],
|
||||
PaymentMethod: methodsMap[e.ID],
|
||||
}
|
||||
}
|
||||
return result, totalPages, nil
|
||||
}
|
||||
|
||||
func (s *ExpenseService) GetPaymentMethodsByExpenseIDs(expenseIDs []string) (map[string]*model.PaymentMethod, error) {
|
||||
return s.expenseRepo.GetPaymentMethodsByExpenseIDs(expenseIDs)
|
||||
}
|
||||
|
||||
func (s *ExpenseService) GetExpense(id string) (*model.Expense, error) {
|
||||
return s.expenseRepo.GetByID(id)
|
||||
}
|
||||
|
|
@ -191,6 +247,7 @@ func (s *ExpenseService) UpdateExpense(dto UpdateExpenseDTO) (*model.Expense, er
|
|||
existing.AmountCents = dto.Amount
|
||||
existing.Type = dto.Type
|
||||
existing.Date = dto.Date
|
||||
existing.PaymentMethodID = dto.PaymentMethodID
|
||||
existing.UpdatedAt = time.Now()
|
||||
|
||||
if err := s.expenseRepo.Update(existing, dto.TagIDs); err != nil {
|
||||
|
|
|
|||
109
internal/service/payment_method.go
Normal file
109
internal/service/payment_method.go
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.juancwu.dev/juancwu/budgit/internal/model"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/repository"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreatePaymentMethodDTO struct {
|
||||
SpaceID string
|
||||
Name string
|
||||
Type model.PaymentMethodType
|
||||
LastFour string
|
||||
CreatedBy string
|
||||
}
|
||||
|
||||
type UpdatePaymentMethodDTO struct {
|
||||
ID string
|
||||
Name string
|
||||
Type model.PaymentMethodType
|
||||
LastFour string
|
||||
}
|
||||
|
||||
type PaymentMethodService struct {
|
||||
methodRepo repository.PaymentMethodRepository
|
||||
}
|
||||
|
||||
func NewPaymentMethodService(methodRepo repository.PaymentMethodRepository) *PaymentMethodService {
|
||||
return &PaymentMethodService{
|
||||
methodRepo: methodRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PaymentMethodService) CreateMethod(dto CreatePaymentMethodDTO) (*model.PaymentMethod, error) {
|
||||
name := strings.TrimSpace(dto.Name)
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("payment method name cannot be empty")
|
||||
}
|
||||
if dto.Type != model.PaymentMethodTypeCredit && dto.Type != model.PaymentMethodTypeDebit {
|
||||
return nil, fmt.Errorf("invalid payment method type")
|
||||
}
|
||||
if len(dto.LastFour) != 4 {
|
||||
return nil, fmt.Errorf("last four digits must be exactly 4 characters")
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
method := &model.PaymentMethod{
|
||||
ID: uuid.NewString(),
|
||||
SpaceID: dto.SpaceID,
|
||||
Name: name,
|
||||
Type: dto.Type,
|
||||
LastFour: &dto.LastFour,
|
||||
CreatedBy: dto.CreatedBy,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
err := s.methodRepo.Create(method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func (s *PaymentMethodService) GetMethodsForSpace(spaceID string) ([]*model.PaymentMethod, error) {
|
||||
return s.methodRepo.GetBySpaceID(spaceID)
|
||||
}
|
||||
|
||||
func (s *PaymentMethodService) GetMethod(id string) (*model.PaymentMethod, error) {
|
||||
return s.methodRepo.GetByID(id)
|
||||
}
|
||||
|
||||
func (s *PaymentMethodService) UpdateMethod(dto UpdatePaymentMethodDTO) (*model.PaymentMethod, error) {
|
||||
name := strings.TrimSpace(dto.Name)
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("payment method name cannot be empty")
|
||||
}
|
||||
if dto.Type != model.PaymentMethodTypeCredit && dto.Type != model.PaymentMethodTypeDebit {
|
||||
return nil, fmt.Errorf("invalid payment method type")
|
||||
}
|
||||
if len(dto.LastFour) != 4 {
|
||||
return nil, fmt.Errorf("last four digits must be exactly 4 characters")
|
||||
}
|
||||
|
||||
method, err := s.methodRepo.GetByID(dto.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
method.Name = name
|
||||
method.Type = dto.Type
|
||||
method.LastFour = &dto.LastFour
|
||||
|
||||
err = s.methodRepo.Update(method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func (s *PaymentMethodService) DeleteMethod(id string) error {
|
||||
return s.methodRepo.Delete(id)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue