Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Financial Laravel Package

jarouche/financial

A Laravel package for financial calculations, offering helpers for interest rates, amortization schedules, loan payments, and present/future value computations. Integrates cleanly with your PHP applications to handle common finance math without external dependencies.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and locate the code. The package is a single-purpose math helper, so onboarding is minutes, not days:

composer require jarouche/financial

There is no service provider, no config file, no facade, and no migrations. The entire package is one or two files under vendor/jarouche/financial/src/. Read the source before you write any code — it is short enough to read in full, and since the last release was December 2018 there is no documentation website, no README examples to trust, and no test suite to describe the contract for you. Open the class, note the namespace and the exact method signature, and confirm the argument order matches Excel's PMT(rate, nper, pv, [fv], [type]).

Know what it does and does not do. It computes the Excel PMT function: the constant periodic payment for a loan or annuity given an interest rate per period, number of periods, present value, and optional future value / payment timing. That is the whole feature set. There is no IPMT, PPMT, RATE, NPER, FV, or NPV — despite the description promising "more functions in the future," nothing has shipped since 2018. Plan around that: anything beyond a fixed-level payment you will implement yourself.

Your first use case. A checkout or quoting screen that shows "12x de R$ 1.234,56" for a financed purchase, or a loan simulator form. That is the 80% path:

use Jarouche\Financial\...; // confirm the real namespace in vendor/ first

$payment = PMT::calculate(
    rate: 0.0199,   // 1.99% per month, as a DECIMAL per period
    nper: 12,       // 12 monthly periods
    pv: 12000.00,   // amount financed
);

Verify the output against Excel or Google Sheets using the same inputs before you trust it in any UI. Do this once, note the result in a test, and move on. If the sign convention surprises you (Excel returns a negative number for an outflow), check whether the package preserves or normalizes that — it is the single most common source of "the number is wrong" bug reports with PMT implementations.

Implementation Patterns

Wrap it, always. Because this is a 1-star, unmaintained dependency, never call it directly from controllers, Blade templates, or models. Put it behind one class of your own:

namespace App\Support\Finance;

final class LoanCalculator
{
    public function monthlyPayment(
        float $principal,
        float $annualRate,
        int $months,
    ): float {
        $periodicRate = $annualRate / 12;

        if ($periodicRate === 0.0) {
            return round($principal / $months, 2);
        }

        return round(abs(PMT::calculate($periodicRate, $months, $principal)), 2);
    }
}

This gives you three things the package does not: a stable API you control, a place to handle the zero-rate edge case, and a single file to change if you ever swap the package out (which, given its age, is a realistic outcome). Bind it in a service provider if you want it injectable and mockable in tests.

Normalize units at the boundary. The single biggest source of wrong answers is rate/period mismatch. Users type "2.5%" and "24 months." The package wants 0.025 and 24. Do the division and the /100 in a form request or a DTO, not in the view:

class LoanSimulationRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'amount'         => ['required', 'numeric', 'min:100'],
            'annual_rate'    => ['required', 'numeric', 'between:0,200'],
            'installments'   => ['required', 'integer', 'between:1,360'],
        ];
    }

    public function periodicRate(): float
    {
        return $this->float('annual_rate') / 100 / 12;
    }
}

Build the amortization table yourself. Since IPMT/PPMT do not exist in this package, compute interest per period from the outstanding balance and derive principal as payment - interest. This is trivially correct and avoids depending on functions that were never implemented:

$balance = $principal;
$rows = [];

for ($i = 1; $i <= $months; $i++) {
    $interest  = round($balance * $periodicRate, 2);
    $principalPart = round($payment - $interest, 2);
    $balance = round($balance - $principalPart, 2);

    $rows[] = compact('i', 'interest', 'principalPart', 'balance');
}

Expect a small residual on the final row from rounding — adjust the last installment so the balance lands exactly on zero, or you will get customer support tickets about a one-cent discrepancy.

Cache simulator responses. Loan simulation endpoints are hit repeatedly by indecisive users and are pure functions of their inputs. Cache::remember() keyed on a hash of (principal, rate, months) costs nothing and removes the call entirely for repeat traffic. For batch generation of amortization schedules (e.g. exporting a full table for a contract), push it to a queued job and stream a CSV rather than building thousands of rows in the request cycle.

Format at the edge, calculate in the core. Keep everything as float/minor-units through the calculation and only format in the response layer:

'installment' => Number::currency($payment, 'BRL', 'pt_BR'),

If your app already uses moneyphp/money or brick/money, do not try to teach this package about value objects — convert to float, call it, convert back, and round explicitly at the boundary.

Gotchas and Tips

There is no rate = 0 guard you can rely on. The PMT closed form divides by the rate (or by (1+r)^n - 1), so a 0% financing offer will throw a division-by-zero or return INF/NAN. Always branch on $rate == 0.0 before calling into the package, as shown above.

Percentages vs decimals is the #1 bug. Excel's PMT takes 0.05 for 5%, and this package mirrors that. A user-entered 5 passed straight through produces a payment roughly a hundred times too large — and it will look plausible enough that nobody catches it until a contract is signed. Validate the range aggressively and write a test asserting 5% annual over 12 months on 1000 ≈ 86.07.

Sign convention. Excel returns a negative payment for a positive present value, because the payment is an outflow. If you don't see that behavior, the package may have normalized it. Either way, pin the behavior with a test rather than relying on abs() sprinkled through your code — otherwise a future version (unlikely as that is) silently flips your signs.

type matters and is undocumented here. type = 0 means payment at end of period, type = 1 at the beginning. Annuity-due payments are smaller by a factor of (1 + rate). Confirm which default the package uses before quoting "first payment today" scenarios.

Pin the version and consider vendoring. One star, zero dependents, no release in seven years, no CI badge worth trusting. That is fine for a formula — the math hasn't changed since 2018 — but it is not fine for something you composer update blindly. Commit the lockfile, and if your team is strict about supply-chain risk, copy the ten lines of the formula into App\Support\Finance and drop the dependency. You lose nothing.

Check the PHP version constraint. A 2018 package may declare php: ^7.0 and lack scalar type hints or return types. It will usually still install and run on PHP 8.2+, but if composer require fails on a platform check, use --ignore-platform-req=php cautiously or fork it. Add a smoke test that calls the function once so an upgrade that breaks on deprecation notices gets caught in CI rather than in production.

No extension points means no customization. There is no config array, no strategy interface, no injection. If you need different rounding modes, banker's rounding, or multi-currency precision, you must wrap and post-process. Treat the package as a sealed black box: one call in, one float out.

Debugging recipe. When a number looks wrong, reduce to a known case: 1000 principal, 1% per period, 10 periods, end-of-period. Cross-check against Excel =PMT(1%,10,1000). If those disagree, the problem is your inputs, not your business logic. If they agree, the problem is downstream in rounding or currency formatting.

Testing. Use the package in exactly one or two unit tests; test your LoanCalculator wrapper everywhere else. A table-driven test with four or five Excel-verified fixtures (zero rate, standard rate, one period, 360 periods, annuity due) is a complete safety net for a package this small.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource