generated from dave/wails-template
251 lines
6.7 KiB
Go
251 lines
6.7 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)
|
|
}
|
|
|
|
func (s *BillService) MovePayment(billid int64, fromMonth time.Time, toMonth time.Time) (Payment, error) {
|
|
log.Printf("MovePayment for %d from %v to %v", billid, fromMonth, toMonth)
|
|
res := Payment{}
|
|
if s == nil {
|
|
return res, fmt.Errorf("calling MovePayment on nil BillService")
|
|
}
|
|
if s.db == nil || !s.db.Ready {
|
|
return res, fmt.Errorf("cannot move payment, db is nil or not ready - %v", s.db)
|
|
}
|
|
|
|
// First get the existing payment
|
|
existingPayment, err := s.GetPaymentForBillAndDate(billid, fromMonth)
|
|
if err != nil {
|
|
return res, fmt.Errorf("failed to get existing payment: %w", err)
|
|
}
|
|
|
|
// Delete the old payment
|
|
_, err = s.db.writeConn.Exec(`
|
|
DELETE FROM Payment WHERE billid = ? AND monthFor = date(strftime('%Y-%m-01', ?))
|
|
`, billid, fromMonth)
|
|
if err != nil {
|
|
return res, fmt.Errorf("failed to delete old payment: %w", err)
|
|
}
|
|
|
|
// Create new payment in the target month
|
|
payment, err := s.MarkPaid(billid, toMonth, existingPayment.PaymentDate)
|
|
if err != nil {
|
|
return res, fmt.Errorf("failed to create new payment: %w", err)
|
|
}
|
|
|
|
return payment, nil
|
|
}
|
|
|
|
func (s *BillService) AddBill(name string) (Bill, error) {
|
|
log.Printf("AddBill with name %s", name)
|
|
res := Bill{}
|
|
if s == nil {
|
|
return res, fmt.Errorf("calling AddBill on nil BillService")
|
|
}
|
|
if s.db == nil || !s.db.Ready {
|
|
return res, fmt.Errorf("cannot add bill, db is nil or not ready - %v", s.db)
|
|
}
|
|
|
|
qres, err := s.db.writeConn.Exec(`
|
|
INSERT INTO Bill (name) VALUES (?)
|
|
`, name)
|
|
if err != nil {
|
|
return res, fmt.Errorf("failed to insert bill: %w", err)
|
|
}
|
|
|
|
id, err := qres.LastInsertId()
|
|
if err != nil {
|
|
return res, fmt.Errorf("failed to get last insert id: %w", err)
|
|
}
|
|
|
|
res.Id = id
|
|
res.Name = name
|
|
|
|
// Refresh the bills cache
|
|
_, _ = s.GetAllBills()
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *BillService) RemoveBill(billid int64) error {
|
|
log.Printf("RemoveBill with id %d", billid)
|
|
if s == nil {
|
|
return fmt.Errorf("calling RemoveBill on nil BillService")
|
|
}
|
|
if s.db == nil || !s.db.Ready {
|
|
return fmt.Errorf("cannot remove bill, db is nil or not ready - %v", s.db)
|
|
}
|
|
|
|
// Delete all payments for this bill first
|
|
_, err := s.db.writeConn.Exec(`
|
|
DELETE FROM Payment WHERE billid = ?
|
|
`, billid)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete payments for bill: %w", err)
|
|
}
|
|
|
|
// Delete the bill
|
|
_, err = s.db.writeConn.Exec(`
|
|
DELETE FROM Bill WHERE id = ?
|
|
`, billid)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete bill: %w", err)
|
|
}
|
|
|
|
// Refresh the bills cache
|
|
_, _ = s.GetAllBills()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *BillService) UnmarkPaid(billid int64, month time.Time) error {
|
|
log.Printf("UnmarkPaid for %d and %v", billid, month)
|
|
if s == nil {
|
|
return fmt.Errorf("calling UnmarkPaid on nil BillService")
|
|
}
|
|
if s.db == nil || !s.db.Ready {
|
|
return fmt.Errorf("cannot unmark paid, db is nil or not ready - %v", s.db)
|
|
}
|
|
|
|
_, err := s.db.writeConn.Exec(`
|
|
DELETE FROM Payment WHERE billid = ? AND monthFor = date(strftime('%Y-%m-01', ?))
|
|
`, billid, month)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete payment: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|