Established Participants and Tickets model. Migrated concepts.

This commit is contained in:
Pen Anderson 2026-03-04 10:53:42 -06:00
parent 0df93e1886
commit cd8e1e3b3b
22 changed files with 1345 additions and 191 deletions

View file

@ -10,7 +10,6 @@ import (
type ImportResult struct {
Inserted int `json:"inserted"`
Grouped int `json:"grouped"`
Skipped int `json:"skipped"`
Errors []string `json:"errors"`
}
@ -57,12 +56,14 @@ func (app *App) importCSV(r io.Reader) (ImportResult, error) {
}
var (
nameIdx, emailIdx, ticketIDIdx, ticketTypeIdx, noteIdx int
hasEmail, hasTicketID, hasTicketType, hasNote bool
nameIdx, emailIdx, ticketIDIdx, ticketTypeIdx int
hasEmail, hasTicketID, hasTicketType bool
isCrowdWork bool
)
if idx, ok := colIndex["patron name"]; ok {
// CrowdWork / ticketing platform format
isCrowdWork = true
nameIdx = idx
if idx, ok := colIndex["patron email"]; ok {
emailIdx, hasEmail = idx, true
@ -85,9 +86,6 @@ func (app *App) importCSV(r io.Reader) (ImportResult, error) {
if idx, ok := colIndex["ticket_type"]; ok {
ticketTypeIdx, hasTicketType = idx, true
}
if idx, ok := colIndex["note"]; ok {
noteIdx, hasNote = idx, true
}
} else {
return ImportResult{}, fmt.Errorf("CSV must have a 'name' or 'patron name' column")
}
@ -111,33 +109,49 @@ func (app *App) importCSV(r io.Reader) (ImportResult, error) {
continue
}
a := Attendee{Name: name}
email := ""
if hasEmail {
a.Email = strings.TrimSpace(csvGet(record, emailIdx))
email = strings.TrimSpace(csvGet(record, emailIdx))
}
externalID := ""
if hasTicketID {
a.TicketID = strings.TrimSpace(csvGet(record, ticketIDIdx))
externalID = strings.TrimSpace(csvGet(record, ticketIDIdx))
}
ticketType := ""
if hasTicketType {
a.TicketType = strings.TrimSpace(csvGet(record, ticketTypeIdx))
}
if hasNote {
a.Note = strings.TrimSpace(csvGet(record, noteIdx))
ticketType = strings.TrimSpace(csvGet(record, ticketTypeIdx))
}
_, err = app.createAttendee(a)
source := "manual"
orderID := ""
if isCrowdWork {
source = "crowdwork"
orderID = externalID
}
// Find or create participant when email is present.
var participantID *int
if email != "" {
p, _, err := app.upsertParticipant(email, name)
if err != nil {
result.Errors = append(result.Errors, fmt.Sprintf("line %d (%s): participant: %v", lineNum, name, err))
continue
}
if p != nil {
participantID = &p.ID
}
}
_, err = app.createTicket(Ticket{
ParticipantID: participantID,
Name: name,
TicketType: ticketType,
Source: source,
ExternalID: externalID,
OrderID: orderID,
})
if err != nil {
if strings.Contains(err.Error(), "UNIQUE constraint failed") {
// CrowdWork exports one row per ticket under the purchaser's name.
// If we have a ticket_id and the same (name, ticket_id) already exists,
// increment party_size instead of skipping.
if hasTicketID && a.TicketID != "" {
merged, mergeErr := app.incrementPartySize(a.Name, a.TicketID)
if mergeErr == nil && merged {
result.Grouped++
continue
}
}
result.Skipped++
} else {
result.Errors = append(result.Errors, fmt.Sprintf("line %d (%s): %v", lineNum, name, err))