Skip to content
Snippets Groups Projects
ordernumbers_woocommerce.php 14.58 KiB
<?php
/**
 * This is the actual ordernumber plugin class for WooCommerce.
 * Copyright (C) 2015 Reinhold Kainhofer, Open Tools
 * Author: Open Tools, Reinhold Kainhofer
 * Author URI: http://open-tools.net
 * License: GPL2+
*/
if ( ! defined( 'ABSPATH' ) ) { 
	exit; // Exit if accessed directly
}
if (!class_exists( 'OpenToolsOrdernumbersBasic' )) 
	require_once (dirname(__FILE__) . '/ordernumbers_woocommerce_basic.php');
	
class OpenToolsOrdernumbers extends OpenToolsOrdernumbersBasic {
	/**
	 * Construct the plugin object
	 */
	public function __construct($basename) {
		parent::__construct($basename);
		$this->is_advanced = true;

		$this->helper->registerCallback('setupStoreReplacements',		array($this, 'setupStoreReplacements'));
		$this->helper->registerCallback('setupOrderReplacements',		array($this, 'setupOrderReplacements'));
		$this->helper->registerCallback('setupUserReplacements',		array($this, 'setupUserReplacements'));
		$this->helper->registerCallback('setupShippingReplacements',	array($this, 'setupShippingReplacements'));
		$this->helper->registerCallback('setupThirdPartyReplacements',	array($this, 'setupThirdPartyReplacements'));
	}
	/**
	 * Override the initializeBasicSettings method, which restricts some functionality in the basic plugin.
	 */
	protected function initializeBasicSettings() {}
	
	/**
	 * Install all neccessary filters and actions for this plugin
	 */
	protected function initializeHooks() {
		parent::initializeHooks();
		
		// Custom table widget for custom variable definitions: Hooks for creating and storing values
		add_action( 'woocommerce_admin_field_ordernumber_variables',    array( $this, 'admin_field_variables' ) );
		add_action( 'pre_update_option_ordernumber_variables',          array( $this, 'update_option_variables'));

		// Install hooks for third-party plugin support:
		$this->thirdparty_wpo_wcpdf_init();
		
	}
	
	protected function initializeSettingsGeneral() {
		// Remove the NAG screen of the basic version
		return array();
	}
	/**
	 * Return the tooltip for the number format settings textinput (the two plugin versions have different features!)
	 */
	protected function getNumberFormatSettingsLabel() {
		return $this->helper->__( '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.');
	}
	protected function addGlobalCounterSettings($settings) {
		$settings[] = 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' 		=> 'ordernumber_global',
				'type' 		=> 'checkbox',
				'default'	=> 'no',
			);
		return $settings;
	}
	
	
	protected function initializeSettingsOther() {
		return array_merge(
			$this->initializeSettingsInvoiceNumbers(),
			$this->initializeSettingsReplacements()
		);
	}
	
	protected function initializeSettingsInvoiceNumbers() {
		$settings = array(
			/**
			 * 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' )
		);
		
		add_option ('customize_invoice', 'no');
		add_option ('invoice_format',    "#");
		add_option ('invoice_global',    'no');
		return $settings;
	}
	
	protected function initializeSettingsReplacements() {
		$settings = array(
			array(
				'name' 		=> $this->helper->__( 'Custom Variables'),
				'desc'		=> $this->helper->__( 'Define your own (conditional) variables for use in the number formats'),
				'type' 		=> 'title',
				'id' 		=> 'ordernumber_variables'
			),
			array(
				'id' 		=> 'ordernumber_variables',
				'type' 		=> 'ordernumber_variables',
			),
			array( 'type' => 'sectionend', 'id' => 'ordernumber_variables' )
		);
 		add_option ('ordernumber_variables',  array());
 		return $settings;
	}

	
	/**
	 * Render the Custom Variables configuration table
	 */
	public function admin_field_variables($settings) {
		$variables = get_option( $settings['id'], array() );
		if (!is_array($variables)) {
			$variables = array();
		} ?>
		<tr valign="top">
		    <td class="forminp forminp-<?php echo sanitize_title( $settings['type'] ) ?>" colspan="2">
				<?php
					print $this->helper->custom_variables_create_table($settings['id'], $variables);
				?>
			</td>
		</tr> 
		<?php
	}

	/** 
	 * Store the variable replacements array into the options. Need to transpose the array before we can store it into the options...
	 * This filter is called directly before the option is saved.
	 */
	public function update_option_variables ($value) {
		return OrdernumberHelper::transposeCustomVariables($value);
	}


	/** ***********************************************************
	 * 
	 *  REPLACEMENT FUNCTIONS
	 *
	 **************************************************************/
	
	public function setupAddressReplacements(&$reps, $prefix, $address, $nrtype) {
		$reps["[email]"]     = $address->billing_email;
		$reps["[firstname]"] = $address->billing_first_name;
		$reps["[lastname]"]  = $address->billing_last_name;

		$reps["[company]"]   = $address->billing_company;
		$reps["[zip]"]       = $address->billing_postcode;
		$reps["[postcode]"]  = $address->billing_postcode;
		$reps["[city]"]      = $address->billing_city;
    
		$country = $address->billing_country;
		$state = $address->billing_state;
		$allcountries = WC()->countries->get_countries();
		$states = WC()->countries->get_states($country);
		$reps["[country]"]     = $country;
		$reps["[countryname]"] = ( isset( $allcountries[ $country ] ) ) ? $allcountries[ $country ] : $country;

		$reps["[state]"]       = $state;
		$reps["[statename]"]   = ( $country && $state && isset( $states[ $country ][ $state ] ) ) ? $states[ $country ][ $state ] : $state;
	}
	
	public function setupStoreReplacements (&$reps, $order, $nrtype) {
	}
    
	public function setupOrderReplacements (&$reps, $order, $nrtype) {
		$reps["[orderid]"] = $order->id;
		
		if ($nrtype != 'ordernumber') {
			$reps["[ordernumber]"] = $order->get_order_number();
		}
		$reps["[orderstatus]"] = $order->get_status();
		$reps["[currency]"]    = $order->get_order_currency();

		$this->setupAddressReplacements($reps, "", $order, $nrtype);
	
		$reps["[articles]"]    = $order->get_item_count();
// 		$reps["[downloadpermitted]"] = $order->is_download_permitted();
// 		$reps["[hasdownloads]"] = $order->has_downloadable_item();
// 		$reps["[coupons]"] = $order->get_used_coupons();
		$reps["[ordertotal]"]      = $order->get_total();
		$reps["[amount]"]      = $order->get_total();
		$reps["[ordersubtotal]"]      = $order->get_subtotal();
		$reps["[totaltax]"]      = $order->get_total_tax();
		$reps["[totalshipping]"]      = $order->get_total_shipping();
		
		// List-valued properties for custom variable checks:
		// TODO: Also implement variable for:
		//  - Shipping needed
		//  - Downloads available
		$lineitems = $order->get_items();
		$skus = array();
		$categories = array();
		$tags = array();
		$shippingclasses = array();
		foreach ($lineitems as $l) {
			$p = $order->get_product_from_item($l);
			$skus[$p->get_sku()] = 1;
			foreach (wc_get_product_terms( $p->id, 'product_cat') as $c) {
				$categories[$c->slug] = 1;
			}
			foreach (wc_get_product_terms( $p->id, 'product_tag') as $c) {
				$tags[$c->slug] = 1;
			}
			$shippingclasses[$p->get_shipping_class()] = 1;
		}
		$reps["[skus]"] = array_keys($skus);
		$reps["[categories]"] = array_keys($categories);
		$reps["[tags]"] = array_keys($tags);
		$reps["[shippingclasses]"] = array_keys($shippingclasses);
	}

	public function setupUserReplacements (&$reps, $details, $nrtype) {
		$reps["[ipaddress]"]   = $details->customer_ip_address;
		$reps["[userid]"]      = $details->get_user_id();
	}

	public function setupShippingReplacements(&$reps, $order, $nrtype) {
// 		$reps["[shippingmethod]"] = $order->getShippingMethod();
	}
	
	/*public function setupInvoiceReplacements (&$reps, $invoice, $order, $nrtype) {
		$reps["[invoiceid]"] = $invoice->getId();
	}*/

	public function setupThirdPartyReplacements (&$reps, $details, $nrtype) {
		$reps = apply_filters( 'opentools_ordernumber_replacements', $reps, $details, $nrtype);
	}

	/** ************************************************************
	 *  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>.' );
		}
	}

}