133 lines
3.8 KiB
Go
133 lines
3.8 KiB
Go
package services
|
|
|
|
import (
|
|
"FamilyHub/src/domain"
|
|
"FamilyHub/src/integrations/receiptProvider"
|
|
"FamilyHub/src/repositories"
|
|
"FamilyHub/src/utils"
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
type ReceiptService interface {
|
|
AddReceipt(ctx context.Context, req domain.AddReceiptRequest) (*domain.Receipt, error)
|
|
}
|
|
|
|
type receiptService struct {
|
|
provider receiptProvider.ReceiptProvider
|
|
repo repositories.ReceiptsRepository
|
|
transactionRepo repositories.TransactionRepository
|
|
}
|
|
|
|
func NewReceiptService(
|
|
provider receiptProvider.ReceiptProvider,
|
|
repo repositories.ReceiptsRepository,
|
|
transactionRepo repositories.TransactionRepository,
|
|
) ReceiptService {
|
|
return &receiptService{
|
|
provider: provider,
|
|
repo: repo,
|
|
transactionRepo: transactionRepo,
|
|
}
|
|
}
|
|
|
|
func (s *receiptService) AddReceipt(
|
|
ctx context.Context,
|
|
req domain.AddReceiptRequest,
|
|
) (*domain.Receipt, error) {
|
|
log.Printf("receipt add request: payload=%s", utils.ToLogJSON(req))
|
|
|
|
receipt, err := s.provider.GetReceipt(ctx, req.Date, req.Number)
|
|
if err != nil {
|
|
log.Printf("receipt add failed: err=%v payload=%s", err, utils.ToLogJSON(req))
|
|
return nil, err
|
|
}
|
|
|
|
receiptID, err := s.repo.Create(ctx, receipt)
|
|
if err != nil {
|
|
log.Printf("receipt persist failed: err=%v receipt=%s", err, utils.ToLogJSON(receipt))
|
|
return nil, err
|
|
}
|
|
receipt.ID = int(receiptID)
|
|
|
|
if !s.shouldCreateTransaction(req) {
|
|
log.Printf("receipt add response: payload=%s", utils.ToLogJSON(receipt))
|
|
return receipt, nil
|
|
}
|
|
|
|
transaction, err := s.createTransactionForReceipt(ctx, receipt, req, receiptID)
|
|
if err != nil {
|
|
if rollbackErr := s.repo.Delete(ctx, receiptID); rollbackErr != nil {
|
|
return nil, fmt.Errorf("create receipt transaction: %w (rollback receipt %d: %v)", err, receiptID, rollbackErr)
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
receipt.TransactionID = &transaction.ID
|
|
log.Printf("receipt add response: payload=%s", utils.ToLogJSON(receipt))
|
|
return receipt, nil
|
|
}
|
|
|
|
func (s *receiptService) shouldCreateTransaction(req domain.AddReceiptRequest) bool {
|
|
return s.transactionRepo != nil && req.FamilyID != nil && req.CreatedBy != nil
|
|
}
|
|
|
|
func (s *receiptService) createTransactionForReceipt(
|
|
ctx context.Context,
|
|
receipt *domain.Receipt,
|
|
req domain.AddReceiptRequest,
|
|
receiptID int64,
|
|
) (*domain.Transaction, error) {
|
|
transactionType := "expense"
|
|
if req.Type != nil && strings.TrimSpace(*req.Type) != "" {
|
|
transactionType = strings.TrimSpace(*req.Type)
|
|
}
|
|
|
|
category := "receipt"
|
|
if req.Category != nil && strings.TrimSpace(*req.Category) != "" {
|
|
category = strings.TrimSpace(*req.Category)
|
|
}
|
|
|
|
description := buildReceiptTransactionDescription(receipt, req.Description)
|
|
|
|
transaction := &domain.Transaction{
|
|
FamilyID: *req.FamilyID,
|
|
Description: description,
|
|
Type: transactionType,
|
|
DateTime: receipt.IssuedAt,
|
|
Category: category,
|
|
Amount: receipt.TotalAmount,
|
|
CreatedBy: *req.CreatedBy,
|
|
ReceiptID: &receiptID,
|
|
}
|
|
log.Printf("%+v\n", transaction)
|
|
log.Printf("receipt transaction create request: payload=%s", utils.ToLogJSON(transaction))
|
|
if err := s.transactionRepo.Create(ctx, transaction); err != nil {
|
|
log.Printf("receipt transaction create failed: err=%v payload=%s", err, utils.ToLogJSON(transaction))
|
|
return nil, err
|
|
}
|
|
|
|
log.Printf("receipt transaction create response: payload=%s", utils.ToLogJSON(transaction))
|
|
return transaction, nil
|
|
}
|
|
|
|
func buildReceiptTransactionDescription(receipt *domain.Receipt, explicit *string) *string {
|
|
if explicit != nil && strings.TrimSpace(*explicit) != "" {
|
|
value := strings.TrimSpace(*explicit)
|
|
return &value
|
|
}
|
|
|
|
if name := strings.TrimSpace(receipt.NameTO); name != "" {
|
|
return &name
|
|
}
|
|
|
|
if number := strings.TrimSpace(receipt.ReceiptNumber); number != "" {
|
|
value := fmt.Sprintf("Receipt %s", number)
|
|
return &value
|
|
}
|
|
|
|
return nil
|
|
}
|