When using WooCommerce Germanized you might end up with processed orders but the invoices can not be generated. Clicking onto the Create invoice button throws the following error:
An invoice could not be created due to changes to or inconsistent order data. Please review the corresponding order.
For debugging purposes, you can look into wp-content/plugins/woocommerce-germanized-pro/packages/storeabill/src/WooCommerce/Order.php
. Somewhere in protected function get_order_items_to_cancel( $args = array() )
WooCommerce Germanized detects a pricing difference.
This is most likely to a mismatch between the data provided during the payment and the current point in time.
WooCommerce Germanize does the following:
- If not present, create a new invoice in the table
storeabill_documents
- Fill up the invoice items in table
storeabill_document_items
by loading the data fromwoocommerce_order_items
- Fill up the invoice meta data in table
storeabill_document_itemmeta
by loading the data fromwoocommerce_order_itemmeta
- Check, if the generated invoice has the same sum for each of the line items
- If the invoice does not match the order, the invoice is automatically deleted.
⚠️ As soon as you click theSync
button in the WooCommerce order UI, the process is repeated. For sake of sanity, do not manipulate any of the thestoreabill_document_item*
tables but instead fix the data inwoocommerce_order_items
.
Check that the taxes are calculated properly. Copy the Billing Address to the Shipping Address field by using Copy billing address. WooCommerce Germanized might use the Shipping Address to calculate the total taxes. This might differ between the order time and the time of the creation of the invoice.
In case of a tax rate change between the original invoice date and today (e.g. if your state has changed the tax rate from 16% to 19%), update the database:
-- find order_item_id containing the order_item_type = tax; ${ORDER_ID} can be extracted from the `post` GET parameter
SELECT * FROM woocommerce_order_items WHERE order_id = ${ORDER_ID} AND order_item_type = 'tax';
-- check if the the meta_key = 'rate_percent' matches the official tax rate at tha point in time during invoice/payment creation
SELECT * FROM woocommerce_order_itemmeta WHERE order_item_id = ${ORDER_ITEM_ID} AND meta_key = 'rate_percent'
-- set correct tax rate
UPDATE woocommerce_order_itemmeta SET meta_value = 16 WHERE order_item_id = ${ORDER_ITEM_ID} AND meta_key = 'rate_percent';
Now you should be able to generate a new invoice draft by clicking onto the Create invoice button. Do not finalize yet.
If the invoice date is in the past, you have to apply a WordPress hook. Otherwise, the invoice gets the current date as invoice date. Due to WooCommerce Germanized architecture it is not sufficient to just modify a database entry.
- Get the invoice document ID by hovering over the Preview button and note the
document_id
GET parameter. - Add the following code to a
functions.php
in yourwp-content/plugins
folder:add_action('storeabill_invoice_before_finalize', function($invoice) { if ($invoice->get_id() == '${DOCUMENT_ID}') { // change to the date you want $invoice->set_date_created('2021-12-03 15:00:00'); } }, 10, 1);
- The hook then gets called by
public function finalize( $defer_render = false )
inVendidero\StoreaBill\Invoice\Invoice.php
and resets the invoice date, before rendering the PDF.
⚠️ You do not want to do this. Fix the data inwoocommerce_order_items
. Really. The values get overwritten as soon as a new invoice for the order (or subscription) is generated. :warning I've added the script so that I do not try to be smart again.
Create a new invoice. It is automatically called Draft ${DRAFT_NUMBER}
. You can manipulate the draft state by executing the following SQL script.
UPDATE adi_storeabill_documentmeta
SET meta_value = 'no'
WHERE
meta_key = '_is_reverse_charge'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = 'yes'
WHERE
meta_key = '_is_taxable'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${PRICE_INCLUDING_TAXES}'
WHERE
meta_key = '_total'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${PRICE_INCLUDING_TAXES}'
WHERE
meta_key = '_subtotal'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${PRICE_INCLUDING_TAXES}'
WHERE
meta_key = '_total_paid'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${PRICE_INCLUDING_TAXES}'
WHERE
meta_key = '_product_total'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${PRICE_INCLUDING_TAXES}'
WHERE
meta_key = '_product_subtotal'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${ONLY_TAX_AMOUNT}'
WHERE
meta_key = '_total_tax'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${ONLY_TAX_AMOUNT}'
WHERE
meta_key = '_product_tax'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${ONLY_TAX_AMOUNT}'
WHERE
meta_key = '_subtotal_tax'
AND storeabill_document_id = '${DRAFT_NUMBER}';
UPDATE adi_storeabill_documentmeta
SET meta_value = '${ONLY_TAX_AMOUNT}'
WHERE
meta_key = '_product_subtotal_tax'
AND storeabill_document_id = '${DRAFT_NUMBER}';