Shipping Migration: - Move shipping configuration from product-level to form-level - Add form shipping tab in form settings (no_shipping, flat_rate, free_shipping) - Update FlatRate to register at form level instead of product level - Update checkout logic to read from form settings - Support percentage-based flat rate calculation - Simplify shipping method IDs (flat_rate, free_shipping) Currency Flags Integration: - Add formipay_get_all_currency_flags() to read from admin/assets/json/flags.json - Remove hardcoded CURRENCY_FLAGS emoji map from VariationField.js - Create CurrencyFlag component to render base64 flag images - Localize currency_flags to window.formipayProductDetails - Update shipping info display in admin order details Benefits: - Form-level shipping prevents multiplying shipping costs per product - Single source of truth for currency flags (flags.json) - Better support for future cart system - Consistent with e-commerce standards
734 lines
28 KiB
PHP
734 lines
28 KiB
PHP
<?php
|
|
namespace Formipay\Shipping;
|
|
use Formipay\Traits\SingletonTrait;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) exit;
|
|
|
|
/**
|
|
* Abstract Shipping Class - Core Carrier Extension System
|
|
*
|
|
* This class provides the hook system for carrier API extensions.
|
|
* Carriers like Rajaongkir, Biteship, etc. can extend Formipay shipping
|
|
* by registering themselves via the provided hooks.
|
|
*
|
|
* @phase 4 - Carrier API Extension System
|
|
*/
|
|
abstract class Shipping {
|
|
|
|
use SingletonTrait;
|
|
|
|
abstract public function add_shipping_method($shipping_methods);
|
|
abstract public function add_shipping_settings($fields);
|
|
abstract public function add_shipping_to_order_details($details, $form_id, $order_data);
|
|
|
|
protected function __construct() {
|
|
|
|
// Phase 1-3: Core shipping functionality
|
|
add_filter( 'formipay/global-settings', [$this, 'add_setting_shipping_menu'], 15 );
|
|
add_filter( 'formipay/form-config', [$this, 'add_form_shipping_config'], 75 );
|
|
add_filter( 'formipay/global-settings/tab:shipping', [$this, 'add_global_shipping_settings'], 15 );
|
|
|
|
// Phase 4: Carrier Extension Hooks
|
|
// Carrier registration - allows carriers to register themselves
|
|
add_filter( 'formipay/shipping/carriers', '__return_empty_array', 5 );
|
|
|
|
// Carrier API keys - inject into global shipping settings
|
|
add_filter( 'formipay/global-settings/tab:shipping', [$this, 'add_carrier_api_settings'], 20 );
|
|
|
|
// Checkout address fields - inject carrier-specific address fields
|
|
add_filter( 'formipay/checkout/shipping-address-fields', [$this, 'get_carrier_address_fields'], 10, 3 );
|
|
|
|
// Live rate fetching - allow carriers to provide real-time rates
|
|
add_filter( 'formipay/shipping/live-rates', '__return_empty_array', 10, 4 );
|
|
|
|
// AJAX handler for testing carrier connection
|
|
add_action( 'wp_ajax_formipay_test_carrier_connection', [$this, 'ajax_test_carrier_connection'], 10 );
|
|
add_action( 'wp_ajax_nopriv_formipay_test_carrier_connection', [$this, 'ajax_test_carrier_connection'], 10 );
|
|
|
|
// Phase 5: Checkout Integration
|
|
// AJAX endpoint for getting available shipping methods for checkout
|
|
add_action( 'wp_ajax_formipay_get_shipping_methods', [$this, 'ajax_get_shipping_methods'], 10 );
|
|
add_action( 'wp_ajax_nopriv_formipay_get_shipping_methods', [$this, 'ajax_get_shipping_methods'], 10 );
|
|
|
|
// AJAX endpoint for getting supported countries
|
|
add_action( 'wp_ajax_formipay_get_supported_countries', [$this, 'ajax_get_supported_countries'], 10 );
|
|
add_action( 'wp_ajax_nopriv_formipay_get_supported_countries', [$this, 'ajax_get_supported_countries'], 10 );
|
|
|
|
// Hook to add shipping cost to cart calculation
|
|
add_filter( 'formipay/checkout/cart/calculation', [$this, 'add_shipping_to_cart'], 10, 3 );
|
|
|
|
// Hook to add shipping data to order submission
|
|
add_filter( 'formipay/order/process-data', [$this, 'add_shipping_to_order_data'], 10, 2 );
|
|
|
|
}
|
|
|
|
public function add_setting_shipping_menu($fields){
|
|
|
|
$shipping_settings = [];
|
|
|
|
$shipping_settings = apply_filters( 'formipay/global-settings/tab:shipping', $shipping_settings );
|
|
|
|
if(!empty($shipping_settings)){
|
|
$fields['shipping'] = array(
|
|
'name' => __('Shipping', 'formipay'),
|
|
'fields' => $shipping_settings
|
|
);
|
|
}
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
/**
|
|
* Add global shipping settings fields
|
|
* This implements Phase 3 of the shipping module: Global Shipping Settings
|
|
*/
|
|
public function add_global_shipping_settings($fields) {
|
|
|
|
// Load countries from JSON file
|
|
$countries_json = FORMIPAY_PATH . 'admin/assets/json/country.json';
|
|
$countries = file_exists($countries_json) ? json_decode(file_get_contents($countries_json), true) : [];
|
|
|
|
$country_options = [];
|
|
if (is_array($countries)) {
|
|
foreach ($countries as $country) {
|
|
$code = $country['code'] ?? '';
|
|
$name = $country['name'] ?? '';
|
|
if ($code && $name) {
|
|
$country_options[$code] = $name;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Store Origin Section
|
|
$fields['shipping_origin_group'] = array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Store Origin', 'formipay' ),
|
|
'description' => __( 'Your business location for shipping calculations', 'formipay' ),
|
|
'group' => 'started'
|
|
);
|
|
|
|
$fields['shipping_origin_country'] = array(
|
|
'type' => 'select',
|
|
'label' => __( 'Origin Country', 'formipay' ),
|
|
'options' => $country_options,
|
|
'searchable' => true,
|
|
'description' => __( 'Select the country where your products ship from', 'formipay' ),
|
|
);
|
|
|
|
$fields['shipping_weight_unit'] = array(
|
|
'type' => 'select',
|
|
'label' => __( 'Weight Unit', 'formipay' ),
|
|
'options' => array(
|
|
'kg' => __( 'Kilograms (kg)', 'formipay' ),
|
|
'g' => __( 'Grams (g)', 'formipay' ),
|
|
'lb' => __( 'Pounds (lb)', 'formipay' ),
|
|
'oz' => __( 'Ounces (oz)', 'formipay' ),
|
|
),
|
|
'value' => 'kg',
|
|
);
|
|
|
|
$fields['shipping_dimension_unit'] = array(
|
|
'type' => 'select',
|
|
'label' => __( 'Dimension Unit', 'formipay' ),
|
|
'options' => array(
|
|
'cm' => __( 'Centimeters (cm)', 'formipay' ),
|
|
'in' => __( 'Inches (in)', 'formipay' ),
|
|
'm' => __( 'Meters (m)', 'formipay' ),
|
|
),
|
|
'value' => 'cm',
|
|
'group' => 'ended'
|
|
);
|
|
|
|
// Shipping Calculation Method
|
|
$fields['shipping_calculation_group'] = array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Shipping Calculation', 'formipay' ),
|
|
'description' => __( 'How shipping costs are calculated for orders', 'formipay' ),
|
|
'group' => 'started'
|
|
);
|
|
|
|
$fields['shipping_calculation_method'] = array(
|
|
'type' => 'select',
|
|
'label' => __( 'Calculation Method', 'formipay' ),
|
|
'options' => array(
|
|
'per_order' => __( 'Per Order (single shipping fee for entire order)', 'formipay' ),
|
|
'per_item' => __( 'Per Item (shipping fee multiplied by quantity)', 'formipay' ),
|
|
),
|
|
'value' => 'per_order',
|
|
'group' => 'ended'
|
|
);
|
|
|
|
// Supported Destinations Section
|
|
$fields['shipping_destinations_group'] = array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Supported Destinations', 'formipay' ),
|
|
'description' => __( 'Configure which countries you ship to and their shipping rates', 'formipay' ),
|
|
'group' => 'started'
|
|
);
|
|
|
|
// Get enabled currencies for flat rate table
|
|
$formipay_settings = get_option('formipay_settings', []);
|
|
$enabled_currencies = [];
|
|
|
|
if (!empty($formipay_settings['multicurrencies']) && is_array($formipay_settings['multicurrencies'])) {
|
|
foreach ($formipay_settings['multicurrencies'] as $currency) {
|
|
if (isset($currency['currency'])) {
|
|
$parts = explode(':::', $currency['currency']);
|
|
$enabled_currencies[] = [
|
|
'code' => $parts[0] ?? '',
|
|
'title' => $parts[1] ?? '',
|
|
'symbol' => $parts[2] ?? $parts[0] ?? '',
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback to default currency if multicurrency is not enabled
|
|
if (empty($enabled_currencies)) {
|
|
$default_currency = $formipay_settings['default_currency'] ?? 'IDR:::Indonesian rupiah:::Rp';
|
|
$parts = explode(':::', $default_currency);
|
|
$enabled_currencies[] = [
|
|
'code' => $parts[0] ?? 'IDR',
|
|
'title' => $parts[1] ?? 'Indonesian rupiah',
|
|
'symbol' => $parts[2] ?? 'Rp',
|
|
];
|
|
}
|
|
|
|
// Build currency amount fields for the repeater
|
|
$currency_fields = [];
|
|
foreach ($enabled_currencies as $curr) {
|
|
$code = $curr['code'];
|
|
$symbol = $curr['symbol'];
|
|
$currency_fields['flat_rate_' . $code] = array(
|
|
'type' => 'number',
|
|
'label' => sprintf(__( 'Flat Rate (%s)', 'formipay' ), $code),
|
|
'step' => 0.01,
|
|
'min' => 0,
|
|
'placeholder' => '0.00',
|
|
);
|
|
}
|
|
|
|
// Build free shipping threshold field (use primary currency)
|
|
$primary_currency = $enabled_currencies[0] ?? [];
|
|
$primary_symbol = $primary_currency['symbol'] ?? '';
|
|
|
|
$fields['shipping_destinations'] = array(
|
|
'type' => 'repeater',
|
|
'label' => __( 'Destinations', 'formipay' ),
|
|
'description' => __( 'Add countries you ship to and configure their shipping options', 'formipay' ),
|
|
'fields' => array_merge(
|
|
[
|
|
'country' => array(
|
|
'type' => 'select',
|
|
'label' => __('Country', 'formipay'),
|
|
'options' => $country_options,
|
|
'required' => true,
|
|
'searchable' => true,
|
|
'is_group_title' => true
|
|
),
|
|
'rate_source' => array(
|
|
'type' => 'select',
|
|
'label' => __('Rate Source', 'formipay'),
|
|
'options' => array(
|
|
'flat_rate' => __( 'Flat Rate', 'formipay' ),
|
|
// 'api' => __( 'Carrier API', 'formipay' ), // Phase 4
|
|
),
|
|
'value' => 'flat_rate',
|
|
),
|
|
],
|
|
$currency_fields,
|
|
[
|
|
'free_shipping_threshold' => array(
|
|
'type' => 'number',
|
|
'label' => sprintf(__( 'Free Shipping Threshold (%s)', 'formipay' ), $primary_symbol),
|
|
'description' => __( 'Order amount above which shipping is free. Leave empty to disable.', 'formipay' ),
|
|
'step' => 0.01,
|
|
'min' => 0,
|
|
'placeholder' => 'Empty = disabled',
|
|
),
|
|
]
|
|
)
|
|
);
|
|
|
|
// Note: Carrier API settings will be added in Phase 4
|
|
$fields['carrier_api_note'] = array(
|
|
'type' => 'notification_message',
|
|
'description' => __( '
|
|
<h3>Carrier API Integration</h3>
|
|
<p>Live carrier rates (Rajaongkir, Biteship, etc.) will be available in Phase 4 of the shipping module.</p>
|
|
<p>Currently, only Flat Rate and Free Shipping methods are available at the product level.</p>
|
|
', 'formipay' ),
|
|
);
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
/**
|
|
* Add shipping configuration to form settings
|
|
* This replaces product-level shipping with form-level shipping
|
|
*/
|
|
public function add_form_shipping_config($fields) {
|
|
|
|
$shipping_methods = apply_filters( 'formipay/form-settings/tab:shipping/method', [
|
|
'no_shipping' => [
|
|
'method' => __( 'No Shipping Required', 'formipay' )
|
|
],
|
|
'flat_rate' => [
|
|
'method' => __( 'Flat Rate', 'formipay' )
|
|
],
|
|
'free_shipping' => [
|
|
'method' => __( 'Free Shipping', 'formipay' )
|
|
]
|
|
] );
|
|
|
|
$shipping_options = [];
|
|
foreach($shipping_methods as $id => $shipping){
|
|
$label = $shipping['method'];
|
|
if(isset($shipping['courier'])){
|
|
$label .= ' - '.$shipping['courier'];
|
|
if(isset($shipping['service'])){
|
|
$label .= ' - '.$shipping['service'];
|
|
}
|
|
}
|
|
$shipping_options[$id] = $label;
|
|
}
|
|
|
|
// Main shipping configuration group
|
|
$shipping_config_group = [
|
|
'shipping_enable_group' => [
|
|
'type' => 'group_title',
|
|
'label' => __( 'Shipping Configuration', 'formipay' ),
|
|
'description' => __( 'Configure shipping options for this form. Shipping will be calculated based on form settings, not per-product.', 'formipay' ),
|
|
'group' => 'started'
|
|
],
|
|
'shipping_enabled' => [
|
|
'type' => 'radio',
|
|
'label' => __( 'Shipping Method', 'formipay' ),
|
|
'options' => $shipping_options,
|
|
'value' => 'no_shipping',
|
|
'description' => __( 'Select how shipping should be handled for orders from this form', 'formipay' ),
|
|
]
|
|
];
|
|
|
|
$shipping_config_group = apply_filters( 'formipay/form-settings/tab:shipping/group:config', $shipping_config_group );
|
|
$last_config_key = array_key_last($shipping_config_group);
|
|
$shipping_config_group[$last_config_key]['group'] = 'ended';
|
|
|
|
// Apply carrier-specific settings (Flat Rate, etc.)
|
|
$carrier_settings = apply_filters( 'formipay/form-settings/tab:shipping', [] );
|
|
|
|
$all_shipping_fields = array_merge($shipping_config_group, $carrier_settings);
|
|
|
|
$fields['formipay_form_settings']['shipping'] = [
|
|
'name' => __( 'Shipping', 'formipay' ),
|
|
'fields' => $all_shipping_fields
|
|
];
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
/**
|
|
* =============================================
|
|
* PHASE 4: CARRIER EXTENSION HOOKS
|
|
* =============================================
|
|
*/
|
|
|
|
/**
|
|
* Add carrier API settings to global shipping settings
|
|
* Carriers can hook into `formipay/global-settings/tab:shipping/carriers` to add their API key fields
|
|
*
|
|
* @param array $fields Existing shipping settings fields
|
|
* @return array Updated fields with carrier API settings
|
|
*/
|
|
public function add_carrier_api_settings($fields) {
|
|
|
|
// Get all registered carriers
|
|
$carriers = apply_filters('formipay/shipping/carriers', []);
|
|
|
|
if (empty($carriers)) {
|
|
// No carriers registered, add info message
|
|
$fields['carrier_api_info'] = array(
|
|
'type' => 'notification_message',
|
|
'description' => __( '
|
|
<h3>Carrier API Integration</h3>
|
|
<p>To enable live shipping rates, install a carrier extension plugin.</p>
|
|
<p>Extensions register themselves via the <code>formipay/shipping/carriers</code> filter.</p>
|
|
', 'formipay' ),
|
|
);
|
|
return $fields;
|
|
}
|
|
|
|
// Add carrier API settings section
|
|
$fields['carrier_api_group'] = array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Carrier API Keys', 'formipay' ),
|
|
'description' => __( 'Configure API credentials for live shipping rate calculation', 'formipay' ),
|
|
'group' => 'started'
|
|
);
|
|
|
|
// Allow carriers to inject their API key fields
|
|
$carrier_fields = apply_filters('formipay/global-settings/tab:shipping/carriers', []);
|
|
|
|
foreach ($carrier_fields as $key => $field) {
|
|
$fields[$key] = $field;
|
|
}
|
|
|
|
// Add test connection buttons for each carrier
|
|
foreach ($carriers as $carrier_id => $carrier) {
|
|
if (isset($carrier['test_connection']) && $carrier['test_connection']) {
|
|
$fields['test_connection_' . $carrier_id] = array(
|
|
'type' => 'html',
|
|
'label' => __( 'Test Connection', 'formipay' ),
|
|
'html' => sprintf(
|
|
'<button type="button" class="button formipay-test-connection" data-carrier="%s">%s</button>
|
|
<span class="formipay-connection-result" style="margin-left: 10px;"></span>',
|
|
esc_attr($carrier_id),
|
|
esc_html__('Test Connection', 'formipay')
|
|
),
|
|
'group' => ($carrier_id === array_key_last($carriers)) ? 'ended' : null,
|
|
);
|
|
}
|
|
}
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
/**
|
|
* Get carrier-specific address fields for checkout
|
|
* Carriers can hook into `formipay/checkout/address-fields/{carrier_id}` to provide their fields
|
|
*
|
|
* @param array $fields Current address fields
|
|
* @param string $carrier_id Carrier identifier (e.g., 'rajaongkir', 'biteship')
|
|
* @param string $country_code Destination country code
|
|
* @return array Address fields for this carrier
|
|
*/
|
|
public function get_carrier_address_fields($fields, $carrier_id, $country_code) {
|
|
|
|
// Get carrier-specific address fields
|
|
$carrier_fields = apply_filters('formipay/checkout/address-fields/' . $carrier_id, [], $country_code);
|
|
|
|
return array_merge($fields, $carrier_fields);
|
|
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for testing carrier connection
|
|
* Carriers can hook into `formipay/test_carrier_connection/{carrier_id}` to handle the test
|
|
*/
|
|
public function ajax_test_carrier_connection() {
|
|
|
|
check_ajax_referer('formipay-admin', 'nonce', true);
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error(['message' => __('Unauthorized', 'formipay')]);
|
|
}
|
|
|
|
$carrier_id = isset($_POST['carrier']) ? sanitize_text_field(wp_unslash($_POST['carrier'])) : '';
|
|
|
|
if (empty($carrier_id)) {
|
|
wp_send_json_error(['message' => __('Missing carrier ID', 'formipay')]);
|
|
}
|
|
|
|
// Allow carriers to handle their own connection test
|
|
$result = apply_filters('formipay/test_carrier_connection/' . $carrier_id, [
|
|
'success' => false,
|
|
'message' => __('Carrier does not implement connection test', 'formipay'),
|
|
], $_POST);
|
|
|
|
if ($result['success']) {
|
|
wp_send_json_success($result);
|
|
} else {
|
|
wp_send_json_error($result);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Helper method: Get registered carriers
|
|
* Returns all carriers that have registered via the filter
|
|
*
|
|
* @return array Registered carriers
|
|
*/
|
|
public static function get_registered_carriers() {
|
|
|
|
return apply_filters('formipay/shipping/carriers', []);
|
|
|
|
}
|
|
|
|
/**
|
|
* Helper method: Get carrier by ID
|
|
*
|
|
* @param string $carrier_id Carrier identifier
|
|
* @return array|null Carrier data or null if not found
|
|
*/
|
|
public static function get_carrier($carrier_id) {
|
|
|
|
$carriers = self::get_registered_carriers();
|
|
return $carriers[$carrier_id] ?? null;
|
|
|
|
}
|
|
|
|
/**
|
|
* Helper method: Check if carrier supports a country
|
|
*
|
|
* @param string $carrier_id Carrier identifier
|
|
* @param string $country_code Country code to check
|
|
* @return bool True if carrier supports the country
|
|
*/
|
|
public static function carrier_supports_country($carrier_id, $country_code) {
|
|
|
|
$carrier = self::get_carrier($carrier_id);
|
|
if (!$carrier) {
|
|
return false;
|
|
}
|
|
|
|
$supported_countries = $carrier['countries'] ?? [];
|
|
return in_array($country_code, $supported_countries, true);
|
|
|
|
}
|
|
|
|
/**
|
|
* Helper method: Fetch live rates from carrier
|
|
*
|
|
* @param string $carrier_id Carrier identifier
|
|
* @param array $params Rate request parameters (origin, destination, weight, dimensions)
|
|
* @return array Available rates with costs
|
|
*/
|
|
public static function fetch_live_rates($carrier_id, $params) {
|
|
|
|
$default_params = [
|
|
'origin_country' => '',
|
|
'origin_city' => '',
|
|
'origin_postcode' => '',
|
|
'destination_country' => '',
|
|
'destination_city' => '',
|
|
'destination_postcode' => '',
|
|
'weight' => 0,
|
|
'weight_unit' => 'kg',
|
|
'length' => 0,
|
|
'width' => 0,
|
|
'height' => 0,
|
|
'dimension_unit' => 'cm',
|
|
];
|
|
|
|
$params = wp_parse_args($params, $default_params);
|
|
|
|
return apply_filters('formipay/shipping/live-rates', [], $carrier_id, $params);
|
|
|
|
}
|
|
|
|
/**
|
|
* =============================================
|
|
* PHASE 5: CHECKOUT INTEGRATION
|
|
* =============================================
|
|
*/
|
|
|
|
/**
|
|
* AJAX: Get available shipping methods for a form
|
|
* Now reads from form-level shipping settings instead of global settings
|
|
*/
|
|
public function ajax_get_shipping_methods() {
|
|
|
|
check_ajax_referer('formipay-public', 'nonce', true);
|
|
|
|
$form_id = isset($_POST['form_id']) ? intval($_POST['form_id']) : 0;
|
|
$country_code = isset($_POST['country']) ? sanitize_text_field(wp_unslash($_POST['country'])) : '';
|
|
$currency = isset($_POST['currency']) ? sanitize_text_field(wp_unslash($_POST['currency'])) : '';
|
|
|
|
if (!$form_id) {
|
|
wp_send_json_error(['message' => __('Invalid request', 'formipay')]);
|
|
}
|
|
|
|
// Get form shipping settings
|
|
$form_settings = get_post_meta($form_id, 'formipay_form_settings', true);
|
|
$shipping_enabled = $form_settings['shipping_enabled'] ?? 'no_shipping';
|
|
|
|
$available_methods = [];
|
|
|
|
if ($shipping_enabled === 'flat_rate') {
|
|
// Get flat rate from form settings
|
|
$currency_code = $currency ?: 'IDR';
|
|
$rate_key = 'flat_rate_amount_' . $currency_code;
|
|
$flat_rate = floatval($form_settings[$rate_key] ?? 0);
|
|
$flat_rate_type = $form_settings['flat_rate_type'] ?? 'fixed';
|
|
|
|
// For percentage, we'll calculate on frontend based on cart total
|
|
// For now, store the type so frontend knows how to handle it
|
|
$available_methods[] = [
|
|
'id' => 'flat_rate',
|
|
'name' => __('Standard Shipping', 'formipay'),
|
|
'description' => $flat_rate_type === 'percentage'
|
|
? sprintf(__('%s%% of order total', 'formipay'), $flat_rate)
|
|
: __('Delivery in 3-5 business days', 'formipay'),
|
|
'cost' => $flat_rate,
|
|
'currency' => $currency_code,
|
|
'type' => $flat_rate_type,
|
|
];
|
|
|
|
} elseif ($shipping_enabled === 'free_shipping') {
|
|
// Free shipping from form settings
|
|
$free_label = $form_settings['free_shipping_label'] ?? __('Free Shipping', 'formipay');
|
|
$available_methods[] = [
|
|
'id' => 'free_shipping',
|
|
'name' => $free_label,
|
|
'description' => __('No shipping cost', 'formipay'),
|
|
'cost' => 0,
|
|
'currency' => $currency_code ?? '',
|
|
];
|
|
}
|
|
|
|
// If country-specific shipping is needed in future, add check here
|
|
// For now, form-level shipping applies to all countries
|
|
|
|
if (empty($available_methods)) {
|
|
wp_send_json_error([
|
|
'message' => __('Shipping is not available for this form', 'formipay'),
|
|
'methods' => []
|
|
]);
|
|
}
|
|
|
|
wp_send_json_success([
|
|
'methods' => $available_methods,
|
|
'default_method' => $available_methods[0]['id'],
|
|
]);
|
|
|
|
}
|
|
|
|
/**
|
|
* Add shipping cost to cart calculation
|
|
* Hooked into formipay/checkout/cart/calculation
|
|
*/
|
|
public function add_shipping_to_cart($cart, $form_id, $selected_currency) {
|
|
|
|
// Check if shipping is enabled for this form
|
|
$form_settings = get_post_meta($form_id, 'formipay_form_settings', true);
|
|
$shipping_enabled = $form_settings['shipping_enabled'] ?? 'no_shipping';
|
|
|
|
if ($shipping_enabled === 'no_shipping') {
|
|
return $cart;
|
|
}
|
|
|
|
// Get selected shipping method from POST data or session
|
|
$shipping_method = isset($_POST['shipping_method']) ? sanitize_text_field(wp_unslash($_POST['shipping_method'])) : '';
|
|
$shipping_country = isset($_POST['shipping_country']) ? sanitize_text_field(wp_unslash($_POST['shipping_country'])) : '';
|
|
|
|
if (empty($shipping_method) || empty($shipping_country)) {
|
|
return $cart;
|
|
}
|
|
|
|
// Parse shipping method ID to get cost
|
|
// Format: flat_rate, free_shipping, or {carrier}_{service}
|
|
if ($shipping_method === 'free_shipping') {
|
|
// Free shipping
|
|
$cart['shipping'] = [
|
|
'name' => __('Free Shipping', 'formipay'),
|
|
'cost' => 0,
|
|
];
|
|
} elseif ($shipping_method === 'flat_rate') {
|
|
// Flat rate - get cost from form settings
|
|
$currency_code = $selected_currency ?: 'IDR';
|
|
$rate_key = 'flat_rate_amount_' . $currency_code;
|
|
$flat_rate = floatval($form_settings[$rate_key] ?? 0);
|
|
|
|
// Check if percentage
|
|
$flat_rate_type = $form_settings['flat_rate_type'] ?? 'fixed';
|
|
if ($flat_rate_type === 'percentage') {
|
|
$subtotal = floatval($cart['subtotal'] ?? 0);
|
|
$flat_rate = ($subtotal * $flat_rate) / 100;
|
|
}
|
|
|
|
$cart['shipping'] = [
|
|
'name' => __('Standard Shipping', 'formipay'),
|
|
'cost' => $flat_rate,
|
|
];
|
|
|
|
// Recalculate totals
|
|
$cart['subtotal'] = floatval($cart['subtotal'] ?? 0);
|
|
$cart['tax'] = floatval($cart['tax'] ?? 0);
|
|
$cart['discount'] = floatval($cart['discount'] ?? 0);
|
|
|
|
$cart['grand'] = $cart['subtotal'] + $cart['tax'] + $cart['shipping']['cost'] - $cart['discount'];
|
|
}
|
|
|
|
return $cart;
|
|
|
|
}
|
|
|
|
/**
|
|
* Add shipping data to order submission
|
|
* Hooked into formipay/order/process-data
|
|
*/
|
|
public function add_shipping_to_order_data($form_data, $form_id) {
|
|
|
|
// Check if shipping is enabled for this form
|
|
$form_settings = get_post_meta($form_id, 'formipay_form_settings', true);
|
|
$shipping_enabled = $form_settings['shipping_enabled'] ?? 'no_shipping';
|
|
|
|
if ($shipping_enabled === 'no_shipping') {
|
|
return $form_data;
|
|
}
|
|
|
|
// Add shipping info to form data
|
|
if (isset($_POST['shipping_method'])) {
|
|
$form_data['shipping_method'] = sanitize_text_field(wp_unslash($_POST['shipping_method']));
|
|
}
|
|
|
|
if (isset($_POST['shipping_country'])) {
|
|
$form_data['shipping_country'] = sanitize_text_field(wp_unslash($_POST['shipping_country']));
|
|
}
|
|
|
|
return $form_data;
|
|
|
|
}
|
|
|
|
/**
|
|
* AJAX: Get supported shipping countries
|
|
* With form-level shipping, returns all available countries
|
|
*/
|
|
public function ajax_get_supported_countries() {
|
|
|
|
// Verify nonce
|
|
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'formipay_public_nonce')) {
|
|
wp_send_json_error(['message' => __('Invalid security token', 'formipay')]);
|
|
}
|
|
|
|
$form_id = isset($_POST['form_id']) ? intval($_POST['form_id']) : 0;
|
|
|
|
if (!$form_id) {
|
|
wp_send_json_error(['message' => __('Invalid form ID', 'formipay')]);
|
|
}
|
|
|
|
// Load countries from JSON file
|
|
$countries_json = FORMIPAY_PATH . 'admin/assets/json/country.json';
|
|
$all_countries = file_exists($countries_json) ? json_decode(file_get_contents($countries_json), true) : [];
|
|
|
|
// Build country list
|
|
$countries = [];
|
|
if (is_array($all_countries)) {
|
|
foreach ($all_countries as $country) {
|
|
$code = $country['code'] ?? '';
|
|
$name = $country['name'] ?? '';
|
|
if ($code && $name) {
|
|
$countries[$code] = $name;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($countries)) {
|
|
wp_send_json_error([
|
|
'message' => __('No countries available', 'formipay'),
|
|
'countries' => []
|
|
]);
|
|
}
|
|
|
|
wp_send_json_success([
|
|
'countries' => $countries,
|
|
]);
|
|
|
|
}
|
|
|
|
} |