invoices: multi-crypto payment support
One asset per invoice from a registry (lib/crypto_asset.rb): BTC, LTC, ETH, XMR, SOL, ALGO, USDT/USDC on ERC-20/TRC-20/BEP-20/Solana/Algorand. Migration 003 generalizes the ltc_* columns to crypto_* + crypto_coin (existing LTC invoices backfilled). QR payload adapts per asset: BIP21 amount URIs where supported, bare address for tokens with a network hint on the PDF. Default addresses come from the CRYPTO_ADDRESSES secret (JSON code=>address); LTC_ADDRESS still works as legacy.
This commit is contained in:
parent
f9c7001e7a
commit
0fbb6ee809
20 changed files with 410 additions and 143 deletions
|
|
@ -83,28 +83,39 @@
|
|||
<textarea id="notes" name="notes" rows="3" maxlength="1000"><%= @form_values[:notes] %></textarea>
|
||||
</div>
|
||||
|
||||
<h2>Litecoin payment <span class="optional">(optional)</span></h2>
|
||||
<p class="optional" style="margin-top:-6px;">Leave the address blank to omit the LTC block and QR from the invoice.</p>
|
||||
<div class="field">
|
||||
<label for="ltc_address">LTC address</label>
|
||||
<input type="text" id="ltc_address" name="ltc_address"
|
||||
value="<%= @form_values[:ltc_address] || ENV['LTC_ADDRESS'] %>"
|
||||
placeholder="ltc1..." maxlength="90" />
|
||||
<h2>Crypto payment <span class="optional">(optional)</span></h2>
|
||||
<p class="optional" style="margin-top:-6px;">Leave the address blank to omit the crypto block and QR from the invoice.</p>
|
||||
<div class="invoice-grid">
|
||||
<div class="field">
|
||||
<label for="crypto_coin">Coin</label>
|
||||
<select id="crypto_coin" name="crypto_coin">
|
||||
<% CryptoAsset::CODES.each do |c| %>
|
||||
<option value="<%= c %>" <%= 'selected' if (@form_values[:crypto_coin] || 'LTC') == c %>><%= c %> — <%= CryptoAsset.name(c) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="crypto_address">Address</label>
|
||||
<input type="text" id="crypto_address" name="crypto_address"
|
||||
value="<%= @form_values[:crypto_address] || CryptoAsset.default_addresses[@form_values[:crypto_coin] || 'LTC'] %>"
|
||||
placeholder="payout address" maxlength="128" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-grid">
|
||||
<div class="field">
|
||||
<label for="ltc_rate">LTC rate (1 LTC in <span id="ltc-rate-ccy">currency</span>)</label>
|
||||
<input type="text" id="ltc_rate" name="ltc_rate" value="<%= @form_values[:ltc_rate] %>"
|
||||
<label for="crypto_rate">Rate (1 <span id="crypto-rate-coin">coin</span> in <span id="crypto-rate-ccy">currency</span>)</label>
|
||||
<input type="text" id="crypto_rate" name="crypto_rate" value="<%= @form_values[:crypto_rate] %>"
|
||||
placeholder="e.g. 85.20" inputmode="decimal" />
|
||||
<button type="button" id="fetch-ltc-rate" class="link-button">↻ Fetch live</button>
|
||||
<span id="ltc-rate-status" class="optional"></span>
|
||||
<button type="button" id="fetch-crypto-rate" class="link-button">↻ Fetch live</button>
|
||||
<span id="crypto-rate-status" class="optional"></span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="ltc_amount">LTC amount due <span class="optional">(auto from rate; editable)</span></label>
|
||||
<input type="text" id="ltc_amount" name="ltc_amount" value="<%= @form_values[:ltc_amount] %>"
|
||||
<label for="crypto_amount">Amount due <span class="optional">(auto from rate; editable)</span></label>
|
||||
<input type="text" id="crypto_amount" name="crypto_amount" value="<%= @form_values[:crypto_amount] %>"
|
||||
placeholder="auto" inputmode="decimal" />
|
||||
</div>
|
||||
</div>
|
||||
<script type="application/json" id="crypto-defaults"><%== CryptoAsset.default_addresses.to_json %></script>
|
||||
|
||||
<button type="submit">Create invoice</button>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@
|
|||
<% if @invoice.paid_at %>
|
||||
<dt>Paid at</dt><dd class="mono"><%= @invoice.paid_at.utc.strftime('%Y-%m-%d %H:%M UTC') %></dd>
|
||||
<% end %>
|
||||
<% if @invoice.ltc? %>
|
||||
<dt>LTC</dt>
|
||||
<% if @invoice.crypto? %>
|
||||
<dt><%= @invoice.crypto_coin %></dt>
|
||||
<dd class="mono">
|
||||
<% if (amt = @invoice.ltc_amount_due) %><%= amt.to_s('F').sub(/\.?0+$/, '') %> LTC<% if @invoice.ltc_rate %> @ <%= @invoice.ltc_rate.to_s('F').sub(/(\.\d*?)0+$/, '\1').sub(/\.$/, '') %> <%= @invoice.currency %><% end %><br /><% end %>
|
||||
<span style="word-break:break-all;"><%= @invoice.ltc_address %></span>
|
||||
<% if (amt = @invoice.crypto_amount_due) %><%= fmt_crypto(amt) %> <%= @invoice.crypto_coin %><% if @invoice.crypto_rate %> @ <%= fmt_rate(@invoice.crypto_rate) %> <%= @invoice.currency %><% end %><br /><% end %>
|
||||
<span style="word-break:break-all;"><%= @invoice.crypto_address %></span>
|
||||
</dd>
|
||||
<% end %>
|
||||
</dl>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
<% unless @invoice.currency == 'GEL' %>
|
||||
<dt>In GEL</dt><dd class="mono">GEL <%= '%.2f' % @invoice.total_gel %> <span class="optional">@ <%= fmt_rate(@invoice.gel_rate) %></span></dd>
|
||||
<% end %>
|
||||
<% if @invoice.ltc? && (ltc = @invoice.ltc_amount_due) %>
|
||||
<dt>In LTC</dt><dd class="mono"><%= fmt_ltc(ltc) %> LTC<% if @invoice.ltc_rate %> <span class="optional">@ <%= fmt_rate(@invoice.ltc_rate) %> <%= @invoice.currency %></span><% end %></dd>
|
||||
<% if @invoice.crypto? && (amt = @invoice.crypto_amount_due) %>
|
||||
<dt>In <%= @invoice.crypto_coin %></dt><dd class="mono"><%= fmt_crypto(amt) %> <%= @invoice.crypto_coin %><% if @invoice.crypto_rate %> <span class="optional">@ <%= fmt_rate(@invoice.crypto_rate) %> <%= @invoice.currency %></span><% end %></dd>
|
||||
<% end %>
|
||||
<dt>Status</dt><dd><span class="badge badge-<%= @invoice.status %>"><%= @invoice.status %></span></dd>
|
||||
</dl>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue