Symfony Console App for Automated Invoice Generation
Build a command-line tool in PHP that creates PDF invoices automatically, for example for a small business that bills clients monthly. It reads clients and their billable items from a CSV file or a database, fills an HTML invoice template made with Twig, and turns it into a professional PDF with DomPDF, one per client. It can run once for a single client, or in batch mode from a scheduled job to invoice every client that's due, with invoice numbers that never repeat, a dry-run option, and a log of what happened. You'll learn the Symfony Console component (commands, arguments, options and output styling), Twig outside a web framework, HTML-to-PDF generation, correct money calculations, and testing console commands.
- Estimate
- ~11h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Symfony Console · Twig · DomPDF
Project roadmap
- 01
Set up the console app
~1.5hCreate a project with Composer and install symfony/console, twig/twig and dompdf/dompdf. Create bin/invoices with an Application and an invoices:generate command taking an optional client id, and the options --month (default: last month), --out (default ./invoices) and --dry-run. Done when: bin/invoices list shows the command, and --help describes every option.
- 02
Load billing data
~2hRead clients (id, name, address, VAT number, billing day) and line items (client, date, description, quantity, unit price) from CSV files, behind a BillingSource interface so a database source can be added later. Validate every row and report errors with the file and line. Store money as whole cents (integers) to avoid rounding errors. Done when: the data loads, and a row with a bad price is reported with its line number.
- 03
Design the invoice template
~2hCreate an invoice.html.twig template with your company details, the client's address, the invoice number and date, a table of items with quantity, unit price and line total, then the subtotal, VAT and total. Put the calculations in PHP, not in the template, and format money with a Twig filter. Keep the CSS simple, since DomPDF supports only part of CSS. Done when: rendering the template for one client produces correct HTML that looks right in a browser.
- 04
Generate the PDFs
~1.5hRender the HTML with DomPDF on A4 paper and save it as invoices/2026-03/INV-2026-0042-client-name.pdf. Assign invoice numbers from a counter file updated safely with a file lock, so two runs never produce the same number. Done when: generating an invoice produces a correct, readable PDF with a unique number.
- 05
Add batch mode and logging
~2hWithout a client id, generate invoices for every client with billable items in the month. Skip clients already invoiced for that month (keep a record), so re-running is safe. With --dry-run, only show what would be created, as a table. Show a progress bar, log successes and failures to a log file, keep going after a failure, and exit with an error code if anything failed. Done when: a batch run invoices every due client once, and running it again creates nothing new.
- 06
Test it
~2hWrite PHPUnit tests: totals and VAT calculations in cents (including rounding), CSV validation, invoice number uniqueness, skipping already-invoiced clients, and the command itself with Symfony's CommandTester (dry run output and exit codes). Check that a generated file starts with %PDF. Done when: vendor/bin/phpunit passes.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack