ci: add Gitea Actions workflows and placeholder tests
Some checks failed
CI / ci (push) Failing after 47s

This commit is contained in:
Cosmo
2026-03-01 00:05:08 +00:00
parent 2a50e50771
commit b91e67ac1d
6 changed files with 240 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
package service
import (
"fmt"
"log"
"math"
"time"
"github.com/daniil/homelab-api/internal/model"
"github.com/jmoiron/sqlx"
)
type InterestService struct {
db *sqlx.DB
}
func NewInterestService(db *sqlx.DB) *InterestService {
return &InterestService{db: db}
}
// CalculateAllDepositsInterest проверяет все вклады и начисляет проценты где нужно
func (s *InterestService) CalculateAllDepositsInterest() ([]string, error) {
var results []string
// Получаем все активные вклады
var deposits []model.SavingsCategory
err := s.db.Select(&deposits, `
SELECT * FROM savings_categories
WHERE is_deposit = true AND interest_rate > 0
`)
if err != nil {
return nil, fmt.Errorf("failed to fetch deposits: %w", err)
}
log.Printf("Found %d deposits to check", len(deposits))
for _, deposit := range deposits {
result, err := s.CalculateInterestForDeposit(&deposit)
if err != nil {
log.Printf("Error calculating interest for %s: %v", deposit.Name, err)
results = append(results, fmt.Sprintf("❌ %s: %v", deposit.Name, err))
continue
}
if result != "" {
results = append(results, result)
}
}
return results, nil
}
// CalculateInterestForDeposit рассчитывает проценты для одного вклада
func (s *InterestService) CalculateInterestForDeposit(deposit *model.SavingsCategory) (string, error) {
if !deposit.IsDeposit || deposit.InterestRate <= 0 {
return "", nil
}
if !deposit.DepositStartDate.Valid {
return "", fmt.Errorf("no start date")
}
now := time.Now()
startDate := deposit.DepositStartDate.Time
// Проверяем не истёк ли срок вклада
if deposit.DepositTerm > 0 {
endDate := startDate.AddDate(0, deposit.DepositTerm, 0)
if now.After(endDate) {
log.Printf("Deposit %s expired on %v", deposit.Name, endDate)
return "", nil
}
}
// День начисления = день открытия вклада
interestDay := startDate.Day()
// Сегодня день начисления?
if now.Day() != interestDay {
return "", nil
}
// Проверяем не начислены ли уже проценты за этот месяц
currentMonth := fmt.Sprintf("%02d.%d", now.Month(), now.Year())
searchPattern := "%" + currentMonth + "%"
var count int
err := s.db.Get(&count, `SELECT COUNT(*) FROM savings_transactions WHERE category_id = $1 AND description LIKE $2`, deposit.ID, searchPattern)
if err != nil {
return "", err
}
if count > 0 {
log.Printf("Interest for %s already calculated for %s", deposit.Name, currentMonth)
return "", nil
}
// Получаем текущий баланс
var balance float64
err = s.db.Get(&balance, `SELECT COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE -amount END), 0) FROM savings_transactions WHERE category_id = $1`, deposit.ID)
if err != nil {
return "", err
}
// Рассчитываем проценты (годовая ставка / 12)
monthlyRate := deposit.InterestRate / 12 / 100
interest := balance * monthlyRate
interest = math.Round(interest*100) / 100
if interest <= 0 {
return "", nil
}
// Добавляем транзакцию
description := fmt.Sprintf("Проценты за %s (%.2f%% годовых)", currentMonth, deposit.InterestRate)
_, err = s.db.Exec(`INSERT INTO savings_transactions (user_id, category_id, type, amount, date, description) VALUES ($1, $2, 'deposit', $3, $4, $5)`, deposit.UserID, deposit.ID, interest, now.Format("2006-01-02"), description)
if err != nil {
return "", err
}
result := fmt.Sprintf("✅ %s: +%.2f₽ (баланс: %.2f₽)", deposit.Name, interest, balance+interest)
log.Printf(result)
return result, nil
}