Gourav bagora
Gourav bagora

Reputation: 73

How do I insert a value in a custom field in a table in Prestashop?

I added a custom field named "deldate" in "ps_orders" table, and I added a text box on "OPC" checkout page. Now when I click on order confirm button the value in the textbox should be saved in "deldate" field of "ps_orders" table. The textbox is showing perfectly but in which files do I need to make changes to save the textbox value in the table? (Theme is default one.)

snap of textbox

snap of custom field in table.

class/order/order.php

class OrderCore extends ObjectModel 
{ 
public $deldate; 
} 

And

public static $definition = array( 
'fields' => array( 
'deldate'=> array('type' => self::TYPE_STRING),
),
)

Shopping-cart.tpl

<div class="box">
<div class="required form-group">
<form method="post">
<label for="Fecha de entrega deseada">{l s='Desired delivery date' mod='deldate'}</label>
<input type="text" id="deldate" name="deldate" class="form-control" value="hello" />
</form>
</div>

</div>

Upvotes: 0

Views: 2599

Answers (3)

marsaldev
marsaldev

Reputation: 3349

Ok, I figured out the solution... If you want to add some information to the order in the checkout process you have to save this informations elsewhere, if you look the cart table are very similar to order table. Why you have to do this? Because you don't have an order before the confirmation by customer, so until the checkout is not complete that informations can't be saved in the order table.

So, first, create the field in database, in this case you have to add in ps_orders and in the ps_cart as well. (In your case I suggest to use a DATETIME field)

Second, override the Order class:

class Order extends OrderCore
{
    public function __construct($id = null, $id_lang = null)
    {
        self::$definition['fields']['deldate'] = array('type' => self::TYPE_DATE);

        parent::__construct($id, $id_lang);
    }
}

and the Cart class:

class Cart extends CartCore
{
    public function __construct($id = null, $id_lang = null)
    {
        self::$definition['fields']['deldate'] = array('type' => self::TYPE_DATE);

        parent::__construct($id, $id_lang);
    }
}

Now we have to save the field during the checkout process, so we override the OrderController:

class OrderController extends OrderControllerCore
{
    public function processAddress()
    {
        parent::processAddress();

        // Here we begin our story
        if(Tools::getIsset('deldate')) // Check if the field isn't empty
        {
            $deldate = Tools::getValue('deldate');

            // Here you must parse and check data validity (I leave to you the code)
            /* ... */

            // Assign the data to context cart
            $this->context->cart->deldate = $deldate;
            // Save information
            $this->context->cart->update();
        }
    }
}

Now you have to 'transport' this informations from the cart to the order, this will be done through the PaymentModule class, specifically with the validateOrder method.

So, another override:

class PaymentModule extends PaymentModuleCore
{
    public function validateOrder($id_cart, $id_order_state, $amount_paid, $payment_method = 'Unknown', $message = null, $extra_vars = array(), $currency_special = null, $dont_touch_amount = false, $secure_key = false, Shop $shop = null)
    {
        $result = parent::validateOrder($id_cart, $id_order_state, $amount_paid, $payment_method, $message, $extra_vars, $currency_special, $dont_touch_amount, $secure_key, $shop);

        if($result)
        {
            $oldcart = new Cart($id_cart);
            $neworder = new Order($this->currentOrder);
            $neworder->deldate = $oldcart->deldate;
            $neworder->update();
            return true; // important
        } 
        else 
        {
            return $result;
        }
    }
}

After all of this you have the deldate field saved. However, I absolutely don't suggest this method, it's more safe and simple with a module and hooks... But this is another story :)

This will works only with the five steps checkout.

For next code lines, God save me...

If you want to works with OPC you have to dirty your hands with JS and override the OrderOpcController. Start with the JS, edit the order-opc.js in js folder of enabled theme, find bindInputs function and append this lines of code:

function bindInputs()
{
    /* ... */

    $('#deldate').on('change', function(e){
        updateDelDateInput(); // custom function to update deldate
    });
}

then append to the file your custom function:

function updateDelDateInput()
{
    $.ajax({
            type: 'POST',
            headers: { "cache-control": "no-cache" },
            url: orderOpcUrl + '?rand=' + new Date().getTime(),
            async: false,
            cache: false,
            dataType : "json",
            data: 'ajax=true&method=updateDelDate&deldate=' + encodeURIComponent($('#deldate').val()) + '&token=' + static_token ,
            success: function(jsonData)
            {
                if (jsonData.hasError)
                {
                    var errors = '';
                    for(var error in jsonData.errors)
                        //IE6 bug fix
                        if(error !== 'indexOf')
                            errors += $('<div />').html(jsonData.errors[error]).text() + "\n";
                    alert(errors);
                }
                // Here you can add code to display the correct updating of field
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                if (textStatus !== 'abort')
                    alert("TECHNICAL ERROR: unable to save message \n\nDetails:\nError thrown: " + XMLHttpRequest + "\n" + 'Text status: ' + textStatus);
            }
        });
}

Then override the OrderOpcController, copy all the init method and change the line of code as below:

class OrderOpcController extends OrderOpcControllerCore
{
    public function init()
    {
        // parent::init(); // comment or delete this line
        FrontController::init(); // Very important!
        // Then in this switch `switch (Tools::getValue('method'))` add your case
        /* ... */
        case 'updateDelDate':
            if(Tools::isSubmit('deldate'))
            {
                $deldate = urldecode(Tools::getValue('deldate'));

                // Here you must parse and check data validity (I leave to you the code)
                /* ... */

                // Assign the data to context cart
                $this->context->cart->deldate = $deldate;
                // Save information
                $this->context->cart->update();
                $this->ajaxDie(true);
            }
        break;
        /* ... */
    }
}

Obviously, is necessary the override of Order, Cart and PaymentModule as well.

PS: I hope that I didn't forget anything.

Upvotes: 1

sadlyblue
sadlyblue

Reputation: 2987

Try this in the override of the class Order

class Order extends OrderCore
{

    public function __construct($id = null, $id_lang = null)
    {
        parent::__construct($id, $id_lang);

        self::$definition['fields']['deldate'] = array('type' => self::TYPE_STRING);
        Cache::clean('objectmodel_def_Order');

    }

}

The Cache::clean is need because getDefinition tries to retrieve from cache, and cache is set without the override on parent::__construct

I then tried to create a new empty Order and get the definition fields and it showed there, so it should save to mysql

$order = new Order();
var_dump(ObjectModel::getDefinition($order));exit;

Upvotes: 0

Related Questions