205 lines
5.6 KiB
Go
205 lines
5.6 KiB
Go
package handlers
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
type LegalHandler struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
func NewLegalHandler(db *sql.DB) *LegalHandler {
|
|
return &LegalHandler{DB: db}
|
|
}
|
|
|
|
type Contract struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
Counterparty string `json:"counterparty"`
|
|
Type string `json:"type"`
|
|
Status string `json:"status"`
|
|
Value float64 `json:"value"`
|
|
Currency string `json:"currency"`
|
|
StartDate *time.Time `json:"start_date"`
|
|
EndDate *time.Time `json:"end_date"`
|
|
RenewalDate *time.Time `json:"renewal_date"`
|
|
DocumentURL *string `json:"document_url"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type ContractReminder struct {
|
|
ID string `json:"id"`
|
|
ContractID string `json:"contract_id"`
|
|
Type string `json:"type"`
|
|
DueDate time.Time `json:"due_date"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
func (h *LegalHandler) ListContracts(w http.ResponseWriter, r *http.Request) {
|
|
status := r.URL.Query().Get("status")
|
|
if status == "" {
|
|
status = "active"
|
|
}
|
|
|
|
rows, err := h.DB.Query(`
|
|
SELECT id, title, counterparty, type, status, value, currency,
|
|
start_date, end_date, renewal_date, document_url, created_at
|
|
FROM boc_contracts
|
|
WHERE status = $1
|
|
ORDER BY renewal_date ASC NULLS LAST
|
|
`, status)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "database error")
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
contracts := []Contract{}
|
|
for rows.Next() {
|
|
var c Contract
|
|
if err := rows.Scan(&c.ID, &c.Title, &c.Counterparty, &c.Type, &c.Status,
|
|
&c.Value, &c.Currency, &c.StartDate, &c.EndDate, &c.RenewalDate,
|
|
&c.DocumentURL, &c.CreatedAt); err != nil {
|
|
continue
|
|
}
|
|
contracts = append(contracts, c)
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"contracts": contracts,
|
|
"total": len(contracts),
|
|
})
|
|
}
|
|
|
|
func (h *LegalHandler) CreateContract(w http.ResponseWriter, r *http.Request) {
|
|
var req Contract
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid request")
|
|
return
|
|
}
|
|
|
|
var id string
|
|
err := h.DB.QueryRow(`
|
|
INSERT INTO boc_contracts (title, counterparty, type, status, value, currency,
|
|
start_date, end_date, renewal_date, document_url)
|
|
VALUES ($1, $2, $3, 'draft', $4, $5, $6, $7, $8, $9)
|
|
RETURNING id
|
|
`, req.Title, req.Counterparty, req.Type, req.Value, req.Currency,
|
|
req.StartDate, req.EndDate, req.RenewalDate, req.DocumentURL).Scan(&id)
|
|
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "failed to create contract")
|
|
return
|
|
}
|
|
|
|
// Create reminder if renewal date is set
|
|
if req.RenewalDate != nil {
|
|
reminderDate := req.RenewalDate.AddDate(0, 0, -30) // 30 days before
|
|
h.DB.Exec(`
|
|
INSERT INTO boc_contract_reminders (contract_id, type, due_date, status)
|
|
VALUES ($1, 'renewal', $2, 'pending')
|
|
`, id, reminderDate)
|
|
}
|
|
|
|
writeJSON(w, http.StatusCreated, map[string]interface{}{
|
|
"id": id,
|
|
"message": "Contract created",
|
|
})
|
|
}
|
|
|
|
func (h *LegalHandler) GetContract(w http.ResponseWriter, r *http.Request) {
|
|
id := chi.URLParam(r, "id")
|
|
|
|
var c Contract
|
|
err := h.DB.QueryRow(`
|
|
SELECT id, title, counterparty, type, status, value, currency,
|
|
start_date, end_date, renewal_date, document_url, created_at
|
|
FROM boc_contracts WHERE id = $1
|
|
`, id).Scan(&c.ID, &c.Title, &c.Counterparty, &c.Type, &c.Status,
|
|
&c.Value, &c.Currency, &c.StartDate, &c.EndDate, &c.RenewalDate,
|
|
&c.DocumentURL, &c.CreatedAt)
|
|
|
|
if err == sql.ErrNoRows {
|
|
writeError(w, http.StatusNotFound, "contract not found")
|
|
return
|
|
}
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "database error")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, c)
|
|
}
|
|
|
|
func (h *LegalHandler) UpdateContract(w http.ResponseWriter, r *http.Request) {
|
|
id := chi.URLParam(r, "id")
|
|
|
|
var req Contract
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid request")
|
|
return
|
|
}
|
|
|
|
_, err := h.DB.Exec(`
|
|
UPDATE boc_contracts
|
|
SET title = $1, counterparty = $2, type = $3, status = $4,
|
|
value = $5, currency = $6, start_date = $7, end_date = $8,
|
|
renewal_date = $9, document_url = $10
|
|
WHERE id = $11
|
|
`, req.Title, req.Counterparty, req.Type, req.Status, req.Value, req.Currency,
|
|
req.StartDate, req.EndDate, req.RenewalDate, req.DocumentURL, id)
|
|
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "failed to update contract")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"message": "Contract updated",
|
|
})
|
|
}
|
|
|
|
func (h *LegalHandler) ListReminders(w http.ResponseWriter, r *http.Request) {
|
|
rows, err := h.DB.Query(`
|
|
SELECT r.id, r.contract_id, r.type, r.due_date, r.status,
|
|
c.title as contract_title
|
|
FROM boc_contract_reminders r
|
|
JOIN boc_contracts c ON r.contract_id = c.id
|
|
WHERE r.status = 'pending'
|
|
ORDER BY r.due_date ASC
|
|
LIMIT 50
|
|
`)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "database error")
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
reminders := []map[string]interface{}{}
|
|
for rows.Next() {
|
|
var id, contractID, reminderType, status, contractTitle string
|
|
var dueDate time.Time
|
|
if err := rows.Scan(&id, &contractID, &reminderType, &dueDate, &status, &contractTitle); err != nil {
|
|
continue
|
|
}
|
|
reminders = append(reminders, map[string]interface{}{
|
|
"id": id,
|
|
"contract_id": contractID,
|
|
"contract_title": contractTitle,
|
|
"type": reminderType,
|
|
"due_date": dueDate,
|
|
"status": status,
|
|
})
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{
|
|
"reminders": reminders,
|
|
"total": len(reminders),
|
|
})
|
|
}
|