feat: #44 fatura de cartão com data futura fica pendente até confirmação
- Nova tabela pending_bill_imports (migration 016) - ImportHandler.Confirm: quando is_credit_card=true e payment_date > hoje, salva como pending em vez de inserir transações - Novos endpoints: GET /pending-bills, POST /pending-bills/:id/confirm, DELETE /pending-bills/:id - Dashboard inclui pending_bill_imports no payload - Frontend: resultado "fatura salva como pendente" no ImportView - AccountsView exibe widget de faturas pendentes com ações de confirmar/descartar - dashboard_test: mock de PendingBillRepo + TransactionRepository Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"financeiro-carvalho/internal/middleware"
|
||||
"financeiro-carvalho/internal/model"
|
||||
)
|
||||
|
||||
type PendingBillRepository interface {
|
||||
List(ctx context.Context) ([]model.PendingBillImport, error)
|
||||
Create(ctx context.Context, filename, paymentDate string, total float64, rows []model.ImportRow) (*model.PendingBillImport, error)
|
||||
GetByID(ctx context.Context, id int) (*model.PendingBillImport, error)
|
||||
Delete(ctx context.Context, id int) error
|
||||
}
|
||||
|
||||
type pendingBillRepo struct{ pool *pgxpool.Pool }
|
||||
|
||||
func NewPendingBillRepository(pool *pgxpool.Pool) PendingBillRepository {
|
||||
return &pendingBillRepo{pool: pool}
|
||||
}
|
||||
|
||||
func (r *pendingBillRepo) List(ctx context.Context) ([]model.PendingBillImport, error) {
|
||||
pid := middleware.ProfileIDFromCtx(ctx)
|
||||
rows, err := r.pool.Query(ctx, `
|
||||
SELECT id, filename, payment_date::text, total, rows, created_at::text
|
||||
FROM pending_bill_imports
|
||||
WHERE profile_id = $1
|
||||
ORDER BY payment_date
|
||||
`, pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []model.PendingBillImport
|
||||
for rows.Next() {
|
||||
var p model.PendingBillImport
|
||||
var rowsJSON []byte
|
||||
if err := rows.Scan(&p.ID, &p.Filename, &p.PaymentDate, &p.Total, &rowsJSON, &p.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = json.Unmarshal(rowsJSON, &p.Rows)
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (r *pendingBillRepo) Create(ctx context.Context, filename, paymentDate string, total float64, rows []model.ImportRow) (*model.PendingBillImport, error) {
|
||||
pid := middleware.ProfileIDFromCtx(ctx)
|
||||
rowsJSON, err := json.Marshal(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var p model.PendingBillImport
|
||||
var rowsBack []byte
|
||||
err = r.pool.QueryRow(ctx, `
|
||||
INSERT INTO pending_bill_imports (profile_id, filename, payment_date, total, rows)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, filename, payment_date::text, total, rows, created_at::text
|
||||
`, pid, filename, paymentDate, total, rowsJSON).
|
||||
Scan(&p.ID, &p.Filename, &p.PaymentDate, &p.Total, &rowsBack, &p.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = json.Unmarshal(rowsBack, &p.Rows)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (r *pendingBillRepo) GetByID(ctx context.Context, id int) (*model.PendingBillImport, error) {
|
||||
pid := middleware.ProfileIDFromCtx(ctx)
|
||||
var p model.PendingBillImport
|
||||
var rowsJSON []byte
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
SELECT id, filename, payment_date::text, total, rows, created_at::text
|
||||
FROM pending_bill_imports
|
||||
WHERE id = $1 AND profile_id = $2
|
||||
`, id, pid).Scan(&p.ID, &p.Filename, &p.PaymentDate, &p.Total, &rowsJSON, &p.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = json.Unmarshal(rowsJSON, &p.Rows)
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (r *pendingBillRepo) Delete(ctx context.Context, id int) error {
|
||||
pid := middleware.ProfileIDFromCtx(ctx)
|
||||
_, err := r.pool.Exec(ctx, `DELETE FROM pending_bill_imports WHERE id = $1 AND profile_id = $2`, id, pid)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user