Jump to content
Liyali

Adding a custom field during the Checkout process

Recommended Posts

Hi everybody,

 

I need to add a custom field (checkbox) during the Checkout process and then register the data in database. Later I would like to have this data appearing on the PDF invoice in the back-office.

 

What I have done so far:

- Create the field in the template /themes/themeName/order-carrier.tpl (I want my field to appear right after the TOS section)

- Add a new field in database in the ps_orders table (TINYINT)

- Add this function in /override/classes/Order.php :

 

<?php

class Order extends OrderCore
{
public         $myFieldName;

   public function getFields()
   {
       $fields = parent::getFields();

       $fields['myFieldName'] = pSQL($this->myFieldName);
       return $fields;
   }
}

 

When I die(); inside my getFields() function (var_dump($myFieldName);die;), it appears that my field is always empty. In fact it seems obvious since I never filled $myFieldName before. There is probably a function to override where I should have something like:

 

$myFieldName = $_POST['myFieldName'];

 

but I have no idea where to do that though. Does anyone can help me? Any PS [spam-filter] around here?

Also, any idea how to deal with the invoice later on?

 

Thanks :)

  • Like 1

Share this post


Link to post
Share on other sites

Thank you Elpatron for your prompt answer.

 

However, my custom field has no relationship with any product of my catalog. Imagine for example a "Receipt" field, which means that when it is checked, a receipt will be sent with this purchase.

  • Like 1

Share this post


Link to post
Share on other sites

How can I add my custom field to the contextual cart for a OnePageCheckout process?

Share this post


Link to post
Share on other sites

Unfortunately for you it isn't quite as simple as that since during the order process it isn't actually an Order object that's being manipulated but rather it is a Cart object.

 

If you look at the function _processCarrier() in the ParentOrderController class you'll see that there's a hook function available which you could use to insert your own code into the process. In a module this would be implemented as:

 

public function hookActionCarrierProcess(Array $params)
{
$cart = $params['cart'];
 if (!($cart instanceof Cart))
		return;

$cart->myField = Tools::getValue('myFieldName');
}

 

You could override the Cart class and add your field to that. When it finally becomes an order (e.g. by the time you want to generate the invoice) the order object has a data member $id_cart which you can use to get the Cart object and thus your saved data. To display the data on the invoice you can use the hook function hookDisplayPDFInvoice().

 

public function hookDisplayPDFInvoice(Array $params)
{
	$order_invoice = $params['object'];
	if (!($order_invoice instanceof OrderInvoice))
		return;

	$order = new Order((int)$order_invoice->id_order);
	$cart = new Cart($order->id_cart);

	return 'My field data was :'.$cart->myField;
}

Edited by Paul C (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Unfortunately for you it isn't quite as simple as that since during the order process it isn't actually an Order object that's being manipulated but rather it is a Cart object. [...]

 

Thank you for your explanation, I managed to do it using with a very similar way too.

Hope this can help someone else in the future.

Edited by Liyali (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Hi Paul C:

 

I am using your solution, but user input to field are not being saved to database. I implemented hookActionCarrierProcess but the value in $cart->myfield is not getting saved. What am I missing here?

 

Iftikhar 

Share this post


Link to post
Share on other sites

Thank you for your explanation, I managed to do it using with a very similar way too.

Hope this can help someone else in the future.

It surely can help, if you care to share your solution.

Share this post


Link to post
Share on other sites

In complement of Paul C answer, for PS 1.7.1 :

 

- In a module class, add colums to database in the ps_orders and ps_cart tables : 

private function installSQL()
    {
        $sql = array();

        $sql[] = "ALTER TABLE `"._DB_PREFIX_."cart` ADD client_message TEXT";
        $sql[] = "ALTER TABLE `"._DB_PREFIX_."orders` ADD client_message TEXT";

        $this->executeSQL($sql);

        return true;
    }

    private function uninstallSQL(){
        $sql = array();
        $sql[] = "ALTER TABLE `"._DB_PREFIX_."cart` DROP client_message";
        $sql[] = "ALTER TABLE `"._DB_PREFIX_."orders` DROP client_message";

        $this->executeSQL($sql);
    }

    private function executeSQL($requests){

        foreach ($requests as $q) {
            if (!DB::getInstance()->execute($q)) {
                return false;
            }
        }

    }

Declare your field in Cart.php and Order.php classes :

// at the top
public $client_message;

// in $definition
'fields' => array(
...,
'client_message' => array('type' => self::TYPE_STRING, 'validate' => 'isMessage'),
),

In classes/checkout/CheckoutDeliveryStep.php at the end of the handleRequest function, get the correct params for our module hook function :

$checkoutCart = $this->getCheckoutSession()->getCart();

        if( isset($requestParams['client_message'])){
            $checkoutCart->client_message = $requestParams['client_message'];
        }

Hook::exec('actionCarrierProcess', array( 'cart' => $checkoutCart));

In the module hook :

public function hookActionCarrierProcess(Array $params)
    {

        $cart = $params['cart'];
        if (!($cart instanceof Cart))
            return;


        if( isset($params['cart']->client_message) ){

            $cart->client_message = $params['cart']->client_message;

        }
        $cart->save();
        
    }

And in classes/PaymentModule.php in the validateOrder function : 

$order->client_message = $this->context->cart->client_message;
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

And you also need to add in AdminCartsController in ajaxProcessUpdateDeliveryOption function : 

if (Validate::isMessage(($client_message = pSQL(Tools::getValue('client_message'))))) {
                $this->context->cart->client_message = $client_message;
            }

What's the purpose of trying to do something modular if for only one field you need to modify 5 files...

 

Or is there a way to implement these overrides from the module directly ??

  • Thanks 1

Share this post


Link to post
Share on other sites

i have tried this anthony, but i think you forgot to add these fields in the templates? Cause they dont show up?

Share this post


Link to post
Share on other sites

@r4yn0r

I did that trick to send the client_message it in the order confirmation email, i don't use the value in templates.

You can access the variable in templates with {$cart.client_message}, or ($order.client_message}, obviously if $cart and $order are set and not empty, as well as the client_message value.

You can try {debug} in your template to output the accessible smarty variables and look into $cart and $order.

Share this post


Link to post
Share on other sites

@Anthony IVOL thank you very much for your post.

I have Prestashop 1.7. I did earlier in my module what you described:
a) At module install step - additional cols in database were added in two tables.
b) New field was declared in this two classes - Cart and Order by extending it from module files.
c) I changed /classes/checkout/CheckoutD eliveryStep.php as you described.
d) I created assigning value from params - from cart to order object and save it in actionCar rierProc ess hook in module.
e) Also change in va lidate Order functi o n.

@Anthony IVOL@r4yn0r mentioned about showing this field on fronted. I also mean that you wrote about processing this new value - but of course, on some step, user should have possibility to type this message. How? Where? How to get this value from frontend in PS 1.7?
I understand that you later don't show this value. But you need to source this value in some way ;)

Please see how I added this new field (a little success) on front in shipping method step:

checkout-newField.png.8a418f6f6a2ea6eaeb549c6ad8945964.png

I achieved this by hook DisplayAfterCarrier (with html code from module's tpl file) and hook Header (added by module JS file by addJS controller). And JS code moves this code "higher" on frontend by this code: $('#myID').prependTo('#delivery');

I can't get this value from this field. I can't do it in any way. I tried to use action hooks (ActionCarrierProcess, ActionCartSave, ActionValidateOrder), I tested this attempts by saving data to txt file - just for debug.

You skip this part how to present this new field for user and how to get this value :) Please help, please give some advice :)

Share this post


Link to post
Share on other sites
Am 7/27/2019 um 10:58 AM schrieb Rynraf:

@Anthony IVOL thank you very much for your post.

I have Prestashop 1.7. I did earlier in my module what you described:
a) At module install step - additional cols in database were added in two tables.
b) New field was declared in this two classes - Cart and Order by extending it from module files.
c) I changed /classes/checkout/CheckoutD eliveryStep.php as you described.
d) I created assigning value from params - from cart to order object and save it in actionCar rierProc ess hook in module.
e) Also change in va lidate Order functi o n.

@Anthony IVOL@r4yn0r mentioned about showing this field on fronted. I also mean that you wrote about processing this new value - but of course, on some step, user should have possibility to type this message. How? Where? How to get this value from frontend in PS 1.7?
I understand that you later don't show this value. But you need to source this value in some way ;)

Please see how I added this new field (a little success) on front in shipping method step:

checkout-newField.png.8a418f6f6a2ea6eaeb549c6ad8945964.png

I achieved this by hook DisplayAfterCarrier (with html code from module's tpl file) and hook Header (added by module JS file by addJS controller). And JS code moves this code "higher" on frontend by this code: $('#myID').prependTo('#delivery');

I can't get this value from this field. I can't do it in any way. I tried to use action hooks (ActionCarrierProcess, ActionCartSave, ActionValidateOrder), I tested this attempts by saving data to txt file - just for debug.

You skip this part how to present this new field for user and how to get this value :) Please help, please give some advice :)

Any solution here? I have exact the same problem.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More