Commit d3076e9a authored by Reinhold Kainhofer's avatar Reinhold Kainhofer

Implement invoice numbers for wpo wcpdf invoices and packaging slips

parent 41d40415
......@@ -38,3 +38,18 @@ woocommerce_new_order', $order_id );
Order created in BackEnd:
Created: wp_insert_post => Assign placeholder (no address yet)
Modified:
TODO:
Check order/invoice numbers for renewals: https://wordpress.org/support/topic/subscription-renewal-duplicate-invoice-number?replies=6#post-6138110
INVOICES:
=========
woocommerce-pdf-invoices-packing-slips:
-) Uses order_meta: _wcpdf_invoice_number => Set it manually to prevent the plugin from using its own counter
-) Calls filter wpo_wcpdf_invoice_number($invoice_number, $order_number, $order_id, $order_data) to format the invoice number.
-) Triggers before PDF creation: wp_wcpdf_before_pdf, wpo_wcpdf_process_order_ids, wpo_wcpdf_process_template_order($template_type, $order_id)
......@@ -7,9 +7,23 @@ jQuery( function ( $ ) {
if ($(this).is(':checked')) {
$('#ordernumber_format').closest('tr').show();
$('#ordernumber_global').closest('tr').show();
$('#ordernumber-countertable-ordernumber').closest('tr').show();
} else {
$('#ordernumber_format').closest('tr').hide();
$('#ordernumber_global').closest('tr').hide();
$('#ordernumber-countertable-ordernumber').closest('tr').hide();
}
}).change();
$('input#customize_invoice').change(function() {
if ($(this).is(':checked')) {
$('#invoice_format').closest('tr').show();
$('#invoice_global').closest('tr').show();
$('#ordernumber-countertable-invoice').closest('tr').show();
} else {
$('#invoice_format').closest('tr').hide();
$('#invoice_global').closest('tr').hide();
$('#ordernumber-countertable-invoice').closest('tr').hide();
}
}).change();
......
......@@ -39,6 +39,14 @@ class OrdernumberHelper {
$this->registerCallback ("setupDateTimeReplacements", array($this, "setupDateTimeReplacements"));
}
static function getHelper() {
static $helper = null;
if (!$helper) {
$helper = new OrdernumberHelper();
}
return $helper;
}
function getStyle($key) {
if (isset($this->_styles[$key])) {
return $this->_styles[$key];
......@@ -388,7 +396,7 @@ class OrdernumberHelper {
public function counter_modification_create_table($type, $counters) {
$html=array();
$html[] = "<img src='" . $this->urlPath ('images', 'loading.gif') . "' class='ordernumber-loading' />";
$html[] = "<table class=\"ordernumber-countertable " . $this->getStyle('counter-table-class') . "\" " . $this->getStyle('counter-table-style') . ">";
$html[] = "<table class=\"ordernumber-countertable " . $this->getStyle('counter-table-class') . "\" " . $this->getStyle('counter-table-style') . " id='ordernumber-countertable-" . $type . "'>";
$html[] = "<thead>";
$html[] = " <tr>";
$html[] = " <th class='counter_format'>" . $this->__ ('PLG_ORDERNUMBER_COUNTERLIST_HEADER_COUNTER')."</th>";
......@@ -560,4 +568,30 @@ var ajax_ordernumber = ' . json_encode($json) . ';
return $js;
}
public function ajax_counter_delete($type, $counter) {
// TODO: Check if counter value has changed meanwhile
$json = array('action' => 'delete_counter', 'success' => 0);
$json['success'] = $this->deleteCounter($type, $counter);
return $json;
}
public function ajax_counter_add ($type, $counter, $value) {
// TODO: Check if counter value has changed meanwhile
$json = array('action' => 'add_counter', 'success' => 0);
if ($this->getCounter($type, $counter, -1) != -1) {
// Counter already exists => error message
$json['error'] = sprintf($this->__('Counter "%s" already exists, cannot create again.'), $counter);
} else {
$json['success'] = $this->setCounter($type, $counter, $value);
$json['row'] = $this->counter_modification_create_row($type, $counter, $value);
}
return $json;
}
public function ajax_counter_set ($type, $counter, $value) {
$json = array('action' => 'set_counter', 'success' => 0);
$json['success'] = $this->setCounter($type, $counter, $value);
$json['row'] = $this->counter_modification_create_row($type, $counter, $value);
return $json;
}
}
......@@ -64,9 +64,11 @@ class OpenToolsOrdernumbers {
// When a new order is created, we immediately assign the order number:
add_action( 'wp_insert_post', array(&$this, 'check_assignNumber'), 10, 3);
// add_action( 'save_post', array(&$this, 'check_assignNumber'), 10, 3);
// The filter to actually return the order number for the given order
add_filter ('woocommerce_order_number', array(&$this, 'get_ordernumber'), 10, 2/*<= Also get the order object! */);
$this->thirdparty_wpo_wcpdf_init();
}
......@@ -101,8 +103,7 @@ class OpenToolsOrdernumbers {
),
array(
'title' => $this->helper->__( 'Use global counter'),
'desc' => $this->helper->__( 'A global counter is independent of the number format and will never reset. A non-global counter runs within the number format and will start from the inital value whenever any of the variables used in the format changes (to be precise: a new counter will be used, so it is possible to have multiple counters running in parallel).'),
'desc_tip' => true,
'desc' => $this->helper->__( 'A global counter never resets. Non-global counters run within each number format and reset whenever any variable changes.'),
'id' => 'ordernumber_global',
'type' => 'checkbox',
'default' => 'no',
......@@ -117,6 +118,51 @@ class OpenToolsOrdernumbers {
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_options' ),
/**
* Invoice number settings
*/
array(
'name' => $this->helper->__( 'Advanced Invoice Numbers'),
'desc' => $this->helper->__('This plugin currently supports modifying the invoice number formats of the following invoicing plugins: <a href="https://wordpress.org/plugins/woocommerce-pdf-invoices-packing-slips/">WooCommerce PDF Invoices & Packing Slips</a>'),
'type' => 'title',
'id' => 'invoice_options'
),
array(
'name' => $this->helper->__( 'Customize Invoice Numbers'),
'desc' => $this->helper->__( 'Check to use custom invoice numbers rather than the default format of your invoicing plugin.'),
'id' => 'customize_invoice',
'type' => 'checkbox',
'default' => 'no'
),
array(
'title' => $this->helper->__( 'Invoice number format'),
'desc' => $this->helper->__( 'The format for the invoice numbers (variables can be entered as [...], the counter is indicated by the #). To use a different counter name than displayed, put the custom counter name after a |, e.g. "[year]-[month]/#|[year]" to use the month in the invoice number, but reset the counter only yearly. Advanced settings for the counter can be added as [#####:start/step], e.g. [#:100] to start new counters at 100, or [#/5] to increment the counter by 5. The number of # in the format determine how many digits are shown at least, e.g. [########] will always show at least 8 digits for the counter, e.g. 00000014.'),
'desc_tip' => true,
'id' => 'invoice_format',
'default' => '#',
'type' => 'text',
'css' => 'width: 100%',
),
array(
'title' => $this->helper->__( 'Use global counter'),
'desc' => $this->helper->__( 'A global counter never resets. Non-global counters run within each number format and reset whenever any variable changes.'),
'id' => 'invoice_global',
'type' => 'checkbox',
'default' => 'no',
),
array(
'name' => $this->helper->__( 'All invoice number counters'),
'desc' => $this->helper->__( 'View and modify the current counter values. The counter value is the value used for the previous number. All changes are immediately applied!'),
'desc_tip' => true,
'id' => 'ordernumber_counters',
'type' => 'ordernumber_counters',
'nrtype' => 'invoice',
),
array( 'type' => 'sectionend', 'id' => 'invoice_options' ),
// TODO: customize order password, and other numbers!
array(
......@@ -131,19 +177,16 @@ class OpenToolsOrdernumbers {
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_variables' ),
array(
'name' => $this->helper->__( 'Current Counters'),
'type' => 'title',
'id' => 'ordernumber_counters'
),
array( 'type' => 'sectionend', 'id' => 'ordernumber_counters' ),
);
// Default options
add_option ('customize_ordernumber', 'no');
add_option ('ordernumber_format', "#");
add_option ('ordernumber_global', 'no');
add_option ('customize_invoice', 'no');
add_option ('invoice_format', "#");
add_option ('invoice_global', 'no');
add_option ('ordernumber_variables', array());
}
......@@ -294,30 +337,17 @@ class OpenToolsOrdernumbers {
*/
public function counter_delete_callback() {
$json = array('action' => 'delete_counter', 'success' => 0);
$json['success'] = $this->helper->deleteCounter($_POST['nrtype'], $_POST['counter']);
$json = $this->helper->ajax_counter_delete($_POST['nrtype'], $_POST['counter']);
wp_send_json($json);
}
public function counter_add_callback () {
$type = $_POST['nrtype'];
$format = $_POST['counter'];
$value = isset($_POST['value'])?$_POST['value']:"0";
$json = array('action' => 'add_counter', 'success' => 0);
if ($this->helper->getCounter($type, $format, -1) != -1) {
// Counter already exists => error message
$json['error'] = sprintf($this->helper->__('Counter "%s" already exists, cannot create again.'), $format);
} else {
$json['success'] = $this->helper->setCounter($type, $format, $value);
$json['row'] = $this->helper->counter_modification_create_row($type, $format, $value);
}
$json = $this->helper->ajax_counter_add($_POST['nrtype'], $_POST['counter'], isset($_POST['value'])?$_POST['value']:"0");
wp_send_json($json);
}
public function counter_set_callback () {
$json = array('action' => 'set_counter', 'success' => 0);
$json['success'] = $this->helper->setCounter($_POST['nrtype'], $_POST['counter'], $_POST['value']);
$json['row'] = $this->helper->counter_modification_create_row($_POST['nrtype'], $_POST['counter'], $_POST['value']);
$json = $this->helper->ajax_counter_set($_POST['nrtype'], $_POST['counter'], $_POST['value']);
wp_send_json($json);
}
......@@ -460,6 +490,15 @@ class OpenToolsOrdernumbers {
return $number;
}
function get_or_create_number($orderid, $order, $type = 'ordernumber') {
$stored_number = get_post_meta( $orderid, $this->ordernumber_meta.$type, true);
if (!empty($stored_number)) {
return $stored_number;
} else {
return $this->generateNumber($orderid, $order, $type);
}
}
/**
* The generic function to retrieve a particular number
*/
......@@ -479,9 +518,81 @@ class OpenToolsOrdernumbers {
/**
* Callback function for Woocommerce to retrieve the ordernumber for an order
* The hook to customize order numbers (requests the order number from the database;
* creates a new ordernumber if no entry exists in the database)
*/
function get_ordernumber($orderid, $order) {
return $this->get_number($orderid, $order);
return $this->get_number($orderid, $order, 'ordernumber');
}
/** ************************************************************
* Support for WPO WooCommerce PDF Invoices and Packaging Slips
** ************************************************************
*
* - Invoice numbers are stored in the _wcpdf_invoice_number post meta
* - the filter wpo_wcpdf_invoice_number($invoice_number, $order_number, $order_id, $order_data) is called
* to format the (existing) invoice number retrieved from that post meta
* - The action wpo_wcpdf_process_template_order($template_type, $order_id) is called right before
* the invoice is created. There we can already set the _wcpdf_invoice_number post meta with our own value
*/
/**
* Initialize support for WPO WooCommerce PDF Invoices and Packaging Slips
*/
protected function thirdparty_wpo_wcpdf_init() {
// TODO: Wheck whether the woocommerce-pdf-invoices-packing-slips plugin is installed at all
add_filter ('wpo_wcpdf_invoice_number', array($this, 'thirdparty_wpo_wcpdf_invoice_number'), 30, 4);
add_action ('wpo_wcpdf_process_template_order', array($this, 'thirdparty_wpo_wcpdf_create_number'), 10, 2);
// Disable the invoice number-related controls in the config of the other plugin
add_action ('woocommerce_page_wpo_wcpdf_options_page', array($this, 'thirdparty_wpo_wcpdf_remove_options'));
}
/**
* Support for WPO WooCommere PDF Invoices and Packaging Slips
* Filter to return the invoice number => simply return the first argument unchanged (was already
* created in the correct format, no need to format it now again)
*/
function thirdparty_wpo_wcpdf_invoice_number($invoice_number, $order_number, $order_id, $order_data) {
$nr = $this->get_number($order_id, $order_data, 'invoice');
if ($nr == $order_id) {
// No number was found, so the default is the order id => reset to invoice number
return $invoice_number;
} else {
return $nr;
}
}
/**
* The action to actually create the number and store it as post meta with the order
*/
function thirdparty_wpo_wcpdf_create_number($type, $orderid) {
if ($type=='invoice' && (get_option('customize_'.$type, 'no')!='no') ) {
$_of = new WC_Order_Factory();
$order = $_of->get_order($orderid);
$number = $this->get_or_create_number($orderid, $order, $type);
// TODO: Store the invoice number counter in _wcpdf_invoice_number and the custom invoice
// number in the opentools meta, because the plugin assumes the number to be numeric...
update_post_meta( $orderid, '_wcpdf_invoice_number', $number );
}
}
/**
* The action that is called for the WPO WCPDF invoice plugin only, when the options page is loaded.
* If this plugin is enabled and invoice numbers are configured, we simply remove all invoice number-specific
* settings, because this plugin will be responsible....
*/
function thirdparty_wpo_wcpdf_remove_options() {
global $wp_settings_fields;
if (get_option('customize_invoice', 'no')!='no') {
$wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['display_number']['title'] = $this->helper->__('Display invoice number');
$wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['display_number']['args']['description'] = $this->helper->__('The <a href="admin.php?page=wc-settings&tab=checkout&section=ordernumber">Open Tools Ordernumber plugin</a> has invoice numbers enabled and will generate invoice numbers for this plugin.' );
unset($wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['next_invoice_number']);
unset($wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['invoice_number_formatting']);
} else {
$wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['display_number']['args']['description'] = $this->helper->__('To let the Open Tools ordernumber plugin create invoice numbers with your desired format, please enable invoices in <a href="admin.php?page=wc-settings&tab=checkout&section=ordernumber">that plugin\'s configuration page</a>.' );
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment