account/internal/handler/snapshot.go
GnomeZworc 0f2d7126eb
ajoute snapshot
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
2026-06-13 22:52:13 +02:00

128 lines
3.6 KiB
Go

package handler
import (
"errors"
"net/http"
"time"
"git.g3e.fr/H6N/account/internal/snapshot"
"git.g3e.fr/H6N/account/internal/store"
"github.com/jackc/pgx/v5"
)
type SnapshotHandler struct {
engine *snapshot.Engine
}
func NewSnapshotHandler(e *snapshot.Engine) *SnapshotHandler {
return &SnapshotHandler{engine: e}
}
func (h *SnapshotHandler) RegisterRoutes(mux *http.ServeMux) {
mux.HandleFunc("GET /accounts/{id}/snapshots", h.listAccountSnapshots)
mux.HandleFunc("GET /accounts/{id}/snapshots/positions", h.listPositionSnapshots)
mux.HandleFunc("POST /accounts/{id}/snapshots/recompute", h.recomputeAccount)
}
// parseDateParam parse un paramètre de query YYYY-MM-DD. Retourne time.Time{} si absent.
func parseDateParam(r *http.Request, key string) (time.Time, error) {
v := r.URL.Query().Get(key)
if v == "" {
return time.Time{}, nil
}
return time.Parse("2006-01-02", v)
}
// GET /accounts/{id}/snapshots?from=YYYY-MM-DD&to=YYYY-MM-DD
// Liste les snapshots agrégés (valeur totale) d'un compte.
// from/to optionnels : sans borne → pas de filtre de ce côté.
func (h *SnapshotHandler) listAccountSnapshots(w http.ResponseWriter, r *http.Request) {
accountID, err := parseID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid account id")
return
}
from, err := parseDateParam(r, "from")
if err != nil {
writeError(w, http.StatusBadRequest, "invalid from date")
return
}
to, err := parseDateParam(r, "to")
if err != nil {
writeError(w, http.StatusBadRequest, "invalid to date")
return
}
rows, err := h.engine.Store().ListAccountSnapshots(r.Context(), accountID, from, to)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if rows == nil {
rows = []store.AccountSnapshotRow{}
}
writeJSON(w, http.StatusOK, rows)
}
// GET /accounts/{id}/snapshots/positions?from=YYYY-MM-DD&to=YYYY-MM-DD
// Liste les positions détaillées (par instrument) d'un compte.
func (h *SnapshotHandler) listPositionSnapshots(w http.ResponseWriter, r *http.Request) {
accountID, err := parseID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid account id")
return
}
from, err := parseDateParam(r, "from")
if err != nil {
writeError(w, http.StatusBadRequest, "invalid from date")
return
}
to, err := parseDateParam(r, "to")
if err != nil {
writeError(w, http.StatusBadRequest, "invalid to date")
return
}
rows, err := h.engine.Store().ListPositionSnapshots(r.Context(), accountID, from, to)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if rows == nil {
rows = []store.PositionSnapshotRow{}
}
writeJSON(w, http.StatusOK, rows)
}
// POST /accounts/{id}/snapshots/recompute
// Recalcule les snapshots du compte depuis sa date d'invalidation jusqu'à aujourd'hui.
// Retourne 204 si aucune invalidation n'est en attente.
func (h *SnapshotHandler) recomputeAccount(w http.ResponseWriter, r *http.Request) {
accountID, err := parseID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid account id")
return
}
from, to, err := h.engine.RecomputeAccount(r.Context(), accountID)
if errors.Is(err, pgx.ErrNoRows) {
writeError(w, http.StatusNotFound, "account not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
if from.IsZero() {
w.WriteHeader(http.StatusNoContent) // aucune invalidation en attente
return
}
writeJSON(w, http.StatusOK, map[string]any{
"account_id": accountID,
"from": from.Format("2006-01-02"),
"to": to.Format("2006-01-02"),
"status": "ok",
})
}