Bei Firmenanlage (Registrierung + Betreiber-Firmenanlage) müssen jetzt Adresse (Straße, PLZ, Ort, Land) und Abrechnungsdaten (Rechnungsemail, optional USt-IdNr.) erfasst werden, nicht nur der Firmenname (Migration 0023). USt-IdNr. bewusst optional - Kleinunternehmer nach §19 UStG haben keine. Neue Seite /verwaltung/firma (admin-only) zum Einsehen/ Nachtragen für bestehende Firmen. store.CreateAccount nimmt jetzt ein AccountInput statt nur einen Namen entgegen (Signaturänderung betrifft ~20 Testaufrufe, mechanisch umgestellt). register.html/ betreiber_account_neu.html auf form-card/form-grid umgestellt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
141 lines
3.9 KiB
Go
141 lines
3.9 KiB
Go
package store_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/netcell-it/deklarix/internal/store"
|
|
)
|
|
|
|
func TestAppUserRoleAllowsBetreiber(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
|
|
u, err := s.CreateUser(ctx, accID, "admin@example.com", "hash", "betreiber")
|
|
if err != nil {
|
|
t.Fatalf("CreateUser mit role=betreiber: %v", err)
|
|
}
|
|
if u.Role != "betreiber" {
|
|
t.Fatalf("Role = %q, want betreiber", u.Role)
|
|
}
|
|
}
|
|
|
|
func TestAppUserRoleRejectsUnknownRole(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
|
|
if _, err := s.CreateUser(ctx, accID, "unbekannt@example.com", "hash", "kanzlei"); err == nil {
|
|
t.Fatal("expected the old role 'kanzlei' to be rejected after the product pivot")
|
|
}
|
|
}
|
|
|
|
func TestListAccounts(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
before, err := s.ListAccounts(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ListAccounts: %v", err)
|
|
}
|
|
acc, err := s.CreateAccount(ctx, store.AccountInput{Name: "Neuer Mandant fuer ListAccounts"})
|
|
if err != nil {
|
|
t.Fatalf("CreateAccount: %v", err)
|
|
}
|
|
|
|
after, err := s.ListAccounts(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ListAccounts: %v", err)
|
|
}
|
|
if len(after) != len(before)+1 {
|
|
t.Fatalf("expected exactly one more account, got %d -> %d", len(before), len(after))
|
|
}
|
|
found := false
|
|
for _, a := range after {
|
|
if a.ID == acc.ID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("expected the newly created account in ListAccounts")
|
|
}
|
|
}
|
|
|
|
func TestListUsersForAccount(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
otherAccID := testAccountID(t, s)
|
|
|
|
if _, err := s.CreateUser(ctx, accID, "eins@example.com", "hash", "mitarbeiter"); err != nil {
|
|
t.Fatalf("CreateUser: %v", err)
|
|
}
|
|
if _, err := s.CreateUser(ctx, accID, "zwei@example.com", "hash", "verantwortlicher"); err != nil {
|
|
t.Fatalf("CreateUser: %v", err)
|
|
}
|
|
if _, err := s.CreateUser(ctx, otherAccID, "fremd@example.com", "hash", "mitarbeiter"); err != nil {
|
|
t.Fatalf("CreateUser: %v", err)
|
|
}
|
|
|
|
list, err := s.ListUsersForAccount(ctx, accID)
|
|
if err != nil {
|
|
t.Fatalf("ListUsersForAccount: %v", err)
|
|
}
|
|
if len(list) != 2 {
|
|
t.Fatalf("expected exactly 2 users for this account, got %d: %+v", len(list), list)
|
|
}
|
|
}
|
|
|
|
func TestAuditLogCreateAndList(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
admin, err := s.CreateUser(ctx, accID, "admin-audit@example.com", "hash", "betreiber")
|
|
if err != nil {
|
|
t.Fatalf("CreateUser: %v", err)
|
|
}
|
|
|
|
entry, err := s.CreateAuditEntry(ctx, admin.ID, "werkzeug.aktualisiert", "werkzeug", accID, "manuell geprüft")
|
|
if err != nil {
|
|
t.Fatalf("CreateAuditEntry: %v", err)
|
|
}
|
|
if entry.ActorUserID != admin.ID {
|
|
t.Fatalf("ActorUserID = %q, want %q", entry.ActorUserID, admin.ID)
|
|
}
|
|
|
|
list, err := s.ListAuditLog(ctx, 10)
|
|
if err != nil {
|
|
t.Fatalf("ListAuditLog: %v", err)
|
|
}
|
|
if len(list) == 0 {
|
|
t.Fatal("expected at least one audit entry")
|
|
}
|
|
if list[0].ID != entry.ID {
|
|
t.Fatalf("expected the newest entry first, got %+v", list[0])
|
|
}
|
|
}
|
|
|
|
func TestAuditLogIsAppendOnly(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
admin, err := s.CreateUser(ctx, accID, "admin-appendonly@example.com", "hash", "betreiber")
|
|
if err != nil {
|
|
t.Fatalf("CreateUser: %v", err)
|
|
}
|
|
entry, err := s.CreateAuditEntry(ctx, admin.ID, "werkzeug.aktualisiert", "werkzeug", accID, "")
|
|
if err != nil {
|
|
t.Fatalf("CreateAuditEntry: %v", err)
|
|
}
|
|
|
|
_, err = s.Pool.Exec(ctx, `UPDATE audit_log SET action = 'geaendert' WHERE id = $1`, entry.ID)
|
|
if err == nil {
|
|
t.Fatal("expected UPDATE on audit_log to be rejected by the append-only trigger")
|
|
}
|
|
_, err = s.Pool.Exec(ctx, `DELETE FROM audit_log WHERE id = $1`, entry.ID)
|
|
if err == nil {
|
|
t.Fatal("expected DELETE on audit_log to be rejected by the append-only trigger")
|
|
}
|
|
}
|