Digitalising and automating the invoicing flow of a maritime logistics operator
FACTS
sector
maritime logistics
role
Senior software developer (freelance)
period
2024 – 2025
team
2 developers
stack
PHP · Laravel · MySQL
PROBLEM
A maritime logistics operator was already running custom software to manage most of their day-to-day logistics operation.
This included accepting orders through their service desk or directly from customers on the platform, planning the
deliveries across their fleet, and letting the operators in the field manage each order as they fulfilled it.
Management and the finance department also had a stake in the application, as they pulled several reports and
statistics from its data to drive their forecasts and decision-making.
The only missing pieces of the puzzle were the invoicing flow and stock management. With B2B electronic invoicing becoming mandatory in Belgium from January 2026, they decided to tackle it head-on and implement new business software that could fill the gaps. I was hired along with another developer (who also doubled as the PM for this project) to integrate the chosen business software into their existing application.
CONSTRAINTS
- Critical application: almost the entire company's day-to-day operations ran on the app, so any bugs or outages would have a large impact.
- Technical debt: the application had grown over the years and often didn't follow Laravel's conventions or common best practices. Any change, however small, meant working in that code.
- Complex VAT structure: figuring out the correct VAT codes and rules is particularly complex in the maritime sector. The codes and tariffs to apply vary per type of product, sometimes even per specific product, by where it was delivered or by who it was sold to.
- Hard deadline: a new invoicing flow has a direct impact on the books, and new software changes the finance department's processes. The changeover was set for the start of the next financial year, so different systems and processes would not mix and cause errors or confusion.
APPROACH
Getting up to speed
In the first few weeks, I started out with a few small issues and changes to get to know the application. As it was my first encounter with Laravel, this also allowed me to get familiar with the framework and its ecosystem.
Very quickly, I noticed that the existing application didn't follow many common best practices, both general and
Laravel-specific ones. The most notable were (almost) raw SQL queries and functionality built by hand where Laravel
already provided it.
It was also clear that while Laravel had been updated, most of the code hadn't moved along with it. Features added here
and there made use of more recent framework features, but the rest had been left as is, even when changes were made to it.
Code quality
Because of that, I pushed for a 'boy-scout mentality': when updating a piece of code, leave it better than you found it.
Within reason, of course: adding a single field to a form and its model shouldn't trigger a day-long refactor of the
entire controller handling the form. Simply moving the complex form logic from the controller into a service or handler
is already a great improvement that only takes a few minutes. Any further change to that logic could then be another
reason to refactor, which would already be smaller in scope by then.
In addition to cleaning up the parts of the code I needed to modify, I also set up a few code quality tools to enforce
a minimum level we should keep. This included PHPStan, basic composer checks, PHP linting and PHPCS with a Laravel
ruleset.
PHPStan was set up with the forgiving level 5 and a baseline, so it wouldn't get in the way and demand we fix all the
existing issues first.
Some time later, when the code quality checks had been running smoothly, I also set up a basic automated deployment pipeline. It ran the code quality checks, installed dependencies and compiled the needed assets, then transferred the files to the server and created and activated the release.
Integration
The new business software was going to be used for bookkeeping, invoicing and stock management. This meant it needed to integrate with almost every part of the application:
- Products pushed from the app to the business software, for stock management and invoicing
- Customer data pushed from the app to the business software, for invoicing
- Orders pushed from the app to the business software, for stock management and invoicing
- Invoices pulled from the business software back into the app
Since the integration would touch almost every part of the application and change several processes, we wanted to avoid a big bang at the start of the new financial year as much as possible. Instead, we opted for an incremental approach, deploying small pieces often so they could already sit in production and surface any issues quickly.
Because the new parts were already pushing to a test environment of the business software until the changeover, it
allowed us to test with real data and real scenarios without (a big) impact on the current functionality.
One of the things we uncovered this way was that while the business software supported sending invoices by email, it
did not allow adding attachments besides the invoice PDF. Because we needed to attach delivery receipts, we chose to
pull the invoice back into the app and send the email from there.
Changeover
The changeover was still riskier than we wanted because of two things.
The first was that, as much as we had integrated and tested in production already, some parts had only been tested on
our test environment or not at all.
This included everything coming back from the business software into the app, such as pulling in invoices, stock level
synchronisation and invoice payment status. We obviously didn't want any data or invoices from a test environment to end up in
production, least of all ones generated by a system that was only meant to be used from the new financial year on.
The second was the VAT setup. Getting the maritime sector's rules and codes right depended on the finance department's
knowledge, but they had very little time alongside their day-to-day work to explore the new business software ahead of
time and work out the right setup.
As a result, the VAT logic wasn't fully in place before the changeover.
At the start of the new financial year, we switched to the production environment of the business software and
activated the features pulling data into the app. As the finance department learned how to work with the new software,
several processes and edge cases surfaced that we hadn't heard about before.
About three months after the changeover, we'd tackled all the issues that had come up and the integration was running
smoothly.
RESULT
By the time the integration had stabilised, the operator's back-office flow was almost fully automated. Invoices were
generated automatically when orders were completed, and stock levels were kept up to date from the orders.
The finance department had moved its bookkeeping to the new business software, and with that the operator was set up for
the electronic invoicing obligation coming in January 2026.
Similar challenge?