Skip to main content

PDF Invoices & Packing Slips

Overview​

The Invoicing module numbers and stores a document per order — an invoice or a packing slip — built from a template, and gives the customer a link to it from the order emails and from My Account. Store staff generate, list, view and delete documents from the admin screen.

It is for stores that need a numbered document per order with their own company details, tax number and layout on it.

What the module produces​

Documents are generated and stored as HTML, not as PDF files. InvoiceGenerator renders the template and writes the result to wp-content/uploads/aiowc-invoices/<year>/<month>/<invoice-number>.html, and stores that path in the invoice row's pdf_path column. The download route returns the rendered HTML in its response body.

A separate PdfGeneratorService exists that would render through TCPDF or Dompdf, falling back to writing HTML when neither is present. Neither library is a declared dependency of the plugin, and no shipped code path calls that service: the generator and the REST routes both use the HTML path above. The module manifest records the two missing classes as a known issue.

The directory is protected on creation with an .htaccess denying access and an empty index.php, so documents are not served directly from uploads on an Apache host.

Availability​

ItemValue
Module keyinvoicing
TierPremium
Entitlement keyinvoicing
Admin tabinvoicing, under Operations
Enabled optionaiowc_module_enabled_invoicing (off until turned on)
REST namespaceaiowc/v1

Enabling the module creates the two tables below, seeds the defaults and schedules the two jobs.

Settings​

Stored in the bundled option row aiowc_inv_settings; legacy per-key options aiowc_inv_<key> are migrated on first read.

API nameStored keyDefaultMeaning
companyNamecompany_namesite titleCompany name printed on the document.
companyAddresscompany_addressemptyCompany address block.
companyLogoUrlcompany_logo_urlemptyLogo shown on the document.
taxNumbertax_numberemptyTax or VAT registration number.
invoicePrefixinvoice_prefixINV-Prefix on generated numbers.
nextInvoiceNumbernext_invoice_number1The next sequence number.
templateIdtemplate_id0Template used; 0 means the built-in one.
autoAttachEmailauto_attach_emailtrueWhether a link to the invoice is added to customer order emails.
paperSizepaper_sizea4Stored size. Only the unused PDF service reads it, so it has no effect on the HTML output.

Admin screens​

The Invoices tab has two sub-tabs:

Sub-tabWhat it offers
InvoicesThe invoice list with its filters, generation for an order, viewing and deletion.
SettingsA form over the company details, numbering and email settings above.

An order meta box exists in the code (Frontend/OrderHandler.php, with admin_post handlers for generating and viewing) but it is never registered: the module initialises only the email and account handlers. There is no invoice control on the WooCommerce order edit screen in this release.

REST API endpoints​

All routes are on aiowc/v1. "Manage" means manage_woocommerce plus a REST nonce on cookie-authenticated requests.

MethodPathPurposeRequired argsPermission
POST/invoicing/generateGenerate a document for an order; type selects invoice or packing slip.order_idManage
GET/invoicing/invoicesList documents; accepts page, per_page, type, status, order_id, search.–Manage
GET/invoicing/invoices/{id}Read one document record.idManage
DELETE/invoicing/invoices/{id}Delete the record and its stored file.idManage
GET/invoicing/invoices/{id}/downloadReturn the rendered document.idSee below
GET/invoicing/overviewCounts for the admin overview.–Manage
GET/invoicing/settingsRead the settings above.–Manage
PUT / PATCH / POST/invoicing/settingsUpdate the settings above.–Manage

The download route has its own check: a user with manage_woocommerce is allowed; otherwise the caller must be signed in, and the invoice must exist. An anonymous caller is refused with 401.

WooCommerce integration​

HookWhat the module does
woocommerce_email_after_order_tableAdds an invoice link to customer order emails, in both HTML and plain text.
woocommerce_my_account_my_orders_actionsAdds an invoice action button to the My Account orders list.
woocommerce_order_details_after_order_tableShows an invoice download section on the order detail page, only to the order's own customer.
template_redirectServes ?aiowc_invoice=<id>&key=<order key>.

The email link is added only when autoAttachEmail is on, only to customer-facing mail (never the admin copy), and only for the completed, processing, invoice and on-hold customer emails. It links to the first non-cancelled document of type invoice for that order.

The public view path takes the invoice id and the WooCommerce order key. The order key is treated as the credential and compared with hash_equals; a caller with manage_woocommerce or the order's own customer is allowed. A missing invoice or order is a 404.

Database schema​

TableHolds
{prefix}aiowc_invoicesOne row per document: order, number, type, status, stored file path, total, tax total, currency, issue date.
{prefix}aiowc_invoice_templatesDocument templates.

Background jobs​

Both are Action Scheduler recurring actions in the aiowc-invoicing group.

HookIntervalWork
aiowc_invoice_cleanupWeeklyDeletes documents older than 365 days. The retention period is fixed in the job, not a setting.
aiowc_invoice_number_resetDailyOnce per calendar year, prefixes the invoice prefix with the new year and resets the next number to 1.

AutoGenerateJob exists in the module but is never instantiated or registered, so documents are not generated automatically on an order transition. Generation is a deliberate call to POST /invoicing/generate.

Entitlement limits​

invoicing is an on/off grant with no licence-side cap on the number of documents. Retention is bounded by the cleanup job's fixed 365 days.

Health check​

The module reports a warning when its tables are missing, when WooCommerce is inactive, or when the invoice storage directory is not writable, and otherwise reports that it is functioning normally.