Files
formipay/includes/Shipping/FlatRate.php
dwindown 008188b790 feat: migrate shipping to form-level and integrate flags.json as single source of truth
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
2026-04-23 08:12:40 +07:00

168 lines
6.5 KiB
PHP

<?php
namespace Formipay\Shipping;
use Formipay\Traits\SingletonTrait;
use Formipay\Shipping\Shipping;
if ( ! defined( 'ABSPATH' ) ) exit;
class FlatRate extends Shipping {
use SingletonTrait;
private $shipping_method = 'flat_rate';
protected function __construct() {
parent::__construct();
// Register flat rate as a form-level shipping method
add_filter( 'formipay/form-settings/tab:shipping/method', [$this, 'add_shipping_method'], 15 );
add_filter( 'formipay/form-settings/tab:shipping', [$this, 'add_shipping_settings'], 15 );
// Add to order details
add_filter( 'formipay/order/order-details', [$this, 'add_shipping_to_order_details'], 99, 3 );
}
public function add_shipping_method($shipping_methods){
$shipping_methods['flat_rate'] = [
'method' => __( 'Flat Rate', 'formipay' ),
];
return $shipping_methods;
}
/**
* Add flat rate settings to form shipping configuration
* These fields are shown when "Flat Rate" is selected as the shipping method
*/
public function add_shipping_settings($fields) {
// Get global currencies configuration
$global_currencies = get_global_currency_array();
// Basic flat rate fields (type and label)
$flat_rate_fields = array(
$this->shipping_method.'_group' => array(
'type' => 'group_title',
'label' => __( 'Flat Rate Setup', 'formipay' ),
'description' => __( 'Configure flat rate shipping cost for this form', 'formipay' ),
'dependency' => array(
'key' => 'shipping_enabled',
'value' => 'flat_rate'
),
'group' => 'started'
),
$this->shipping_method.'_type' => array(
'type' => 'select',
'label' => __( 'Type', 'formipay' ),
'options' => array(
'fixed' => __( 'Fixed Amount', 'formipay' ),
'percentage' => __( 'Percentage of Order Total', 'formipay' )
),
'value' => 'fixed',
'dependency' => array(
'key' => 'shipping_enabled',
'value' => 'flat_rate'
),
),
);
// Add per-currency amount fields
foreach ($global_currencies as $currency) {
// Get the currency code (first part of triple) - this is used for meta key suffix
$currency_code = formipay_get_currency_data_by_value($currency['currency'], 'symbol');
$step = ($currency['decimal_digits'] ?? 2) > 0 ? pow(10, -($currency['decimal_digits'] ?? 2)) : 1;
$is_last = ($currency === end($global_currencies));
$flat_rate_fields[$this->shipping_method.'_amount_'.$currency_code] = array(
'type' => 'number',
'label' => sprintf(__( 'Amount (%s)', 'formipay' ), $currency_code),
'description' => $is_last ? __( 'Shipping cost for this form (not per-product)', 'formipay' ) : '',
'step' => $step,
'min' => 0,
'placeholder' => $is_last ? __( 'Enter Amount...', 'formipay' ) : __( 'Auto', 'formipay' ),
'dependency' => array(
'key' => 'shipping_enabled',
'value' => 'flat_rate'
),
'group' => $is_last ? 'ended' : null,
);
}
// Merge fields into the main fields array
foreach($flat_rate_fields as $key => $value){
$fields[$key] = $value;
}
return $fields;
}
/**
* Add shipping cost to order details
*
* @param array $details Order details array
* @param int $form_id Product/form ID
* @param array $order_data Order data from submission
* @return array Updated order details
*/
public function add_shipping_to_order_details( $details, $form_id, $order_data ) {
if ( formipay_get_post_meta($form_id, 'product_type') == 'physical' && formipay_get_post_meta($form_id, 'shipping_method') == 'flat_rate' ) {
$flat_rate_type = formipay_get_post_meta($form_id, 'flat_rate_type');
$flat_rate_label = formipay_get_post_meta($form_id, 'flat_rate_label');
// Get the selected currency from request (same way Order class does it)
$currency = isset($_REQUEST['currency']) ? sanitize_text_field( wp_unslash($_REQUEST['currency']) ) : (string) formipay_default_currency('code');
// Get flat rate amount - check for currency-specific first, then fallback to base
$flat_rate_amount = formipay_get_post_meta($form_id, 'flat_rate_amount_' . $currency);
if (empty($flat_rate_amount)) {
$flat_rate_amount = formipay_get_post_meta($form_id, 'flat_rate_amount');
}
$amount = floatval( formipay_price_format($flat_rate_amount) );
// For percentage-based, calculate from actual product price paid
if ( $flat_rate_type == 'percentage' ) {
// Find the actual product price from order details (already currency-aware)
$product_price = 0;
foreach ($details as $item) {
if (isset($item['context']) && $item['context'] == 'product') {
// Use the first product's amount (already in selected currency)
$product_price = floatval($item['amount']);
break;
}
}
// If no product found in details, fallback to lookup by currency
if ($product_price == 0) {
$regular_key = 'setting_product_price_regular_' . $currency;
$sale_key = 'setting_product_price_sale_' . $currency;
$regular_price = formipay_get_post_meta($form_id, $regular_key);
$sale_price = formipay_get_post_meta($form_id, $sale_key);
$product_price = ($sale_price !== '' && $sale_price !== null) ? floatval($sale_price) : floatval($regular_price);
}
$calculate = $product_price * $amount / 100;
$amount = floatval($calculate);
}
$details[] = [
'item' => $flat_rate_label,
'amount' => $amount,
'subtotal' => $amount
];
}
return $details;
}
}