Proposal for a general API for third-party WooCommerce invoice numbering plugins
While WooCommerce provides a standard way for third-party plugins to generate nice order numbers via the filter
woocommerce_order_number($orderid, $order)
it does not provide any invoicing solution. There are several third-party invoicing plugins available, each of which implement their own numbering schemes with their own settings. And each of them stores the invoice numbers for an order differently, so switching to another invoicing plugin is not possible without loosing all invoice numbers for existing orders.
Furthermore, most invoice plugins only allow simple running counters with a prefix and a postfix as invoice numbers, possibly with a yearly reset. Our OpenTools "Advanced Order Numbers for WooCommerce" plugin, however, allows for much more flexible numbers, like monthly numbers (like 2016-02-0001) or even per-country numbers (like 2016-DE-0001, 2016-US-0001, etc.).
We therefore propose a general API for invoice numbering plugins that invoice plugins can call to allow third-party plugins provide more flexible invoice numbers.
Possible Use Cases
- Dedicated numbering plugins like our OpenTools Advanced Ordernumbers plugin, or the WooCommerce Sequential Ordernumbers Pro plugin
- Interfacing plugins that connect WooCommerce to an external bookeeping system, which would make sure invoices for in-shop purchases and online purchases use the same sequential invoice numbering, while invoices for online purchases are still created by WooCommerce.
- Payment providers that generate their own invoice numbers, but don't actually issue a PDF invoice and leave that up to the webshop.
Filters to be implemented by Numbering plugins (can be applied from invoicing plugins)
woocommerce_invoice_number($default, $orderID)
Similar to WooCommerce's woocommerce_order_number filter. If an invoice number already exists for the order, the numbering plugin should return it, otherwise it should create a new number. If a numbering plugin is configured not to create invoice numbers, $default should be passed through.
woocommerce_generate_invoice_number($default, $order)
Always create a new invoice number for the given order (full WC_Order object) and return it. This can be used by invoice plugins to make sure a new number is created when the order is finalized or to reset the invoice for an existing order.
woocommerce_invoice_number_by_plugin($third_party)
Return whether a third-party plugin will respond to the filters above and provide invoice numbers. In particular, this can be used by invoice plugins to check whether a third-party numbering plugin is installed and configured. The invoice plugin would then not create an invoice number itself, and it can also hide all corresponding invoice number settings. It can even provide a link to the numbering plugin's configuration page using the following filter:
woocommerce_invoice_number_configuration_link($default=null)
Return the URL of the third-party numbering plugin's configuration page, e.g. 'admin.php?page=wc-settings&tab=checkout§ion=ordernumber'
How to use these filters in invoicing plugins
Typical code when an invoice is first created (e.g. the order status changes to a status where an invoice should be created) and thus a new invoice number should be created. Please note that the woocommerce_invoice_number_by_plugin filter is not strictly neccessary and might be left out. Also note that one could also use the woocommerce_invoice_number filter, which would create an invoice number only if it doesn't exit (which is the case for a new order).
function woocommerce_completed_order_create_invoice_number( $order ) {
if (apply_filters('woocommerce_invoice_number_by_plugin', false)) {
$invnum = apply_filters('woocommerce_generate_invoice_number', null, $order);
if ($invnum != null)
return $invnum;
}
// No third-party plugin provides an invoice number -> use the built-in numbering
....
}
Typical code when an invoice is to be displayed (and the order number has possibly been generated in the past, e.g. because the invoice is in HTML format):
function woocommerce_display_invoice( $order_id ) {
if (apply_filters('woocommerce_invoice_number_by_plugin', false)) {
$invoice_number =
apply_filters('woocommerce_invoice_number', null, $order_id);
} else {
$invoice_number = get_post_meta($order_id, '_MYINVPLUG_invoice_number', 1);
}
// Now, display the invoice with the above invoice number
....
}
Typical code to hide certain configuration settings regarding built-in invoice counters:
$plugin_options = array(
....
'section_invoices' => array('name' => __('Invoices', 'my-pdf-invoice-plugin'),
'type' => 'title',
'id' => 'invoice_section',
),
'invoice_prefix' => array(
'name' => __('Invoice prefix', 'my-pdf-invoice-plugin'),
'type' => 'text',
'id' => 'invoice_prefix',
),
....
'invoices_end' => array(
'type' => 'sectionend',
'id' => 'invoice_section_end',
),
);
if (apply_filters('woocommerce_invoice_number_by_plugin', false)) {
$config_link = esc_attr(apply_filters('woocommerce_invoice_number_configuration_link', null));
$desc = __( 'Invoice numbers are created by a third-party extension.', 'my-pdf-invoice-plugin');
if ($config_link) {
$desc .= ' '.sprintf(__( 'Configure it <a href="/%s">here</a>.', 'my-pdf-invoice-plugin'), $config_link);
}
$general_options['documents']['section_invoice_settings']['desc'] = '<i>'.$desc.'</i>';
unset($plugin_options['invoice_prefix']);
}
Patches for existing Invoice plugins
WooCommerce PDF Invoices by WooThemes (woocommerce-pdf-invoice)
- Code Review: https://codereview.appspot.com/287270043
WooCommerce PDF Invoices by Bas Elbers (woocommerce-pdf-invoices)
- Code Review: https://codereview.appspot.com/287260044
YITH PDF Invoices for WooCommerce (yith-woocommerce-pdf-invoice)
- Code Review: https://codereview.appspot.com/289320043
WooCommerce PDF Invoices & Packing Slips by Ewout Fernhout (woocommerce-pdf-invoices-packing-slips)
- Code Review: https://codereview.appspot.com/286500043/
WooCommerce Print Invoice & Delivery Note by Triggvy Gunderson (woocommerce-delivery-notes)
- Code Review: https://codereview.appspot.com/286490043/
- GIT Pull request: https://github.com/piffpaffpuff/woocommerce-delivery-notes/pull/126