Skip to content

Commit

Permalink
Refactor invoices
Browse files Browse the repository at this point in the history
These changes utilize the Money library to format money values from the invoice and invoice line objects. It makes use of the invoice's currency to make sure there's no currency conflict when trying to display the values.

New Composer requirements:

- moneyphp/money: used for formatting money values
- ext-intl: used for the above library to properly format currencies

This brings along quite some changes as well:

- Removal of the $currencySymbol setting on the Cashier object along with the useCurrencySymbol and usesCurrencySymbol methods
- Removal of the $symbol parameter from the useCurrency method on the Cashier object and its guessCurrencySymbol method
- Refactored the formatAmount method to a formatMoney method which takes a Money object
- The starting balance is now no longer subtracted from the total and subtotal of an invoice
- The rawTotal method now returns an integer instead of a float
- A new amountDue() method is added to the Invoice object to display the amount left to pay
- A new rawDiscount() method is added to the Invoice object which return the discount but as a raw integer value
- A new tax() method is added to the Invoice object which returns the invoice tax formatted with its currency

And finally the invoice pdf got a make over:

- Subtotal is now displayed below the amount of each row and a total of all rows combined
- Discount and Tax are displayed below subtotal
- Total is now the summary of Subtotal - Discount - Tax
- Starting balance is shown below the total as an extra subtracting from the total
- Which results in the amount due which is displayed as the final value for the invoice which should be paid
  • Loading branch information
driesvints committed Jun 7, 2019
1 parent a844ad4 commit 34f606a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 112 deletions.
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
],
"require": {
"php": "^7.1.3",
"ext-intl": "*",
"ext-json": "*",
"dompdf/dompdf": "^0.8.0",
"illuminate/contracts": "~5.8.0|~5.9.0",
Expand All @@ -23,6 +24,7 @@
"illuminate/routing": "~5.8.0|~5.9.0",
"illuminate/support": "~5.8.0|~5.9.0",
"illuminate/view": "~5.8.0|~5.9.0",
"moneyphp/money": "^3.2",
"nesbot/carbon": "^1.26.3|^2.0",
"stripe/stripe-php": "^6.0",
"symfony/http-kernel": "^4.2"
Expand Down
79 changes: 45 additions & 34 deletions resources/views/receipt.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Invoice</title>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background: #fff;
Expand All @@ -19,38 +19,34 @@
font-size:28px;
color:#cccccc;
}
.bold {
font-weight: bold;
}
.container {
padding-top:30px;
}
.invoice-head td {
padding: 0 8px;
}
.invoice-body{
background-color:transparent;
}
.logo {
padding-bottom: 10px;
}
.table th {
vertical-align: bottom;
font-weight: bold;
padding: 8px;
line-height: 20px;
text-align: left;
border-bottom: 1px solid #dddddd;
}
.table tr.row td {
border-bottom: 1px solid #dddddd;
}
.table td {
padding: 8px;
line-height: 20px;
text-align: left;
vertical-align: top;
border-top: 1px solid #dddddd;
}
.well {
margin-top: 15px;
}
</style>
</head>

<body>
<div class="container">
<table style="margin-left: auto; margin-right: auto" width="550">
Expand Down Expand Up @@ -121,24 +117,17 @@
<th align="right">Amount</th>
</tr>

<!-- Existing Balance -->
<tr>
<td>Starting Balance</td>
<td>&nbsp;</td>
<td>{{ $invoice->startingBalance() }}</td>
</tr>

<!-- Display The Invoice Items -->
@foreach ($invoice->invoiceItems() as $item)
<tr>
<tr class="row">
<td colspan="2">{{ $item->description }}</td>
<td>{{ $item->total() }}</td>
</tr>
@endforeach

<!-- Display The Subscriptions -->
@foreach ($invoice->subscriptions() as $subscription)
<tr>
<tr class="row">
<td>Subscription ({{ $subscription->quantity }})</td>
<td>
{{ $subscription->startDateAsCarbon()->formatLocalized('%B %e, %Y') }} -
Expand All @@ -148,34 +137,56 @@
</tr>
@endforeach

<!-- Display The Subtotal -->
@if ($invoice->hasDiscount() || $invoice->tax_percent)
<tr>
<td colspan="2" style="text-align: right;">Subtotal</td>
<td>{{ $invoice->subtotal() }}</td>
</tr>
@endif

<!-- Display The Discount -->
@if ($invoice->hasDiscount())
<tr>
@if ($invoice->discountIsPercentage())
<td>{{ $invoice->coupon() }} ({{ $invoice->percentOff() }}% Off)</td>
@else
<td>{{ $invoice->coupon() }} ({{ $invoice->amountOff() }} Off)</td>
@endif
<td>&nbsp;</td>
<td colspan="2" style="text-align: right;">
@if ($invoice->discountIsPercentage())
{{ $invoice->coupon() }} ({{ $invoice->percentOff() }}% Off)
@else
{{ $invoice->coupon() }} ({{ $invoice->amountOff() }} Off)
@endif
</td>

<td>-{{ $invoice->discount() }}</td>
</tr>
@endif

<!-- Display The Tax Amount -->
@if ($invoice->tax_percent)
<tr>
<td>Tax ({{ $invoice->tax_percent }}%)</td>
<td>&nbsp;</td>
<td>{{ Laravel\Cashier\Cashier::formatAmount($invoice->tax) }}</td>
<td colspan="2" style="text-align: right;">Tax ({{ $invoice->tax_percent }}%)</td>
<td>{{ $invoice->tax() }}</td>
</tr>
@endif

<!-- Display The Final Total -->
<tr style="border-top:2px solid #000;">
<td>&nbsp;</td>
<td style="text-align: right;"><strong>Total</strong></td>
<td><strong>{{ $invoice->total() }}</strong></td>
<tr {{ $invoice->hasStartingBalance() ? '' : 'class="bold"' }}>
<td colspan="2" style="text-align: right;">Total</td>
<td>{{ $invoice->total() }}</td>
</tr>

<!-- Starting Balance -->
@if ($invoice->hasStartingBalance())
<tr>
<td colspan="2" style="text-align: right;">Applied Balance</td>
<td>{{ $invoice->startingBalance() }}</td>
</tr>

<!-- Display The Amount Due -->
<tr>
<td colspan="2" style="text-align: right;"><strong>Amount Due</strong></td>
<td><strong>{{ $invoice->amountDue() }}</strong></td>
</tr>
@endif
</table>
</td>
</tr>
Expand Down
74 changes: 18 additions & 56 deletions src/Cashier.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace Laravel\Cashier;

use Exception;
use Illuminate\Support\Str;
use Money\Money;
use NumberFormatter;
use Money\Currencies\ISOCurrencies;
use Money\Formatter\IntlMoneyFormatter;

class Cashier
{
Expand Down Expand Up @@ -36,11 +38,11 @@ class Cashier
protected static $currency = 'usd';

/**
* The current currency symbol.
* The locale used to format money values.
*
* @var string
*/
protected static $currencySymbol = '$';
protected static $currencyLocale = 'en_US';

/**
* The custom currency formatter.
Expand Down Expand Up @@ -142,38 +144,11 @@ public static function stripeModel()
* Set the currency to be used when billing Stripe models.
*
* @param string $currency
* @param string|null $symbol
* @return void
* @throws \Exception
*/
public static function useCurrency($currency, $symbol = null)
public static function useCurrency($currency)
{
static::$currency = $currency;

static::useCurrencySymbol($symbol ?: static::guessCurrencySymbol($currency));
}

/**
* Guess the currency symbol for the given currency.
*
* @param string $currency
* @return string
* @throws \Exception
*/
protected static function guessCurrencySymbol($currency)
{
switch (strtolower($currency)) {
case 'usd':
case 'aud':
case 'cad':
return '$';
case 'eur':
return '';
case 'gbp':
return '£';
default:
throw new Exception('Unable to guess symbol for currency. Please explicitly specify it.');
}
}

/**
Expand All @@ -187,24 +162,14 @@ public static function usesCurrency()
}

/**
* Set the currency symbol to be used when formatting currency.
* Set the currency locale to format money.
*
* @param string $symbol
* @param string $currencyLocale
* @return void
*/
public static function useCurrencySymbol($symbol)
public static function useCurrencyLocale($currencyLocale)
{
static::$currencySymbol = $symbol;
}

/**
* Get the currency symbol currently in use.
*
* @return string
*/
public static function usesCurrencySymbol()
{
return static::$currencySymbol;
static::$currencyLocale = $currencyLocale;
}

/**
Expand All @@ -219,24 +184,21 @@ public static function formatCurrencyUsing(callable $callback)
}

/**
* Format the given amount into a displayable currency.
* Format the given money into a displayable currency.
*
* @param int $amount
* @param \Money\Money $money
* @return string
*/
public static function formatAmount($amount)
public static function formatMoney(Money $money)
{
if (static::$formatCurrencyUsing) {
return call_user_func(static::$formatCurrencyUsing, $amount);
return call_user_func(static::$formatCurrencyUsing, $money);
}

$amount = number_format($amount / 100, 2);

if (Str::startsWith($amount, '-')) {
return '-'.static::usesCurrencySymbol().ltrim($amount, '-');
}
$numberFormatter = new NumberFormatter(static::$currencyLocale, NumberFormatter::CURRENCY);
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies());

return static::usesCurrencySymbol().$amount;
return $moneyFormatter->format($money);
}

/**
Expand Down
Loading

0 comments on commit 34f606a

Please sign in to comment.