|
|
|
@ -19,6 +19,11 @@ type StatusButton struct { |
|
|
|
ConfirmText string |
|
|
|
} |
|
|
|
|
|
|
|
// Cannot move from draft status to pending_accounting status
|
|
|
|
// Cannot move from draft status to processed status
|
|
|
|
// Cannot move from draft status to failed status
|
|
|
|
// Cannot move from failed status to pending_accounting status
|
|
|
|
// Cannot move from failed status to processed status
|
|
|
|
var statusButtons = []StatusButton{ |
|
|
|
{"draft", "Draft Invoice", "success-button", "Are you sure you want to draft this invoice?"}, |
|
|
|
{"ok", "Ok Invoice", "success-button", "Are you sure you want to mark this invoice as OK?"}, |
|
|
|
@ -119,28 +124,44 @@ func handleInvoiceSearch(w http.ResponseWriter, r *http.Request, session *api.Se |
|
|
|
func getInvoiceStatusButtons(invoiceID, currentStatus string) []map[string]string { |
|
|
|
var buttons []map[string]string |
|
|
|
|
|
|
|
switch currentStatus { |
|
|
|
case "processed": |
|
|
|
// Only allow voiding for processed invoices
|
|
|
|
for _, button := range statusButtons { |
|
|
|
if button.Status == "void" { |
|
|
|
buttons = append(buttons, map[string]string{ |
|
|
|
"Action": fmt.Sprintf("/%s-invoice/%s", button.Status, invoiceID), |
|
|
|
"Label": button.Label, |
|
|
|
"Class": button.Class, |
|
|
|
"ConfirmText": button.ConfirmText, |
|
|
|
}) |
|
|
|
break |
|
|
|
} |
|
|
|
// Define allowed transitions for each status
|
|
|
|
allowedTransitions := map[string]map[string]bool{ |
|
|
|
"draft": { |
|
|
|
"ok": true, |
|
|
|
"void": true, |
|
|
|
// draft cannot transition to pending_accounting, processed, or failed
|
|
|
|
}, |
|
|
|
"ok": { |
|
|
|
"draft": true, |
|
|
|
"failed": true, |
|
|
|
"pending_accounting": true, |
|
|
|
"processed": true, |
|
|
|
"void": true, |
|
|
|
}, |
|
|
|
"failed": { |
|
|
|
"draft": true, |
|
|
|
"ok": true, |
|
|
|
"void": true, |
|
|
|
// failed cannot transition to pending_accounting or processed
|
|
|
|
}, |
|
|
|
"pending_accounting": { |
|
|
|
"failed": true, |
|
|
|
"processed": true, |
|
|
|
"void": true, |
|
|
|
}, |
|
|
|
"processed": { |
|
|
|
"void": true, |
|
|
|
// processed can only be voided
|
|
|
|
}, |
|
|
|
"void": { |
|
|
|
// void has no allowed transitions
|
|
|
|
}, |
|
|
|
} |
|
|
|
case "void": |
|
|
|
// No buttons for voided invoices
|
|
|
|
return buttons |
|
|
|
default: |
|
|
|
// For all other statuses, show all buttons except the current status
|
|
|
|
|
|
|
|
// If we have defined transitions for this status, use them
|
|
|
|
if transitions, exists := allowedTransitions[currentStatus]; exists { |
|
|
|
for _, button := range statusButtons { |
|
|
|
fmt.Printf("btn status: %s, curr status: %s", button.Status, currentStatus) |
|
|
|
if button.Status != currentStatus { |
|
|
|
if transitions[button.Status] { |
|
|
|
buttons = append(buttons, map[string]string{ |
|
|
|
"Action": fmt.Sprintf("/%s-invoice/%s", button.Status, invoiceID), |
|
|
|
"Label": button.Label, |
|
|
|
@ -223,21 +244,7 @@ func UpdateInvoiceStatusHandler(w http.ResponseWriter, r *http.Request) { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// If successful, fetch the updated invoice details
|
|
|
|
invoice, err := session.GetInvoice(invoiceID) |
|
|
|
if err != nil { |
|
|
|
log.Printf("Error fetching updated invoice: %v", err) |
|
|
|
http.Error(w, fmt.Sprintf("Error fetching updated invoice: %v", err), http.StatusInternalServerError) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
log.Printf("Updated invoice after status change to %s: %+v", status, invoice) |
|
|
|
|
|
|
|
// Render the updated invoice details
|
|
|
|
err = root.WebTemplates.ExecuteTemplate(w, "invoice_search_results", invoice) |
|
|
|
if err != nil { |
|
|
|
log.Printf("Error executing template: %v", err) |
|
|
|
http.Error(w, "Error rendering template", http.StatusInternalServerError) |
|
|
|
return |
|
|
|
} |
|
|
|
mockReq, _ := http.NewRequest("GET", fmt.Sprintf("?search=%s", invoiceID), nil) |
|
|
|
mockReq = mockReq.WithContext(r.Context()) |
|
|
|
handleInvoiceSearch(w, mockReq, session) |
|
|
|
} |
|
|
|
|