Jump to content
draganv

Change the Order Reference to Number Reference

Recommended Posts

Hi,

 

I`m using Prestashop 1.6.1.4. I would like to change the Order reference ( alphabets ) to alphanumeric value.

 

Thanks.

Share this post


Link to post
Share on other sites

you can ignore the reference #, and use order ID as format it into the digits you wanted. most places you can directly use it in many places.

It depends what kind of data is ready in the smarty or PHP context, you can change either one of following

 

$order->reference ==> $order->id

 

or

 

$order['reference'] ==> $order['id_order'] 

Share this post


Link to post
Share on other sites

I find solution.

 

In classes/order/Order.php  replace

 

public static function generateReference()
{
    return strtoupper(Tools::passwdGen(9, 'NO_NUMERIC'));
}
 
to
 
public static function generateReference()
{
    $last_id = Db::getInstance()->getValue('
        SELECT MAX(id_order)
        FROM '._DB_PREFIX_.'orders');
    return str_pad((int)$last_id + 1, 9, '000000000', STR_PAD_LEFT);
 
}
  • Like 3

Share this post


Link to post
Share on other sites

You can use the following code to change the behavior without disturbing the prestashop core code:

<?php
/*
*  RETURN ORDER REFERENCE TO SEQUENTIAL NUMERIC VALUE
*
*  2016 PrestaShop v1.6.1.x
*  Override by Obewanz
*/

Class Order extends OrderCore
{
  public static function generateReference()
  {
    $last_id = Db::getInstance()->getValue('
        SELECT MAX(id_order)
        FROM '._DB_PREFIX_.'orders');
    return str_pad((int)$last_id + 1, 9, '000000000', STR_PAD_LEFT);
  }
}

You should create a file called order.php in the folder /override/classes/order and paste the above code.

 

I looked into doing more complicated types of reference numbers, but in the end, I felt that a plain numeric string that goes to over 999 million was the best, most simple solution. If you must change to something else, next best idea is to replace the first three characters of the 000000000 string to NR-000000 or something similar. The field in the database is set to a 9 character maximum length so the best solution to adding an alpha would be to put it in a configuration record and append it to all requests for the number - just my opinion. (which is also beyond the scope of where I want to go at this point in time.)

 

Anyway, the alternate to implementing this solution (for non-programmers) is to upload the attached file to the /override/classes/order folder.

 

Note: after you have uploaded the file - don't forget to delete the class_index.php file in the /cache folder.

 

Hope this helps!

order.php

Edited by obewanz (see edit history)
  • Like 3
  • Thanks 3

Share this post


Link to post
Share on other sites
On 9/6/2016 at 10:00 AM, obewanz said:

You can use the following code to change the behavior without disturbing the prestashop core code:


<?php
/*
*  RETURN ORDER REFERENCE TO SEQUENTIAL NUMERIC VALUE
*
*  2016 PrestaShop v1.6.1.x
*  Override by Obewanz
*/

Class Order extends OrderCore
{
  public static function generateReference()
  {
    $last_id = Db::getInstance()->getValue('
        SELECT MAX(id_order)
        FROM '._DB_PREFIX_.'orders');
    return str_pad((int)$last_id + 1, 9, '000000000', STR_PAD_LEFT);
  }
}

You should create a file called order.php in the folder /override/classes/order and paste the above code.

 

I looked into doing more complicated types of reference numbers, but in the end, I felt that a plain numeric string that goes to over 999 million was the best, most simple solution. If you must change to something else, next best idea is to replace the first three characters of the 000000000 string to NR-000000 or something similar. The field in the database is set to a 9 character maximum length so the best solution to adding an alpha would be to put it in a configuration record and append it to all requests for the number - just my opinion. (which is also beyond the scope of where I want to go at this point in time.)

 

Anyway, the alternate to implementing this solution (for non-programmers) is to upload the attached file to the /override/classes/order folder.

 

Note: after you have uploaded the file - don't forget to delete the class_index.php file in the /cache folder.

 

Hope this helps!

order.php

 

I can confirm it is working for 1.7.4.2 Thank you.

Edited by Daniuz (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Working in v. 1.7.3.4

Cache folder changed to: var/cache/dev & var/cache/prod
So after overriding order.php, remember to delete class_index.php from above folders.

Code with little modifications,
conditions:
- generate random NUMERIC reference number
- check if new reference number is UNIQUE
- if not, after 10 tries, change first number to RANDOM letter

Should be enought for many orders.

 

Quote

<?php
/**
 * Author: FER-TECH
 * Based on: SEQUENTIAL NUMERIC ORDER REFERENCE override by Obewanz
 * Date: 17.11.2018
 * Generating random numeric reference
 * Prestashop v. 1.7.4.3
 */


Class Order extends OrderCore
{
    public static function generateReference()
    {
        $regenerate = 1;
        $retries = 0;

        while($regenerate > 0){
            // Generate new randomised reference number
            $newReference = strtoupper(Tools::passwdGen(9, 'NUMERIC'));

            // After 10 tries, change first numer to random letter
            if($retries > 10){
                $newReference = substr_replace($newReference, Tools::passwdGen(1, 'NO_NUMERIC') ,0,1);
            }

            //Check if new reference number is unique
            $regenerate = self::checkIfReferenceNumberExist($newReference);

            $retries++;
        }

        return $newReference;
    }

    private static function checkIfReferenceNumberExist($newReferenceNumber)
    {
        $quantityOfReferences =
            Db::getInstance()->getValue('
              SELECT COUNT(id_order)
              FROM '._DB_PREFIX_.'orders
              WHERE reference = "'. $newReferenceNumber .'"
            ');

        return $quantityOfReferences;
    }
}

 

Edited by Fertechpl
Asked to change comment (see edit history)

Share this post


Link to post
Share on other sites

I also uses the code to create a referencenumber bases on the order id. I have a problem with my payment service provider. When to customers order at the same time, sometimes the same reference number is sent by prestahop to that serviceprovider. The first one that pays succeeds, the second will get error. And there is no second order in shop.

How can i solve this? 

Share this post


Link to post
Share on other sites

When You're first checking what's max. order ID in database and then You're creating new reference number based on that, You will always have problem when 2 clients will use that function in same time.

To solve this problem, You must first create order, return ID of that new order and then create new reference number based on that returned ID.

That's why, I'm checking database for same reference number in my example above. It's not perfect, but almost no chance to generate RANDOM reference by 2 clients in same time.

Edited by Fertechpl (see edit history)

Share this post


Link to post
Share on other sites
22 hours ago, folkifoon said:

I also uses the code to create a referencenumber bases on the order id. I have a problem with my payment service provider. When to customers order at the same time, sometimes the same reference number is sent by prestahop to that serviceprovider. The first one that pays succeeds, the second will get error. And there is no second order in shop.

How can i solve this? 

9

Are you talking about the SEQUENTIAL override or the RANDOM override?

What other modifications have you made to the code?

What payment service provider do you use?
How many orders per minute do you receive?

Share this post


Link to post
Share on other sites

The first one, SEQUENTIAL. It is so much easier having a reference that correspondents with the order id.

But i need the sequential code combined with the code that checks if a reference exist and the change it to something diffferent.

Share this post


Link to post
Share on other sites
On ‎1‎/‎23‎/‎2019 at 11:37 AM, obewanz said:

Are you talking about the SEQUENTIAL override or the RANDOM override?

What other modifications have you made to the code?

What payment service provider do you use?
How many orders per minute do you receive?

Hi, i use Mollie (Netherlands). I have around 20 orders a day, but already 3 times at the same time giving me problems.

I use your code, that is perfect for me, but it needs to check if the reference number does exist. So i think i need a part of the code that is posted by Fertechpl.

So my reference is
ML121500  (order id is 500)

The next one will be ML121501. Now  a second customers comes on the the site, and is paying before the one that started payment first. This will give a problem.
So for that i need the reference to be changed to QML12150Q or something

ML121500  (order id 500)
ML121501  (order id 501)
ML12150Q (order id 502)
ML121503 (order id 503)

Can you help me with that? 

Share this post


Link to post
Share on other sites
On 2/9/2019 at 3:09 AM, folkifoon said:

Hi, i use Mollie (Netherlands). I have around 20 orders a day, but already 3 times at the same time giving me problems.

I use your code, that is perfect for me, but it needs to check if the reference number does exist. So i think i need a part of the code that is posted by Fertechpl.

So my reference is
ML121500  (order id is 500)

The next one will be ML121501. Now  a second customers comes on the the site, and is paying before the one that started payment first. This will give a problem.
So for that i need the reference to be changed to QML12150Q or something

ML121500  (order id 500)
ML121501  (order id 501)
ML12150Q (order id 502)
ML121503 (order id 503)

Can you help me with that? 

So I made an assumption that I should not have made and did not ask... What version of Prestashop are you running?
 

The Technical Concepts:
The Reference Number in the ps_orders table is NOT unique (see screencap below) and so duplicates would only stop an order from processing if the selected payment provider is being fed the Reference Number from the 'ps_orders' table and said provider requires that value to be UNIQUE. (This could possibly be addressed in the payment module.) Having said that, in order to replicate your issue, I believe one would have to have two browsers open and submit both orders at EXACTLY the same time. The solution requested to append a letter and disturb the natural sequential interval would not be acceptable to me, nor would I expect it to be for most other larger store owners.

So at first glance, to fix the level of problem you explain, one would likely have to write a substantially more complex override that would actually store the order, grab the value in the 'order_id' field of the ps_orders table (since that IS a UNIQUE value), then return a prepended string of that value storing it in the 'reference' field and THEN allowing the process to continue within the Prestashop order flow. On second thought, THIS could (possibly) be accomplished with an override to the PaymentModule.php class, but the public function validateOrder is complex enough that I'm a little concerned with this approach given Prestashop's history with code patching, etc. With that in mind, I'll work to add a new override in a followup post with the changes needed to insure the reference number is as unique as the order_id.

So the short answer is - off the top of my head - there is no simple solution to your dilemma other than to address the apparent latency issues or write a different override.

Sorry!

image.png.103050b542fc1e1ef6a019bfe89cc9fa.png

Edited by obewanz
updated with possible option (see edit history)

Share this post


Link to post
Share on other sites

Thank you obewanz, instead of the Order ID, I changed SQL query to slightly improve your code, now it is counting the total orders of the current year. So it is a string like RO-2019/000001 and so on.

 

<?php
class Order extends OrderCore
{
  public static function generateReference()
  {
    $last_id = Db::getInstance()->getValue("SELECT count(`id_order`) FROM `ps_orders` WHERE `date_add` > '" . date('Y') . "-01-01'");
    $next_id = (int)$last_id + 1;

    return "RO-".date('Y')."/".str_pad($next_id, 6, '0', STR_PAD_LEFT);
  }

}

 

Share this post


Link to post
Share on other sites
Posted (edited)
16 hours ago, zod said:

Thank you obewanz, instead of the Order ID, I changed SQL query to slightly improve your code, now it is counting the total orders of the current year. So it is a string like RO-2019/000001 and so on.

 


<?php
class Order extends OrderCore
{
  public static function generateReference()
  {
    $last_id = Db::getInstance()->getValue("SELECT count(`id_order`) FROM `ps_orders` WHERE `date_add` > '" . date('Y') . "-01-01'");
    $next_id = (int)$last_id + 1;

    return "RO-".date('Y')."/".str_pad($next_id, 6, '0', STR_PAD_LEFT);
  }

}

Interesting take, I had thought of doing something similar, especially using count() instead of max(), but haven't really revisted the override since its original writing, until lately anyway. Did you by chance change the field length of the "reference" column in the table as well?

I have (finally) provided a new override to folkifoon to test to see if it fixes his problem. It modifies the paymentModuleCore so the value gets created and inserted during the validation part of the process, this is the only place I could find to make certain the reference number would be unique no matter what since it relies on the autonumber value created in the database for the sequential value.

4
5
3

 

Edited by obewanz (see edit history)

Share this post


Link to post
Share on other sites
Posted (edited)

Yes, i forgot to tell you i had to change the reference field lenght in database (from 9 to 16). 
The field is "reference" in table "orders" and "order_reference" in table "order_payment".

In addition it is required another file: override/classes/order/OrdperPayment.php
with following code

<?php
class OrderPayment extends OrderPaymentCore
{

  public function __construct($id = null, $id_lang = null, $id_shop = null)
  {
      self::$definition['fields']['order_reference']['size'] = 16;
      parent::__construct($id, $id_lang, $id_shop);
  }

}

 

Edited by zod
More details and additional code (see edit history)

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.

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