user5838715
user5838715

Reputation:

Laravel - generate unique order number

I'm currently trying to generate a unique order number when the user reaches the create method. The order numbers are generated like this in the seed and need to look like this as well

Seed

foreach(range(1,25) as $index)
    {
        DB::table('orders')->insert([

            'user_id' => rand(1,25),
            'order_nr' => '#' . sprintf("%08d", $index),
            'price_sum' => $faker->randomNumber($nbDigits = 4, $strict = false) . '.' . $faker->randomNumber($nbDigits = 2, $strict = false),
            'status' => $faker->randomElement(['paid', 'pending', 'failed']),
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),

        ]);
    }

The order numbers look like this #00000001 or #00000002. Now when the user reaches the create method in my controller a new unique order number in this sequence needs to be created. How can I achieve that? The controller currently looks like this:

 public function create()
{
    $order = new Order;

    $order->user_id = Auth()->id();
    $order->order_nr = 


    dd($order);


    return view('steps.order');
}

It needs to check the latest order number and create one with +1 on that order number. Say for instance there are 25 orders and the last one is #00000025 the one that needs to be created next needs to be #00000026. How can I achieve that?

Upvotes: 6

Views: 40693

Answers (6)

Harun
Harun

Reputation: 1247

You can use the Laravel ID generator.

First Install it: composer require haruncpi/laravel-id-generator

Import the class in your controller.

use Haruncpi\LaravelIdGenerator\IdGenerator;

Now simply use it

$prefix = "#";  
$id = IdGenerator::generate(['table' => 'your_table_name', 'length' => 9, 'prefix' =>$prefix]);

Output

#00000001
#00000002
#00000003
...

Upvotes: 5

Mahoor13
Mahoor13

Reputation: 5617

There is a problem in reading the maximum id and increment it. In heavy servers or parallel requests, two requests may read the same max(id) from MySQL.

The best way to create unique sequence number is use a sequence table with just one auto increment field.

  1. First insert new record in the sequence table.
  2. Then read the last inserted id from db by LAST_INSERT_ID() MySQL function.
  3. At last you can remove old records lower than your id.

Laravel way:

$id = DB::table('seq_foo')->insertGetId(['id' => null]);
DB::table('seq_foo')->where('id', '<', $id)->delete();

$id is your unique sequence number.

Upvotes: 2

Rajakishore B
Rajakishore B

Reputation: 1

I have found a better solution:

$paynowbillprefix1="ADDON-";
$paynowbillprefix1=strlen($paynowbillprefix1);
$query2 = "select gen_id from user_cart_addon order by id desc limit 0, 1";
$exec2 = mysqli_query($conn,$query2) or die ("Error in Query2".mysqli_error());
$res2 = mysqli_fetch_array($exec2);
$num2 = mysqli_num_rows($exec2);
$billnumber = $res2["gen_id"];
$billdigit=strlen($billnumber);
if ($billnumber == '')
{
    $billnumbercode ='ADDON-'.'1';
}
else
{
    $billnumber = $res2["gen_id"];
    $billnumbercode = substr($billnumber,$paynowbillprefix1, $billdigit);
    $billnumbercode = intval($billnumbercode);
    $billnumbercode = $billnumbercode + 1;
    $maxanum = $billnumbercode;   
    $billnumbercode = 'ADDON-'.$maxanum;
}

Upvotes: 0

Adam
Adam

Reputation: 29079

Use the auto column id value of your rows to generate the order number. However, do not create an extra column for your order number, because this would give you an unnormalized DB, since the order-column is completely dependent of the id column.

Instead, add this method to you order model

public function get_order_number()
{
    return '#' . str_pad($this->id, 8, "0", STR_PAD_LEFT);
}

If your last order had the id 5 and you would delete it, then the next order would have the id 6.

The only possible exception is if you create orders within an transaction. If a transaction is rolled back, the associated order id would be skipped.

Upvotes: 5

Nazmus Shakib
Nazmus Shakib

Reputation: 832

You may try with this:

public function generateOrderNR()
{
    $orderObj = \DB::table('orders')->select('order_nr')->latest('id')->first();
    if ($orderObj) {
        $orderNr = $orderObj->order_nr;
        $removed1char = substr($orderNr, 1);
        $generateOrder_nr = $stpad = '#' . str_pad($removed1char + 1, 8, "0", STR_PAD_LEFT);
    } else {
        $generateOrder_nr = '#' . str_pad(1, 8, "0", STR_PAD_LEFT);
    }
    return $generateOrder_nr;
}

You can generate order_nr by using this: $this->generateOrderNR(); in your create() function.

In addition mt_rand() is 4 times faster than rand() you may use this for better user experience.

Upvotes: 1

KalyanLahkar
KalyanLahkar

Reputation: 855

Try doing as following

$order = new Order;

$order->user_id = Auth()->id();
$latestOrder = App\Order::orderBy('created_at','DESC')->first();
$order->order_nr = '#'.str_pad($latestOrder->id + 1, 8, "0", STR_PAD_LEFT);
$order->save();

Here I am assuming that the id is auto-incrementing. See the str_pad method for more details

Upvotes: 15

Related Questions