-
Reinhold Kainhofer authored
Add variable issuborder to let admins use different order number formats for suborders created by YITH multivendor Fixes #16
Reinhold Kainhofer authoredAdd variable issuborder to let admins use different order number formats for suborders created by YITH multivendor Fixes #16
ordernumbers_woocommerce.php 23.59 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');
/*
* RK: This debugging function is taken from the debug_backtrace documentation page of php.net:
* Send the output from a backtrace to the error_log
* @param string $message Optional message that will be sent the the error_log before the backtrace
*/
function log_trace($message = '') {
$trace = debug_backtrace();
if ($message) {
error_log($message);
}
$caller = array_shift($trace);
$function_name = $caller['function'];
error_log(sprintf('%s: Called from %s:%s', $function_name, $caller['file'], $caller['line']));
foreach ($trace as $entry_id => $entry) {
$entry['file'] = $entry['file'] ? : '-';
$entry['line'] = $entry['line'] ? : '-';
if (empty($entry['class'])) {
error_log(sprintf('%s %3s. %s() %s:%s', $function_name, $entry_id + 1, $entry['function'], $entry['file'], $entry['line']));
} else {
error_log(sprintf('%s %3s. %s->%s() %s:%s', $function_name, $entry_id + 1, $entry['class'], $entry['function'], $entry['file'], $entry['line']));
}
}
}
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'));
// SUPPORT FOR BUILT-IN PLUGINS AND PAYMENT METHODS:
$this->paypal_invoicenumber_init();
// THIRD-PARTY PLUGIN SUPPORT
// Install hooks for third-party plugin support:
$this->thirdparty_invoicenumber_init();
// Support for specific plugins:
$this->thirdparty_wpo_wcpdf_init();
$this->thirdparty_wt_wc_pdf_invoice_init();
$this->thirdparty_bewpi_invoices_init();
$this->thirdparty_yith_pdf_invoice_init();
$this->thirdparty_wc_delivery_notes_init();
// END THIRD-PARTY PLUGIN SUPPORT
}
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["[issuborder]"] = ($order->post->post_parent != 0);
$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();
$vendors = 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;
// THIRD-PARTY SUPPORT
// "WC Vendors" support (vendors stored as post author)
if (class_exists("WC_Vendors")) {
$vendor = $p->post->post_author;
$vnd = get_user_by('id', $vendor); // Get user name by user id
$vendors[] = $vendor;
$vendors[] = $vnd->user_login;
}
// "WooThemes Vendor Products" support (vendors stored in its own taxonomy)
if (class_exists("WooCommerce_Product_Vendors") && function_exists("get_product_vendors")) {
foreach (get_product_vendors($p->id) as $vendor) {
$vendors[] = $vendor->slug;
$vendors[] = $vendor->ID;
}
}
// "YITH WooCommerce Multi Vendor" support (vendors stored in its own taxonomy)
if (function_exists("yith_get_vendor")) {
$vendor = yith_get_vendor($p->id, 'product');
if ($vendor->is_valid()) {
$vendors[] = $vendor->slug;
$vendors[] = $vendor->term_id;
}
}
// END THIRD-PARTY SUPPORT
}
$reps["[skus]"] = array_keys($skus);
$reps["[categories]"] = array_keys($categories);
$reps["[tags]"] = array_keys($tags);
$reps["[shippingclasses]"] = array_keys($shippingclasses);
$reps["[vendors]"] = array_unique($vendors);
}
public function setupUserReplacements (&$reps, $details, $nrtype) {
$reps["[ipaddress]"] = $details->customer_ip_address;
$uid = $details->get_user_id();
$userinfo = get_userdata($uid);
$reps["[userid]"] = $uid;
$roles = array();
if (isset($userinfo->roles) && is_array($userinfo->roles)) {
$roles = $userinfo->roles;
}
$reps["[userroles]"] = $roles;
}
public function setupShippingReplacements(&$reps, $order, $nrtype) {
$reps["[shipping]"] = $order->get_total_shipping();
$smethods = array();
$reps["[shippingmethodids]"] = array();
$reps["[shippingmethodtypes]"] = array();
$reps["[shippinginstanceids]"] = array();
foreach ($order->get_shipping_methods() as $ship) {
$smethods[] = $ship['name'];
$reps["[shippingmethodids]"][] = $ship['method_id'];
// With the shipping zones introduced in WC 2.6, the method_id
// contains the shipping method type and the instance ID separated
// by a :. If the ":" is not present, it is a legacy method and
// has no instance ID.
$ids = explode(':', $ship['method_id'], 2);
$reps["[shippingmethodtypes]"][] = $ids[0];
if (isset($ids[1])) {
$reps["[shippinginstanceids]"][] = $ids[1];
}
}
$reps["[shippingmethods]"] = implode(", ", $smethods);
}
/*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);
}
// PAYPAL SUPPORT
protected function paypal_invoicenumber_init() {
add_filter ('woocommerce_paypal_args', array( &$this, 'paypal_arguments'), 10, 2/*<= Also get the order object! */);
}
public function paypal_arguments($vals, $order) {
if ($this->invoicenumbers_activated()) {
$vals['invoice'] = $this->get_or_create_number($order->order_id, $order, 'invoice');
}
return $vals;
}
// THIRD-PARTY PLUGIN SUPPORT
/** ****************************************************************
* Generic Invoice Number handling for third-party invoice plugins
** ****************************************************************
*
* - Filter woocommerce_generate_invoice_number($default, $order) to create the invoice number
* - Filter woocommerce_invoice_number($default, $orderID) to retrieve the
* invoice number (also create the invoice number if it does not yet exist)
*/
protected function thirdparty_invoicenumber_init() {
// The filter to actually return the order number for the given order
add_filter ('woocommerce_generate_invoice_number', array( &$this, 'thirdparty_create_invoicenumber'), 10, 2/*<= Also get the order object! */);
add_filter ('woocommerce_invoice_number', array( &$this, 'thirdparty_get_invoicenumber'), 10, 2/*<= Also get the order ID! */);
}
/**
* Callback function for WooThemes PDF Invoices to generate an invoice number for an order
* The hook to customize invoice numbers (requests the invoice number from the database;
* creates a new invoice number if no entry exists in the database)
*/
function thirdparty_create_invoicenumber($default, $order) {
if ($this->invoicenumbers_activated()) {
return $this->get_or_create_number($default, $order, 'invoice');
} else {
return $default;
}
}
function thirdparty_get_invoicenumber($default, $orderid) {
if ($this->invoicenumbers_activated()) {
$_of = new WC_Order_Factory();
$order = $_of->get_order($orderid);
return $this->get_number($orderid, $order, 'invoice');
} else {
return $default;
}
}
/** ************************************************************
* 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() {
// Patch by OpenTools implements the generic interface, so nothing special needs to be done, except to include hints in the plugin config
// 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'));
// If this plugin is enabled, but invoice numbers are not, display an information message and a link to the config
add_action ('woocommerce_page_wpo_wcpdf_options_page', array($this, 'thirdparty_wpo_wcpdf_configuration_link'));
}
/**
* 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_date) {
if ($this->invoicenumbers_activated() ) {
$_of = new WC_Order_Factory();
$order = $_of->get_order($order_id);
$nr = $this->get_or_create_number($order_id, $order, '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;
}
} else {
return $invoice_number;
}
}
/**
* 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' && $this->invoicenumbers_activated() ) {
$_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 ($this->invoicenumbers_activated()) {
$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§ion=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']);
unset($wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['yearly_reset_invoice_number']);
} 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§ion=ordernumber">that plugin\'s configuration page</a>.' );
}
}
/**
* If this plugin is installed, but not configured for invoice numbers,
* Display an information message about this plugin and a link to its config.
*/
function thirdparty_wpo_wcpdf_configuration_link() {
global $wp_settings_fields;
if (!$this->invoicenumbers_activated()) {
$wp_settings_fields['wpo_wcpdf_template_settings']['invoice']['display_number']['args']['description'] = '<i>' . sprintf($this->helper->__( 'The Open Tools Ordernumbers plugin is installed, but not configured to create invoice numbers. Configure it <a href="%s">here</a> to create invoice numbers.'), $this->invoicenumbers_config_link()) . '</i>';
}
}
/** ************************************************************
* Support for WooCommerce PDF Invoice (woocommerce-pdf-invoice) by WooThemes
** ************************************************************
*/
protected function thirdparty_wt_wc_pdf_invoice_init() {
// Patch by OpenTools implements the generic interface, so nothing special needs to be done
}
/** ************************************************************
* Support for WooCommerce PDF Invoices (woocommerce-pdf-invoices) by Bas Elbers
** ************************************************************
*/
protected function thirdparty_bewpi_invoices_init() {
// The plugin has code itself to hide the counter settings when a third-party plugin is enabled
// Patch by OpenTools implements the generic interface, so nothing special needs to be done
}
/** ************************************************************
* Support for YITH WooCommerce PDF Invoice (yith-woocommerce-pdf-invoice)
** ************************************************************
*/
protected function thirdparty_yith_pdf_invoice_init() {
// Patch by OpenTools implements the generic interface, so nothing special needs to be done
}
/** ************************************************************
* Support for WooCommerce Print Invoice and Delivery Notes (woocommerce-delivery-notes) by Triggvy Gunderson
** ************************************************************
*/
protected function thirdparty_wc_delivery_notes_init() {
// Patch by OpenTools implements the generic interface, so nothing special needs to be done
// Setting use WP Settings API, remove the counter-specific settings
add_filter ('wcdn_get_settings_no_section', array($this, 'thirdparty_wc_delivery_notes_configuration_link'));
}
/**
* If this plugin is installed, but not configured for invoice numbers,
* Display an information message about this plugin and a link to its config.
*/
function thirdparty_wc_delivery_notes_configuration_link($settings) {
if (!$this->invoicenumbers_activated()) {
$settings['invoice_options']['desc'] = '<i>' . sprintf($this->helper->__( 'The Open Tools Ordernumbers plugin is installed, but not configured to create invoice numbers. Configure it <a href="%s">here</a> to create invoice numbers.'), $this->invoicenumbers_config_link()) . '</i>';
}
return $settings;
}
// END THIRD-PARTY PLUGIN SUPPORT
}