Plugin Directory

Changeset 3446938


Ignore:
Timestamp:
01/26/2026 08:46:07 AM (2 months ago)
Author:
enituretechnology
Message:

2.4.16 - 2026-01-26

  • Update: Added product-level offset days feature to allow more granular shipment timing control.
  • Update: Added pallet vertical rotation and ship as own pallet parameters to line items for enhanced freightdesk.online metadata handling.
  • Update: Added parent product checks to handle empty properties in variant products and prevent invalid data processing.
  • Fix: Resolved UI issues related to extra white background and the logs pop-up form display.
  • Fix: Removed duplicate in-store pickup and local delivery quotes to prevent repeated rate entries.

Ticket 23708293437

Location:
ltl-freight-quotes-freightquote-edition
Files:
22 edited
1 copied

Legend:

Unmodified
Added
Removed
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/css/freightquote_ltl_style.css

    r3373518 r3446938  
    610610.woocommerce_variable_attributes.wc-metabox-content [class^="_nmfc_number"],
    611611.woocommerce_variable_attributes.wc-metabox-content [class^="_en_product_markup"],
     612.woocommerce_variable_attributes.wc-metabox-content [class^="_eniture_product_level_fulfillment_offset_days"],
    612613.woocommerce_variable_attributes.wc-metabox-content [class^="_nestedPercentage"],
    613614.woocommerce_variable_attributes.wc-metabox-content [class^="en_flat_rate_price"],
     
    633634.woocommerce_variable_attributes.wc-metabox-content [class^="en_flat_rate_price"],
    634635.woocommerce_variable_attributes.wc-metabox-content [class^="_en_product_markup"],
     636.woocommerce_variable_attributes.wc-metabox-content [class^="_eniture_product_level_fulfillment_offset_days"],
    635637.woocommerce_variable_attributes.wc-metabox-content [class^="_nestedPercentage"],
    636638.woocommerce_variable_attributes.wc-metabox-content [class^="_nestedDimension"],
     
    642644.woocommerce_variable_attributes.wc-metabox-content .data p[class*="en_flat_rate_price"] span.woocommerce-help-tip,
    643645.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_en_product_markup"] span.woocommerce-help-tip,
     646.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_eniture_product_level_fulfillment_offset_days"] span.woocommerce-help-tip,
    644647.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_nestedPercentage"] span.woocommerce-help-tip,
    645648.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_nestedDimension"] span.woocommerce-help-tip,
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/fdo/en-fdo.php

    r3373518 r3446938  
    5050        $this->en_fdo_meta_data['items'] = [];
    5151        foreach ($items as $item_key => $item_data) {
    52             $nmfc_number = $productId = $productName = $productQty = $actualProductPrice = $products = $productPrice = $productWeight = $productLength = $productWidth = $productHeight = $ptype = $hazardousMaterial = $productType = $productSku = $productClass = $attributes = $variantId = $nestedMaterial = $nestedPercentage = $nestedDimension = $nestedItems = $stakingProperty = '';
     52            $nmfc_number = $productId = $productName = $productQty = $actualProductPrice = $products = $productPrice = $productWeight = $productLength = $productWidth = $productHeight = $ptype = $hazardousMaterial = $productType = $productSku = $productClass = $attributes = $variantId = $nestedMaterial = $nestedPercentage = $nestedDimension = $nestedItems = $stakingProperty = $ship_as_own_pallet = $vertical_rotation_for_pallet = '';
    5353            $attributes = [];
    5454            extract($item_data);
     
    9292                'nested_items' => $nestedItems,
    9393                'staking_property' => $stakingProperty,
    94                 'nmfc_number' => $nmfc_number
     94                'nmfc_number' => $nmfc_number,
     95                'pallet_vertical_rotation' => $vertical_rotation_for_pallet,
     96                'ship_as_own_pallet' => $ship_as_own_pallet
    9597            ];
    9698
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/feightquote-carrier-service.php

    r3373518 r3446938  
    8383        if ($freightquote_delivery_estimates == 'delivery_days' || $freightquote_delivery_estimates == 'delivery_date') {
    8484            $order_cut_off_time = $this->quote_settings['orderCutoffTime'];
    85             $shipment_off_set_days = $this->quote_settings['shipmentOffsetDays'];
     85
     86             // Use product-level fulfillment offset days if available, otherwise use global setting
     87            if (isset($packages['max_fulfillment_offset_days']) && is_numeric($packages['max_fulfillment_offset_days']) && $packages['max_fulfillment_offset_days'] > 0) {
     88                $shipment_off_set_days = $packages['max_fulfillment_offset_days'];
     89            } else {
     90                $shipment_off_set_days = $this->quote_settings['shipmentOffsetDays'];
     91            }
     92
    8693            $modify_shipment_date_time = ($order_cut_off_time != '' || $shipment_off_set_days != '' || (is_array($shipment_week_days) && count($shipment_week_days) > 0)) ? 1 : 0;
    8794            $store_date_time = $today = gmdate('Y-m-d H:i:s', current_time('timestamp'));
     
    314321            $cachable_data['addressLine2'] = (isset($request_data['addressLine2'])) ? $request_data['addressLine2'] : '';
    315322            $cachable_data['defaultRADAddressType'] = $request_data['defaultRADAddressType'];
     323            $cachable_data['defaultRADWithoutStreetAddress'] = $request_data['defaultRADWithoutStreetAddress'];
    316324            $cachable_data['poboxAddressValidation'] = $request_data['poboxAddressValidation'];
    317325        }
     
    673681                    $quotes[$count] = apply_filters('en_product_markup', $quotes[$count]);
    674682
     683                    // Add pallet fee
     684                    $quotes[$count] = has_filter('en_pallet_price') ? apply_filters('en_pallet_price', $quotes[$count]) : $quotes[$count];
     685
    675686                    $en_fdo_meta_data['rate'] = $quotes[$count];
    676687                    if (isset($en_fdo_meta_data['rate']['meta_data'])) {
     
    781792                    $simple_quotes[$count] = apply_filters('en_product_markup', $simple_quotes[$count]);
    782793
     794                    // Add pallet fee
     795                    $simple_quotes[$count] = has_filter('en_pallet_price') ? apply_filters('en_pallet_price', $simple_quotes[$count]) : $simple_quotes[$count];
     796
    783797                    // FDO
    784798                    $en_fdo_meta_data['rate'] = $simple_quotes[$count];
     
    869883                    $tl_quotes[$count] = apply_filters('en_product_markup', $tl_quotes[$count]);
    870884
     885                    // Add pallet fee
     886                    $tl_quotes[$count] = has_filter('en_pallet_price') ? apply_filters('en_pallet_price', $tl_quotes[$count]) : $tl_quotes[$count];
     887
    871888                    // FDO
    872889                    $en_fdo_meta_data['rate'] = $tl_quotes[$count];
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/freightquote-group-package.php

    r3359670 r3446938  
    145145            if ($nested_material == "yes") {
    146146                $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
    147                 $nestedPercentage = get_post_meta($post_id, '_nestedPercentage', true);
    148                 $nestedDimension = get_post_meta($post_id, '_nestedDimension', true);
    149                 $nestedItems = get_post_meta($post_id, '_maxNestedItems', true);
    150                 $StakingProperty = get_post_meta($post_id, '_nestedStakingProperty', true);
     147                $nestedPercentage = $this->get_property_value('_nestedPercentage', $values, $_product);
     148                $nestedDimension = $this->get_property_value('_nestedDimension', $values, $_product);
     149                $nestedItems = $this->get_property_value('_maxNestedItems', $values, $_product);
     150                $StakingProperty = $this->get_property_value('_nestedStakingProperty', $values, $_product);
    151151            }
    152152
     
    156156            $hm_status = (!is_array($hm_plan) && $hazardous_material == 'yes') ? TRUE : FALSE;
    157157
    158             $product_title = str_replace(array("'", '"'), '', $_product->get_title());
     158            $product_title = str_replace(array("'", '"'), '', $_product->get_name());
    159159            $product_level_markup = $this->fq_ltl_get_product_level_markup($_product, $values['variation_id'], $values['product_id'], $values['quantity']);
    160160            // check if TL enable
    161161            $tl_enable = $this->freightquote_ltl_enable_shipping_class($_product, true);
     162            $product_level_fulfillment_offset = $this->freightquote_ltl_get_product_level_fulfillment_offset_days($_product, $values['variation_id'], $values['product_id']);
    162163
    163164            // Shippable handling units
     
    204205                'ship_as_own_pallet' => $ship_as_own_pallet,
    205206                'vertical_rotation_for_pallet' => $vertical_rotation_for_pallet,
    206                 'markup' => $product_level_markup
     207                'markup' => $product_level_markup,
     208                'fulfillment_offset_days' => $product_level_fulfillment_offset
    207209            ];
    208210
     
    275277
    276278            $ltl_package[$locationId]['shipment_weight'] = isset($ltl_package[$locationId]['shipment_weight']) ? $ltl_package[$locationId]['shipment_weight'] + $weight : $weight;
     279
     280            // Track maximum fulfillment offset days
     281            if (is_numeric($product_level_fulfillment_offset) && $product_level_fulfillment_offset > 0) {
     282                if (!isset($ltl_package[$locationId]['max_fulfillment_offset_days']) || $product_level_fulfillment_offset > $ltl_package[$locationId]['max_fulfillment_offset_days']) {
     283                    $ltl_package[$locationId]['max_fulfillment_offset_days'] = $product_level_fulfillment_offset;
     284                }
     285            }
    277286
    278287            $smallPluginExist = 0;
     
    366375    {
    367376        $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
    368         return get_post_meta($post_id, '_nestedMaterials', true);
     377        $nested_material = get_post_meta($post_id, '_nestedMaterials', true);
     378
     379        // check nested material in parent
     380        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($nested_material)) {
     381            $post_id = isset($values['product_id']) ? $values['product_id'] : $_product->get_parent_id();
     382            $nested_material = get_post_meta($post_id, '_nestedMaterials', true);
     383        }
     384
     385        return $nested_material;
    369386    }
    370387
     
    378395    {
    379396        $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
    380         return get_post_meta($post_id, '_hazardousmaterials', true);
     397        $hazardous_material = get_post_meta($post_id, '_hazardousmaterials', true);
     398
     399        // check hazmat in parent
     400        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($hazardous_material)) {
     401            $post_id = isset($values['product_id']) ? $values['product_id'] : $_product->get_parent_id();
     402            $hazardous_material = get_post_meta($post_id, '_hazardousmaterials', true);
     403        }
     404
     405        return $hazardous_material;
    381406    }
    382407
     
    396421        (isset($values['variation_id']) && $values['variation_id'] > 0) ? $post_id = $values['variation_id'] : $post_id = $_product->get_id();
    397422        $enable_dropship = get_post_meta($post_id, '_enable_dropship', true);
     423
     424        // check dropship in parent
     425        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($enable_dropship)) {
     426            $post_id = isset($values['product_id']) ? $values['product_id'] : $post_id;
     427            $enable_dropship = get_post_meta($post_id, '_enable_dropship', true);
     428        }
     429
    398430        if ($enable_dropship == 'yes') {
    399431            $get_loc = get_post_meta($post_id, '_dropship_location', true);
     
    513545        if ($_product->get_type() == 'variation') {
    514546            $variation_class = get_post_meta($values['variation_id'], '_ltl_freight_variation', true);
    515             if ($variation_class == 0) {
     547            $variation_class = empty($variation_class) ? get_post_meta($values['variation_id'], '_ltl_freight', true) : $variation_class;
     548
     549            if (empty($variation_class) || $variation_class == 0 || $variation_class == 'get_parent') {
    516550                $variation_class = get_post_meta($values['product_id'], '_ltl_freight', true);
    517551                $freightclass_ltl_gross = $variation_class;
     
    519553                if ($variation_class > 0) {
    520554                    $freightclass_ltl_gross = get_post_meta($values['variation_id'], '_ltl_freight_variation', true);
     555                    $freightclass_ltl_gross = empty($freightclass_ltl_gross) ? get_post_meta($values['variation_id'], '_ltl_freight', true) : $freightclass_ltl_gross;
    521556                } else {
    522557                    $freightclass_ltl_gross = get_post_meta($_product->get_id(), '_ltl_freight', true);
     
    662697    {
    663698        $pp_suspended = get_option('suspend_automatic_detection_of_pallets');
     699        $pp_fq_suspended = get_option('suspend_freightquote_quests_automatic_detection_of_pallets');
    664700        // Check if Pallet Packaging is enabled, then this feature will not work
    665         if (is_plugin_active('pallet-packaging-for-woocommerce/pallet-packaging-for-woocommerce.php') && has_filter('en_pallet_identify') && $pp_suspended != 'yes') {
     701        if (is_plugin_active('pallet-packaging-for-woocommerce/pallet-packaging-for-woocommerce.php') && has_filter('en_pallet_identify') && $pp_suspended != 'yes' && $pp_fq_suspended != 'yes') {
    666702            return $item;
    667703        }
     
    693729    }
    694730
     731    function get_property_value($property_key, $values, $_product)
     732    {
     733        $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
     734        $property_enabled = get_post_meta($post_id, $property_key, true);
     735
     736        // check property in parent
     737        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($property_enabled)) {
     738            $post_id = isset($values['product_id']) ? $values['product_id'] : $_product->get_parent_id();
     739            $property_enabled = get_post_meta($post_id, $property_key, true);
     740        }
     741
     742        return $property_enabled;
     743    }
     744
     745    function freightquote_ltl_get_product_level_fulfillment_offset_days($_product, $variation_id, $product_id)
     746    {
     747        $fulfillment_offset_days = '';
     748        $field_name = '_eniture_product_level_fulfillment_offset_days';
     749
     750        if ($_product->get_type() == 'variation' && $variation_id > 0) {
     751            $fulfillment_offset_days = get_post_meta($variation_id, $field_name, true);
     752
     753            if (empty($fulfillment_offset_days) || !is_numeric($fulfillment_offset_days)) {
     754                $parent_id = $_product->get_parent_id();
     755                if ($parent_id > 0) {
     756                    $fulfillment_offset_days = get_post_meta($parent_id, $field_name, true);
     757                }
     758            }
     759        } else {
     760            $fulfillment_offset_days = get_post_meta($_product->get_id(), $field_name, true);
     761        }
     762
     763        if (empty($fulfillment_offset_days) || !is_numeric($fulfillment_offset_days)) {
     764            $fulfillment_offset_days = get_post_meta($product_id, $field_name, true);
     765        }
     766
     767        // Validate and sanitize the value before returning
     768        if (is_numeric($fulfillment_offset_days)) {
     769            $value = intval($fulfillment_offset_days);
     770            return $value;
     771        }
     772
     773        // Return empty string if invalid
     774        return '';
     775    }
     776
    695777}
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/freightquote-ltl-shipping-class.php

    r3373518 r3446938  
    101101
    102102            /**
    103              * Virtual Products
    104              */
    105             public function en_virtual_products()
    106             {
    107                 global $woocommerce;
    108                 $products = $woocommerce->cart->get_cart();
    109                 $items = $product_name = [];
    110                 foreach ($products as $key => $product_obj) {
    111                     $product = $product_obj['data'];
    112                     $is_virtual = $product->get_virtual();
    113 
    114                     if ($is_virtual == 'yes') {
    115                         $attributes = $product->get_attributes();
    116                         $product_qty = $product_obj['quantity'];
    117                         $product_title = str_replace(array("'", '"'), '', $product->get_title());
    118                         $product_name[] = $product_qty . " x " . $product_title;
    119 
    120                         $meta_data = [];
    121                         if (!empty($attributes)) {
    122                             foreach ($attributes as $attr_key => $attr_value) {
    123                                 $meta_data[] = [
    124                                     'key' => $attr_key,
    125                                     'value' => $attr_value,
    126                                 ];
    127                             }
    128                         }
    129 
    130                         $items[] = [
    131                             'id' => $product_obj['product_id'],
    132                             'name' => $product_title,
    133                             'quantity' => $product_qty,
    134                             'price' => $product->get_price(),
    135                             'weight' => 0,
    136                             'length' => 0,
    137                             'width' => 0,
    138                             'height' => 0,
    139                             'type' => 'virtual',
    140                             'product' => 'virtual',
    141                             'sku' => $product->get_sku(),
    142                             'attributes' => $attributes,
    143                             'variant_id' => 0,
    144                             'meta_data' => $meta_data,
    145                         ];
    146                     }
    147                 }
    148 
    149                 $virtual_rate = [];
    150 
    151                 if (!empty($items)) {
    152                     $virtual_rate = [
    153                         'id' => 'en_virtual_rate',
    154                         'label' => 'Virtual Quote',
    155                         'cost' => 0,
    156                     ];
    157 
    158                     $virtual_fdo = [
    159                         'plugin_type' => 'ltl',
    160                         'plugin_name' => 'b2b',
    161                         'accessorials' => '',
    162                         'items' => $items,
    163                         'address' => '',
    164                         'handling_unit_details' => '',
    165                         'rate' => $virtual_rate,
    166                     ];
    167 
    168                     $meta_data = [
    169                         'sender_origin' => 'Virtual Product',
    170                         'product_name' => wp_json_encode($product_name),
    171                         'en_fdo_meta_data' => $virtual_fdo,
    172                     ];
    173 
    174                     $virtual_rate['meta_data'] = $meta_data;
    175 
    176                 }
    177 
    178                 return $virtual_rate;
    179             }
    180 
    181             /**
    182103             * Third party quotes
    183104             * @param type $forceShowMethods
     
    316237
    317238                            // Add backup rates in the shipping rates
    318                             if ((empty($response) && get_option('fq_ltl_backup_rates_carrier_returns_error') == 'yes') || (is_array($response) && isset($response['error']) && $response['error'] == 'backup_rate' && get_option('fq_ltl_backup_rates_carrier_fails_to_return_response') == 'yes')) {
     239                            $backup_rates_error = is_array($response) && isset($response['error']) && $response['error'] == 'backup_rate';
     240                            if ((empty($response) && get_option('fq_ltl_backup_rates_carrier_returns_error') == 'yes') || ($backup_rates_error && get_option('fq_ltl_backup_rates_carrier_fails_to_return_response') == 'yes')) {
    319241                                $this->fq_ltl_backup_rates();
    320242
     
    322244                            }
    323245
    324                             if (empty($response)) {
     246                            if (empty($response) || $backup_rates_error) {
    325247                                return [];
    326248                            }
     
    355277                $smallQuotes = (is_array($smallQuotes) && (!empty($smallQuotes))) ? reset($smallQuotes) : $smallQuotes;
    356278                $smallMinRate = (is_array($smallQuotes) && (!empty($smallQuotes))) ? current($smallQuotes) : $smallQuotes;
    357                 // Virtual products
    358                 $virtual_rate = $this->en_virtual_products();
    359279
    360280                // FDO
     
    398318                $Ltl_Freights_Quotes = new Freightquote_Ltl_Freights_Quotes();
    399319
    400                 $en_is_shipment = ((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1 || !empty($virtual_rate) ? 'multi_shipment' : 'single_shipment';
     320                $en_is_shipment = ((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1 ? 'multi_shipment' : 'single_shipment';
    401321                // Eniture debug mode
    402322                do_action("eniture_debug_mood", "FreightQuote Ltl Shipment Type", $en_is_shipment);
    403323
    404                 // Multi-shipment qutoes / Virtual products
    405                 if (((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1 || !empty($virtual_rate)) {
     324                // Multi-shipment qutoes
     325                if (((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1) {
    406326                    $multi_cost = 0;
    407327                    $s_multi_cost = 0;
     
    456376                    }
    457377
    458                     // Virtual products
    459                     if (!empty($virtual_rate)) {
    460                         $en_virtual_fdo_meta_data[] = $virtual_rate['meta_data']['en_fdo_meta_data'];
    461                         $virtual_meta_rate['virtual_rate'] = $virtual_rate;
    462                         $this->minPrices['LIFT'] = isset($this->minPrices['LIFT']) && !empty($this->minPrices['LIFT']) ? array_merge($this->minPrices['LIFT'], $virtual_meta_rate) : $virtual_meta_rate;
    463                         $this->minPrices['NOTLIFT'] = isset($this->minPrices['NOTLIFT']) && !empty($this->minPrices['NOTLIFT']) ? array_merge($this->minPrices['NOTLIFT'], $virtual_meta_rate) : $virtual_meta_rate;
    464                         $this->minPrices['LIMITED_ACCESS'] = isset($this->minPrices['LIMITED_ACCESS']) && !empty($this->minPrices['LIMITED_ACCESS']) ? array_merge($this->minPrices['LIMITED_ACCESS'], $virtual_meta_rate) : $virtual_meta_rate;
    465                         $this->minPrices['LIFT_LIMITED_ACCESS'] = isset($this->minPrices['LIFT_LIMITED_ACCESS']) && !empty($this->minPrices['LIFT_LIMITED_ACCESS']) ? array_merge($this->minPrices['LIFT_LIMITED_ACCESS'], $virtual_meta_rate) : $virtual_meta_rate;
    466                         // International quotes
    467                         $this->minPrices['NOTLIFT_INT'] = isset($this->minPrices['NOTLIFT_INT']) && !empty($this->minPrices['NOTLIFT_INT']) ? array_merge($this->minPrices['NOTLIFT_INT'], $virtual_meta_rate) : $virtual_meta_rate;
    468                         $this->minPrices['LIFT_INT'] = isset($this->minPrices['LIFT_INT']) && !empty($this->minPrices['LIFT_INT']) ? array_merge($this->minPrices['LIFT_INT'], $virtual_meta_rate) : $virtual_meta_rate;
    469                         // Appointment Delivery
    470                         foreach ($appt_indexes as $appt_index) {
    471                             $this->minPrices[$appt_index] = isset($this->minPrices[$appt_index]) && !empty($this->minPrices[$appt_index]) ? array_merge($this->minPrices[$appt_index], $virtual_meta_rate) : $virtual_meta_rate;
    472                         }
    473 
    474                         $this->en_fdo_meta_data_third_party = !empty($this->en_fdo_meta_data_third_party) ? array_merge($this->en_fdo_meta_data_third_party, $en_virtual_fdo_meta_data) : $en_virtual_fdo_meta_data;
    475                     }
    476 
    477378                    $lt_involed = false;
    478379                    $all_shipmens_rates = array();
     
    941842
    942843                $pickup_delivery = array(
    943                     'id' => $this->id . ':' . 'in-store-pick-up',
     844                    'id' => 'in-store-pick-up',
    944845                    'cost' => 0,
    945846                    'label' => $label,
     
    966867
    967868                $local_delivery = array(
    968                     'id' => $this->id . ':' . 'local-delivery',
     869                    'id' => 'local-delivery',
    969870                    'cost' => $cost,
    970871                    'label' => $label,
     
    12011102
    12021103                            $rate['label'] = $this->set_label_in_quote($rate);
     1104                           
     1105                            // Update rate label in FDO meta data
     1106                            if (isset($rate['meta_data']['en_fdo_meta_data']['rate']['label']) || empty($rate['meta_data']['en_fdo_meta_data']['rate']['label'])) {
     1107                                $rate['meta_data']['en_fdo_meta_data']['rate']['label'] = $rate['label'];
     1108                            }
    12031109
    12041110                            if (isset($rate['meta_data'])) {
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/freightquote-tab-class.php

    r3398598 r3446938  
    471471                        'name' => __('Fullfillment Offset Days ', 'eniture-freightquote-ltl'),
    472472                        'type' => 'text',
    473                         'desc' => 'The number of days the ship date needs to be moved to allow the processing of the order.',
     473                        'desc' => 'The number of days the ship date needs to be moved to allow for the processing of the order.',
    474474                        'placeholder' => 'Fullfillment Offset Days, e.g. 2',
    475475                        'id' => 'freightquote_freight_shipment_offset_days',
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/js/en-freightquote.js

    r3373518 r3446938  
    210210// Cuttoff Time
    211211    jQuery("#freightquote_freight_shipment_offset_days").closest('tr').addClass("freightquote_freight_shipment_offset_days_tr");
    212     jQuery('#freightquote_freight_shipment_offset_days').attr('maxlength', '1');
     212    jQuery('#freightquote_freight_shipment_offset_days').attr('maxlength', '2');
    213213    jQuery("#all_shipment_days_freightquote").closest('tr').addClass("all_shipment_days_freightquote_tr");
    214214    jQuery(".freightquote_shipment_day").closest('tr').addClass("freightquote_shipment_day_tr");
     
    609609       
    610610        const offset_days = jQuery('#freightquote_freight_shipment_offset_days').val();
    611         if (offset_days && (offset_days > 8 || isNaN(offset_days))) {
    612             jQuery("#mainform .quote_section_class_ltl").prepend('<div id="message" class="error inline handlng_fee_error"><p><strong>Error!</strong> Fullfilment Offset days must be less than or equal to 8.</p></div>');
     611        if (offset_days && offset_days < 1) {
     612            jQuery("#mainform .quote_section_class_ltl").prepend('<div id="message" class="error inline handlng_fee_error"><p><strong>Error!</strong> Fullfilment Offset days must be greater than or equal to 1.</p></div>');
     613            jQuery('html, body').animate({
     614                'scrollTop': jQuery('.handlng_fee_error').position().top
     615            });
     616            return false;
     617        }
     618
     619        if (offset_days && (offset_days > 20 || isNaN(offset_days))) {
     620            jQuery("#mainform .quote_section_class_ltl").prepend('<div id="message" class="error inline handlng_fee_error"><p><strong>Error!</strong> Fullfilment Offset days must be less than or equal to 20.</p></div>');
    613621            jQuery('html, body').animate({
    614622                'scrollTop': jQuery('.handlng_fee_error').position().top
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/logs/en-json-tree-view/en-jtv-style.css

    r3172919 r3446938  
    9797.en_jtv li.en_folder > div.en_key > span::before {
    9898  content: "\2212";
    99   opacity: 0.33;
    100   color: #111;
    101   background-color: #e0eaef;
     99  opacity: 1;
     100  color: #fff;
     101  background-color: black !important;
    102102  text-align: center;
    103103  display: inline-block;
     
    112112.en_jtv li.en_folder.en_folded > div.en_key > span::before {
    113113  content: "+";
     114  font-weight: bolder;
     115    background-color: black !important;
     116    color: #fff !important;
    114117}
    115118
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/ltl-freight-quotes-freightquote-edition.php

    r3398598 r3446938  
    66  Author: Eniture Technology
    77  Author URI: http://eniture.com/
    8   Version: 2.4.15
     8  Version: 2.4.16
    99  Text Domain: eniture-freightquote-ltl
    1010  License:           GPL-2.0-or-later
    1111  License URI:       https://www.gnu.org/licenses/gpl-2.0.html
    12   Requires at least: 6.6
    13   Requires PHP:      7.4
    1412  Requires Plugins: woocommerce
    1513 */
     
    179177{
    180178    wp_enqueue_script('jquery');
    181     wp_enqueue_script('freightquote_en_script', plugin_dir_url(__FILE__) . 'js/en-freightquote.js', array(), '1.0.4');
     179    wp_enqueue_script('freightquote_en_script', plugin_dir_url(__FILE__) . 'js/en-freightquote.js', array(), '1.0.5');
    182180    wp_localize_script('freightquote_en_script', 'en_freight_quote_admin_script', array(
    183181        'plugins_url' => plugins_url(),
     
    222220
    223221    wp_enqueue_script('freightquote_wickedpicker_script');
    224     wp_register_style('freightquote_ltl_style', plugin_dir_url(__FILE__) . '/css/freightquote_ltl_style.css', array(), '1.2.6', 'screen');
     222    wp_register_style('freightquote_ltl_style', plugin_dir_url(__FILE__) . '/css/freightquote_ltl_style.css', array(), '1.2.7', 'screen');
    225223    wp_enqueue_style('freightquote_ltl_style');
    226224}
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/product/en-product-detail.php

    r3278743 r3446938  
    112112                    $custom_field = (isset($custom_field['id'])) ? $custom_field['id'] : '';
    113113                    $en_updated_product = (isset($_POST[$custom_field][$postId])) ? sanitize_text_field( wp_unslash($_POST[$custom_field][$postId])) : '';
    114                     $en_updated_product = $custom_field == '_dropship_location' ?
    115                         (maybe_serialize(is_array($en_updated_product) ? array_map('intval', $en_updated_product) : $en_updated_product)) : esc_attr($en_updated_product);
     114
     115                    if ($custom_field == '_dropship_location') {
     116                        $en_updated_product = maybe_serialize(is_array($en_updated_product) ? array_map('intval', $en_updated_product) : $en_updated_product);
     117                    } elseif ($custom_field == '_eniture_product_level_fulfillment_offset_days') {
     118                        $en_updated_product = $this->sanitize_fulfillment_offset_days($en_updated_product);
     119                    } else {
     120                        $en_updated_product = esc_attr($en_updated_product);
     121                    }
     122
    116123                    update_post_meta($postId, $custom_field, $en_updated_product);
    117124                }
    118125            }
     126        }
     127
     128            private function sanitize_fulfillment_offset_days($value)
     129        {
     130            $value = trim($value);
     131            if ($value === '' || $value === null) return '';
     132
     133            $value = preg_replace('/[^0-9.-]/', '', $value);
     134            if (!is_numeric($value)) return '';
     135
     136            $value = intval(floor(floatval($value)));
     137            return $value < 0 ? '' : strval($value);
    119138        }
    120139
     
    224243                [
    225244                    'type' => 'input_field',
     245                    'input_type' => 'number',
     246                    'id' => '_eniture_product_level_fulfillment_offset_days',
     247                    'class' => '_eniture_product_level_fulfillment_offset_days short',
     248                    'label' => __( 'Fulfillment Offset Days', 'woocommerce' ),
     249                    'placeholder' => 'Fulfillment offset days, e.g. 2',
     250                    'description' => "The number of days the ship date needs to be moved to allow for the processing of the order. If set, this will override the global Fulfillment Offset Days setting for this product.",
     251                    'custom_attributes' => [
     252                        'min' => '1',
     253                        'max' => '20',
     254                        'step' => '1',
     255                        'title' => 'Value must be greater than or equal to 1 and less than or equal to 20',
     256                        'oninvalid' => "this.setCustomValidity(this.validity.rangeUnderflow ? 'Value must be greater than or equal to 1' : this.validity.rangeOverflow ? 'Value must be less than or equal to 20' : '')",
     257                        'oninput' => "this.setCustomValidity('')"
     258                    ]
     259                ],
     260                [
     261                    'type' => 'input_field',
    226262                    'id' => '_en_weight_of_handling_unit',
    227263                    'class' => '_en_weight_of_handling_unit short',
     
    350386                'label' => $custom_field['label'],
    351387                'class' => $custom_field['class'],
    352                 'placeholder' => $custom_field['label'],
     388                'placeholder' => isset($custom_field['placeholder']) ? $custom_field['placeholder'] : $custom_field['label'],
    353389                'value' => get_post_meta($postId, $custom_field['id'], true)
    354390            ];
     391
     392              // Add input type if specified (e.g., 'number')
     393            if (isset($custom_field['input_type'])) {
     394                $custom_input_field['type'] = $custom_field['input_type'];
     395            }
     396
     397            // Add custom attributes if specified (e.g., min, max, step)
     398            if (isset($custom_field['custom_attributes'])) {
     399                $custom_input_field['custom_attributes'] = $custom_field['custom_attributes'];
     400            }
    355401
    356402            if (isset($custom_field['description'])) {
  • ltl-freight-quotes-freightquote-edition/tags/2.4.16/readme.txt

    r3398598 r3446938  
    33 Tags: eniture,FreightQuote,LTL freight rates,LTL freight quotes, shipping estimates
    44Requires at least: 6.4
    5 Tested up to:  6.8
    6 Stable tag: 2.4.15
     5Tested up to:  6.9
     6Stable tag: 2.4.16
    77License: GPL-2.0-or-later
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    170170== Changelog ==
    171171
     172= 2.4.16 - 2026-01-26 =
     173* Update: Added **product-level offset days** feature to allow more granular shipment timing control.
     174* Update: Added **pallet vertical rotation** and **ship as own pallet** parameters to line items for enhanced freightdesk.online metadata handling.
     175* Update: Added parent product checks to handle empty properties in variant products and prevent invalid data processing.
     176* Fix: Resolved UI issues related to extra white background and the logs pop-up form display.
     177* Fix: Removed duplicate in-store pickup and local delivery quotes to prevent repeated rate entries.
     178
    172179= 2.4.15 - 2025-11-19 =
    173180* Update: Added support for new carriers: **Double D Express Inc.** and **Shipby.com, LLC (Unis Transportation)**.
  • ltl-freight-quotes-freightquote-edition/trunk/css/freightquote_ltl_style.css

    r3373518 r3446938  
    610610.woocommerce_variable_attributes.wc-metabox-content [class^="_nmfc_number"],
    611611.woocommerce_variable_attributes.wc-metabox-content [class^="_en_product_markup"],
     612.woocommerce_variable_attributes.wc-metabox-content [class^="_eniture_product_level_fulfillment_offset_days"],
    612613.woocommerce_variable_attributes.wc-metabox-content [class^="_nestedPercentage"],
    613614.woocommerce_variable_attributes.wc-metabox-content [class^="en_flat_rate_price"],
     
    633634.woocommerce_variable_attributes.wc-metabox-content [class^="en_flat_rate_price"],
    634635.woocommerce_variable_attributes.wc-metabox-content [class^="_en_product_markup"],
     636.woocommerce_variable_attributes.wc-metabox-content [class^="_eniture_product_level_fulfillment_offset_days"],
    635637.woocommerce_variable_attributes.wc-metabox-content [class^="_nestedPercentage"],
    636638.woocommerce_variable_attributes.wc-metabox-content [class^="_nestedDimension"],
     
    642644.woocommerce_variable_attributes.wc-metabox-content .data p[class*="en_flat_rate_price"] span.woocommerce-help-tip,
    643645.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_en_product_markup"] span.woocommerce-help-tip,
     646.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_eniture_product_level_fulfillment_offset_days"] span.woocommerce-help-tip,
    644647.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_nestedPercentage"] span.woocommerce-help-tip,
    645648.woocommerce_variable_attributes.wc-metabox-content .data p[class*="_nestedDimension"] span.woocommerce-help-tip,
  • ltl-freight-quotes-freightquote-edition/trunk/fdo/en-fdo.php

    r3373518 r3446938  
    5050        $this->en_fdo_meta_data['items'] = [];
    5151        foreach ($items as $item_key => $item_data) {
    52             $nmfc_number = $productId = $productName = $productQty = $actualProductPrice = $products = $productPrice = $productWeight = $productLength = $productWidth = $productHeight = $ptype = $hazardousMaterial = $productType = $productSku = $productClass = $attributes = $variantId = $nestedMaterial = $nestedPercentage = $nestedDimension = $nestedItems = $stakingProperty = '';
     52            $nmfc_number = $productId = $productName = $productQty = $actualProductPrice = $products = $productPrice = $productWeight = $productLength = $productWidth = $productHeight = $ptype = $hazardousMaterial = $productType = $productSku = $productClass = $attributes = $variantId = $nestedMaterial = $nestedPercentage = $nestedDimension = $nestedItems = $stakingProperty = $ship_as_own_pallet = $vertical_rotation_for_pallet = '';
    5353            $attributes = [];
    5454            extract($item_data);
     
    9292                'nested_items' => $nestedItems,
    9393                'staking_property' => $stakingProperty,
    94                 'nmfc_number' => $nmfc_number
     94                'nmfc_number' => $nmfc_number,
     95                'pallet_vertical_rotation' => $vertical_rotation_for_pallet,
     96                'ship_as_own_pallet' => $ship_as_own_pallet
    9597            ];
    9698
  • ltl-freight-quotes-freightquote-edition/trunk/feightquote-carrier-service.php

    r3373518 r3446938  
    8383        if ($freightquote_delivery_estimates == 'delivery_days' || $freightquote_delivery_estimates == 'delivery_date') {
    8484            $order_cut_off_time = $this->quote_settings['orderCutoffTime'];
    85             $shipment_off_set_days = $this->quote_settings['shipmentOffsetDays'];
     85
     86             // Use product-level fulfillment offset days if available, otherwise use global setting
     87            if (isset($packages['max_fulfillment_offset_days']) && is_numeric($packages['max_fulfillment_offset_days']) && $packages['max_fulfillment_offset_days'] > 0) {
     88                $shipment_off_set_days = $packages['max_fulfillment_offset_days'];
     89            } else {
     90                $shipment_off_set_days = $this->quote_settings['shipmentOffsetDays'];
     91            }
     92
    8693            $modify_shipment_date_time = ($order_cut_off_time != '' || $shipment_off_set_days != '' || (is_array($shipment_week_days) && count($shipment_week_days) > 0)) ? 1 : 0;
    8794            $store_date_time = $today = gmdate('Y-m-d H:i:s', current_time('timestamp'));
     
    314321            $cachable_data['addressLine2'] = (isset($request_data['addressLine2'])) ? $request_data['addressLine2'] : '';
    315322            $cachable_data['defaultRADAddressType'] = $request_data['defaultRADAddressType'];
     323            $cachable_data['defaultRADWithoutStreetAddress'] = $request_data['defaultRADWithoutStreetAddress'];
    316324            $cachable_data['poboxAddressValidation'] = $request_data['poboxAddressValidation'];
    317325        }
     
    673681                    $quotes[$count] = apply_filters('en_product_markup', $quotes[$count]);
    674682
     683                    // Add pallet fee
     684                    $quotes[$count] = has_filter('en_pallet_price') ? apply_filters('en_pallet_price', $quotes[$count]) : $quotes[$count];
     685
    675686                    $en_fdo_meta_data['rate'] = $quotes[$count];
    676687                    if (isset($en_fdo_meta_data['rate']['meta_data'])) {
     
    781792                    $simple_quotes[$count] = apply_filters('en_product_markup', $simple_quotes[$count]);
    782793
     794                    // Add pallet fee
     795                    $simple_quotes[$count] = has_filter('en_pallet_price') ? apply_filters('en_pallet_price', $simple_quotes[$count]) : $simple_quotes[$count];
     796
    783797                    // FDO
    784798                    $en_fdo_meta_data['rate'] = $simple_quotes[$count];
     
    869883                    $tl_quotes[$count] = apply_filters('en_product_markup', $tl_quotes[$count]);
    870884
     885                    // Add pallet fee
     886                    $tl_quotes[$count] = has_filter('en_pallet_price') ? apply_filters('en_pallet_price', $tl_quotes[$count]) : $tl_quotes[$count];
     887
    871888                    // FDO
    872889                    $en_fdo_meta_data['rate'] = $tl_quotes[$count];
  • ltl-freight-quotes-freightquote-edition/trunk/freightquote-group-package.php

    r3359670 r3446938  
    145145            if ($nested_material == "yes") {
    146146                $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
    147                 $nestedPercentage = get_post_meta($post_id, '_nestedPercentage', true);
    148                 $nestedDimension = get_post_meta($post_id, '_nestedDimension', true);
    149                 $nestedItems = get_post_meta($post_id, '_maxNestedItems', true);
    150                 $StakingProperty = get_post_meta($post_id, '_nestedStakingProperty', true);
     147                $nestedPercentage = $this->get_property_value('_nestedPercentage', $values, $_product);
     148                $nestedDimension = $this->get_property_value('_nestedDimension', $values, $_product);
     149                $nestedItems = $this->get_property_value('_maxNestedItems', $values, $_product);
     150                $StakingProperty = $this->get_property_value('_nestedStakingProperty', $values, $_product);
    151151            }
    152152
     
    156156            $hm_status = (!is_array($hm_plan) && $hazardous_material == 'yes') ? TRUE : FALSE;
    157157
    158             $product_title = str_replace(array("'", '"'), '', $_product->get_title());
     158            $product_title = str_replace(array("'", '"'), '', $_product->get_name());
    159159            $product_level_markup = $this->fq_ltl_get_product_level_markup($_product, $values['variation_id'], $values['product_id'], $values['quantity']);
    160160            // check if TL enable
    161161            $tl_enable = $this->freightquote_ltl_enable_shipping_class($_product, true);
     162            $product_level_fulfillment_offset = $this->freightquote_ltl_get_product_level_fulfillment_offset_days($_product, $values['variation_id'], $values['product_id']);
    162163
    163164            // Shippable handling units
     
    204205                'ship_as_own_pallet' => $ship_as_own_pallet,
    205206                'vertical_rotation_for_pallet' => $vertical_rotation_for_pallet,
    206                 'markup' => $product_level_markup
     207                'markup' => $product_level_markup,
     208                'fulfillment_offset_days' => $product_level_fulfillment_offset
    207209            ];
    208210
     
    275277
    276278            $ltl_package[$locationId]['shipment_weight'] = isset($ltl_package[$locationId]['shipment_weight']) ? $ltl_package[$locationId]['shipment_weight'] + $weight : $weight;
     279
     280            // Track maximum fulfillment offset days
     281            if (is_numeric($product_level_fulfillment_offset) && $product_level_fulfillment_offset > 0) {
     282                if (!isset($ltl_package[$locationId]['max_fulfillment_offset_days']) || $product_level_fulfillment_offset > $ltl_package[$locationId]['max_fulfillment_offset_days']) {
     283                    $ltl_package[$locationId]['max_fulfillment_offset_days'] = $product_level_fulfillment_offset;
     284                }
     285            }
    277286
    278287            $smallPluginExist = 0;
     
    366375    {
    367376        $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
    368         return get_post_meta($post_id, '_nestedMaterials', true);
     377        $nested_material = get_post_meta($post_id, '_nestedMaterials', true);
     378
     379        // check nested material in parent
     380        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($nested_material)) {
     381            $post_id = isset($values['product_id']) ? $values['product_id'] : $_product->get_parent_id();
     382            $nested_material = get_post_meta($post_id, '_nestedMaterials', true);
     383        }
     384
     385        return $nested_material;
    369386    }
    370387
     
    378395    {
    379396        $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
    380         return get_post_meta($post_id, '_hazardousmaterials', true);
     397        $hazardous_material = get_post_meta($post_id, '_hazardousmaterials', true);
     398
     399        // check hazmat in parent
     400        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($hazardous_material)) {
     401            $post_id = isset($values['product_id']) ? $values['product_id'] : $_product->get_parent_id();
     402            $hazardous_material = get_post_meta($post_id, '_hazardousmaterials', true);
     403        }
     404
     405        return $hazardous_material;
    381406    }
    382407
     
    396421        (isset($values['variation_id']) && $values['variation_id'] > 0) ? $post_id = $values['variation_id'] : $post_id = $_product->get_id();
    397422        $enable_dropship = get_post_meta($post_id, '_enable_dropship', true);
     423
     424        // check dropship in parent
     425        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($enable_dropship)) {
     426            $post_id = isset($values['product_id']) ? $values['product_id'] : $post_id;
     427            $enable_dropship = get_post_meta($post_id, '_enable_dropship', true);
     428        }
     429
    398430        if ($enable_dropship == 'yes') {
    399431            $get_loc = get_post_meta($post_id, '_dropship_location', true);
     
    513545        if ($_product->get_type() == 'variation') {
    514546            $variation_class = get_post_meta($values['variation_id'], '_ltl_freight_variation', true);
    515             if ($variation_class == 0) {
     547            $variation_class = empty($variation_class) ? get_post_meta($values['variation_id'], '_ltl_freight', true) : $variation_class;
     548
     549            if (empty($variation_class) || $variation_class == 0 || $variation_class == 'get_parent') {
    516550                $variation_class = get_post_meta($values['product_id'], '_ltl_freight', true);
    517551                $freightclass_ltl_gross = $variation_class;
     
    519553                if ($variation_class > 0) {
    520554                    $freightclass_ltl_gross = get_post_meta($values['variation_id'], '_ltl_freight_variation', true);
     555                    $freightclass_ltl_gross = empty($freightclass_ltl_gross) ? get_post_meta($values['variation_id'], '_ltl_freight', true) : $freightclass_ltl_gross;
    521556                } else {
    522557                    $freightclass_ltl_gross = get_post_meta($_product->get_id(), '_ltl_freight', true);
     
    662697    {
    663698        $pp_suspended = get_option('suspend_automatic_detection_of_pallets');
     699        $pp_fq_suspended = get_option('suspend_freightquote_quests_automatic_detection_of_pallets');
    664700        // Check if Pallet Packaging is enabled, then this feature will not work
    665         if (is_plugin_active('pallet-packaging-for-woocommerce/pallet-packaging-for-woocommerce.php') && has_filter('en_pallet_identify') && $pp_suspended != 'yes') {
     701        if (is_plugin_active('pallet-packaging-for-woocommerce/pallet-packaging-for-woocommerce.php') && has_filter('en_pallet_identify') && $pp_suspended != 'yes' && $pp_fq_suspended != 'yes') {
    666702            return $item;
    667703        }
     
    693729    }
    694730
     731    function get_property_value($property_key, $values, $_product)
     732    {
     733        $post_id = (isset($values['variation_id']) && $values['variation_id'] > 0) ? $values['variation_id'] : $_product->get_id();
     734        $property_enabled = get_post_meta($post_id, $property_key, true);
     735
     736        // check property in parent
     737        if (isset($values['variation_id']) && $values['variation_id'] > 0 && empty($property_enabled)) {
     738            $post_id = isset($values['product_id']) ? $values['product_id'] : $_product->get_parent_id();
     739            $property_enabled = get_post_meta($post_id, $property_key, true);
     740        }
     741
     742        return $property_enabled;
     743    }
     744
     745    function freightquote_ltl_get_product_level_fulfillment_offset_days($_product, $variation_id, $product_id)
     746    {
     747        $fulfillment_offset_days = '';
     748        $field_name = '_eniture_product_level_fulfillment_offset_days';
     749
     750        if ($_product->get_type() == 'variation' && $variation_id > 0) {
     751            $fulfillment_offset_days = get_post_meta($variation_id, $field_name, true);
     752
     753            if (empty($fulfillment_offset_days) || !is_numeric($fulfillment_offset_days)) {
     754                $parent_id = $_product->get_parent_id();
     755                if ($parent_id > 0) {
     756                    $fulfillment_offset_days = get_post_meta($parent_id, $field_name, true);
     757                }
     758            }
     759        } else {
     760            $fulfillment_offset_days = get_post_meta($_product->get_id(), $field_name, true);
     761        }
     762
     763        if (empty($fulfillment_offset_days) || !is_numeric($fulfillment_offset_days)) {
     764            $fulfillment_offset_days = get_post_meta($product_id, $field_name, true);
     765        }
     766
     767        // Validate and sanitize the value before returning
     768        if (is_numeric($fulfillment_offset_days)) {
     769            $value = intval($fulfillment_offset_days);
     770            return $value;
     771        }
     772
     773        // Return empty string if invalid
     774        return '';
     775    }
     776
    695777}
  • ltl-freight-quotes-freightquote-edition/trunk/freightquote-ltl-shipping-class.php

    r3373518 r3446938  
    101101
    102102            /**
    103              * Virtual Products
    104              */
    105             public function en_virtual_products()
    106             {
    107                 global $woocommerce;
    108                 $products = $woocommerce->cart->get_cart();
    109                 $items = $product_name = [];
    110                 foreach ($products as $key => $product_obj) {
    111                     $product = $product_obj['data'];
    112                     $is_virtual = $product->get_virtual();
    113 
    114                     if ($is_virtual == 'yes') {
    115                         $attributes = $product->get_attributes();
    116                         $product_qty = $product_obj['quantity'];
    117                         $product_title = str_replace(array("'", '"'), '', $product->get_title());
    118                         $product_name[] = $product_qty . " x " . $product_title;
    119 
    120                         $meta_data = [];
    121                         if (!empty($attributes)) {
    122                             foreach ($attributes as $attr_key => $attr_value) {
    123                                 $meta_data[] = [
    124                                     'key' => $attr_key,
    125                                     'value' => $attr_value,
    126                                 ];
    127                             }
    128                         }
    129 
    130                         $items[] = [
    131                             'id' => $product_obj['product_id'],
    132                             'name' => $product_title,
    133                             'quantity' => $product_qty,
    134                             'price' => $product->get_price(),
    135                             'weight' => 0,
    136                             'length' => 0,
    137                             'width' => 0,
    138                             'height' => 0,
    139                             'type' => 'virtual',
    140                             'product' => 'virtual',
    141                             'sku' => $product->get_sku(),
    142                             'attributes' => $attributes,
    143                             'variant_id' => 0,
    144                             'meta_data' => $meta_data,
    145                         ];
    146                     }
    147                 }
    148 
    149                 $virtual_rate = [];
    150 
    151                 if (!empty($items)) {
    152                     $virtual_rate = [
    153                         'id' => 'en_virtual_rate',
    154                         'label' => 'Virtual Quote',
    155                         'cost' => 0,
    156                     ];
    157 
    158                     $virtual_fdo = [
    159                         'plugin_type' => 'ltl',
    160                         'plugin_name' => 'b2b',
    161                         'accessorials' => '',
    162                         'items' => $items,
    163                         'address' => '',
    164                         'handling_unit_details' => '',
    165                         'rate' => $virtual_rate,
    166                     ];
    167 
    168                     $meta_data = [
    169                         'sender_origin' => 'Virtual Product',
    170                         'product_name' => wp_json_encode($product_name),
    171                         'en_fdo_meta_data' => $virtual_fdo,
    172                     ];
    173 
    174                     $virtual_rate['meta_data'] = $meta_data;
    175 
    176                 }
    177 
    178                 return $virtual_rate;
    179             }
    180 
    181             /**
    182103             * Third party quotes
    183104             * @param type $forceShowMethods
     
    316237
    317238                            // Add backup rates in the shipping rates
    318                             if ((empty($response) && get_option('fq_ltl_backup_rates_carrier_returns_error') == 'yes') || (is_array($response) && isset($response['error']) && $response['error'] == 'backup_rate' && get_option('fq_ltl_backup_rates_carrier_fails_to_return_response') == 'yes')) {
     239                            $backup_rates_error = is_array($response) && isset($response['error']) && $response['error'] == 'backup_rate';
     240                            if ((empty($response) && get_option('fq_ltl_backup_rates_carrier_returns_error') == 'yes') || ($backup_rates_error && get_option('fq_ltl_backup_rates_carrier_fails_to_return_response') == 'yes')) {
    319241                                $this->fq_ltl_backup_rates();
    320242
     
    322244                            }
    323245
    324                             if (empty($response)) {
     246                            if (empty($response) || $backup_rates_error) {
    325247                                return [];
    326248                            }
     
    355277                $smallQuotes = (is_array($smallQuotes) && (!empty($smallQuotes))) ? reset($smallQuotes) : $smallQuotes;
    356278                $smallMinRate = (is_array($smallQuotes) && (!empty($smallQuotes))) ? current($smallQuotes) : $smallQuotes;
    357                 // Virtual products
    358                 $virtual_rate = $this->en_virtual_products();
    359279
    360280                // FDO
     
    398318                $Ltl_Freights_Quotes = new Freightquote_Ltl_Freights_Quotes();
    399319
    400                 $en_is_shipment = ((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1 || !empty($virtual_rate) ? 'multi_shipment' : 'single_shipment';
     320                $en_is_shipment = ((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1 ? 'multi_shipment' : 'single_shipment';
    401321                // Eniture debug mode
    402322                do_action("eniture_debug_mood", "FreightQuote Ltl Shipment Type", $en_is_shipment);
    403323
    404                 // Multi-shipment qutoes / Virtual products
    405                 if (((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1 || !empty($virtual_rate)) {
     324                // Multi-shipment qutoes
     325                if (((is_array($quotes) && count($quotes) > 1) || $smpkgCost > 0) || $no_param_multi_ship == 1) {
    406326                    $multi_cost = 0;
    407327                    $s_multi_cost = 0;
     
    456376                    }
    457377
    458                     // Virtual products
    459                     if (!empty($virtual_rate)) {
    460                         $en_virtual_fdo_meta_data[] = $virtual_rate['meta_data']['en_fdo_meta_data'];
    461                         $virtual_meta_rate['virtual_rate'] = $virtual_rate;
    462                         $this->minPrices['LIFT'] = isset($this->minPrices['LIFT']) && !empty($this->minPrices['LIFT']) ? array_merge($this->minPrices['LIFT'], $virtual_meta_rate) : $virtual_meta_rate;
    463                         $this->minPrices['NOTLIFT'] = isset($this->minPrices['NOTLIFT']) && !empty($this->minPrices['NOTLIFT']) ? array_merge($this->minPrices['NOTLIFT'], $virtual_meta_rate) : $virtual_meta_rate;
    464                         $this->minPrices['LIMITED_ACCESS'] = isset($this->minPrices['LIMITED_ACCESS']) && !empty($this->minPrices['LIMITED_ACCESS']) ? array_merge($this->minPrices['LIMITED_ACCESS'], $virtual_meta_rate) : $virtual_meta_rate;
    465                         $this->minPrices['LIFT_LIMITED_ACCESS'] = isset($this->minPrices['LIFT_LIMITED_ACCESS']) && !empty($this->minPrices['LIFT_LIMITED_ACCESS']) ? array_merge($this->minPrices['LIFT_LIMITED_ACCESS'], $virtual_meta_rate) : $virtual_meta_rate;
    466                         // International quotes
    467                         $this->minPrices['NOTLIFT_INT'] = isset($this->minPrices['NOTLIFT_INT']) && !empty($this->minPrices['NOTLIFT_INT']) ? array_merge($this->minPrices['NOTLIFT_INT'], $virtual_meta_rate) : $virtual_meta_rate;
    468                         $this->minPrices['LIFT_INT'] = isset($this->minPrices['LIFT_INT']) && !empty($this->minPrices['LIFT_INT']) ? array_merge($this->minPrices['LIFT_INT'], $virtual_meta_rate) : $virtual_meta_rate;
    469                         // Appointment Delivery
    470                         foreach ($appt_indexes as $appt_index) {
    471                             $this->minPrices[$appt_index] = isset($this->minPrices[$appt_index]) && !empty($this->minPrices[$appt_index]) ? array_merge($this->minPrices[$appt_index], $virtual_meta_rate) : $virtual_meta_rate;
    472                         }
    473 
    474                         $this->en_fdo_meta_data_third_party = !empty($this->en_fdo_meta_data_third_party) ? array_merge($this->en_fdo_meta_data_third_party, $en_virtual_fdo_meta_data) : $en_virtual_fdo_meta_data;
    475                     }
    476 
    477378                    $lt_involed = false;
    478379                    $all_shipmens_rates = array();
     
    941842
    942843                $pickup_delivery = array(
    943                     'id' => $this->id . ':' . 'in-store-pick-up',
     844                    'id' => 'in-store-pick-up',
    944845                    'cost' => 0,
    945846                    'label' => $label,
     
    966867
    967868                $local_delivery = array(
    968                     'id' => $this->id . ':' . 'local-delivery',
     869                    'id' => 'local-delivery',
    969870                    'cost' => $cost,
    970871                    'label' => $label,
     
    12011102
    12021103                            $rate['label'] = $this->set_label_in_quote($rate);
     1104                           
     1105                            // Update rate label in FDO meta data
     1106                            if (isset($rate['meta_data']['en_fdo_meta_data']['rate']['label']) || empty($rate['meta_data']['en_fdo_meta_data']['rate']['label'])) {
     1107                                $rate['meta_data']['en_fdo_meta_data']['rate']['label'] = $rate['label'];
     1108                            }
    12031109
    12041110                            if (isset($rate['meta_data'])) {
  • ltl-freight-quotes-freightquote-edition/trunk/freightquote-tab-class.php

    r3398598 r3446938  
    471471                        'name' => __('Fullfillment Offset Days ', 'eniture-freightquote-ltl'),
    472472                        'type' => 'text',
    473                         'desc' => 'The number of days the ship date needs to be moved to allow the processing of the order.',
     473                        'desc' => 'The number of days the ship date needs to be moved to allow for the processing of the order.',
    474474                        'placeholder' => 'Fullfillment Offset Days, e.g. 2',
    475475                        'id' => 'freightquote_freight_shipment_offset_days',
  • ltl-freight-quotes-freightquote-edition/trunk/js/en-freightquote.js

    r3373518 r3446938  
    210210// Cuttoff Time
    211211    jQuery("#freightquote_freight_shipment_offset_days").closest('tr').addClass("freightquote_freight_shipment_offset_days_tr");
    212     jQuery('#freightquote_freight_shipment_offset_days').attr('maxlength', '1');
     212    jQuery('#freightquote_freight_shipment_offset_days').attr('maxlength', '2');
    213213    jQuery("#all_shipment_days_freightquote").closest('tr').addClass("all_shipment_days_freightquote_tr");
    214214    jQuery(".freightquote_shipment_day").closest('tr').addClass("freightquote_shipment_day_tr");
     
    609609       
    610610        const offset_days = jQuery('#freightquote_freight_shipment_offset_days').val();
    611         if (offset_days && (offset_days > 8 || isNaN(offset_days))) {
    612             jQuery("#mainform .quote_section_class_ltl").prepend('<div id="message" class="error inline handlng_fee_error"><p><strong>Error!</strong> Fullfilment Offset days must be less than or equal to 8.</p></div>');
     611        if (offset_days && offset_days < 1) {
     612            jQuery("#mainform .quote_section_class_ltl").prepend('<div id="message" class="error inline handlng_fee_error"><p><strong>Error!</strong> Fullfilment Offset days must be greater than or equal to 1.</p></div>');
     613            jQuery('html, body').animate({
     614                'scrollTop': jQuery('.handlng_fee_error').position().top
     615            });
     616            return false;
     617        }
     618
     619        if (offset_days && (offset_days > 20 || isNaN(offset_days))) {
     620            jQuery("#mainform .quote_section_class_ltl").prepend('<div id="message" class="error inline handlng_fee_error"><p><strong>Error!</strong> Fullfilment Offset days must be less than or equal to 20.</p></div>');
    613621            jQuery('html, body').animate({
    614622                'scrollTop': jQuery('.handlng_fee_error').position().top
  • ltl-freight-quotes-freightquote-edition/trunk/logs/en-json-tree-view/en-jtv-style.css

    r3172919 r3446938  
    9797.en_jtv li.en_folder > div.en_key > span::before {
    9898  content: "\2212";
    99   opacity: 0.33;
    100   color: #111;
    101   background-color: #e0eaef;
     99  opacity: 1;
     100  color: #fff;
     101  background-color: black !important;
    102102  text-align: center;
    103103  display: inline-block;
     
    112112.en_jtv li.en_folder.en_folded > div.en_key > span::before {
    113113  content: "+";
     114  font-weight: bolder;
     115    background-color: black !important;
     116    color: #fff !important;
    114117}
    115118
  • ltl-freight-quotes-freightquote-edition/trunk/ltl-freight-quotes-freightquote-edition.php

    r3398598 r3446938  
    66  Author: Eniture Technology
    77  Author URI: http://eniture.com/
    8   Version: 2.4.15
     8  Version: 2.4.16
    99  Text Domain: eniture-freightquote-ltl
    1010  License:           GPL-2.0-or-later
    1111  License URI:       https://www.gnu.org/licenses/gpl-2.0.html
    12   Requires at least: 6.6
    13   Requires PHP:      7.4
    1412  Requires Plugins: woocommerce
    1513 */
     
    179177{
    180178    wp_enqueue_script('jquery');
    181     wp_enqueue_script('freightquote_en_script', plugin_dir_url(__FILE__) . 'js/en-freightquote.js', array(), '1.0.4');
     179    wp_enqueue_script('freightquote_en_script', plugin_dir_url(__FILE__) . 'js/en-freightquote.js', array(), '1.0.5');
    182180    wp_localize_script('freightquote_en_script', 'en_freight_quote_admin_script', array(
    183181        'plugins_url' => plugins_url(),
     
    222220
    223221    wp_enqueue_script('freightquote_wickedpicker_script');
    224     wp_register_style('freightquote_ltl_style', plugin_dir_url(__FILE__) . '/css/freightquote_ltl_style.css', array(), '1.2.6', 'screen');
     222    wp_register_style('freightquote_ltl_style', plugin_dir_url(__FILE__) . '/css/freightquote_ltl_style.css', array(), '1.2.7', 'screen');
    225223    wp_enqueue_style('freightquote_ltl_style');
    226224}
  • ltl-freight-quotes-freightquote-edition/trunk/product/en-product-detail.php

    r3278743 r3446938  
    112112                    $custom_field = (isset($custom_field['id'])) ? $custom_field['id'] : '';
    113113                    $en_updated_product = (isset($_POST[$custom_field][$postId])) ? sanitize_text_field( wp_unslash($_POST[$custom_field][$postId])) : '';
    114                     $en_updated_product = $custom_field == '_dropship_location' ?
    115                         (maybe_serialize(is_array($en_updated_product) ? array_map('intval', $en_updated_product) : $en_updated_product)) : esc_attr($en_updated_product);
     114
     115                    if ($custom_field == '_dropship_location') {
     116                        $en_updated_product = maybe_serialize(is_array($en_updated_product) ? array_map('intval', $en_updated_product) : $en_updated_product);
     117                    } elseif ($custom_field == '_eniture_product_level_fulfillment_offset_days') {
     118                        $en_updated_product = $this->sanitize_fulfillment_offset_days($en_updated_product);
     119                    } else {
     120                        $en_updated_product = esc_attr($en_updated_product);
     121                    }
     122
    116123                    update_post_meta($postId, $custom_field, $en_updated_product);
    117124                }
    118125            }
     126        }
     127
     128            private function sanitize_fulfillment_offset_days($value)
     129        {
     130            $value = trim($value);
     131            if ($value === '' || $value === null) return '';
     132
     133            $value = preg_replace('/[^0-9.-]/', '', $value);
     134            if (!is_numeric($value)) return '';
     135
     136            $value = intval(floor(floatval($value)));
     137            return $value < 0 ? '' : strval($value);
    119138        }
    120139
     
    224243                [
    225244                    'type' => 'input_field',
     245                    'input_type' => 'number',
     246                    'id' => '_eniture_product_level_fulfillment_offset_days',
     247                    'class' => '_eniture_product_level_fulfillment_offset_days short',
     248                    'label' => __( 'Fulfillment Offset Days', 'woocommerce' ),
     249                    'placeholder' => 'Fulfillment offset days, e.g. 2',
     250                    'description' => "The number of days the ship date needs to be moved to allow for the processing of the order. If set, this will override the global Fulfillment Offset Days setting for this product.",
     251                    'custom_attributes' => [
     252                        'min' => '1',
     253                        'max' => '20',
     254                        'step' => '1',
     255                        'title' => 'Value must be greater than or equal to 1 and less than or equal to 20',
     256                        'oninvalid' => "this.setCustomValidity(this.validity.rangeUnderflow ? 'Value must be greater than or equal to 1' : this.validity.rangeOverflow ? 'Value must be less than or equal to 20' : '')",
     257                        'oninput' => "this.setCustomValidity('')"
     258                    ]
     259                ],
     260                [
     261                    'type' => 'input_field',
    226262                    'id' => '_en_weight_of_handling_unit',
    227263                    'class' => '_en_weight_of_handling_unit short',
     
    350386                'label' => $custom_field['label'],
    351387                'class' => $custom_field['class'],
    352                 'placeholder' => $custom_field['label'],
     388                'placeholder' => isset($custom_field['placeholder']) ? $custom_field['placeholder'] : $custom_field['label'],
    353389                'value' => get_post_meta($postId, $custom_field['id'], true)
    354390            ];
     391
     392              // Add input type if specified (e.g., 'number')
     393            if (isset($custom_field['input_type'])) {
     394                $custom_input_field['type'] = $custom_field['input_type'];
     395            }
     396
     397            // Add custom attributes if specified (e.g., min, max, step)
     398            if (isset($custom_field['custom_attributes'])) {
     399                $custom_input_field['custom_attributes'] = $custom_field['custom_attributes'];
     400            }
    355401
    356402            if (isset($custom_field['description'])) {
  • ltl-freight-quotes-freightquote-edition/trunk/readme.txt

    r3398598 r3446938  
    33 Tags: eniture,FreightQuote,LTL freight rates,LTL freight quotes, shipping estimates
    44Requires at least: 6.4
    5 Tested up to:  6.8
    6 Stable tag: 2.4.15
     5Tested up to:  6.9
     6Stable tag: 2.4.16
    77License: GPL-2.0-or-later
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    170170== Changelog ==
    171171
     172= 2.4.16 - 2026-01-26 =
     173* Update: Added **product-level offset days** feature to allow more granular shipment timing control.
     174* Update: Added **pallet vertical rotation** and **ship as own pallet** parameters to line items for enhanced freightdesk.online metadata handling.
     175* Update: Added parent product checks to handle empty properties in variant products and prevent invalid data processing.
     176* Fix: Resolved UI issues related to extra white background and the logs pop-up form display.
     177* Fix: Removed duplicate in-store pickup and local delivery quotes to prevent repeated rate entries.
     178
    172179= 2.4.15 - 2025-11-19 =
    173180* Update: Added support for new carriers: **Double D Express Inc.** and **Shipby.com, LLC (Unis Transportation)**.
Note: See TracChangeset for help on using the changeset viewer.