Developing shipping plugin with own field

  • Posts: 41
  • Thank you received: 6
  • Hikashop Business
1 month 1 week ago #365060

Hi,

I’m trying to develop shipping plugin. I want to add a text field that user can write some data. Then that data should be available in order details.
How to do it properly?

I am able to display field adding it like that. But how to save it in database in order?

function onShippingDisplay(&$order,&$methods,&$usable_methods,&$messages) {

	
		foreach ($methods as $method) {
            if ($method->shipping_type !== 'newpluginshipping') {
                continue;
            }

            $method->shipping_name = 'My Shipping';
            $method->shipping_description = 'More info.';

			$html = '<div class="my-shipping-field">';
			$html .= '<label for="my-shipping-field">Write detalis</label>';
			$html .= '<input type="text" name="my-shipping-field" id=" my-shipping-field" value="" />';
			$html .= '</div>';
	
			$method->custom_html = $html;
            $usable_methods[] = $method;


		}
	}

Last edit: 1 month 1 week ago by nicolas.

Please Log in or Create an account to join the conversation.

  • Posts: 83182
  • Thank you received: 13438
  • MODERATOR
1 month 1 week ago #365061

Hi,

You need to use a specific "name" in your input field:

$name = 'checkout[shipping][custom]'.(isset($order->shipping_warehouse_id) ? ('['.$order->shipping_warehouse_id.']') : '').'['.$method->shipping_id.']';
Then, it will be saved in the cart in the database for you.
However, you will have to save it in the order yourself in the "onBeforeOrderCreate" event like so:
public function onBeforeOrderCreate(&$order, &$do) {
	$cart_shipping_ids = $order->cart->cart_shipping_ids;
	$cart_params = $order->cart->cart_params;
	$process = array();
	if(empty($cart_shipping_ids))
		return;
	if(is_string($cart_shipping_ids))
		$cart_shipping_ids = explode(',', $cart_shipping_ids);
	foreach($cart_shipping_ids as $shipping_id) {
		list($sip,$warehouse) = explode('@', $shipping_id, 2);
		$current = null;
		foreach($order->cart->shipping as $shipping) {
			if($shipping->shipping_id != $sip)
				continue;
			$current = $shipping;
			break;
		}
		if(empty($current) || $current->shipping_type != $this->name)
			continue;
		$process[$warehouse] = $sip;
	}
	if(empty($process))
		return;

	$order_shipping_params = $order->order_shipping_params;
	foreach($process as $warehouse => $id) {
		$shipping_data = null;
		if(!empty($order->cart->cart_params->shipping) && is_object($order->cart->cart_params->shipping) && isset($order->cart->cart_params->shipping->{$warehouse}))
			$shipping_data = $order->cart->cart_params->shipping->{$warehouse};
		if(!empty($order->cart->cart_params->shipping) && is_array($order->cart->cart_params->shipping) && isset($order->cart->cart_params->shipping[$warehouse]))
			$shipping_data = $order->cart->cart_params->shipping[$warehouse];
		if(!empty($shipping_data)) {
			$data = (isset($shipping_data->{$id}) ? $shipping_data->{$id} : null);
			if(empty($order_shipping_params->newpluginshipping))
				$order_shipping_params->newpluginshipping = array();
			$order_shipping_params->newpluginshipping[$warehouse]  = $data;
		}
	}
	$order->order_shipping_params = $order_shipping_params;
}
It's a bit complex to do because with HikaShop, you can have different shipping methods sections for the same cart, one for each warehouse / vendor. So, for one order, you can potentially end up with several shipping methods of the same plugin to process.

While, in most cases, this is overkill, if you want to share your plugin so that it can work for anyone using HikaShop, this is the best approach.

A simpler approach would be to implement the event onShippingSave in order to look in the POST for your input value (in that case, you can use whatever name you want in the input), store the value in the user session, and then you can use onBeforeOrderCreate to store the value from the session to the order.
However, there are several limitations with this. You will have a hard time supporting different warehouses/vendors, if the user session timeout, you'll loose the value previously entered by the user, even though there rest of the information provided by the user will still be available to him if he logs back in, and you need to build some logic and checks yourself when the user doesn't fill in the field, or when another shipping method is selected.

Please Log in or Create an account to join the conversation.

  • Posts: 41
  • Thank you received: 6
  • Hikashop Business
1 month 1 week ago #365062

Hmm. It’s really a bit complicated. If I will modify function onShippingDisplay and add a onBeforeOrderCreate like you write it will be working and a data from field will be saved to order?

function onShippingDisplay(&$order,&$methods,&$usable_methods,&$messages) {

	$name = 'checkout[shipping][custom]'.(isset($order->shipping_warehouse_id) ? ('['.$order->shipping_warehouse_id.']') : '').'['.$method->shipping_id.']';


	foreach ($methods as $method) {
		if ($method->shipping_type !== 'newpluginshipping') {
			continue;
		}

		$method->shipping_name = 'My Shipping';
		$method->shipping_description = 'More info.';

		$html = '<div class="my-shipping-field">';
		$html .= '<label for="my-shipping-field">Write detalis</label>';
		$html .= '<input type="text" name="$name" id=" my-shipping-field" value="" />';
		$html .= '</div>';

		$method->custom_html = $html;
		$usable_methods[] = $method;

	}
}

Please Log in or Create an account to join the conversation.

  • Posts: 83182
  • Thank you received: 13438
  • MODERATOR
1 month 1 week ago #365064

Hi,

Yes. Note however that your code is wrong.
The line:

$html .= '<input type="text" name="$name" id=" my-shipping-field" value="" />';
should be:
$html .= '<input type="text" name="'.$name.'" id=" my-shipping-field" value="" />';
otherwise, the name of your input will be $name, and not the text in the $name variable.

Please Log in or Create an account to join the conversation.

  • Posts: 41
  • Thank you received: 6
  • Hikashop Business
1 month 1 week ago #365069

Thank You. I see that value is saving in hikashop_order table in order_shipping_params field fled (below) but how to display that value in backend -> hikashop-> orders in that specific order?

O:8:"stdClass":2:{s:6:"prices";a:1:{s:3:"3@0";O:8:"stdClass":3:{s:14:"price_with_tax";d:24.6;s:3:"tax";d:4.600000000000001;s:5:"taxes";a:1:{s:7:"23% VAT";d:4.6;}}}s:17:"newpluginshipping";a:1:{i:0;s:5:"saved custom value";}}

Please Log in or Create an account to join the conversation.

  • Posts: 83182
  • Thank you received: 13438
  • MODERATOR
1 month 1 week ago #365070

Hi,

So, you mean that you want to display it as an extra column in the orders listing ?
In that case, you want to implement the onHikashopBeforeDisplayView(&$view) event in your plugin.
You can use code like this:

	function onHikashopBeforeDisplayView(&$view) {
		$viewName = $view->getName();
		if($viewName != 'order')
			return;
		$layout = $view->getLayout();
		if($layout != 'listing')
			return;
		$column = new stdClass();
		$column->name = JText::_('MY_COLUMN_NAME');
		$column->value = 'my_column';
		$view->extrafields['my_column'] = $column;
		if(!empty($view->rows)) {
				foreach($view->rows as $k => $v) {
					if(empty($v->order_shipping_params)) {
						continue;
					}
					if(is_string($v->order_shipping_params))
						$v->order_shipping_params = hikashop_unserialize($v->order_shipping_params);
					if(empty($v->order_shipping_params->newpluginshipping))
						$view->rows[$k]->my_column = $v->order_shipping_params->newpluginshipping;
				}
		}
	}

Please Log in or Create an account to join the conversation.

  • Posts: 41
  • Thank you received: 6
  • Hikashop Business
1 month 1 week ago #365081

Thank you for help. Not necessarily a column but I want to see that value (from that custom filed) when I will open a order in CMS backend panel (like other data – address, payment method etc.) Value is saved to data base but it don’t display in CMS backend (I see only that client choose a my new shipping method but I don’t see what was entered in that new filed I created). How to do that?

Please Log in or Create an account to join the conversation.

  • Posts: 83182
  • Thank you received: 13438
  • MODERATOR
1 month 1 week ago #365082

Hi,

Well, you could use the code from my previous message to display the value from the order_shipping_params as a column of the orders listing.
A simple approach would be to change your code in the onBeforeOrderCreate event of your plugin to store the data in a custom field of the table "order". You can create custom fields via the menu Display>Custom fields of the HikaShop backend.
If your custom field's column name is, for example, "newpluginshipping", then you can change the code:

if(empty($order_shipping_params->newpluginshipping))
				$order_shipping_params->newpluginshipping = array();
			$order_shipping_params->newpluginshipping[$warehouse]  = $data;
to:
$order->newpluginshipping = $data;
and HikaShop will automatically store your data to that custom field.
Then, with the display settings of the custom field, you can choose to display the data as a column of the orders listing, an extra row in the "additional information" area of the order detail page, etc.

The following user(s) said Thank You: Bprak

Please Log in or Create an account to join the conversation.

  • Posts: 41
  • Thank you received: 6
  • Hikashop Business
1 month 1 week ago #365083

Perfect! It’s working! Thank you for help. I had also add a private function that added to database custom filed in _field table and a new column with same name in _order table (so I don’t have to do it manually). Now value from my field is adding and displaying in proper way in order details. I think that would be nice to add that example in developer documentation.

The following user(s) said Thank You: nicolas

Please Log in or Create an account to join the conversation.

  • Posts: 4775
  • Thank you received: 648
  • MODERATOR
1 month 5 days ago #365108

Hello,

Thanks for your returns, we have updated our developer documentation following your suggestion.
Regards

Last edit: 1 month 5 days ago by Philip.

Please Log in or Create an account to join the conversation.

Time to create page: 0.070 seconds
Powered by Kunena Forum