Option to Add a variable Tip

Help for integrating the Laravel package
Forum rules
Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
xarga
Posts: 43
Joined: 16 Dec 2019, 22:54

Option to Add a variable Tip

Post by xarga » 06 Apr 2020, 22:41

In light of Covid 19 delivery risks, restaurant delivery personnel want to present customers with the OPTION of adding a variable tip to the order - similar to that now seen in many cafe's using tablets and touch screen point of sale devices.

After completing product selection and during final checkout the customer would be presented with the option:
-------------------------
Leave a tip?

o 20%
o 15%
o 10%
o No Tip
--------------------------
OR
--------------------------
Leave a tip?

[ 12 ] % (using a form field - any value customer enters)

--------------------------
Selection of a tip would add that percentage to the order total before tax and shipping.

Is there a way to configure this in the standard product through a service or other method?

User avatar
aimeos
Administrator
Posts: 7873
Joined: 01 Jan 1970, 00:00

Re: Option to Add a variable Tip

Post by aimeos » 08 Apr 2020, 07:20

There are two options:

1.) You can add a product attribute with code "custom" and type "price" to each product so customers can chose the amount of the tip themselves in the product detail view

2.) You write a service decorator that adds the list of possible values to the delivery or payment option and add the calculated tip on top of the price of that option. Your implementation would be a combination of those two decorators:
- For the list of options: https://github.com/aimeos/aimeos-core/b ... pplier.php
- For adding the tip: https://github.com/aimeos/aimeos-core/b ... /Costs.php
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

xarga
Posts: 43
Joined: 16 Dec 2019, 22:54

Re: Option to Add a variable Tip

Post by xarga » 13 Apr 2020, 07:26

Thanks - I'm at a loss as to how to pass the array of tip values to the decorator and how to get the html to show up in the cart.

Attached is what I have so far but I'm especially struggling with how to modify a copy of the second decorator example (Supplier.php).

From copy of the costs.php decorator:

Code: Select all

<?php

/**
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
 * @copyright Metaways Infosystems GmbH, 2013
 * @copyright Aimeos (aimeos.org), 2015-2018
 * @package MShop
 * @subpackage Service
 */
namespace Aimeos\MShop\Service\Provider\Decorator;
/**
 * Decorator for service providers adding additional costs.
 *
 * @package MShop
 * @subpackage Service
 */
class Tip
	extends \Aimeos\MShop\Service\Provider\Decorator\Base
	implements \Aimeos\MShop\Service\Provider\Decorator\Iface
{
	private $beConfig = array(
		'costs.percent' => array(
			'code' => 'tip.percent',
			'internalcode' => 'tip.percent',
			'label' => 'Costs: Decimal percent value',
			'type' => 'number',
			'internaltype' => 'float',
			'default' => 0,
			'required' => true,
		),
	);
	/**
	 * Checks the backend configuration attributes for validity.
	 *
	 * @param array $attributes Attributes added by the shop owner in the administraton interface
	 * @return array An array with the attribute keys as key and an error message as values for all attributes that are
	 * 	known by the provider but aren't valid
	 */
	public function checkConfigBE( array $attributes )
	{
		$error = $this->getProvider()->checkConfigBE( $attributes );
		$error += $this->checkConfig( $this->beConfig, $attributes );

		return $error;
	}
	/**
	 * Returns the configuration attribute definitions of the provider to generate a list of available fields and
	 * rules for the value of each field in the administration interface.
	 *
	 * @return array List of attribute definitions implementing \Aimeos\MW\Common\Critera\Attribute\Iface
	 */
	public function getConfigBE()
	{
		return array_merge( $this->getProvider()->getConfigBE(), $this->getConfigItems( $this->beConfig ) );
	}
	/**
	 * Returns the tip amount when using the provider.
	 * This is calculated based on
	 * the basket content, e.g. 10% of the value as transaction cost.
	 *
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
	 * @return \Aimeos\MShop\Price\Item\Iface Price item containing the price, shipping, rebate
	 */
	public function calcPrice( \Aimeos\MShop\Order\Item\Base\Iface $basket )
	{
		$config = $this->getServiceItem()->getConfig();

		if( !isset( $config['tip.percent'] ) ) {
			throw new \Aimeos\MShop\Service\Exception( sprintf( 'Missing configuration "%1$s"', 'tip.percent' ) );
		}
		$value = $basket->getPrice()->getValue() * $config['tip.percent'] / 100;
		$price = $this->getProvider()->calcPrice( $basket );
		$price->setCosts( $price->getCosts() + $value );

		return $price;
	}
}
From copy of supplier.php

Code: Select all

<?php
/**
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
 * @copyright Aimeos (aimeos.org), 2017-2018
 * @package MShop
 * @subpackage Service
 */

namespace Aimeos\MShop\Service\Provider\Decorator;
/**
 * Supplier tip decorator for service providers
 * @package MShop
 * @subpackage Service
 */
class TipOptions
	extends \Aimeos\MShop\Service\Provider\Decorator\Base
	implements \Aimeos\MShop\Service\Provider\Decorator\Iface
{
	private $feConfig = array(
		'tip.code' => array(
			'code' => 'tip.code',
			'internalcode' => 'tip.percent',
			'label' => 'Tip Amount',
			'type' => 'list',
			'internaltype' => 'array',
			'default' => [0=>'No Tip'],
			'required' => true
		),
	);
   /* public $tips=array(
        array('tip.code' => 0, 'label' =>'No Tip'),
        array('tip.code' => 10, 'label' =>'5% Tip'),
        array('tip.code' => 15, 'label' =>'10% Tip'),
        array('tip.code' => 20, 'label' =>'15% Tip')
    );  */
	private $beConfig = array(
		'tip.display-code' => array(
			'code' => 'tip.display-code',
			'internalcode' => 'tip.percent',
			'label' => 'Display tip code in summary and email',
			'type' => 'integer',
			'internaltype' => 'integer',
			'default' => 0,
			'required' => false,
		),
	);
	/**
	 * Initializes a new service provider object using the given context object.
	 *
	 * @param \Aimeos\MShop\Service\Provider\Iface $provider Service provider or decorator
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object with required objects
	 * @param \Aimeos\MShop\Service\Item\Iface $serviceItem Service item with configuration for the provider
	 */
	public function __construct( \Aimeos\MShop\Service\Provider\Iface $provider,
		\Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Service\Item\Iface $serviceItem )
	{
		parent::__construct( $provider, $context, $serviceItem );
		$manager = \Aimeos\MShop::create( $context, 'supplier' );
		$tipManager = \Aimeos\MShop::create( $context, 'supplier/tip' );

		$search = $manager->createSearch( true );
		$search->setSortations( [$search->sort( '+', 'tip.percent' )] );

		foreach( $manager->searchItems( $search, ['supplier/tip'] ) as $item )
		{
			$tips = array(0 =>'No Tip', 10 => '10% Tip', 15  =>'10% Tip', 20  =>'10% Tip');

            if( empty( $tips ) ) {
				$tips[] = $tipManager->createItem();
			}

			foreach( $tips as $id => $tip )
			{
				$tipId = ( count( $tips ) > 1) ? $item->getCode() . '-' . $id : $item->getCode();

				$this->feConfig['tip.code']['default'][$tipId] = preg_replace( "/\n+/m", "\n", sprintf(
					/// Tip Format with label (%1$s)
					$context->getI18n()->dt( 'mshop', '%1$s'),
					$tip->getTip()
				) );
				$this->feConfig['tip.code']['short'][$tipId] = preg_replace( "/\n+/m", "\n", sprintf(

					$context->getI18n()->dt( 'mshop', '%1$s'),
					$tip->getTip()
				) );
			}
		}
	}
	/**
	 * Checks the frontend configuration attributes for validity.
	 *
	 * @param array $attributes Attributes entered by the customer during the checkout process
	 * @return array An array with the attribute keys as key and an error message as values for all attributes that are
	 * 	known by the provider but aren't valid resp. null for attributes whose values are OK
	 */
	public function checkConfigFE( array $attributes )
	{
		$result = $this->getProvider()->checkConfigFE( $attributes );

		return array_merge( $result, $this->checkConfig( $this->feConfig, $attributes ) );
	}
	/**
	 * Returns the configuration attribute definitions of the provider to generate a list of available fields and
	 * rules for the value of each field in the frontend.
	 *
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object
	 * @return array List of attribute definitions implementing \Aimeos\MW\Common\Critera\Attribute\Iface
	 */
	public function getConfigFE( \Aimeos\MShop\Order\Item\Base\Iface $basket )
	{
		$feconfig = $this->feConfig;
		try
		{
			$type = \Aimeos\MShop\Order\Item\Base\Service\Base::TYPE_DELIVERY;
			$service = $this->getBasketService( $basket, $type, $this->getServiceItem()->getCode() );

			if( ( $value = $service->getAttribute( 'tip.code', 'delivery' ) ) != ''
				&& isset( $feconfig['tip.code']['default'][$value] )
			) {
				// move to first position so it's selected
				$tip = $feconfig['tip.code']['default'][$value];
				unset( $feconfig['tip.code']['default'][$value] );
				$feconfig['tip.code']['default'] = [$value => $address] + $feconfig['tip.code']['default'];
			}
		}
		catch( \Aimeos\MShop\Service\Exception $e ) {} // If service isn't available

		return array_merge( $this->getProvider()->getConfigFE( $basket ), $this->getConfigItems( $feconfig ) );
	}
	/**
	 * Sets the Payment attributes in the given service.
	 *
	 * @param \Aimeos\MShop\Order\Item\Base\Service\Iface $orderServiceItem Order service item that will be added to the basket
	 * @param array $attributes Attribute key/value pairs entered by the customer during the checkout process
	 * @return \Aimeos\MShop\Order\Item\Base\Service\Iface Order service item with attributes added
	 */
	public function setConfigFE( \Aimeos\MShop\Order\Item\Base\Service\Iface $orderServiceItem, array $attributes )
	{
		if( ( $code = $attributes['tip.code'] ) != '' )
		{
			// add short address as attribute for summary page / customer email
			$attributes['tip.percent'] = $this->feConfig['tip.code']['short'][$code];
			// remove code attribute for summary page / customer email
			if( $this->getConfigValue('tip.display-code') == 0 ) {
				unset( $attributes['tip.code'] );
			}
		}
		return $this->getProvider()->setConfigFE( $orderServiceItem, $attributes );
	}
}

And here's an example of what we want to achieve (From woocommerce)

Image
Attachments
example.-tips.jpg
example.-tips.jpg (35.94 KiB) Viewed 1423 times

User avatar
aimeos
Administrator
Posts: 7873
Joined: 01 Jan 1970, 00:00

Re: Option to Add a variable Tip

Post by aimeos » 15 Apr 2020, 06:45

You need to do this in one decorator, not in two.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

Post Reply