invoices: cancel with stamped PDF, superuser-only hiding
An invoice issued by mistake could only be left pending or marked paid. Add cancel (with an optional reason) and reinstate. Cancelling renders a third PDF variant with a diagonal CANCELLED stamp and the date/reason, and it becomes the current one, so the client's link and download show the invoice as void. Cancelled wins over paid in the status, and marking a cancelled invoice paid is refused. Superusers can also hide an invoice: it disappears from the admin list, dashboard and invoice pages for every other user, while the client's public link keeps working. Assisted-by: Claude:opus-5
This commit is contained in:
parent
97919f3f71
commit
eeac07ed34
10 changed files with 231 additions and 13 deletions
|
|
@ -24,7 +24,7 @@
|
|||
<tbody>
|
||||
<% @invoices.each do |inv| %>
|
||||
<tr>
|
||||
<td class="mono"><%= inv.number %></td>
|
||||
<td class="mono"><%= inv.number %><% if inv.hidden %> <span class="badge badge-hidden">hidden</span><% end %></td>
|
||||
<td><%= inv.client_name %></td>
|
||||
<td class="mono"><%= inv.issued_on.strftime('%Y-%m-%d') %></td>
|
||||
<td class="num mono"><%= inv.currency %> <%= '%.2f' % inv.total %></td>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@
|
|||
<dt>Due</dt><dd class="mono"><%= @invoice.due_on.strftime('%Y-%m-%d') %></dd>
|
||||
<dt>Total</dt><dd class="mono"><%= @invoice.currency %> <%= '%.2f' % @invoice.total %><% unless @invoice.currency == 'GEL' %> · GEL <%= '%.2f' % @invoice.total_gel %><% end %></dd>
|
||||
<dt>Status</dt><dd><span class="badge badge-<%= @invoice.status %>"><%= @invoice.status %></span></dd>
|
||||
<% if @invoice.cancelled? %>
|
||||
<dt>Cancelled</dt><dd class="mono"><%= @invoice.cancelled_at.utc.strftime('%Y-%m-%d %H:%M UTC') %><%= " · #{@invoice.cancel_reason}" if @invoice.cancel_reason %></dd>
|
||||
<% end %>
|
||||
<% if @invoice.hidden %>
|
||||
<dt>Visibility</dt><dd><span class="badge badge-hidden">hidden</span> <span class="optional">only superusers see it in the admin</span></dd>
|
||||
<% end %>
|
||||
<% if @invoice.paid_at %>
|
||||
<dt>Paid at</dt><dd class="mono"><%= @invoice.paid_at.utc.strftime('%Y-%m-%d %H:%M UTC') %></dd>
|
||||
<% end %>
|
||||
|
|
@ -35,10 +41,34 @@
|
|||
<code class="mono">https://asxp.io/i/<%= @invoice.uuid %></code>
|
||||
</p>
|
||||
<% if can?('invoices', 'write') %>
|
||||
<form method="post" action="/admin/invoices/<%= @invoice.uuid %>/paid" style="margin-top: 14px;">
|
||||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||||
<button type="submit">
|
||||
<% if @invoice.paid? %>Mark unpaid<% else %>Mark paid<% end %>
|
||||
<div class="invoice-actions">
|
||||
<% unless @invoice.cancelled? %>
|
||||
<form method="post" action="/admin/invoices/<%= @invoice.uuid %>/paid">
|
||||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||||
<button type="submit" class="link-button"><%= @invoice.paid? ? 'Mark unpaid' : 'Mark paid' %></button>
|
||||
</form>
|
||||
<% end %>
|
||||
<% if @invoice.cancelled? %>
|
||||
<form method="post" action="/admin/invoices/<%= @invoice.uuid %>/reinstate">
|
||||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||||
<button type="submit" class="link-button">↺ Reinstate</button>
|
||||
</form>
|
||||
<% else %>
|
||||
<form method="post" action="/admin/invoices/<%= @invoice.uuid %>/cancel" class="invoice-form cancel-form"
|
||||
onsubmit="return confirm('Cancel this invoice? The client link and PDF will show it as CANCELLED.')">
|
||||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||||
<input type="text" name="reason" maxlength="500" placeholder="Reason (optional, printed on the PDF)" />
|
||||
<button type="submit" class="link-button danger">Cancel invoice</button>
|
||||
</form>
|
||||
<% end %>
|
||||
<% if current_user.superuser %>
|
||||
<form method="post" action="/admin/invoices/<%= @invoice.uuid %>/hide">
|
||||
<input type="hidden" name="authenticity_token" value="<%= csrf_token %>" />
|
||||
<button type="submit" class="link-button"><%= @invoice.hidden ? 'Unhide' : 'Hide (superusers only)' %></button>
|
||||
</form>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</button>
|
||||
</form>
|
||||
<% end %>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue