Skip to content

Commit

Permalink
Merge pull request #685 from laravel/money-lib
Browse files Browse the repository at this point in the history
[10.0] Refactor Invoices
  • Loading branch information
taylorotwell authored Jun 17, 2019
2 parents 0a74a93 + 9eb957d commit 7e45835
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 108 deletions.
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@
"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"
"symfony/http-kernel": "^4.2",
"symfony/intl": "^4.3"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^3.8",
"phpunit/phpunit": "^7.5"
},
"suggest": {
"ext-intl": "Allows for more locales besides the default \"en\" when formatting money values."
},
"autoload": {
"psr-4": {
"Laravel\\Cashier\\": "src/"
Expand Down
68 changes: 35 additions & 33 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 @@ -25,32 +25,25 @@
.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 +114,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,32 +134,48 @@
</tr>
@endforeach

<!-- Display The Subtotal -->
@if ($invoice->hasDiscount() || $invoice->tax_percent || $invoice->hasStartingBalance())
<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

<!-- Starting Balance -->
@if ($invoice->hasStartingBalance())
<tr>
<td colspan="2" style="text-align: right;">Customer Balance</td>
<td>{{ $invoice->startingBalance() }}</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>
<tr>
<td colspan="2" style="text-align: right;"><strong>Total</strong></td>
<td><strong>{{ $invoice->total() }}</strong></td>
</tr>
</table>
Expand Down
75 changes: 22 additions & 53 deletions src/Cashier.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

namespace Laravel\Cashier;

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

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

/**
* The current currency symbol.
* The locale used to format money values.
*
* To use more locales besides the default "en" locale, make
* sure you have the ext-intl installed on your environment.
*
* @var string
*/
protected static $currencySymbol = '$';
protected static $currencyLocale = 'en';

/**
* The custom currency formatter.
Expand Down Expand Up @@ -142,38 +148,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 +166,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 @@ -222,21 +191,21 @@ public static function formatCurrencyUsing(callable $callback)
* Format the given amount into a displayable currency.
*
* @param int $amount
* @param string|null $currency
* @return string
*/
public static function formatAmount($amount)
public static function formatAmount($amount, $currency = null)
{
if (static::$formatCurrencyUsing) {
return call_user_func(static::$formatCurrencyUsing, $amount);
return call_user_func(static::$formatCurrencyUsing, $amount, $currency);
}

$amount = number_format($amount / 100, 2);
$money = new Money($amount, new Currency(strtoupper($currency ?? static::usesCurrency())));

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
44 changes: 25 additions & 19 deletions src/Invoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ public function total()
/**
* Get the raw total amount that was paid (or will be paid).
*
* @return float
* @return int
*/
public function rawTotal()
{
return max(0, $this->invoice->total - ($this->rawStartingBalance() * -1));
return $this->invoice->total + $this->rawStartingBalance();
}

/**
Expand All @@ -77,9 +77,7 @@ public function rawTotal()
*/
public function subtotal()
{
return $this->formatAmount(
max(0, $this->invoice->subtotal - ($this->rawStartingBalance() * -1))
);
return $this->formatAmount($this->invoice->subtotal);
}

/**
Expand All @@ -102,6 +100,16 @@ public function startingBalance()
return $this->formatAmount($this->rawStartingBalance());
}

/**
* Get the raw starting balance for the invoice.
*
* @return int
*/
public function rawStartingBalance()
{
return $this->invoice->starting_balance ?? 0;
}

/**
* Determine if the invoice has a discount.
*
Expand Down Expand Up @@ -174,6 +182,16 @@ public function amountOff()
return $this->formatAmount(0);
}

/**
* Get the tax total amount.
*
* @return string
*/
public function tax()
{
return $this->formatAmount($this->invoice->tax);
}

/**
* Get all of the "invoice item" line items.
*
Expand Down Expand Up @@ -216,14 +234,14 @@ public function invoiceItemsByType($type)
}

/**
* Format the given amount into a string based on the Stripe model's preferences.
* Format the given amount into a displayable currency.
*
* @param int $amount
* @return string
*/
protected function formatAmount($amount)
{
return Cashier::formatAmount($amount);
return Cashier::formatAmount($amount, $this->invoice->currency);
}

/**
Expand Down Expand Up @@ -278,18 +296,6 @@ public function download(array $data)
]);
}

/**
* Get the raw starting balance for the invoice.
*
* @return float
*/
public function rawStartingBalance()
{
return isset($this->invoice->starting_balance)
? $this->invoice->starting_balance
: 0;
}

/**
* Get the Stripe invoice instance.
*
Expand Down
4 changes: 2 additions & 2 deletions src/InvoiceItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ public function isSubscription()
}

/**
* Format the given amount into a string based on the owner model's preferences.
* Format the given amount into a displayable currency.
*
* @param int $amount
* @return string
*/
protected function formatAmount($amount)
{
return Cashier::formatAmount($amount);
return Cashier::formatAmount($amount, $this->item->currency);
}

/**
Expand Down
Loading

0 comments on commit 7e45835

Please sign in to comment.