Files
Crussell/backend/handlers/admin/settings.go
T
popertotsandSisyphus 3d0e2afc4c refactor(backend): migrate db.DB to db.Conn PoolProxy across all handlers
Replace direct *pgxpool.Pool usage with PoolProxy wrapper across the entire backend:

- db.DB renamed to db.Conn (*pgxpool.Pool -> *PoolProxy)
- JWT functions now accept context.Context instead of using context.Background()
- Handler DB calls route through PoolProxy for per-test transaction support
- Fixture/helper/testdb functions accept Querier interface for decoupling
- Query ordering fixed in bookings handlers: COUNT after data query to avoid pgx conn busy
- Time truncation fixed: time.Date instead of Truncate(24*time.Hour) for week start calc
- testmain_test.go files updated with SeedBaseline and NewPoolProxy

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-21 19:28:54 +01:00

160 lines
5.3 KiB
Go

package admin
import (
"crussell/db"
"encoding/json"
"log"
"net/http"
"strconv"
)
type BusinessSettings struct {
BusinessName string `json:"business_name"`
BusinessAddress string `json:"business_address"`
BusinessPhone *string `json:"business_phone,omitempty"`
BusinessEmail *string `json:"business_email,omitempty"`
VATRegistrationNumber *string `json:"vat_registration_number,omitempty"`
IsVATRegistered bool `json:"is_vat_registered"`
DefaultVATRate float64 `json:"default_vat_rate"`
CurrencyCode string `json:"currency_code"`
WebsiteURL *string `json:"website_url,omitempty"`
GiftCardExpiryMonths int `json:"gift_card_expiry_months"`
VoucherType string `json:"voucher_type"`
}
func GetBusinessSettings(w http.ResponseWriter, r *http.Request) {
var s BusinessSettings
err := db.Conn.QueryRow(r.Context(), `
SELECT business_name, business_address, business_phone, business_email,
vat_registration_number, is_vat_registered, default_vat_rate,
currency_code, website_url, gift_card_expiry_months, voucher_type
FROM business_settings
LIMIT 1
`).Scan(
&s.BusinessName, &s.BusinessAddress, &s.BusinessPhone, &s.BusinessEmail,
&s.VATRegistrationNumber, &s.IsVATRegistered, &s.DefaultVATRate,
&s.CurrencyCode, &s.WebsiteURL, &s.GiftCardExpiryMonths, &s.VoucherType,
)
if err != nil {
log.Printf("Failed to fetch business settings: %v", err)
http.Error(w, "Failed to fetch settings", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(s)
}
type UpdateBusinessSettingsRequest struct {
BusinessName *string `json:"business_name,omitempty"`
BusinessAddress *string `json:"business_address,omitempty"`
BusinessPhone *string `json:"business_phone,omitempty"`
BusinessEmail *string `json:"business_email,omitempty"`
VATRegistrationNumber *string `json:"vat_registration_number,omitempty"`
IsVATRegistered *bool `json:"is_vat_registered,omitempty"`
DefaultVATRate *float64 `json:"default_vat_rate,omitempty"`
WebsiteURL *string `json:"website_url,omitempty"`
GiftCardExpiryMonths *int `json:"gift_card_expiry_months,omitempty"`
VoucherType *string `json:"voucher_type,omitempty"`
}
func UpdateBusinessSettings(w http.ResponseWriter, r *http.Request) {
var req UpdateBusinessSettingsRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
if req.VoucherType != nil && *req.VoucherType != "SPV" && *req.VoucherType != "MPV" {
http.Error(w, "voucher_type must be 'SPV' or 'MPV'", http.StatusBadRequest)
return
}
if req.GiftCardExpiryMonths != nil && *req.GiftCardExpiryMonths < 1 {
http.Error(w, "gift_card_expiry_months must be at least 1", http.StatusBadRequest)
return
}
if req.DefaultVATRate != nil && (*req.DefaultVATRate < 0 || *req.DefaultVATRate > 100) {
http.Error(w, "default_vat_rate must be between 0 and 100", http.StatusBadRequest)
return
}
setClauses := []string{}
args := []interface{}{}
argIdx := 1
if req.BusinessName != nil {
setClauses = append(setClauses, "business_name = $"+strconv.Itoa(argIdx))
args = append(args, *req.BusinessName)
argIdx++
}
if req.BusinessAddress != nil {
setClauses = append(setClauses, "business_address = $"+strconv.Itoa(argIdx))
args = append(args, *req.BusinessAddress)
argIdx++
}
if req.BusinessPhone != nil {
setClauses = append(setClauses, "business_phone = $"+strconv.Itoa(argIdx))
args = append(args, *req.BusinessPhone)
argIdx++
}
if req.BusinessEmail != nil {
setClauses = append(setClauses, "business_email = $"+strconv.Itoa(argIdx))
args = append(args, *req.BusinessEmail)
argIdx++
}
if req.VATRegistrationNumber != nil {
setClauses = append(setClauses, "vat_registration_number = $"+strconv.Itoa(argIdx))
args = append(args, *req.VATRegistrationNumber)
argIdx++
}
if req.IsVATRegistered != nil {
setClauses = append(setClauses, "is_vat_registered = $"+strconv.Itoa(argIdx))
args = append(args, *req.IsVATRegistered)
argIdx++
}
if req.DefaultVATRate != nil {
setClauses = append(setClauses, "default_vat_rate = $"+strconv.Itoa(argIdx))
args = append(args, *req.DefaultVATRate)
argIdx++
}
if req.WebsiteURL != nil {
setClauses = append(setClauses, "website_url = $"+strconv.Itoa(argIdx))
args = append(args, *req.WebsiteURL)
argIdx++
}
if req.GiftCardExpiryMonths != nil {
setClauses = append(setClauses, "gift_card_expiry_months = $"+strconv.Itoa(argIdx))
args = append(args, *req.GiftCardExpiryMonths)
argIdx++
}
if req.VoucherType != nil {
setClauses = append(setClauses, "voucher_type = $"+strconv.Itoa(argIdx))
args = append(args, *req.VoucherType)
argIdx++
}
if len(setClauses) == 0 {
http.Error(w, "No fields to update", http.StatusBadRequest)
return
}
query := "UPDATE business_settings SET "
for i, clause := range setClauses {
if i > 0 {
query += ", "
}
query += clause
}
_, err := db.Conn.Exec(r.Context(), query, args...)
if err != nil {
log.Printf("Failed to update business settings: %v", err)
http.Error(w, "Failed to update settings", http.StatusInternalServerError)
return
}
GetBusinessSettings(w, r)
}