File "orders.js"

Full Path: /home/warrior1/public_html/wp-content/plugins/facebook-for-woocommerce/assets/js/admin/orders.js
File size: 13.92 KB
MIME-type: text/plain
Charset: utf-8

/**
 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @package FacebookCommerce
 */

jQuery( document ).ready( ( $ ) => {

	'use strict';

	const isCommerceOrder = Boolean( wc_facebook_commerce_orders.is_commerce_order );

	const commerceOrderOperations = {
		/**
		 * Restrict order status options to only allowed options.
		 *
		 * @param {Object} $orderStatus Order select jQuery DOM object
		 */
		restrict_order_statuses: $orderStatus => {

			$orderStatus.find( 'option' ).each( function ( index, option ) {

				// check if option value in the allowed list or not
				if ( wc_facebook_commerce_orders.allowed_commerce_statuses.indexOf( option.value ) === -1 ) {
					// delete/remove option if not allowed
					option.remove();
				}
			} );
		},


		/**
		 * Enable or Disable order created fields.
		 *
		 * @param {Boolean} enable whether to enable date fields (true) or not (false)
		 */
		toggle_created_date_fields_status: enable => {

			commerceOrderOperations.toggle_field( $( '#order_data' ).find( 'input[name*=order_date]' ), enable );
		},


		/**
		 * Disable order status field
		 *
		 * @param {Object} $orderStatus Order select jQuery DOM object
		 */
		disable_order_status_field: ( $orderStatus ) => {

			commerceOrderOperations.toggle_field( $orderStatus, false );
		},


		/**
		 * Toggle customer field
		 *
		 * @param {Boolean} hide
		 */
		toggle_order_customer_field: ( hide ) => {
			$( '#order_data' ).find( '.form-field.wc-customer-user' ).toggleClass( 'hidden', hide );
		},


		/**
		 * Toggle customer field
		 *
		 * @param {Boolean} hide
		 */
		toggle_billing_and_shipping_fields: ( hide ) => {
			$( '#order_data' ).find( 'a.edit_address' ).toggleClass( 'hidden', hide );
		},


		/**
		 * Disable and hide related fields based on commerce order pending status
		 *
		 * @param {Object} $orderStatus Order select jQuery DOM object
		 */
		disable_pending_order_related_fields: ( $orderStatus ) => {

			commerceOrderOperations.toggle_created_date_fields_status( false );
			commerceOrderOperations.disable_order_status_field( $orderStatus );
			commerceOrderOperations.toggle_order_customer_field( true );
			commerceOrderOperations.toggle_billing_and_shipping_fields( true );
		},


		/**
		 * Hide the refund UI when refunds can't be performed.
		 */
		maybe_disable_refunds: () => {

			// only completed (fulfilled) orders can be refunded
			if ( 'completed' !== wc_facebook_commerce_orders.order_status ) {
				$( '.wc-order-bulk-actions .refund-items' ).hide();
			}
		},


		/**
		 * Uses CSS to enable/disable a form field.
		 *
		 * This function was copied from toggleSettingOptions() in facebook-for-woocommerce-settings-sync.js
		 *
		 * @since 2.1.0
		 *
		 * @param {jQuery} $element the form field
		 * @param {boolean} enable whether to enable or disable the field
		 */
		toggle_field: ( $element, enable ) => {

			if ( $element.hasClass( 'wc-enhanced-select' ) ) {
				$element = $element.next( 'span.select2-container' );
			}

			if ( enable ) {
				$element.css( 'pointer-events', 'all' ).css( 'opacity', '1.0' );
			} else {
				$element.css( 'pointer-events', 'none' ).css( 'opacity', '0.4' );
			}
		}


	};

	let $form                       = $( 'form[id="post"]' );
	let $orderStatusField           = $( '#order_status' );
	let originalOrderStatus         = $orderStatusField.val();
	let shipmentTracking            = wc_facebook_commerce_orders.shipment_tracking;
	let existingTrackingNumber      = '';
	let existingCarrierCode         = '';
	let completeModalTrackingNumber = '';
	let completeModalCarrierCode    = '';

	if ( Array.isArray( shipmentTracking ) && shipmentTracking[0] ) {
		existingTrackingNumber = shipmentTracking[0].tracking_number;
		existingCarrierCode    = shipmentTracking[0].carrier_code;
	}

	if ( isCommerceOrder ) {

		commerceOrderOperations.restrict_order_statuses( $orderStatusField );

		if ( 'pending' === wc_facebook_commerce_orders.order_status ) {
			commerceOrderOperations.disable_pending_order_related_fields( $orderStatusField );
		}

		if ( 'cancelled' === wc_facebook_commerce_orders.order_status ) {
			commerceOrderOperations.disable_order_status_field( $orderStatusField );
		}

		commerceOrderOperations.maybe_disable_refunds();
	}


	/**
	 * Determines whether we need to show the Cancel Order modal.
	 *
	 * @since 2.0.1-dev.1
	 *
	 * @returns {boolean}
	 */
	function shouldShowCancelOrderModal() {

		if ( $( '#post' ).data( 'skip-cancel-modal' ) ) {
			return false;
		}

		if ( 'wc-cancelled' === originalOrderStatus ) {
			return false;
		}

		if ( ! isCommerceOrder ) {
			return false;
		}

		return 'wc-cancelled' === $orderStatusField.val();
	}


	/**
	 * Shows and listens for events on the Cancel Order modal.
	 *
	 * @since 2.0.1-dev.1
	 *
	 * @param {jQuery.Event} event a submit event instance
	 */
	function showCancelOrderModal( event ) {

		event.preventDefault();

		// close existing modals
		$( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );

		new $.WCBackboneModal.View( {
			target: 'facebook-for-woocommerce-modal',
			string: {
				message: wc_facebook_commerce_orders.cancel_modal_message,
				buttons: wc_facebook_commerce_orders.cancel_modal_buttons
			}
		} );

		// handle confirm action
		$( '.facebook-for-woocommerce-modal #btn-ok' )
			.off( 'click.facebook_for_commerce' )
			.on( 'click.facebook_for_commerce', ( event ) => {

				event.preventDefault();
				event.stopPropagation();

				blockModal();

				$.post( ajaxurl, {
					action:      wc_facebook_commerce_orders.cancel_order_action,
					order_id:    $( '#post_ID' ).val(),
					reason_code: $( '.facebook-for-woocommerce-modal [name="wc_facebook_cancel_reason"]' ).val(),
					security:    wc_facebook_commerce_orders.cancel_order_nonce
				}, ( response ) => {

					if ( ! response || ! response.success ) {
						showErrorInModal( response && response.data ? response.data : wc_facebook_commerce_orders.i18n.unknown_error );
						return;
					}

					$( '#post' ).data( 'skip-cancel-modal', true ).trigger( 'submit' );
				} ).fail( () => {

					showErrorInModal( wc_facebook_commerce_orders.i18n.unknown_error );
				} );
			} );

		return false;
	}


	/**
	 * Replaces the content of the active Facebook for WooCommerce modal to show the given error.
	 *
	 * @since 2.0.1-dev.1
	 *
	 * @param {string} error
	 */
	function showErrorInModal( error ) {

		unBlockModal();

		$( '.facebook-for-woocommerce-modal .wc-backbone-modal-content article' ).html( '<p>' + error + '</p>' );
		$( '.facebook-for-woocommerce-modal .wc-backbone-modal-content footer' ).remove();
	}


	/**
	 * Displays the refund modal on form submit.
	 *
	 * @since 2.0.1-dev.1
	 *
	 * @param {Event} event
	 */
	function displayRefundModal( event ) {

		event.preventDefault();

		$( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );


		new $.WCBackboneModal.View( {
			target: 'facebook-for-woocommerce-modal',
			string: {
				message: wc_facebook_commerce_orders.refund_modal_message,
				buttons: wc_facebook_commerce_orders.refund_modal_buttons
			}
		} );

		$( document.body )
			.off( 'wc_backbone_modal_response.facebook_for_commerce' )
			.on( 'wc_backbone_modal_response.facebook_for_commerce', function() {
				// copy the value of the modal select to the WC field
				$( '#refund_reason' ).val( $( '#wc_facebook_refund_reason_modal' ).val() );
				// submit the form
				$form.data( 'allow-submit', true ).submit();
			} );
	}


	/**
	 * Displays the order complete modal on order form submit
	 */
	function displayCompleteModal() {

		$( '#wc-backbone-modal-dialog .modal-close' ).trigger( 'click' );

		if ( completeModalCarrierCode || completeModalTrackingNumber ) {
			$( document.body )
				.off( 'wc_backbone_modal_loaded' )
				.on( 'wc_backbone_modal_loaded', function() {

					if ( completeModalCarrierCode ) {
						$( '#wc_facebook_carrier' ).val( completeModalCarrierCode );
					}

					if ( completeModalTrackingNumber ) {
						$( '#wc_facebook_tracking_number' ).val( completeModalTrackingNumber );
					}
				} );
		}

		new $.WCBackboneModal.View( {
			target: 'facebook-for-woocommerce-modal',
			string: {
				message: wc_facebook_commerce_orders.complete_modal_message,
				buttons: wc_facebook_commerce_orders.complete_modal_buttons
			}
		} );

		// handle confirm action
		$( '.facebook-for-woocommerce-modal #btn-ok' )
			.off( 'click.facebook_for_commerce' )
			.on( 'click.facebook_for_commerce', ( event ) => {

				event.preventDefault();
				event.stopPropagation();

				completeModalCarrierCode    = $( '#wc_facebook_carrier' ).val();
				completeModalTrackingNumber = $( '#wc_facebook_tracking_number' ).val();

				makeCompleteAjaxRequest( true, completeModalTrackingNumber, completeModalCarrierCode );
			} );
	}


	/**
	 * Make complete order AJAX Request
	 *
	 * @param {Boolean} withModal
	 * @param {String} trackingNumber
	 * @param {String} carrierCode
	 */
	function makeCompleteAjaxRequest( withModal = false, trackingNumber = null, carrierCode = null ) {

		if ( ! trackingNumber.length ) {

			alert( wc_facebook_commerce_orders.i18n.missing_tracking_number_error );

			return false;
		}

		if ( withModal ) {
			blockModal();
		}

		$form.find( 'button[type=submit].save_order' ).prop( 'disabled', true ).append( '<span class="spinner is-active"></span>' );

		$.post( ajaxurl, {
			action         : wc_facebook_commerce_orders.complete_order_action,
			order_id       : $( '#post_ID' ).val(),
			tracking_number: trackingNumber,
			carrier_code   : carrierCode,
			nonce          : wc_facebook_commerce_orders.complete_order_nonce
		}, ( response ) => {

			if ( withModal ) {
				unBlockModal();
			}

			if ( ! response || ! response.success ) {

				let error_message = response && response.data ? response.data : wc_facebook_commerce_orders.i18n.unknown_error;

				alert( error_message );

				return;
			}

			$form.data( 'allow-submit', true ).trigger( 'submit' );

		} ).fail( () => {

			showErrorInModal( wc_facebook_commerce_orders.i18n.unknown_error );

		} ).always( () => {

			$form.find( 'button[type=submit].save_order' ).prop( 'disabled', false ).find( 'span.spinner' ).remove();

		} );
	}


	/**
	 *
	 * Move the Facebook refund reason field if this is a Commerce order.
	 *
	 * @since 2.1.0
	 */
	function maybeMoveRefundReasonField() {

		if ( isCommerceOrder ) {
			moveRefundReasonField();
			setupRefunReasonMutationObserver();
		}
	}


	/**
	 * Moves the Facebook refund reason field above WooCommerce's refund reason field.
	 *
	 * It also updates the labels and tooltips.
	 *
	 * @since 2.0.1-dev.1
	 */
	function moveRefundReasonField() {

		let $oldRefundReasonField  = $( '#refund_reason' );
		let $newRefundReasonField  = $( '#wc_facebook_refund_reason' ).clone().css( 'width', $oldRefundReasonField.css( 'width' ) );
		let $refundReasonRow       = $oldRefundReasonField.closest( 'tr' );
		let $refundDescriptionRow  = $refundReasonRow.clone();

		$refundReasonRow
			.find( 'td.total' ).css( 'width', '16em' ).end()
			.find( '#refund_reason' ).replaceWith( $newRefundReasonField.show() ).end()
			.find( 'label[for="refund_reason"]' ).attr( 'for', 'wc_facebook_refund_reason' );

		$refundReasonRow.after( $refundDescriptionRow );

		updateOrderTotalFieldLabel(
			$refundReasonRow,
			'wc_facebook_refund_reason',
			wc_facebook_commerce_orders.i18n.refund_reason_label,
			wc_facebook_commerce_orders.i18n.refund_reason_tooltip
		);

		updateOrderTotalFieldLabel(
			$refundDescriptionRow,
			'refund_reason',
			wc_facebook_commerce_orders.i18n.refund_description_label,
			wc_facebook_commerce_orders.i18n.refund_description_tooltip
		);
	}


	/**
	 * Setups a MutationObserver to detect when the order refund items elements are replaced.
	 *
	 * WooCommerce (meta-boxes-orders.js) does not currently trigger an event when the order items are loaded.
	 * We use the MutationObserver to move the Facebook refund reason field every time the order refund items are refreshed.
	 *
	 * @since 2.1.0
	 */
	function setupRefunReasonMutationObserver() {

		if ( 'undefined' === typeof window.MutationObserver ) {
			return;
		}

		let node = document.querySelector( '#woocommerce-order-items .inside' );

		if ( ! node ) {
			return;
		}

		let observer = new MutationObserver( ( records ) => {

			records.forEach( ( record ) => {

				Array.prototype.forEach.call( record.addedNodes, ( child ) => {

					if ( $( child ).is( '.wc-order-refund-items' ) ) {
						moveRefundReasonField();
					}
				} );
			} );
		} );

		observer.observe( node, { childList: true } );
	}


	/**
	 * Changes the label and tooltip of the specified order total field.
	 *
	 * @since 2.0.1-dev.1
	 *
	 * @param {jQuery} $container an element that contains the label of the field
	 * @param {string} fieldId the id of the field
	 * @param {string} label the new label for the field
	 * @param {string} tooltip the new tooltip for the field
	 */
	function updateOrderTotalFieldLabel( $container, fieldId, label, tooltip ) {

		let $label   = $container.find( 'label[for="' + fieldId + '"]' );
		let $tooltip = $label.find( '.woocommerce-help-tip' ).clone();

		$label.text( label );

		if ( tooltip && $tooltip.length ) {

			$label.prepend( $tooltip );

			$tooltip.attr( 'data-tip', tooltip ).tipTip( {
				'attribute': 'data-tip',
				'fadeIn': 50,
				'fadeOut': 50,
				'delay': 200
			} );
		}
	}


	maybeMoveRefundReasonField();

	$form.on( 'submit', function( event ) {

		if ( shouldShowCancelOrderModal() ) {
			return showCancelOrderModal( event );
		}

		if ( ! isCommerceOrder || $form.data( 'allow-submit' ) ) {
			return;
		}

		let newOrderStatusField = $orderStatusField.val();

		if ( 'wc-refunded' === newOrderStatusField && originalOrderStatus !== newOrderStatusField ) {
			displayRefundModal( event );
		}

		if ( 'wc-completed' === newOrderStatusField ) {

			event.preventDefault();

			if ( existingTrackingNumber || existingCarrierCode ) {
				makeCompleteAjaxRequest( false, existingTrackingNumber, existingCarrierCode );
			} else {
				displayCompleteModal();
			}
		}
	} );

} );