Packages
phoenix_kit
1.7.21
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/billing/web/payment_confirmation_print.html.heex
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Payment Confirmation {@confirmation_number} - {@project_title}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #1f2937;
background: #f3f4f6;
padding: 20px;
}
.confirmation-container {
max-width: 800px;
margin: 0 auto;
background: white;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
border-radius: 8px;
overflow: hidden;
}
.print-controls {
max-width: 800px;
margin: 0 auto 20px;
display: flex;
gap: 10px;
justify-content: flex-end;
}
.print-controls button,
.print-controls a {
padding: 10px 20px;
border-radius: 6px;
font-weight: 500;
cursor: pointer;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-print {
background: #059669;
color: white;
border: none;
}
.btn-print:hover {
background: #047857;
}
.btn-back {
background: white;
color: #374151;
border: 1px solid #d1d5db;
}
.btn-back:hover {
background: #f9fafb;
}
.confirmation-header {
background: linear-gradient(135deg, #047857 0%, #059669 100%);
color: white;
padding: 40px;
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.confirmation-title h1 {
font-size: 28px;
font-weight: 700;
margin-bottom: 5px;
}
.confirmation-number {
font-size: 18px;
opacity: 0.9;
}
.confirmation-status {
padding: 8px 16px;
border-radius: 20px;
font-weight: 600;
font-size: 13px;
text-transform: uppercase;
background: #d1fae5;
color: #047857;
}
.confirmation-status.partial {
background: #fef3c7;
color: #92400e;
}
.confirmation-body {
padding: 40px;
}
.confirmation-meta {
display: flex;
justify-content: space-between;
margin-bottom: 40px;
padding-bottom: 30px;
border-bottom: 2px solid #e5e7eb;
}
.meta-section h3 {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
color: #6b7280;
margin-bottom: 10px;
}
.meta-section p {
line-height: 1.8;
}
.meta-section strong {
font-weight: 600;
}
.company-name {
font-size: 16px;
font-weight: 600;
color: #1f2937;
}
.payment-box {
background: #d1fae5;
border: 1px solid #059669;
border-radius: 8px;
padding: 24px;
margin-bottom: 30px;
}
.payment-box.partial {
background: #fef3c7;
border-color: #f59e0b;
}
.payment-box h4 {
font-size: 16px;
font-weight: 600;
color: #047857;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 10px;
}
.payment-box.partial h4 {
color: #92400e;
}
.payment-details-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.payment-detail {
display: flex;
flex-direction: column;
}
.payment-detail .label {
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #059669;
margin-bottom: 4px;
}
.payment-box.partial .payment-detail .label {
color: #b45309;
}
.payment-detail .value {
font-weight: 600;
color: #047857;
}
.payment-box.partial .payment-detail .value {
color: #92400e;
}
.balance-section {
display: flex;
gap: 20px;
margin-bottom: 30px;
}
.balance-box {
flex: 1;
padding: 20px;
border-radius: 8px;
text-align: center;
}
.balance-box.invoice-total {
background: #f3f4f6;
border: 1px solid #e5e7eb;
}
.balance-box.paid-total {
background: #d1fae5;
border: 1px solid #059669;
}
.balance-box.remaining {
background: #fef3c7;
border: 1px solid #f59e0b;
}
.balance-box.remaining.zero {
background: #d1fae5;
border-color: #059669;
}
.balance-box .label {
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #6b7280;
margin-bottom: 8px;
}
.balance-box .value {
font-size: 24px;
font-weight: 700;
}
.balance-box.invoice-total .value {
color: #374151;
}
.balance-box.paid-total .value {
color: #047857;
}
.balance-box.remaining .value {
color: #b45309;
}
.balance-box.remaining.zero .value {
color: #047857;
}
.invoice-reference {
background: #f9fafb;
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
}
.invoice-reference h4 {
font-size: 14px;
font-weight: 600;
color: #374151;
margin-bottom: 12px;
}
.invoice-reference-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.invoice-ref-item .label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #6b7280;
margin-bottom: 4px;
}
.invoice-ref-item .value {
font-weight: 500;
color: #1f2937;
}
.confirmation-footer {
background: #f9fafb;
padding: 30px 40px;
border-top: 1px solid #e5e7eb;
}
.footer-company {
margin-bottom: 15px;
}
.footer-company .name {
font-weight: 600;
color: #1f2937;
}
.footer-company .details {
font-size: 13px;
color: #6b7280;
}
.footer-note {
font-size: 13px;
color: #6b7280;
}
@media print {
body {
background: white;
padding: 0;
}
.print-controls {
display: none;
}
.confirmation-container {
box-shadow: none;
border-radius: 0;
}
.confirmation-header {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.confirmation-status,
.payment-box,
.balance-box {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
</style>
</head>
<body>
<div class="print-controls">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/invoices/#{@invoice.id}")}
class="btn-back"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m15 18-6-6 6-6" />
</svg>
Back
</.link>
<button onclick="window.print()" class="btn-print">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" /><path d="M6 9V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6" /><rect
x="6"
y="14"
width="12"
height="8"
rx="1"
/>
</svg>
Print
</button>
</div>
<div class="confirmation-container">
<div class="confirmation-header">
<div class="confirmation-title">
<h1>PAYMENT CONFIRMATION</h1>
<div class="confirmation-number">{@confirmation_number}</div>
</div>
<%= if @payment_context.is_final_payment do %>
<div class="confirmation-status">PAID IN FULL</div>
<% else %>
<div class="confirmation-status partial">PARTIAL PAYMENT</div>
<% end %>
</div>
<div class="confirmation-body">
<div class="confirmation-meta">
<div class="meta-section">
<h3>Received From</h3>
<p>
<%= if @invoice.billing_details && map_size(@invoice.billing_details) > 0 do %>
<%= if @invoice.billing_details["type"] == "company" do %>
<span class="company-name">{@invoice.billing_details["company_name"]}</span>
<br />
<%= if @invoice.billing_details["company_vat_number"] do %>
VAT: {@invoice.billing_details["company_vat_number"]}<br />
<% end %>
<% else %>
<span class="company-name">
{@invoice.billing_details["first_name"]} {@invoice.billing_details[
"last_name"
]}
</span>
<br />
<% end %>
<%= if @invoice.billing_details["address_line1"] do %>
{@invoice.billing_details["address_line1"]}<br />
<% end %>
<%= if @invoice.billing_details["city"] do %>
{@invoice.billing_details["city"]}
<%= if @invoice.billing_details["postal_code"] do %>
, {@invoice.billing_details["postal_code"]}
<% end %>
<br />
<% end %>
<%= if @invoice.billing_details["country"] do %>
{@invoice.billing_details["country"]}
<% end %>
<% else %>
<%= if @invoice.user do %>
<span class="company-name">{@invoice.user.email}</span>
<% else %>
<em>No billing information</em>
<% end %>
<% end %>
</p>
</div>
<div class="meta-section">
<h3>Received By</h3>
<p>
<strong>{@company.name}</strong>
<br />
<%= for line <- String.split(@company.address || "", "\n") do %>
{line}<br />
<% end %>
<%= if @company.vat != "" do %>
VAT: {@company.vat}
<% end %>
</p>
</div>
<div class="meta-section" style="text-align: right;">
<h3>Payment Details</h3>
<p>
<strong>Confirmation #:</strong> {@confirmation_number}<br />
<strong>Payment Date:</strong>
{Calendar.strftime(@transaction.inserted_at, "%B %d, %Y")}<br />
<strong>Payment Method:</strong> {String.capitalize(@transaction.payment_method)}<br />
<strong>Currency:</strong> {@invoice.currency}
</p>
</div>
</div>
<%!-- Payment Amount Box --%>
<div class={["payment-box", if(!@payment_context.is_final_payment, do: "partial")]}>
<h4>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" /><polyline points="22 4 12 14.01 9 11.01" />
</svg>
<%= if @payment_context.is_final_payment do %>
Payment Received - Invoice Paid in Full
<% else %>
Partial Payment Received
<% end %>
</h4>
<div class="payment-details-grid">
<div class="payment-detail">
<span class="label">Amount Received</span>
<span class="value" style="font-size: 24px;">
{Decimal.to_string(@transaction.amount, :normal)} {@invoice.currency}
</span>
</div>
<div class="payment-detail">
<span class="label">Payment Date & Time</span>
<span class="value">
{Calendar.strftime(@transaction.inserted_at, "%B %d, %Y at %H:%M")}
</span>
</div>
<div class="payment-detail">
<span class="label">Transaction Number</span>
<span class="value">{@transaction.transaction_number}</span>
</div>
<div class="payment-detail">
<span class="label">
Payment #{@payment_context.payment_number} of {@payment_context.total_payments}
</span>
<span class="value">{String.capitalize(@transaction.payment_method)}</span>
</div>
</div>
</div>
<%!-- Balance Summary --%>
<div class="balance-section">
<div class="balance-box invoice-total">
<div class="label">Invoice Total</div>
<div class="value">
{Decimal.to_string(@invoice.total, :normal)} {@invoice.currency}
</div>
</div>
<div class="balance-box paid-total">
<div class="label">Total Paid</div>
<div class="value">
{Decimal.to_string(@payment_context.total_paid_so_far, :normal)} {@invoice.currency}
</div>
</div>
<div class={[
"balance-box remaining",
if(Decimal.eq?(@payment_context.remaining_balance, Decimal.new(0)), do: "zero")
]}>
<div class="label">Remaining Balance</div>
<div class="value">
{Decimal.to_string(@payment_context.remaining_balance, :normal)} {@invoice.currency}
</div>
</div>
</div>
<%!-- Invoice Reference --%>
<div class="invoice-reference">
<h4>Invoice Reference</h4>
<div class="invoice-reference-grid">
<div class="invoice-ref-item">
<div class="label">Invoice Number</div>
<div class="value">{@invoice.invoice_number}</div>
</div>
<div class="invoice-ref-item">
<div class="label">Invoice Date</div>
<div class="value">{Calendar.strftime(@invoice.inserted_at, "%B %d, %Y")}</div>
</div>
<%= if @invoice.order do %>
<div class="invoice-ref-item">
<div class="label">Order Number</div>
<div class="value">{@invoice.order.order_number}</div>
</div>
<% end %>
</div>
</div>
<%= if @transaction.description do %>
<div style="margin-top: 20px; padding: 16px; background: #f9fafb; border-radius: 8px;">
<h4 style="font-size: 13px; font-weight: 600; color: #6b7280; margin-bottom: 8px;">
Payment Notes
</h4>
<p style="white-space: pre-wrap;">{@transaction.description}</p>
</div>
<% end %>
</div>
<div class="confirmation-footer">
<div class="footer-company">
<div class="name">{@company.name}</div>
<div class="details">
{@company.address}
<%= if @company.vat != "" do %>
• VAT: {@company.vat}
<% end %>
</div>
</div>
<div class="footer-note">
This document confirms receipt of the payment indicated above. Thank you for your business.
</div>
</div>
</div>
</body>
</html>