File "class-location-zones-crud-handler.php"

Full Path: /home/romayxjt/public_html/wp-content/plugins/orderable/inc/modules/location/zones/class-location-zones-crud-handler.php
File size: 9.57 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * Module: Location (Zones).
 *
 * @since   1.18.0
 * @package Orderable/Classes
 */

defined( 'ABSPATH' ) || exit;

/**
 * Orderable_Location_Zones_CRUD_Handler class.
 */
class Orderable_Location_Zones_CRUD_Handler {
	/**
	 * Create a new zone.
	 *
	 * @param array $data Data for this request.
	 * @return array
	 */
	public static function add_new( $data ) {
		try {
			// Create the basic zone.
			$data_store = WC_Data_Store::load( 'shipping-zone' );
			$zone       = new WC_Shipping_Zone();

			$zone->set_zone_name( $data['zone_name'] );
			$zone->set_zone_order( 100 );

			// Add locations.
			$normalized_postcodes = array_map( 'wc_normalize_postcode', explode( ',', $data['zone_postcodes'] ) );
			$locations            = ( ! empty( $data['zone_postcodes'] ) ) ? self::convert_postcodes_to_locations( $normalized_postcodes ) : array();

			$default_country = get_option( 'woocommerce_default_country', false );

			if ( $default_country ) {
				$default_country_arr = explode( ':', $default_country );

				$locations[] = array(
					'type' => 'country',
					'code' => $default_country_arr[0],
				);

				if ( count( $default_country_arr ) === 2 ) {
					$locations[] = array(
						'type' => 'state',
						'code' => $default_country,
					);
				}
			}

			$zone->set_locations( $locations );

			// Add fee meta data, defaulting to free.
			$fee = ! empty( $data['zone_fee'] ) ? preg_replace( '/[^0-9.]/m', '', $data['zone_fee'] ) : 0.00;
			$zone->add_meta_data( 'delivery_fee', floatval( number_format( $fee, 2 ) ) );

			// Create the zone and get the ID.
			$data_store->create( $zone );
			$new_zone_id = $zone->get_id();

			// Add shipping methods.
			$data_store->add_method( $new_zone_id, 'orderable_delivery', 100 );
			$data_store->add_method( $new_zone_id, 'orderable_pickup', 100 );

			self::create_lookup_entry( $data['location_id'], $new_zone_id, $data['time_slot_id'] );

			return array(
				'status'         => true,
				'zone_id'        => $new_zone_id,
				'zone_name'      => $data['zone_name'],
				'zone_postcodes' => join( ',', $normalized_postcodes ),
				'zone_fee'       => floatval( number_format( $fee, 2 ) ),
				'msg'            => esc_html(
					sprintf(
						/* translators: zone name */
						__( '%s succcessfully created!', 'orderable' ),
						$data['zone_name']
					)
				),
			);
		} catch ( Exception $ex ) {
			return array(
				'status'         => false,
				'zone_id'        => null,
				'zone_name'      => null,
				'zone_postcodes' => null,
				'zone_fee'       => null,
				'msg'            => $ex->getMessage(),
			);
		}
	}

	/**
	 * Add an existing zone to a location
	 *
	 * @param array $data Data for this request.
	 * @return array
	 */
	public static function add_existing( $data ) {
		try {
			// Create the lookup table entries (zones, time slots).
			self::create_lookup_entry( $data['location_id'], $data['zone_id'], $data['time_slot_id'] );

			// Send back the same data provided in the request.
			return array(
				'status'         => true,
				'zone_id'        => $data['zone_id'],
				'zone_name'      => $data['zone_name'],
				'zone_postcodes' => $data['zone_postcodes'],
				'zone_fee'       => $data['zone_fee'],
				'msg'            => esc_html(
					sprintf(
						/* translators: zone name */
						__( '%s succcessfully added!', 'orderable' ),
						$data['zone_name']
					)
				),
			);
		} catch ( Exception $ex ) {
			return array(
				'status'         => false,
				'zone_id'        => $data['zone_id'],
				'zone_name'      => $data['zone_name'],
				'zone_postcodes' => $data['zone_postcodes'],
				'zone_fee'       => $data['zone_fee'],
				'msg'            => $ex->getMessage(),
			);
		}
	}

	/**
	 * Update a zone.
	 *
	 * @param array $data Data for this request.
	 * @return array
	 */
	public static function edit( $data ) {
		try {
			$data_store = WC_Data_Store::load( 'shipping-zone' );
			$zone       = new WC_Shipping_Zone( $data['zone_id'] );

			$zone->set_zone_name( $data['zone_name'] );
			$zone->update_meta_data( 'delivery_fee', $data['zone_fee'] );

			$normalized_postcodes = array_map( 'wc_normalize_postcode', explode( ',', $data['zone_postcodes'] ) );
			// clear postcodes but keep other locations type e.g. state, country.
			$zone->clear_locations( ['postcode'] );

			// NOTE: Shipping methods are added in class-location-zones.php;
			// see the `on_shipping_zone_save` method.
			foreach ( $normalized_postcodes as $postcode ) {
				$zone->add_location( $postcode, 'postcode' );
			}

			$data_store->update( $zone );

			return array(
				'status'         => true,
				'zone_id'        => $data['zone_id'],
				'zone_name'      => $data['zone_name'],
				'zone_postcodes' => $data['zone_postcodes'],
				'zone_fee'       => $data['zone_fee'],
				'msg'            => esc_html(
					sprintf(
						/* translators: zone name */
						__( '%s succcessfully updated!', 'orderable' ),
						$data['zone_name']
					)
				),
			);
		} catch ( Exception $ex ) {
			return array(
				'status'         => false,
				'zone_id'        => $data['zone_id'],
				'zone_name'      => $data['zone_name'],
				'zone_postcodes' => $data['zone_postcodes'],
				'zone_fee'       => $data['zone_fee'],
				'msg'            => $ex->getMessage(),
			);
		}
	}

	/**
	 * Delete a delivery zone.
	 *
	 * @param array $data The data sent in the request.
	 * @return array
	 */
	public static function delete( $data ) {
		global $wpdb;

		if ( empty( $data['zone_id'] ) ) {
			return false;
		}

		$zone_id = $data['zone_id'];

		// Delete delivery zones lookup table entry.
		$delete_zones_lookup = $wpdb->delete(
			$wpdb->prefix . 'orderable_location_delivery_zones_lookup',
			array(
				'zone_id' => $zone_id,
			),
			'%d'
		);

		// Delete delivery zone methods.
		$delete_delivery_zone_methods = $wpdb->delete(
			$wpdb->prefix . 'woocommerce_shipping_zone_methods',
			array(
				'zone_id' => $zone_id,
			),
			'%d'
		);

		// Delete delivery zone locations.
		$delete_delivery_zone_locations = $wpdb->delete(
			$wpdb->prefix . 'woocommerce_shipping_zone_locations',
			array(
				'zone_id' => $zone_id,
			),
			'%d'
		);

		// Delete delivery zones.
		$delete_delivery_zones = $wpdb->delete(
			$wpdb->prefix . 'woocommerce_shipping_zones',
			array(
				'zone_id' => $zone_id,
			),
			'%d'
		);

		$result =
			false !== $delete_zones_lookup &&
			false !== $delete_delivery_zone_methods &&
			false !== $delete_delivery_zone_locations &&
			false !== $delete_delivery_zones;

		return array(
			'status' => $result,
			'msg'    => esc_html__( 'Zone succcessfully deleted!', 'orderable' ),
		);
	}

	/**
	 * Remove a zone.
	 *
	 * This does not delete a zone from the DB, rather,
	 * it removes the association between the zone and
	 * locations/time slots.
	 *
	 * @param array $data Data for this request.
	 * @return array
	 */
	public static function remove( $data ) {
		try {
			$zones_removed   = array();
			$zones_to_remove = json_decode( wp_unslash( $data['request_data'] ) );

			foreach ( $zones_to_remove as $zone_data ) {
				if ( empty( $zone_data->zone_id ) || empty( $zone_data->post_id ) || empty( $zone_data->time_slot_id ) ) {
					continue;
				}

				$location_id = Orderable_Location::get_location_id( $zone_data->post_id );

				if ( ! $location_id ) {
					continue;
				}

				$delete = self::delete_lookup_entry( $location_id, $zone_data->zone_id, $zone_data->time_slot_id );

				if ( $delete ) {
					$zones_removed[] = $zone_data->zone_id;
				}
			}

			return array(
				'status'       => true,
				'zone_ids'     => $zones_removed,
				'time_slot_id' => intval( $data['time_slot_id'] ),
				'msg'          => esc_html__( 'Zone(s) succcessfully removed', 'orderable' ),
			);
		} catch ( Exception $ex ) {
			return array(
				'status'       => false,
				'zone_id'      => null,
				'time_slot_id' => intval( $data['time_slot_id'] ),
				'msg'          => $ex->getMessage(),
			);
		}
	}

	/**
	 * Create lookup table DB entries.
	 *
	 * @param int $location_id  Location ID.
	 * @param int $zone_id      Zone ID.
	 * @param int $time_slot_id Time Slot ID.
	 *
	 * @return void
	 */
	public static function create_lookup_entry( $location_id, $zone_id, $time_slot_id ) {
		global $wpdb;

		// Create delivery zones lookup table entry.
		$wpdb->insert(
			$wpdb->prefix . 'orderable_location_delivery_zones_lookup',
			array(
				'location_id'  => $location_id,
				'time_slot_id' => $time_slot_id,
				'zone_id'      => $zone_id,
			)
		);
	}

	/**
	 * Delete lookup table DB entries.
	 *
	 * @param int      $location_id       Location ID.
	 * @param int|bool $zone_id           Zone ID, or false to delete all entries regardless of zone.
	 * @param int|bool $time_slot_id Time Slot ID, or false to delete all entries regardless of time slot.
	 *
	 * @return bool
	 */
	public static function delete_lookup_entry( $location_id, $zone_id = false, $time_slot_id = false ) {
		global $wpdb;

		// Delete delivery zones lookup table entry.
		$delete_where = array(
			'location_id' => $location_id,
		);

		if ( false !== $time_slot_id ) {
			$delete_where['time_slot_id'] = $time_slot_id;
		}

		if ( false !== $zone_id ) {
			$delete_where['zone_id'] = $zone_id;
		}

		$delete_zones_lookup = $wpdb->delete(
			$wpdb->prefix . 'orderable_location_delivery_zones_lookup',
			$delete_where,
			'%d'
		);

		return ( $delete_zones_lookup );
	}

	/**
	 * Parse raw comma delimited postcode data.
	 *
	 * @param array $normalized_postcodes Postcode data.
	 * @return array
	 */
	public static function convert_postcodes_to_locations( $normalized_postcodes ) {
		$locations = array();

		foreach ( $normalized_postcodes as $postcode ) {
			$locations[] = array(
				'type' => 'postcode',
				'code' => $postcode,
			);
		}

		return $locations;
	}
}