Laravel Cashier for Mollie

repository·main·Indexed 41 days ago

https://github.com/mollie/laravel-cashier-mollie

An official integration providing an expressive, fluent interface for managing subscription billing cycles, payments, and customer relationships in Laravel applications using Mollie's billing services. Supports subscription plans, coupons, trial periods (including generic trials and mandate-upfront trials), and one-time charges.

Tokens
22.1K
Snippets
83
Records
106
Agent score
38%

What's inside Laravel Cashier for Mollie

  1. Overview of Laravel Cashier for Mollie

    main
    Laravel Cashier for Mollie provides an expressive and fluent interface for managing subscription billing within Laravel applications using Mollie's billing services. It bridges the gap between Laravel's subscription logic and Mollie's payment infrastructure.
  2. Manage customer balance

    main

    Mollie maintains a customer balance for each currency. This balance is automatically applied to Orders (for example, when a customer has overpaid due to a plan swap).

    If an Order is processed with a negative total amount due, that amount is automatically credited to the user's balance. If the user has no active subscriptions at that moment, a BalanceTurnedStale event is raised. You should listen for this event to handle refunds or user notifications.

    Warning: Use the direct balance manipulation methods with caution.

    // Check credit for a specific currency
    $credit = $user->credit('EUR');
    
    // Manually add credit
    $user->addCredit(money(1000, 'EUR')); // adds €10.00
    
    // Check if user has credit
    $user->hasCredit('EUR');
  3. How failed subscription payments are handled

    main

    When a payment related to a subscription fails, Cashier automatically cancels the subscription immediately.

    If the payment is successfully retried (e.g., via retryNow()), the subscription will be reactivated and will continue its previous billing cycle as if the failure had not occurred.

  4. List all invoices for a user

    main

    You can access all invoices associated with a user by accessing their orders via $user->orders->invoices(). This collection includes invoices for all orders, including those that are unprocessed or failed.

    // Accessing all invoices through the orders relationship
    $invoices = $user->orders->invoices();
  5. How subscription management works in Cashier Mollie

    main

    Unlike standard Mollie subscriptions, Cashier Mollie uses its own subscription engine to schedule payments from the client side. This allows for features not supported by Mollie's native Subscription API.

    The Subscription Lifecycle:

    1. Creation: A Subscription is created using either MandatePaymentSubscriptionBuilder (redirects to Mollie checkout to create a Mandate) or PremandatedSubscriptionBuilder (uses an existing Mandate).
    2. Scheduling: The Subscription generates a scheduled OrderItem at the start of every billing cycle.
    3. Bundling: A scheduled job (typically daily) pre-processes OrderItems (applying dynamic discounts or metered billing) and bundles them into Orders so customers receive a single invoice for multiple items.
    4. Payment Processing: The scheduled job processes the Order:
      • Customer balance is applied first.
      • If the total is positive, a Mollie payment is triggered.
      • If the total is 0, no action is taken.
      • If the total is negative, the amount is added to the user's balance. If no active subscriptions remain, a BalanceTurnedStale event is raised.
    5. Invoicing: You can generate HTML or PDF Invoice documents for the user.
  6. How prorating is handled in Cashier Mollie

    main

    Cashier Mollie applies prorating by default when a subscription quantity is updated or a plan is switched.

    Prorating Process:

    1. The billing cycle is reset.
    2. The customer is credited for unused time; the overpaid amount is added to the customer's balance.
    3. A new billing cycle starts with the new settings. An Order is generated, applying the credited balance to the new total.

    Note: This does not apply to $subscription->swapNextCycle('other-plan'). That method waits until the end of the current billing cycle to update the plan, which is useful for downgrades.

  7. Handle Mollie webhook events in Laravel

    main

    Cashier Mollie automatically handles default Mollie webhook logic, such as cancelling a subscription if a recurring charge fails.

    To implement application-specific behavior (e.g., granting access to a user or notifying an admin), you should listen for specific events provided by the package in the Laravel\ ext{Cashier}\\text{Events} namespace.

    Available events for custom logic:

    • OrderPaymentPaid: Triggered when an order payment succeeds.
    • OrderPaymentFailed: Triggered when an order payment fails.
    • FirstPaymentPaid: Triggered when the initial payment for a subscription succeeds.
    • FirstPaymentFailed: Triggered when the initial payment for a subscription fails.
  8. Prepare the Billable Model

    main

    To make a model (typically the User model) billable, you must perform the following steps:

    1. Add the Laravel\ Cashier\\Billable trait to the model.
    2. (Optional) Override mollieCustomerFields() to define which model fields should be sent to Mollie when creating a Customer.
    3. Implement the Laravel\\Cashier\\Order\\Contracts\\ProvidesInvoiceInformation interface to provide data for invoices.

    Example implementation:

    use Laravel\Cashier\Billable;
    
    class User extends Authenticatable
    {
        use Billable;
    
        public function mollieCustomerFields()
        {
            return [
                'email' => $this->email,
                'name' => $this->name,
            ];
        }
    
        /**
         * Get the receiver information for the invoice.
         * @return array An array of strings
         */
        public function getInvoiceInformation()
        {
            return [$this->name, $this->email];
        }
    
        /**
         * Get additional information to be displayed on the invoice.
         * @return string|null
         */
        public function getExtraBillingInformation()
        {
            return null;
        }
    }
    public function mollieCustomerFields() {
        return [
            'email' => $this->email,
            'name' => $this->name,
        ];
    }
    
    public function getInvoiceInformation()
    {
        return [$this->name, $this->email];
    }
    
    public function getExtraBillingInformation()
    {
        return null;
    }
  9. Translate Cashier translation strings

    main

    Cashier uses English translation strings by default (e.g., for cycle definitions when order items are created). You can translate these using Laravel's standard localization feature by following these steps:

    1. Publish the default translation files: Run the following Artisan command to copy the English translations to your application's resources directory.
    2. Create your language folder: Create a new directory in resources/lang/vendor/cashier/ named after your desired locale (e.g., resources/lang/vendor/cashier/fr).
    3. Add translations: Place your translated JSON or PHP translation files inside that new folder.

    When your application's locale is set to the language you created, Cashier will automatically use your custom translations instead of the defaults.

    php artisan vendor:publish --tag=cashier-translations
  10. Handle processed refunds and credit invoices

    main

    When Mollie successfully processes a refund, Cashier dispatches the RefundProcessed event. You can use this event to access the automatically generated credit order and its corresponding invoice receipt.

    Once you have the invoice object, you can:

    • $invoice->view(): Retrieve a Blade view.
    • $invoice->pdf(): Retrieve a PDF of the Blade view.
    • $invoice->download(): Return a download response for the PDF.

    Credit orders and invoices are treated as regular Cashier orders and invoices, meaning they will appear in the user's standard order and invoice lists (e.g., $user->orders or $user->orders->invoices()).

    $creditOrder = $refundProcessedEvent->refund->order;
    $invoice = $creditOrder->invoice();
    $invoice->view(); // get a Blade view
    $invoice->pdf(); // get a pdf of the Blade view
    $invoice->download(); // get a download response for the pdf
  11. Implement metered billing with Subscription OrderItem preprocessors

    main

    For business cases requiring dynamic subscription amounts, Cashier Mollie provides a mechanism to define custom Subscription OrderItem preprocessors.

    These preprocessors are invoked immediately before an OrderItem is processed into a Mollie payment. This allows you to calculate the final billing amount dynamically based on real-time usage statistics. You can also use this hook to reset usage counters for the next billing cycle.

    To implement this, you must define your custom preprocessor classes in the cashier_plans configuration file.

    // In your cashier_plans config file, define your preprocessors:
    'preprocessors' => [
        App\Billing\MyMeteredUsagePreprocessor::class,
    ],
  12. Offer generic trials without mandate upfront

    main

    A "generic trial" allows you to offer a trial period without collecting payment information immediately. This is achieved by setting a trial_ends_at value on the user record, typically during registration.

    Note: You must add a date mutator for the trial_ends_at column in your Eloquent model definition to ensure it is handled correctly as a date object.

    $user = User::create([
        // Populate other user properties...
        'trial_ends_at' => now()->addDays(10),
    ]);