Skip to content

[Settings]: Invoices — Invoice Template #255

Closed

Description

@nielsdrost7

SMART Plan — Company Panel Invoice Template Settings

Specific

Seven per-company select fields and one textarea in the Invoices → Templates section of the Company Settings page, mapping PDF and email templates to specific invoice lifecycle states:

Setting Type Purpose
Default PDF Template Select (pdf_template) Template used for standard invoice PDFs
Paid PDF Template Select (pdf_template) Template used when invoice status = Paid
Overdue PDF Template Select (pdf_template) Template used when invoice is overdue
Default Public Template Select (public_template) Guest-facing URL template
Default Email Template Select (email_template) Email body for standard invoice sends
Paid Email Template Select (email_template) Email body for payment confirmation
Overdue Email Template Select (email_template) Email body for overdue reminders
PDF Footer Textarea Static HTML/text appended to every invoice PDF

Measurable

  • All eight fields appear in the Invoices → Templates tab of CompanySettings
  • Each saves to settings keyed as invoice_template_pdf_default, invoice_template_pdf_paid, invoice_template_pdf_overdue, invoice_template_public_default, invoice_template_email_default, invoice_template_email_paid, invoice_template_email_overdue, invoice_pdf_footer
  • The PDF and email pipeline reads the correct template key based on invoice status

Achievable

  1. Add eight fields to CompanySettings under the Invoices > Templates tab
  2. Populate template select options from EmailTemplate::forCompany($company)->pluck('name', 'id')
  3. In InvoicePdfService and InvoiceEmailService, resolve the active template by checking the status-specific key, falling back to the _default key

Relevant

Allows companies to apply different PDF layouts and email copy for different invoice states (new, paid, overdue) — necessary for professional billing workflows.

Time-bound

Sprint 6.


Arrange · Act · Assert

// Modules/Core/Tests/Feature/CompanySettingsTest.php

#[Test]
public function it_saves_invoice_template_settings(): void
{
    /* Arrange */
    $emailTemplate = EmailTemplate::factory()->for($this->company)->create();
    $page = Livewire::actingAs($this->user)
        ->test(\Modules\Core\Filament\Company\Pages\CompanySettings::class);

    /* Act */
    $page->set('data.invoice_template_email_default', $emailTemplate->id)
         ->set('data.invoice_pdf_footer', 'Thank you for your business.')
         ->call('save');

    /* Assert */
    $page->assertSuccessful();
    $this->assertDatabaseHas('settings', [
        'company_id' => $this->company->id,
        'key'        => 'invoice_template_email_default',
        'value'      => (string) $emailTemplate->id,
    ]);
    $this->assertDatabaseHas('settings', [
        'company_id' => $this->company->id,
        'key'        => 'invoice_pdf_footer',
        'value'      => 'Thank you for your business.',
    ]);
}

Activity

  1. coderabbitai commented on Dec 28, 2025

    @coderabbitai
    Contributor

    📝 CodeRabbit Plan Mode

    Generate an implementation plan and prompts that you can use with your favorite coding agent.

    • Create Plan
    Examples

    🔗 Similar Issues

    Possible Duplicates

    Related Issues

    👤 Suggested Assignees

    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added this to the v2.0.0-alpha milestone on Dec 28, 2025
  3. deleted a comment from on Mar 5, 2026
  4. deleted a comment from on Mar 5, 2026
  5. deleted a comment from on Mar 5, 2026
  6. deleted a comment from on Mar 5, 2026
  7. deleted a comment from on Mar 5, 2026
  8. changed the title [-]As an admin in the Company Panel, in the Invoice Template Settings (Invoices Tab, Per Company!), I want to be able to set:[/-] [+][Settings]: Invoices — Invoice Template[/+] on Jun 13, 2026
  9. nielsdrost7 commented on Jul 24, 2026

    @nielsdrost7
    CollaboratorAuthor

    SMART Plan — Invoices — Invoice Template

    Specific

    Within the Company panel Settings → Invoices tab, add select fields for email and PDF templates per invoice lifecycle state: sent, paid, overdue, and public link. Each selects from available EmailTemplate and PDF template records scoped to the company. Stored as settings rows scoped to the company.

    Measurable

    • Four select fields for email templates (sent, paid, overdue).
    • One select for public/customer portal template.
    • Selections stored as settings rows.
    • When invoices transition to these states, the corresponding template is used.
    • Success message confirms template assignments were saved.

    Achievable

    1. Add settings keys: invoice_email_template_sent, invoice_email_template_paid, invoice_email_template_overdue, invoice_template_public.
    2. Add Select fields in CompanySettings → Invoices tab, populated from $company->emailTemplates().
    3. In InvoiceObserver/Service, retrieve the appropriate template setting based on invoice state.
    4. Use the template for email composition and customer portal rendering.

    Relevant

    Different invoice states warrant different messaging. Companies want customized templates for new invoices, payment confirmations, and reminders.

    Time-bound

    Sprint 6.

  10. nielsdrost7 commented on Jul 24, 2026

    @nielsdrost7
    CollaboratorAuthor

    Correction: this is already fully implemented on the unmerged branch settings-cluster-2026-07-19 — the Invoices → Invoice Templates section of CompanySettings.php has Setting::KEY_INVOICE_PDF_TEMPLATE, KEY_INVOICE_PAID_PDF_TEMPLATE, KEY_INVOICE_OVERDUE_PDF_TEMPLATE, KEY_INVOICE_PUBLIC_TEMPLATE, KEY_INVOICE_EMAIL_TEMPLATE, KEY_INVOICE_PAID_EMAIL_TEMPLATE, and KEY_INVOICE_OVERDUE_EMAIL_TEMPLATE — matching the seven fields described above. Please check that branch before implementing from scratch — it likely just needs finishing/rebasing and a PR opened, not a fresh implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    refinedRefined with SMART plan / test suggestions

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions