fix(pdf): fix storage volume permissions blocking PDF generation
Named volume mounted root-owned over the app user's chown, so every PDF (orçamento, fatura, download) failed with 500. Entrypoint now fixes ownership on container start and drops to the app user. feat(dashboard): decouple pipeline state from period filter Status counts and recent OTs no longer disappear when an open order was created before the selected period window. feat(workorders): add vehicle/total columns, deadline urgency colors, on-time delivery saldo and efficiency metric, plate search Expose completed_at from wo_status_log so the frontend can compare actual completion date against the deadline. Add "Eficiência de Entrega" metric to Dashboard and Reports. feat(reports): add dedicated vehicle service history report New page with per-vehicle summary (OT count, total spent, last visit) and full itemized service history with print output. chore: relabel OT status "Concluir OT" -> "Concluída" and "Iniciar Trabalho" -> "Em Progresso" (action buttons unchanged) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+4
-3
@@ -6,12 +6,13 @@ COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server
|
||||
|
||||
FROM alpine:3.19
|
||||
RUN apk --no-cache add ca-certificates tzdata
|
||||
RUN apk --no-cache add ca-certificates tzdata su-exec
|
||||
RUN addgroup -S app && adduser -S app -G app
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/server .
|
||||
COPY --from=builder /app/migrations ./migrations
|
||||
RUN mkdir -p /app/storage && chown -R app:app /app
|
||||
USER app
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN mkdir -p /app/storage && chown -R app:app /app && chmod +x /docker-entrypoint.sh
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["./server"]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p /app/storage
|
||||
chown -R app:app /app/storage
|
||||
|
||||
exec su-exec app "$@"
|
||||
@@ -23,8 +23,15 @@ type WorkOrder struct {
|
||||
CreatedBy *string `json:"created_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CompletedAt *time.Time `json:"completed_at"`
|
||||
}
|
||||
|
||||
const completedAtSubquery = `(
|
||||
SELECT changed_at FROM wo_status_log
|
||||
WHERE work_order_id = work_orders.id AND to_status = 'completed'
|
||||
ORDER BY changed_at DESC LIMIT 1
|
||||
)`
|
||||
|
||||
type WOItem struct {
|
||||
ID string `json:"id"`
|
||||
WorkOrderID string `json:"work_order_id"`
|
||||
@@ -76,7 +83,8 @@ func ValidateTransition(from, to string) error {
|
||||
func ListWorkOrders(ctx context.Context, conn *pgxpool.Conn, status string) ([]*WorkOrder, error) {
|
||||
q := `SELECT id, number, client_id, vehicle_id, status,
|
||||
COALESCE(internal_notes,''), COALESCE(client_notes,''), COALESCE(eta_days,1), real_deadline,
|
||||
COALESCE(payment_method,''), payment_date, created_by, created_at, updated_at
|
||||
COALESCE(payment_method,''), payment_date, created_by, created_at, updated_at,
|
||||
` + completedAtSubquery + `
|
||||
FROM work_orders`
|
||||
args := []any{}
|
||||
if status != "" {
|
||||
@@ -94,7 +102,7 @@ func ListWorkOrders(ctx context.Context, conn *pgxpool.Conn, status string) ([]*
|
||||
var wo WorkOrder
|
||||
if err := rows.Scan(&wo.ID, &wo.Number, &wo.ClientID, &wo.VehicleID,
|
||||
&wo.Status, &wo.InternalNotes, &wo.ClientNotes, &wo.ETADays, &wo.RealDeadline,
|
||||
&wo.PaymentMethod, &wo.PaymentDate, &wo.CreatedBy, &wo.CreatedAt, &wo.UpdatedAt); err != nil {
|
||||
&wo.PaymentMethod, &wo.PaymentDate, &wo.CreatedBy, &wo.CreatedAt, &wo.UpdatedAt, &wo.CompletedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list = append(list, &wo)
|
||||
@@ -180,11 +188,12 @@ func GetWorkOrderDetail(ctx context.Context, conn *pgxpool.Conn, id string) (*Wo
|
||||
err := conn.QueryRow(ctx, `
|
||||
SELECT id, number, client_id, vehicle_id, status,
|
||||
COALESCE(internal_notes,''), COALESCE(client_notes,''), COALESCE(eta_days,1), real_deadline,
|
||||
COALESCE(payment_method,''), payment_date, created_by, created_at, updated_at
|
||||
COALESCE(payment_method,''), payment_date, created_by, created_at, updated_at,
|
||||
`+completedAtSubquery+`
|
||||
FROM work_orders WHERE id=$1`, id).
|
||||
Scan(&wo.ID, &wo.Number, &wo.ClientID, &wo.VehicleID,
|
||||
&wo.Status, &wo.InternalNotes, &wo.ClientNotes, &wo.ETADays, &wo.RealDeadline,
|
||||
&wo.PaymentMethod, &wo.PaymentDate, &wo.CreatedBy, &wo.CreatedAt, &wo.UpdatedAt)
|
||||
&wo.PaymentMethod, &wo.PaymentDate, &wo.CreatedBy, &wo.CreatedAt, &wo.UpdatedAt, &wo.CompletedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user