Delivery date integration
August 26, 2025 · AI Conversations
So when a user has a Probo product inside the cart and checkout they should be able to select a delivery date and from there get the suppliers for that specific date.
For example it should look something like this:
This should also work with products that are not from Probo but we don't have a smart solution for that yet.
The delivery date and supplier should be visible inside the order and be send to Probo when syncing the order.
This should completely work with the WooCommerce shipping. For example, different countries of delivery pickup at the store location.
Inside the settings of the plugin it should be possible to edit the following items:
Add a surcharge to the delivery date or supplier costs.
Setup until when the dates should show for next day delivery. For example: Probo has a next day delivery and shows that until 22:00 in the evening. Except the webshop owner wants to set this to 16:00 so that they have time to check the order and make sure it gets send to Probo correctly. So when a customer wants to do a next day delivery at 16:01 they don't see the next day in the dates but the day after that.
Now I want to integrate above in probo please explain above
# What we’re building (quick view)
1. **Cart & Checkout UI**
– For **each Probo line item**: show a date picker → fetch & show suppliers for that date → user selects supplier.
– For **non-Probo items**: (for now) no supplier/date UI (or show a simple “standard delivery” placeholder).
2. **Business rules**
– **Cut-off time** for next-day delivery (configurable, e.g., 16:00). After cut-off, “tomorrow” is hidden.
– Optional **surcharge** per date and/or per supplier.
– Respect WooCommerce **shipping** (country, method, store pickup) to filter dates/suppliers.
3. **Persist + Display**
– Save chosen **date/supplier on the cart item** → carry to **order item meta** → show in:
– Cart/checkout line items
– Order admin (line item meta)
– Emails & My Account
4. **Sync to Probo**
– On your existing Probo order sync, include the line-item `delivery_date` + `supplier_id` (and surcharge if needed).
—
# Settings you’ll add (plugin → Settings → Probo)
– **Cut-off time** (HH:mm, store timezone): e.g., `16:00`.
– **Next-day window** toggle (enable/disable next-day).
– **Date range** to show (e.g., show next N working days).
– **Surcharge rules**:
– Type: None / Flat / Percent
– Scope: Per date / Per supplier / Both
– Optional map: supplier → flat/percent override
– **Supplier source**:
– API endpoint/credentials (your Probo supplier/dates endpoint)
– Cache TTL (e.g., 10 minutes) for suppliers per date & destination country.
– **Countries / Shipping integration**:
– Respect current shipping country/method
– “Pickup at store” mode: limit suppliers/dates accordingly.
Store these in a single option, e.g. `probo_delivery_settings`.
—
# Data model (where we save things)
**Cart item meta keys** (per Probo line item):
– `_probo_delivery_date` (ISO `YYYY-MM-DD`)
– `_probo_supplier_id`
– `_probo_supplier_label` (for display)
– `_probo_delivery_surcharge` (numeric)
On order creation, copy to **order item meta** with the same keys.
—
# UX flow (how it behaves)
1. When the cart renders, detect Probo items (e.g., product type `probo_configurable` or meta `_is_probo = yes`).
2. For each Probo line:
– Show a **DatePicker** (only valid dates; hide “tomorrow” if `now >= cutoff`).
– On date choose → call your **suppliers endpoint** with `{date, ship_to_country, shipping_method}` → render **radio/select** of suppliers.
– When a supplier is chosen, recalc **surcharge** (if any) and add/remove a **cart fee** (or store surcharge per line and add a combined fee).
3. Keep selections in **cart item data**; re-render consistently on refresh.
—
# Shipping integration notes
– Use shipping **country** from checkout to filter suppliers (or dates if country-specific SLA).
– If **local pickup**, you may:
– Show only suppliers that support pickup, or
– Convert to a fixed supplier (“Probo Pickup”) with its own SLA.
– If user changes shipping country/method at checkout → **invalidate** and **re-fetch** suppliers/dates for each Probo line.
—
# Surcharges (how to apply)
Two common approaches:
**A) Per-line surcharge baked into line total**
– Adjust line item price before totals (clean for refunds).
– Pros: Sticks to the item.
– Cons: A bit more bookkeeping.
**B) Cart fee via `WC()->cart->add_fee()`**
– Sum per-line surcharges and show as “Delivery surcharge”.
– Pros: Simple; clear in totals.
– Cons: Fee is global (not per-item).
Pick one; (B) is simpler to start.
—
# Key hooks & skeleton code
### 1) Flag Probo products
function probo_is_product( $product ) {
return $product && ( $product->is_type('probo_configurable') || 'yes' === $product->get_meta('_is_probo') );
}
### 2) Add UI in cart/checkout (line item level)
add_filter('woocommerce_get_item_data', function($item_data, $cart_item) {
if (empty($cart_item['data']) || !probo_is_product($cart_item['data'])) return $item_data;
if (!empty($cart_item['_probo_delivery_date'])) {
$item_data[] = ['key' => __('Delivery date','probo'), 'value' => esc_html($cart_item['_probo_delivery_date'])];
}
if (!empty($cart_item['_probo_supplier_label'])) {
$item_data[] = ['key' => __('Supplier','probo'), 'value' => esc_html($cart_item['_probo_supplier_label'])];
}
return $item_data;
}, 10, 2);
Render the selectors using:
– **Cart**: `woocommerce_after_cart_item_name`
– **Checkout**: `woocommerce_checkout_before_order_review` (with per-item UI inside table rows)
Store selections back into `$cart_item` via AJAX endpoints you add, e.g.:
– `wp_ajax_probo_set_delivery`
– `wp_ajax_nopriv_probo_set_delivery`
### 3) Validate before checkout
add_action('woocommerce_check_cart_items', function() {
foreach (WC()->cart->get_cart() as $key => $item) {
if (probo_is_product($item['data'])) {
if (empty($item['_probo_delivery_date']) || empty($item['_probo_supplier_id'])) {
wc_add_notice(__('Please choose delivery date and supplier for all Probo items.'), 'error');
break;
}
}
}
});
### 4) Persist to order items
add_action('woocommerce_checkout_create_order_line_item', function($item, $cart_item_key, $values, $order) {
if (probo_is_product($values['data'])) {
foreach (['_probo_delivery_date','_probo_supplier_id','_probo_supplier_label','_probo_delivery_surcharge'] as $k) {
if (!empty($values[$k])) $item->add_meta_data($k, $values[$k], true);
}
}
}, 10, 4);
### 5) Surcharge calculation
add_action('woocommerce_cart_calculate_fees', function($cart){
if (is_admin() && !defined('DOING_AJAX')) return;
$settings = get_option('probo_delivery_settings', []);
$sum = 0;
foreach ($cart->get_cart() as $item) {
if (!probo_is_product($item['data'])) continue;
$date = $item['_probo_delivery_date'] ?? '';
$sup = $item['_probo_supplier_id'] ?? '';
if (!$date || !$sup) continue;
$line = 0;
// Example: flat 2.50 per supplier + 1.00 for “next-day”
if (!empty($settings['supplier_flat'][$sup])) $line += floatval($settings['supplier_flat'][$sup]);
if (probo_is_next_day($date)) $line += floatval($settings['next_day_flat'] ?? 0);
$sum += $line;
$item['_probo_delivery_surcharge'] = $line;
}
if ($sum > 0) {
$cart->add_fee(__('Delivery surcharge','probo'), $sum, true);
}
}, 15);
### 6) Cut-off time logic
function probo_cutoff_passed() {
$settings = get_option('probo_delivery_settings', []);
$cutoff = $settings['cutoff'] ?? '16:00';
$tz = wp_timezone(); // respects site timezone
$now = new DateTime('now', $tz);
[$h,$m] = array_map('intval', explode(':', $cutoff));
$todayCut = (clone $now)->setTime($h, $m, 0);
return $now > $todayCut;
}
function probo_candidate_dates($days=7) {
$tz = wp_timezone();
$dates = [];
$start = new DateTime('tomorrow', $tz);
// If cutoff passed, tomorrow becomes invalid → start from +2
if (probo_cutoff_passed()) $start->modify('+1 day');
for ($i=0; $i<$days; $i++) {
$d = (clone $start)->modify("+$i day");
// Skip weekends if needed
$dates[] = $d->format('Y-m-d');
}
return $dates;
}
### 7) Fetch suppliers for date (AJAX/controller)
add_action('wp_ajax_probo_suppliers_for_date', 'probo_suppliers_for_date');
add_action('wp_ajax_nopriv_probo_suppliers_for_date', 'probo_suppliers_for_date');
function probo_suppliers_for_date() {
check_ajax_referer('probo_nonce','nonce');
$date = sanitize_text_field($_POST['date'] ?? '');
$country= sanitize_text_field($_POST['country'] ?? '');
$method = sanitize_text_field($_POST['method'] ?? '');
// Cache key per date+country+method
$key = 'probo_suppliers_' . md5("$date|$country|$method");
$cached = get_transient($key);
if ($cached) wp_send_json_success($cached);
// TODO: call your Probo endpoint
$suppliers = probo_api_get_suppliers($date, $country, $method); // return [{id,label,eta,...}]
set_transient($key, $suppliers, MINUTE_IN_SECONDS * 10);
wp_send_json_success($suppliers);
}
—
# Sync payload (to Probo)
When you already sync the order, extend per-line items:
$payload = [
'order_id' => $order->get_id(),
'currency' => $order->get_currency(),
'shipping' => [
'country' => $order->get_shipping_country(),
'method' => $order->get_shipping_method(),
],
'items' => array_map(function($item){
/** @var WC_Order_Item_Product $item */
return [
'sku' => $item->get_product()->get_sku(),
'quantity' => $item->get_quantity(),
'price' => (float) $item->get_total() / max(1,$item->get_quantity()),
'delivery_date' => $item->get_meta('_probo_delivery_date'),
'supplier_id' => $item->get_meta('_probo_supplier_id'),
'supplier_label' => $item->get_meta('_probo_supplier_label'),
'surcharge' => (float) $item->get_meta('_probo_delivery_surcharge'),
];
}, $order->get_items())
];
Send as JSON to your Probo API as you already do. Handle API failures gracefully (retry queue).
—
# Emails & My Account
Add the two lines to templates via hooks:
– Emails: `woocommerce_order_item_meta_end`
– My Account: default item meta already shows if you use the item meta keys above. If you want custom labels, filter `woocommerce_order_item_get_formatted_meta_data`.
—
# Non-Probo products (for now)
– Do nothing special; they skip date/supplier UI.
– If you later need a **single order-level delivery date** for all non-Probo items, add a **global** selector in checkout (separate from per-item), with its own surcharge rule.
—
# Edge cases handled
– User changes **shipping country** mid-checkout → re-fetch suppliers, clear invalid selections.
– **Cut-off** flips while user is on the page → on submit validate again and show updated dates.
– Caching suppliers per `{date,country,method}` to keep the checkout snappy.
– Works with **Store Pickup** by limiting suppliers or switching supplier mode.
—
If you want, I can drop in the **exact JS** for the date → supplier AJAX flow and the **admin settings page** skeleton next, but the above is the full integration map you can wire into your existing Probo plugin.