0

i want to make code with 4 digit auto increment integer and current date format MMMyy that has to use carbon. Example: Oct22-0001, Set22-0002, Dec22-0003.

table producs

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('nama_barang');
        $table->string('kode', 10);
        $table->double('harga');
        $table->integer('jumlah');
        $table->timestamps();
    });
}

ProductController

public function store(Request $request) 
{
    $storeData = $request->all();
    $validate = Validator::make($storeData, [
        'nama_barang' => 'required|max:60|unique:products',
        'harga' => 'required|numeric',
        'jumlah' => 'required|numeric'
    ]);

    $lastValue = Product::orderBy('kode', 'desc')->first();
    $storeData = new Product();
    $date = Carbon::now();
    $storeData->kode = $date . '-' . str_pad($lastValue->kode, 4, '0', STR_PAD_LEFT) + 1;

    if($validate->fails())
        return response(['message' => $validate->errors()], 400);

    $product = Product::create($storeData); 
    return response([
        'message' => 'Add product Success',
        'data' => $product
    ], 200);
}

i got error

"message": "Illuminate\Database\Eloquent\Builder::create(): Argument #1 ($attributes) must be of type array, App\Models\Product given, called in C:\Users\nana\test\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php on line 23",

2
  • 1
    the error seems unrelated to your "increment" problem. it specifies that you need to pass an array instead of Product. if you already have an instance of Product, you might want to call ->save() on the instance instead. see docs. Commented Oct 31, 2022 at 13:16
  • also, $lastValue risks having race condition. you should use transaction to ensure no duplicates. though, if you set that kode column as unique you can handle the exception thrown should the kode already used. Commented Oct 31, 2022 at 13:21

1 Answer 1

1

There is a lot wrong in your code. Like already mentioned in the comments, you are trying to create a new Product by throwing an existing product model instance into the create method which causes the exception you're seeing.

This is bad enough, but there are other issues in your code as well.

Here is my quick (untested) refactoring:

public function store(Request $request) 

    $validated = $request->validate([
        'nama_barang' => 'required|max:60|unique:products',
        'harga' => 'required|numeric',
        'jumlah' => 'required|numeric'
    ]);


    $date = now()->format('dy');

    DB::beginTransaction();

    $lastValue = Product::where('kode', 'like', "$date%")
        ->orderBy('kode', 'desc')
        ->first('kode');

    if ($lastValue) {
        $counter = (int)\Str::after($lastValue->kode, '-') + 1;

        $newKode = $date . '-' . str_pad($counter, 4, '0', STR_PAD_LEFT));
    } else {
      $newKode = "{$date}-0001";
    }

    $productData = $validated + ['kode' => $newKode];

    $product = Product::create($productData);

    DB::commit();

    return response([
        'message' => 'Add product Success',
        'data' => $product
    ], 200);
});

Explanation: If you're using the validate method of the request, you don't have to explicitly return any errors, Laravel will do that automatically.
To get the proper format for the date like you mentioned in your example, you have to call the format method including the proper parameters. I always google what letters to use there, this time I found it here :)

I wrapped the database stuff into a transaction to try to prevent the aforementioned race conditions. Not sure if that is enough, but maybe it helps.

Then it's important to filter the products by the current month/year combination first before sorting them, otherwise it would always sort by the month first and then by the year, which would not be very helpful.

for the generation of the code I used the string helper class to get only the "interesting" part of the "kode", converted it to an integer and then directly incremented it by one. In your version you were trying to add one to a string, for which I actually don't know what would be the result there.

Then the actual product data ist created by merging the validated information from the request with the newly created "kode".

As I said; This is untested, but it should hopefully help you with your task.
I actually think that there is way too much happening in this controller and I would suggest to look how to fix this by moving the code into different places. For starters, you could look into form request validation.

Sign up to request clarification or add additional context in comments.

2 Comments

it said "Attempt to read property \"kode\" on null" on line "$counter = (int)\Str::after($lastValue->kode, '-') + 1;"
@BruhBrah: Yes, there was a check missing if this is the first product for the given month/year. I updated my answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.