From 6327cf306d2426e11086f378a1756678daae8e60 Mon Sep 17 00:00:00 2001
From: Reinhold Kainhofer <reinhold@kainhofer.com>
Date: Sun, 19 Apr 2015 20:22:46 +0200
Subject: [PATCH] Implement counter formatting/start/step directly in thee
 format

---
 TODO                                  |   5 +-
 woocommerce-advanced-ordernumbers.php | 178 +++++++++++++++++---------
 2 files changed, 119 insertions(+), 64 deletions(-)

diff --git a/TODO b/TODO
index 19aff74..624b223 100644
--- a/TODO
+++ b/TODO
@@ -4,13 +4,12 @@ OpenTools Advanced Ordernumbers for WooCommerce - Open TODOs
 - Make sure the numbers are generated only for new orders, not for exsiting ones
 - Check REST API
 - Would it make sense to configure the order password format?
-- Implement custom variables
 - Find out how multisite works and make the plugin work with it
 - Add action to create an updated / new order number for an existing order
 - implement woocommerce_hidden_order_itemmeta hook to hide the order number post meta?
 - Use $order->order_date for the date-relating fields!
 - Collect and return php warning messages (i.e. all other output) in the AJAX call and return it inside the JSON rather than as extra HTML.
-
+- Create order number also when ordering in the frontend
 
 
 HOOKS for order handling:
@@ -37,4 +36,4 @@ woocommerce_new_order', $order_id );
 
 Order created in BackEnd:
 Created: wp_insert_post => Assign placeholder (no address yet)
-Modified: 
\ No newline at end of file
+Modified: 
diff --git a/woocommerce-advanced-ordernumbers.php b/woocommerce-advanced-ordernumbers.php
index 062a7d5..b48c436 100644
--- a/woocommerce-advanced-ordernumbers.php
+++ b/woocommerce-advanced-ordernumbers.php
@@ -85,11 +85,12 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
 					),
 					array(
 						'title'		=> self::__( 'Order number format'),
-						'desc' 		=> self::__( 'The format for the order 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 order number, but reset the counter only yearly.'),
+						'desc' 		=> self::__( 'The format for the order 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 order 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' 		=> 'ordernumber_format',
 						'default'	=> '#',
 						'type' 		=> 'text',
+						'css'		=> 'width: 100%',
 					),
 					array(
 						'title'		=> self::__( 'Use global counter'),
@@ -97,32 +98,32 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
 						'desc_tip'	=> true,
 						'id' 		=> 'ordernumber_global',
 						'type' 		=> 'checkbox',
-						'default'	=> 'no'
-					),
-					array(
-						'title' 	=> self::__( 'Counter Digits'),
-						'desc' 		=> self::__( 'Minimum number of digits for the number'),
-						'desc_tip'	=> true,
-						'id' 		=> 'ordernumber_padding',
-						'type' 		=> 'number',
-						'default'	=> '0'
-					),
-					array(
-						'title' 	=> self::__( 'Counter Start'),
-						'desc' 		=> self::__( 'Start value for each new counter'),
-						'desc_tip'	=> true,
-						'id' 		=> 'ordernumber_start',
-						'type' 		=> 'number',
-						'default'	=> '1'
-					),
-					array(
-						'title'		=> self::__( 'Counter step'),
-						'desc' 		=> self::__( 'By how much the counter will be increased after each order. Typically 1.'),
-						'desc_tip'	=> true,
-						'id' 		=> 'ordernumber_step',
-						'type' 		=> 'number',
-						'default'	=> '1'
+						'default'	=> 'no',
 					),
+// 					array(
+// 						'title' 	=> self::__( 'Counter Digits'),
+// 						'desc' 		=> self::__( 'Minimum number of digits for the number'),
+// 						'desc_tip'	=> true,
+// 						'id' 		=> 'ordernumber_padding',
+// 						'type' 		=> 'number',
+// 						'default'	=> '0'
+// 					),
+// 					array(
+// 						'title' 	=> self::__( 'Counter Start'),
+// 						'desc' 		=> self::__( 'Start value for each new counter'),
+// 						'desc_tip'	=> true,
+// 						'id' 		=> 'ordernumber_start',
+// 						'type' 		=> 'number',
+// 						'default'	=> '1'
+// 					),
+// 					array(
+// 						'title'		=> self::__( 'Counter step'),
+// 						'desc' 		=> self::__( 'By how much the counter will be increased after each order. Typically 1.'),
+// 						'desc_tip'	=> true,
+// 						'id' 		=> 'ordernumber_step',
+// 						'type' 		=> 'number',
+// 						'default'	=> '1'
+// 					),
 					array( 'type' => 'sectionend', 'id' => 'ordernumber_options' ),
 					
 					// TODO: customize order password, and other numbers!
@@ -158,10 +159,10 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
 
 				add_option ('customize_ordernumber', '0');
 				add_option ('ordernumber_format',    "#");
-				add_option ('ordernumber_global',    '0');
-				add_option ('ordernumber_padding',   '1');
-				add_option ('ordernumber_start',     '1');
-				add_option ('ordernumber_step',      '1');
+				add_option ('ordernumber_global',    'no');
+// 				add_option ('ordernumber_padding',   '1');
+// 				add_option ('ordernumber_start',     '1');
+// 				add_option ('ordernumber_step',      '1');
 				
  				add_option ('ordernumber_variables',  array());
 
@@ -712,7 +713,7 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
 			}
 
 			
-			protected function applyCustomVariables ($nrtype, $order, $reps, $customvars) {
+			protected function setupCustomVariables ($nrtype, $order, $reps, $customvars) {
 				foreach ($customvars as $c) {
 					$conditionvar = strtolower($c['conditionvar']);
 					$op = $c['conditionop'];
@@ -770,14 +771,8 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
 				return $reps;
 			}
 
-			protected function doReplacements ($fmt, $reps) {
-				// First, replace all random...[n] fields. This needs to be done with a regexp and a callback:
-				$fmt = preg_replace_callback ('/\[(random)(.*?)([0-9]*?)\]/', array($this, 'replaceRandom'), $fmt);
-				return str_ireplace (array_keys($reps), array_values($reps), $fmt);
-			}
-
 			// Allow the user to override the format like any other custom variable:
-			protected function determineNumberFormatString($fmt, $type, $order, $reps) {
+			protected function setupNumberFormatString($fmt, $type, $order, $reps) {
 				if (isset($reps['['.$type.'_format]'])) {
 					return $reps['['.$type.'_format]'];
 				} else {
@@ -785,38 +780,99 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
 				}
 			}
 			
+			protected function doReplacements ($fmt, $reps) {
+				// First, replace all random...[n] fields. This needs to be done with a regexp and a callback:
+				$fmt = preg_replace_callback ('/\[(random)(.*?)([0-9]*?)\]/', array($this, 'replaceRandom'), $fmt);
+				return str_ireplace (array_keys($reps), array_values($reps), $fmt);
+			}
+			
+			protected function extractCounterSettings ($fmt, $type, $ctrsettings) {
+				// First, extract all counter settings, i.e. all strings of the form [#####:startval/increment] or [####/increment:startval]
+				$regexp = '%\[(#+)(/([0-9]+))?(:([0-9]+))?(/([0-9]+))?\]%';
+// 				$counters = array();
+				
+				if (preg_match($regexp, $fmt, $counters)) {
+					// $counters is an array of the form:
+					// Array (
+					// 		[0] => [#####:100/3]
+					// 		[1] => #####
+					// 		[2] => 
+					// 		[3] => 
+					// 		[4] => :100
+					// 		[5] => 100
+					// 		[6] => /3
+					// 		[7] => 3
+					// )
+					$ctrsettings["${type}_padding"] = strlen($counters[1]);
+					if (!empty($counters[2])) {
+						// $counters[2] contains the whole "/n" part, while $counters[3] contains just the step itself
+						$ctrsettings["${type}_step"] = $counters[3]; 
+					}
+					if (!empty($counters[4])) {
+						// $counters[4] contains the whole ":n" part, while $counters[5] contains just the start value itself
+						$ctrsettings["${type}_start"] = $counters[5]; 
+					}
+					
+					if (!empty($counters[6])) {
+						// $counters[6] contains the whole ":n" part, while $counters[7] contains just the start value itself
+						$ctrsettings["${type}_step"] = $counters[7]; 
+					}
+					
+// print("<pre>Counters regexp matches: ".print_r($counters,1)."</pre>");
+// 					$ctrsettings["${type}_padding"] = 
+					$fmt = preg_replace($regexp, "#", $fmt);
+				} else {
+// print("<pre>No counters match the regexp '$regexp' in the format '$fmt'</pre>");
+				}
+				// Replace all extended counter definitions by a single #
+				
+				// Split at a | to get the number format and a possibly different counter increment format
+				// If a separate counter format is given after the |, use it, otherwise reuse the number format itself as counter format
+				
+				
+				$parts = explode ("|", $fmt);
+				$ctrsettings["${type}_format"] = $parts[0];
+				
+				$ctrsettings["${type}_counter"] = ($ctrsettings["${type}_global"]=='yes')?"":$parts[(count($parts)>1)?1:0];
+				
+// print("<pre>Counter settings are: ".print_r($ctrsettings,1)."</pre>");
+				return $ctrsettings;
+			}
 
 			/* replace the variables in the given format. $type indicates the type of number, currently only 'ordernumber', because WooCommerce does not support invoices or customer numbers. We might allow the shop owner to customize the order password, though. */
-			function replace_fields ($fmt, $type, $order, $customvars) {
-				$reps = $this->setupReplacements ($type, $order);
-				$reps = $this->applyCustomVariables ($type, $order, $reps, $customvars);
-				$format = $this->determineNumberFormatString($fmt, $type, $order, $reps);
-				return $this->doReplacements($format, $reps);
+			function createNumber ($fmt, $type, $order, $customvars, $ctrsettings) {
+				$reps   = $this->setupReplacements ($type, $order);
+				$reps   = $this->setupCustomVariables ($type, $order, $reps, $customvars);
+				$format = $this->setupNumberFormatString($fmt, $type, $order, $reps);
+				$format = $this->doReplacements($format, $reps);
+				$ctrsettings = $this->extractCounterSettings ($format, $type, $ctrsettings);
+        
+				$countername = $ctrsettings["${type}_counter"];
+				// Look up the current counter
+				$count = $this->_getCounter($type, $countername, $ctrsettings["${type}_start"] - $ctrsettings["${type}_step"]) + $ctrsettings["${type}_step"];
+				$this->_setCounter($type, $countername, $count);
+				// return the format with the counter inserted
+				$number = str_replace ("#", sprintf('%0' . $ctrsettings["${type}_padding"] . 's', $count), $ctrsettings["${type}_format"]);
+				return $number;
 			}
 			
 			function create_ordernumber($orderid, $order, $type='ordernumber') {
 				if (get_option('customize_'.$type, 'false')) {
 					$fmt     = get_option ($type.'_format',  "#");
-					$global  = get_option ($type.'_global',  1);
-					$padding = get_option ($type.'_padding', 1);
-					$step    = get_option ($type.'_step',    1);
-					$start   = get_option ($type.'_start',   1)-$step; // The counter contains the PREVIOUS number!
+					$ctrsettings = array(
+						"${type}_format"  => '',
+						"${type}_counter" => '',
+						"${type}_global"  => get_option ($type.'_global',  'no'),
+						"${type}_padding" => 1,
+						"${type}_step"    => 1,
+						"${type}_start"   => 1,
+// 						"${type}_padding" => get_option ($type.'_padding', 1),
+// 						"${type}_step"    => get_option ($type.'_step',    1),
+// 						"${type}_start"   => get_option ($type.'_start',   1),
+					);
 					$customvars = get_option ('ordernumber_variables',   array());
 
-					$nr = $this->replace_fields ($fmt, $type, $order, $customvars);
-
-					// Split at a | to get the number format and a possibly different counter increment format
-					// If a separate counter format is given after the |, use it, otherwise reuse the number format itself as counter format
-					$parts = explode ("|", $nr);
-					$format = $parts[0];
-        
-					$counterfmt = ($global==1)?"":$parts[(count($parts)>1)?1:0];
-        
-					// Look up the current counter
-					$count = $this->_getCounter($type, $counterfmt, $start) + $step;
-					$this->_setCounter($type, $counterfmt, $count);
-					// return the format with the counter inserted
-					$number = str_replace ("#", sprintf('%0' . $padding . 's', $count), $format);
+					$number = $this->createNumber ($fmt, $type, $order, $customvars, $ctrsettings);
 					update_post_meta( $orderid, $this->ordernumber_meta, $number );
 					return $number;
 				} else {
-- 
GitLab