File: /var/www/html/ielts-store/wp-content/plugins/woocommerce-zapier/legacy/Trigger/Order/Base.php
<?php
namespace OM4\Zapier\Trigger\Order;
use OM4\Zapier\Feed\Feed;
use OM4\Zapier\Logger;
use OM4\Zapier\Payload\Collection\DownloadableFiles;
use OM4\Zapier\Payload\Collection\LineItems;
use OM4\Zapier\Payload\Collection\Notes;
use OM4\Zapier\Payload\Item\DownloadableFile;
use OM4\Zapier\Payload\Item\LineItem;
use OM4\Zapier\Payload\Item\MetaData;
use OM4\Zapier\Payload\Item\Note;
use OM4\Zapier\Payload\Order as Payload;
use OM4\Zapier\Plugin;
use OM4\Zapier\Trigger\Base as TriggerBase;
use WC_Order_Item_Product;
use WC_Order;
defined( 'ABSPATH' ) || exit;
/**
 * Base (abstract) class of Order related Triggers
 *
 * @deprecated 2.0.0
 */
abstract class Base extends TriggerBase {
	/**
	 * WC_Order instance.
	 *
	 * @var WC_Order
	 */
	protected $wc_order;
	/**
	 * The slug/key for the order status.
	 * Must correspond to a valid WooCommerce order status
	 *
	 * @var string
	 */
	protected $status_slug = '';
	/**
	 * Downloadable files collected from every line item
	 *
	 * @var DownloadableFiles
	 */
	protected $downloadable_files;
	/**
	 * Optional text that is added to the end of this Trigger's title inside brackets.
	 *
	 * @var string|null
	 */
	protected $title_suffix;
	/**
	 * Holds the Logger class.
	 *
	 * @var Logger
	 */
	protected $logger;
	/**
	 * Constructor
	 */
	public function __construct() {
		$this->downloadable_files = new DownloadableFiles();
		$this->logger             = new Logger();
		parent::__construct();
	}
	/**
	 * The sample WooCommerce order data that is sent to Zapier as sample data.
	 * Used if the store doesn't have any existing order data
	 *
	 * @return array
	 */
	protected function get_sample_data() {
		// Use a random order ID so the "Pick a Sample to Set Up Your Zap"
		// screen shows the most recent sample data.
		$order = Payload::from_sample();
		// phpcs:ignore WordPress.WP.AlternativeFunctions.rand_rand
		$order->id = rand( 1000, 100000 );
		return $order->to_array();
	}
	/**
	 * Collect downloadable files for order line items
	 * Only included once the customer has permission to download the files
	 * (typically when the order status is Processing or Completed).
	 *
	 * @see https://docs.woocommerce.com/document/digitaldownloadable-product-handling/#section-3
	 * @param array $downloadable_files_data Data of file associated with Line Item.
	 *
	 * @return void Writes to the $downloadable_files property.
	 */
	protected function assemble_downloadable_files( $downloadable_files_data ) {
		// TODO: also include WC 2.1+ downloadable file name.
		foreach ( $downloadable_files_data as $download_id => $download_details ) {
			$file                       = new DownloadableFile();
			$file->filename             = wc_get_filename_from_url( $download_details['file'] );
			$file->download_url         = $download_details['download_url'];
			$this->downloadable_files[] = $file;
		}
	}
	/**
	 * Collect meta information for order.
	 *
	 * @param WC_Meta_Data[] $item_meta Order meta data.
	 *
	 * @return MetaData
	 */
	protected function assemble_meta_data_for_order( $item_meta ) {
		$meta_data = new MetaData();
		foreach ( $item_meta as $meta ) {
			$meta_key             = Plugin::decode( $meta->key );
			$meta_data->$meta_key = Plugin::decode( $meta->value );
		}
		return $meta_data;
	}
	/**
	 * Collect meta information for line item.
	 *
	 * @param array $item_meta Line item meta data.
	 *
	 * @return MetaData
	 */
	protected function assemble_meta_data_for_line_item( $item_meta ) {
		$meta_data = new MetaData();
		foreach ( $item_meta as $meta_key => $meta_value ) {
			$meta_key             = Plugin::decode( $meta_key );
			$meta_data->$meta_key = Plugin::decode( $meta_value );
		}
		return $meta_data;
	}
	/**
	 * Collect notes
	 *
	 * @param array $notes_array Output of WC_Order::get_customer_order_notes().
	 *
	 * @return Notes
	 */
	protected function assemble_notes( $notes_array ) {
		$collection = new Notes();
		foreach ( $notes_array as $note_data ) {
			$note               = new Note();
			$note->note         = $note_data->comment_content;
			$note->date         = Plugin::format_date( $note_data->comment_date );
			$note->author       = $note_data->comment_author;
			$note->author_email = $note_data->comment_author_email;
			$collection[]       = $note;
		}
		return $collection;
	}
	/**
	 * Collect all data for one line item for order
	 *
	 * @param WC_Order_Item_Product $line_item_data Class with all the line item data.
	 *
	 * @return LineItem
	 */
	protected function assemble_one_line_item( WC_Order_Item_Product $line_item_data ) {
		$product = $line_item_data->get_product();
		$line_item               = new LineItem();
		$line_item->name         = $line_item_data->get_name();
		$line_item->quantity     = $line_item_data->get_quantity();
		$line_item->product_id   = $line_item_data->get_product_id();
		$line_item->variation_id = $line_item_data->get_variation_id();
		$line_item->sku          = $product ? $product->get_sku() : '';
		$line_item->type         = ( false !== $product ) ? $product->get_type() : '';
		/* Getting the categories and tags */
		// If the product is variation we getting the parent product.
		if ( false !== $product && $product->is_type( 'variation' ) ) {
			$product = wc_get_product( $product->get_parent_id() );
		}
		/*
		Also allow for the case where the order/subscription is for a product
		that no longer exists. In this case, $product will be false,
		and category/tags/type will be sent as empty.
		*/
		// Product Categories.
		$line_item->categories = '';
		if ( false !== $product ) {
			$categories = wc_get_product_category_list( $product->get_id() );
			if ( is_string( $categories ) ) {
				// phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
				$line_item->categories = strip_tags( $categories );
			}
		}
		// Product Tags.
		$line_item->tags = '';
		if ( false !== $product ) {
			$tags = wc_get_product_tag_list( $product->get_id() );
			if ( is_string( $tags ) ) {
				// phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
				$line_item->tags = strip_tags( $tags );
			}
		}
		// Line Item Data.
		$line_item->unit_price        = Plugin::format_price( $this->wc_order->get_item_total( $line_item_data, false, true ) );
		$line_item->line_subtotal     = Plugin::format_price( $line_item_data->get_subtotal() );
		$line_item->line_total        = Plugin::format_price( $line_item_data->get_total() );
		$line_item->line_tax          = Plugin::format_price( $line_item_data->get_total_tax() );
		$line_item->line_subtotal_tax = Plugin::format_price( $line_item_data->get_subtotal_tax() );
		$line_item->tax_class         = $line_item_data->get_tax_class();
		$line_item->item_meta         = $this->assemble_meta_data_for_line_item( $line_item_data['item_meta'] );
		// Collect downloadable files data from every line item.
		$this->assemble_downloadable_files( $line_item_data->get_item_downloads() );
		return $line_item;
	}
	/**
	 * Collect every line item for order
	 * NOTE: WC_Order_Item::get_product() without arguments returns only array
	 * of WC_Order_Item_Product::class.
	 *
	 * @return LineItems
	 */
	protected function assemble_line_items() {
		$collection = new LineItems();
		foreach ( $this->wc_order->get_items() as $line_item_data ) {
			$collection[] = $this->assemble_one_line_item( $line_item_data );
		}
		return $collection;
	}
	/**
	 * Collect assign and convert data to assemble data for Zapier
	 *
	 * @param  array  $args        Array of ID, new_status & previous_status (if applicable).
	 * @param  string $action_name Name of WP action that changed the order state.
	 *
	 * @return array
	 */
	public function assemble_data( $args, $action_name ) {
		// The webhook/trigger is being tested. Send the store's most recent
		// order, or if that doesn't exist then send the static hard-coded
		// sample order data.
		if ( $this->is_sample() ) {
			$orders = wc_get_orders(
				array(
					'type'    => 'shop_order',
					'limit'   => 1,
					'orderby' => 'date',
					'order'   => 'DESC',
					'return'  => 'ids',
				)
			);
			// No existing orders found, so send static hard-coded order
			// sample data.
			if ( ! $orders || ! isset( $orders[0] ) ) {
				return $this->get_sample_data();
			}
			$args[0] = $orders[0];
		}
		/* Using real live data from now */
		$order_id = intval( $args[0] );
		if ( ! $order_id ) {
			return false;
		}
		$this->wc_order = new WC_Order( $order_id );
		// Check and prepare current and previous states. If we don't know the
		// previous status, nothing special required here.
		// NOTE: order statuses can be a-z characters or a hyphen.
		if ( 'woocommerce_order_status_changed' === $action_name ) {
			$previous_status = $args[1];
			$new_status      = $args[2];
		} elseif (
			preg_match(
				'/^woocommerce_order_status_([a-z-]+)_to_([a-z-]+)$/i',
				$action_name,
				$matches
			)
		) {
			$previous_status = $matches[1];
			$new_status      = $matches[2];
		} else {
			$new_status      = $this->wc_order->get_status();
			$previous_status = '';
		}
		/* NOTE: this could fire for any order statuses (including pending/unpaid). */
		// Compile the order details/data that will be sent to Zapier.
		$order = new Payload();
		// Getting similarly named fields from WC.
		$similar_fields = array(
			'id',
			'user_id',
			'currency',
			'transaction_id',
			'billing_first_name',
			'billing_last_name',
			'billing_company',
			'billing_email',
			'billing_phone',
			'billing_address_1',
			'billing_address_2',
			'billing_city',
			'billing_postcode',
			'billing_state',
			'billing_country',
			'shipping_first_name',
			'shipping_last_name',
			'shipping_company',
			'shipping_address_1',
			'shipping_address_2',
			'shipping_city',
			'shipping_postcode',
			'shipping_state',
			'shipping_country',
			'shipping_method',
			'prices_include_tax',
			'customer_note',
		);
		foreach ( $similar_fields as $property ) {
			$method           = 'get_' . $property;
			$order->$property = $this->wc_order->$method();
		}
		// Getting similarly named fields from WC which all need to be price
		// formatted.
		$similar_priced_fields = array(
			'total',
			'subtotal',
			'shipping_total',
			'shipping_tax',
		);
		foreach ( $similar_priced_fields as $property ) {
			$method           = 'get_' . $property;
			$order->$property = Plugin::format_price( $this->wc_order->$method() );
		}
		// Getting customized details.
		$order->number           = $this->wc_order->get_order_number();
		$order->status           = $new_status;
		$order->status_previous  = $previous_status;
		$order->date             = Plugin::format_date( $this->wc_order->get_date_created() );
		$order->currency_symbol  = Plugin::decode( get_woocommerce_currency_symbol( $order->currency ) );
		$order->view_url         = $this->wc_order->get_view_order_url();
		$order->billing_address  = Plugin::decode( $this->wc_order->get_formatted_billing_address() );
		$order->shipping_address = Plugin::decode( $this->wc_order->get_formatted_shipping_address() );
		$order->payment_method   = $this->wc_order->get_payment_method_title();
		$order->discount_total   = '';
		$order->cart_discount    = Plugin::format_price( $this->wc_order->get_total_discount() );
		$order->tax_total        = Plugin::format_price( $this->wc_order->get_cart_tax() );
		/* Country & state names */
		// Filling country names.
		if ( ! empty( $order->billing_country ) && isset( WC()->countries->countries[ $order->billing_country ] ) ) {
			$order->billing_country_name = WC()->countries->countries[ $order->billing_country ];
		} else {
			$order->billing_country_name = '';
		}
		if ( ! empty( $order->shipping_country ) && isset( WC()->countries->countries[ $order->shipping_country ] ) ) {
			$order->shipping_country_name = WC()->countries->countries[ $order->shipping_country ];
		} else {
			$order->shipping_country_name = '';
		}
		// Filling state names.
		if ( ! empty( $order->billing_state ) && isset( WC()->countries->states[ $order->billing_country ][ $order->billing_state ] ) ) {
			$order->billing_state_name = WC()->countries->states[ $order->billing_country ][ $order->billing_state ];
		} else {
			$order->billing_state_name = '';
		}
		if ( ! empty( $order->shipping_state ) && isset( WC()->countries->states[ $order->shipping_country ][ $order->shipping_state ] ) ) {
			$order->shipping_state_name = WC()->countries->states[ $order->shipping_country ][ $order->shipping_state ];
		} else {
			$order->shipping_state_name = '';
		}
		// Order Line Items.
		$order->line_items = $this->assemble_line_items();
		$order->item_count = $this->wc_order->get_item_count();
		// A comma-separated list of coupon codes that were used for this order.
		// Method renamed on WC 3.7 from get_used_coupons to get_coupon_codes.
		if ( method_exists( $this->wc_order, 'get_coupon_codes' ) ) {
			$order->coupons = implode( ', ', $this->wc_order->get_coupon_codes() );
		} else {
			$order->coupons = implode( ', ', $this->wc_order->get_used_coupons() );
		}
		// Downloadable files collected from every line item.
		$order->has_downloadable_item = $this->wc_order->has_downloadable_item();
		$order->downloadable_files    = $this->downloadable_files;
		// Customer Notes.
		$order->notes = $this->assemble_notes( $this->wc_order->get_customer_order_notes() );
		// Order Meta data.
		$order->meta_data = $this->assemble_meta_data_for_order( $this->wc_order->get_meta_data() );
		$this->logger->debug( 'Order #%s: Assembled order data.', $order->id );
		// Order data needs to be an array.
		return $order->to_array();
	}
	/**
	 * Executed every time real Order data is sent to a Zapier Feed.
	 * Not executed when sample Order data is sent.
	 *
	 * @param Feed   $feed         Feed data.
	 * @param array  $result       Response from the wp_remote_post() call.
	 * @param string $action_name  Hook/action name (needed to be able to retry failed attempts).
	 * @param array  $arguments    Hook/action arguments (needed to be able to retry failed attempts).
	 * @param int    $num_attempts The number of attempts it took to successfully send the data to Zapier.
	 */
	protected function data_sent_to_feed( Feed $feed, $result, $action_name, $arguments, $num_attempts = 0 ) {
		$note = '';
		if ( 1 === $num_attempts ) {
			// Successful on the first attempt.
			// Translators: %1$s: The URL that of the Edit Feed screen. %2$s: The Title/Name of this Zapier Feed.
			$note .= sprintf( __( 'Order sent to Zapier via the <a href="%1$s">%2$s</a> Zapier feed.', 'woocommerce-zapier' ), $feed->edit_url(), $feed->title() );
		} else {
			// It took more than 1 attempt so add that to the note.
			// Translators: %1$s: The URL that of the Edit Feed screen. %2$s: The Title/Name of this Zapier Feed.
			$note .= sprintf( __( 'Order sent to Zapier via the <a href="%1$s">%2$s</a> Zapier feed after %3$d attempts.', 'woocommerce-zapier' ), $feed->edit_url(), $feed->title(), $num_attempts );
		}
		// Translators: %1$s: The title of this trigger. %2$s: Name of this action.
		$note .= sprintf( _x( '<br ><br />Trigger:<br />%1$s<br />%2$s', 'Order trigger details.', 'woocommerce-zapier' ), $feed->trigger()->get_trigger_title(), "<small>{$action_name}</small>" );
		$note .= $this->data_sent_note_suffix( $feed, $result, $action_name, $arguments, $num_attempts );
		// Add a private note to this order.
		$this->wc_order->add_order_note( $note );
		$this->logger->debug( "Order #%s: Added note:\n%s", array( $this->wc_order->get_id(), $note ) );
		parent::data_sent_to_feed( $feed, $result, $action_name, $arguments, $num_attempts );
	}
	/**
	 * Add optional information to the end of the Order Note that is added to an Order after it is sent to Zapier.
	 *
	 * @param Feed   $feed         Feed data.
	 * @param array  $result       Response from the wp_remote_post() call.
	 * @param string $action_name  Hook/action name (needed to be able to retry failed attempts).
	 * @param array  $arguments    Hook/action arguments (needed to be able to retry failed attempts).
	 * @param int    $num_attempts The number of attempts it took to successfully send the data to Zapier.
	 *
	 * @return string
	 */
	protected function data_sent_note_suffix( Feed $feed, $result, $action_name, $arguments, $num_attempts = 0 ) {
		return '';
	}
}