Files
bill-manager/service.go
2024-08-19 11:35:31 +02:00

137 lines
3.6 KiB
Go

package main
import (
"fmt"
"log"
"time"
)
type BillService struct {
db *DB
bills map[int64]Bill
}
const paymentColumns = "id, billid, monthFor, paymentDate"
const billColumns = "id, name"
func (s *BillService) GetPaymentsForDate(date time.Time) ([]Payment, error) {
log.Printf("GetPaymentsForDate for %v", date)
res := []Payment{}
if s == nil {
return res, fmt.Errorf("calling GetPaymentsFor on nil BillService")
}
if s.db == nil || !s.db.Ready {
return res, fmt.Errorf("cannot get payments, db is nil or not ready - %v", s.db)
}
rows, err := s.db.readConn.Query(fmt.Sprintf(`
SELECT %s
FROM Payment
WHERE monthFor = date(strftime('%%Y-%%m-01', ?));
`, paymentColumns), date)
if err != nil {
return res, fmt.Errorf("query for payments of %s failed with error: %v", date, err)
}
for rows.Next() {
payment := Payment{}
err = rows.Scan(&payment.Id, &payment.BillId, &payment.MonthFor, &payment.PaymentDate)
if err != nil {
Error.Printf("failed to scan row: %v", err)
continue
}
res = append(res, payment)
}
return res, nil
}
func (s *BillService) GetPaymentForBillAndDate(billid int64, date time.Time) (Payment, error) {
log.Printf("GetPaymentForBillAndDate for %d and %s", billid, date)
res := Payment{}
if s == nil {
return res, fmt.Errorf("calling GetPaymentsFor on nil BillService")
}
if s.db == nil || !s.db.Ready {
return res, fmt.Errorf("cannot get payments, db is nil or not ready - %v", s.db)
}
row := s.db.readConn.QueryRow(fmt.Sprintf(`
SELECT %s
FROM Payment
WHERE billid = ? AND monthFor = date(strftime('%%Y-%%m-01', ?));
`, paymentColumns), billid, date)
err := row.Scan(&res.Id, &res.BillId, &res.MonthFor, &res.PaymentDate)
if err != nil {
return res, fmt.Errorf("failed scanning row: %v", err)
}
return res, nil
}
func (s *BillService) GetAllBills() ([]Bill, error) {
log.Printf("GetAllBills")
res := []Bill{}
if s == nil {
return res, fmt.Errorf("calling GetAllBills on nil BillService")
}
if s.db == nil || !s.db.Ready {
return res, fmt.Errorf("cannot get bills, db is nil or not ready - %v", s.db)
}
rows, err := s.db.readConn.Query(fmt.Sprintf(`SELECT %s FROM Bill ORDER BY name`, billColumns))
if err != nil {
return res, fmt.Errorf("failed to query for bills: %w", err)
}
for rows.Next() {
bill := Bill{}
err := rows.Scan(&bill.Id, &bill.Name)
if err != nil {
Error.Printf("failed to scan row: %v", err)
continue
}
res = append(res, bill)
}
s.bills = make(map[int64]Bill)
for _, bill := range res {
s.bills[bill.Id] = bill
}
return res, nil
}
func (s *BillService) MarkPaid(billid int64, monthFor time.Time, when time.Time) (Payment, error) {
log.Printf("MarkPaid for %d, %v and %v", billid, monthFor, when)
res := Payment{}
if s == nil {
return res, fmt.Errorf("calling MarkPaid on nil BillService")
}
if s.db == nil || !s.db.Ready {
return res, fmt.Errorf("cannot mark bill paid, db is nil or not ready - %v", s.db)
}
qres, err := s.db.writeConn.Exec(`
INSERT INTO Payment (billid, monthFor, paymentDate)
VALUES (?, date(strftime('%Y-%m-01', ?)), ?)
ON CONFLICT(billid, monthFor) DO UPDATE SET
paymentDate = excluded.paymentDate
WHERE Payment.paymentDate IS NULL
`, billid, monthFor, when)
if err != nil {
return res, fmt.Errorf("failed upserting into payment with error: %w", err)
}
rows, err := qres.RowsAffected()
if err != nil {
return res, fmt.Errorf("failed to get rows affected: %w", err)
}
if rows == 0 {
return res, fmt.Errorf("no rows affected")
}
return s.GetPaymentForBillAndDate(billid, monthFor)
}