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
phoenix_kit lib modules billing web payment_confirmation_print.ex
Raw

lib/modules/billing/web/payment_confirmation_print.ex

defmodule PhoenixKit.Modules.Billing.Web.PaymentConfirmationPrint do
@moduledoc """
Printable payment confirmation view - displays individual payment in a print-friendly format.
This page is designed to be printed or saved as PDF directly from the browser.
Payment confirmations are generated for individual payment transactions.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.Billing
alias PhoenixKit.Modules.Billing.CountryData
alias PhoenixKit.Modules.Billing.Transaction
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@impl true
def mount(%{"id" => invoice_id, "transaction_id" => transaction_id}, _session, socket) do
with true <- Billing.enabled?(),
%{} = invoice <- Billing.get_invoice(invoice_id, preload: [:user, :order]),
%Transaction{} = transaction <- Billing.get_transaction(transaction_id),
true <- Transaction.payment?(transaction) do
mount_payment_confirmation(socket, invoice, transaction)
else
false ->
{:ok,
socket
|> put_flash(:error, "Billing module is not enabled")
|> push_navigate(to: Routes.path("/admin"))}
nil ->
error_msg =
if Billing.get_invoice(invoice_id) == nil,
do: "Invoice not found",
else: "Transaction not found"
redirect_path =
if Billing.get_invoice(invoice_id) == nil,
do: Routes.path("/admin/billing/invoices"),
else: Routes.path("/admin/billing/invoices/#{invoice_id}")
{:ok,
socket
|> put_flash(:error, error_msg)
|> push_navigate(to: redirect_path)}
%Transaction{} ->
{:ok,
socket
|> put_flash(:error, "Transaction is not a payment")
|> push_navigate(to: Routes.path("/admin/billing/invoices/#{invoice_id}"))}
end
end
defp mount_payment_confirmation(socket, invoice, transaction) do
project_title = Settings.get_setting("project_title", "PhoenixKit")
company_info = get_company_info()
confirmation_number = generate_confirmation_number(transaction)
all_transactions = Billing.list_invoice_transactions(invoice.id)
payment_context = calculate_payment_context(invoice, transaction, all_transactions)
socket =
socket
|> assign(:page_title, "Payment Confirmation #{confirmation_number}")
|> assign(:project_title, project_title)
|> assign(:invoice, invoice)
|> assign(:transaction, transaction)
|> assign(:confirmation_number, confirmation_number)
|> assign(:company, company_info)
|> assign(:payment_context, payment_context)
{:ok, socket, layout: false}
end
@impl true
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
defp get_company_info do
%{
name: Settings.get_setting("billing_company_name", ""),
address: CountryData.format_company_address(),
vat: Settings.get_setting("billing_company_vat", ""),
bank_name: Settings.get_setting("billing_bank_name", ""),
bank_iban: Settings.get_setting("billing_bank_iban", ""),
bank_swift: Settings.get_setting("billing_bank_swift", "")
}
end
defp generate_confirmation_number(transaction) do
prefix = Settings.get_setting("billing_payment_confirmation_prefix", "PMT")
suffix = transaction.transaction_number |> String.replace(~r/^TXN-/, "")
"#{prefix}-#{suffix}"
end
defp calculate_payment_context(invoice, transaction, all_transactions) do
# Payments up to and including this transaction
sorted_payments =
all_transactions
|> Enum.filter(&Decimal.positive?(&1.amount))
|> Enum.sort_by(& &1.inserted_at, {:asc, DateTime})
# Find position of current payment
payment_index =
Enum.find_index(sorted_payments, fn t -> t.id == transaction.id end) || 0
# Total paid up to and including this payment
payments_up_to_now = Enum.take(sorted_payments, payment_index + 1)
total_paid_so_far =
payments_up_to_now
|> Enum.map(& &1.amount)
|> Enum.reduce(Decimal.new(0), &Decimal.add/2)
remaining_balance = Decimal.sub(invoice.total, total_paid_so_far)
is_final_payment = Decimal.lte?(remaining_balance, Decimal.new(0))
%{
payment_number: payment_index + 1,
total_payments: length(sorted_payments),
total_paid_so_far: total_paid_so_far,
remaining_balance: Decimal.max(remaining_balance, Decimal.new(0)),
is_final_payment: is_final_payment
}
end
end