2

I am working on a sales laravelcollective form whereby the sale_quantity entered should not be more than the stock_quantity in DB. When I use the idea at: Laravel validate dynamically added input with custom messages there is one answer with:

'orderQty.*' => 'required|numeric|min:1|max:'.$product['productQty']

I have done this as you will see in my function store and function update in the SalesController.php, no error occurs but the form refuses to submit and shows this as a flash message:

The sale quantity may not be greater than '.$stocks['stock_quantity'].

It does not mean what it shows because their is a greater stock_quantity in the database.

SalesController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use App\Sale;
use App\Stock;

class SalesController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    function __construct()
    {
        $this->middleware('permission:sales-list');
        $this->middleware('permission:sales-create', ['only' => ['create', 'store']]);
        $this->middleware('permission:sales-edit', ['only' => ['edit', 'update']]);
        $this->middleware('permission:sales-delete', ['only' => ['destroy']]);
}

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $sales = Sale::orderBy('updated_at', 'desc')->get();
    return view('sales.index')->with('sales', $sales);
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
    $stocks = Stock::all();
    //dd($stocks);
    return view('sales.create', compact('stocks'));
    //$sales = Sale::pluck('stock_id')->prepend('stock_id');
    //$sales = DB::table('stocks')->select('stock_id')->get();
    //return view('sales.create')->with('sales',$sales);
}

public function getUnitSellingPrice(Request $request, $stock_name)
{

    $stock = Stock::where('stock_name', $stock_name)->first();
    if ($stock == null) {
        return null;
    }

    return response()->json($stock->unit_selling_price);
}

public function store(Request $request)
{
    $this->validate($request, [
        'stock_name' => 'required',
        'sale_quantity' => 'required|numeric|min:1|max:\'.$stock[\'stock_quantity\']',
        'unit_selling_price' => 'required',
        'total_sales_cost' => 'required'
    ]);

    //create stock
    $sale = new Sale;
    $sale->stock_name = $request->input('stock_name');
    $sale->sale_quantity = $request->input('sale_quantity');
    $sale->unit_selling_price = $request->input('unit_selling_price');
    $sale->total_sales_cost = $request->input('total_sales_cost');
    $sale->save();
    DB::table('stocks')->where('stock_name', $request->input('stock_name'))->decrement('stock_quantity', $request->input('sale_quantity'));

    return redirect('/sales')->with('success', 'Sale Saved');
}


public function show($sales_id)
{
    $sale = Sale::find($sales_id);
    return view('sales.show')->with('sale', $sale);
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  int $sales_id
 * @return \Illuminate\Http\Response
 */
public function edit($sales_id)
{
    $sale = Sale::findOrFail($sales_id);
    $stocks = Stock::latest('stock_name', 'unit_selling_price')->get();
    return view('sales.edit', compact('sale', 'stocks'));
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request $request
 * @param  int $sales_id
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, $sales_id)
{
    $this->validate($request, [
        'stock_name' => 'required',
        'sale_quantity' => 'required|numeric|min:1|max:\'.$stock[\'stock_quantity\']',
        'unit_selling_price' => 'required',
        'total_sales_cost' => 'required'

    ]);

    //create stock
    $sale = Sale::find($sales_id);
    $sale->stock_name = $request->input('stock_name');
    $sale->sale_quantity = $request->input('sale_quantity');
    $sale->unit_selling_price = $request->input('unit_selling_price');
    $sale->total_sales_cost = $request->input('total_sales_cost');
    $sale->save();

    return redirect('/sales')->with('success', 'Sale Updated');
}

/**
 * Remove the specified resource from storage.
 *
 * @param  int $sales_id
 * @return \Illuminate\Http\Response
 */
public function destroy($sales_id)
{
    $sale = Sale::find($sales_id);
    $sale->delete();
    return redirect('/sales')->with('success', 'Sale Removed');
}
}

create.blade.php

@extends('layouts.app')

@section('content')
    <br>
    <h1>Add Sale</h1>
    {!! Form::open(['action' => 'SalesController@store', 'method' => 'POST', 'enctype' => 'multipart/form-data']) !!}

<div class="form-group">
    <label>Product Name</label>
    <select name="stock_name" id="stock_name" class="form-control">
        @foreach ($stocks as $stock)
            <option value="{{ $stock->stock_name }}">{{ $stock->stock_name}}</option>
        @endforeach
    </select>
</div>

<div class="form-group">
    {{Form::label('sale_quantity', 'Quantity')}}
    {{Form::text('sale_quantity', '', ['class' => 'form-control', 'placeholder' => 'Quantity', 'id' => 'sales_quantity'])}}
</div>

<div class="form-group">
    {{Form::label('unit_selling_price', 'Unit Selling Price')}}
    {{Form::text('unit_selling_price', '', ['class' => 'form-control', 'placeholder' => 'Unit Selling Price', 'id' => 'unit_selling_price'])}}
</div>

<div class="form-group">
    {{Form::label('total_sales_cost', 'Total Sales Cost')}}
    {{Form::text('total_sales_cost', '', ['class' => 'form-control', 'placeholder' => 'Total Sales Cost', 'id' => 'total_sales_cost', 'readonly' => 'true', 'cursor: pointer' => 'true' ])}}
</div>

{{Form::submit('Submit', ['class' => 'btn btn-primary'])}}
{!! Form::close() !!}

<script>
    $(document).ready(function () {
        $("#stock_name").on('change', function () {
            var stock_name = $(this).val();
            $.ajax({
                url: '/sales-price/getunitsellingprice/'+stock_name,
                method: 'GET',
                success: function (response) {
                    console.log(response);
                    $("#unit_selling_price").val(response);
                },
            });
        });
    });
</script>


<script>
    $(document).ready(function () {
        $("#total_sales_cost").click(function () {
            var sales_quantity = $("#sales_quantity").val();

            var unit_selling_price = $("#unit_selling_price").val();
            var total_sales_cost = (sales_quantity * unit_selling_price);

            $('#total_sales_cost').val(total_sales_cost);
        });
    });
</script>
@endsection
Salim Djerbouh
  • 10,719
  • 6
  • 29
  • 61
Charleskimani
  • 440
  • 7
  • 25
  • Possible duplicate of [laravel validation rule max:value not working with variables](https://stackoverflow.com/questions/31703964/laravel-validation-rule-maxvalue-not-working-with-variables) – Salim Djerbouh Oct 05 '19 at 15:00
  • Can you just dd($stock) before the validation and let me know, if you are able to access it and if it is an array or collection or an object? – Prafulla Kumar Sahu Oct 05 '19 at 15:46
  • when i dd($stock) like shown in the link nothing happens when i run the views. Here: https://slack-files.com/TP02E38GN-FP2TWDPV2-f96e94e9dc @PrafullaKumarSahu – Charleskimani Oct 06 '19 at 12:59
  • Are you trying to say, you are unable to access $stock here? – Prafulla Kumar Sahu Oct 06 '19 at 14:04
  • yes @PrafullaKumarSahu – Charleskimani Oct 09 '19 at 08:04
  • Can you specify the url you are posting to? – Prafulla Kumar Sahu Oct 09 '19 at 08:08
  • I can't undersdant what you mean clearly but here is what I think you are trying to say: Browser url: localhost:8000/sales/create Route: Route::resource('sales', 'SalesController'); Thanks in advance I hope we will crack this. @PrafullaKumarSahu – Charleskimani Oct 15 '19 at 06:52
  • @Charleskimani now in your url, you are not specifying `$stock`, that is why you are unable to access it, you can retrieve `$stock` from the data you have in that method and then use your validation rule. – Prafulla Kumar Sahu Oct 15 '19 at 07:01

2 Answers2

1

SalesController.php changes at function store and update. Those are the only changes, the blade was Okay.

<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use App\Sale;
use DB;
use App\Stock;

class SalesController extends Controller
{
    function __construct()
    {
        $this->middleware('permission:sales-list');
        $this->middleware('permission:sales-create', ['only' => ['create', 'store']]);
        $this->middleware('permission:sales-edit', ['only' => ['edit', 'update']]);
        $this->middleware('permission:sales-delete', ['only' => ['destroy']]);
    }
    public function index()
    {
        $sales = Sale::orderBy('updated_at', 'desc')->get();
        return view('sales.index')->with('sales', $sales);
    }

    public function create()
    {
        $stocks = Stock::all();
        //dd($stocks);
        return view('sales.create', compact('stocks'));
        //$sales = Sale::pluck('stock_id')->prepend('stock_id');
        //$sales = DB::table('stocks')->select('stock_id')->get();
        //return view('sales.create')->with('sales',$sales);
    }

    public function getUnitSellingPrice(Request $request, $stock_name)
    {
        $stock = Stock::where('stock_name', $stock_name)->first();
        if ($stock == null) {
            return null;
        }
        return response()->json($stock->unit_selling_price);
    }

    public function getStockUnitCost(Request $request, $stock_name)
    {
        $stock = Stock::where('stock_name', $stock_name)->first();
        if ($stock == null) {
            return null;
        }
        return response()->json($stock->stock_unit_cost);
    }

    public function salesWebReport(){
        $sales = Sale::orderBy('updated_at', 'desc')->get();
        return view('sales.saleswebreport')->with('sales', $sales);
    }

    public function photocopying(){
        $stocks = Stock::all();
        //dd($stocks);
        return view('sales.photocopy', compact('stocks'));
    }

    public function store(Request $request)
    {
        //get retrieves an array
        //$stock = \App\Stock::where('stock_name', $request->input('stock_name'))->get();

        //first retrieves an array BUT removes everything and produces only the required field value
        $stock = Stock::where('stock_name', $request->input('stock_name'))->firstOrFail();
        $qty = $stock->stock_quantity;

        $this->validate($request, [
            'stock_name' => 'required',
            'sale_quantity' => 'required|numeric|min:1|max:'.$qty,
            'unit_selling_price' => 'required',
            'total_sales_cost' => 'required',
            'stock_profit' => 'required'
        ]);
        //create stock
        $sale = new Sale;
        $sale->stock_name = $request->input('stock_name');
        $sale->sale_quantity = $request->input('sale_quantity');
        $sale->unit_selling_price = $request->input('unit_selling_price');
        $sale->total_sales_cost = $request->input('total_sales_cost');
    $sale->stock_profit = $request->input('stock_profit');
    $sale->save();
    DB::table('stocks')->where('stock_name', $request->input('stock_name'))->decrement('stock_quantity', $request->input('sale_quantity'));

    return redirect('/sales')->with('success', 'Sale Saved');
}

public function show($sales_id)
{
    $sale = Sale::find($sales_id);
    return view('sales.show')->with('sale', $sale);
}

public function edit($sales_id)
{
    $sale = Sale::findOrFail($sales_id);
    $stocks = Stock::latest('stock_name', 'unit_selling_price')->get();
    return view('sales.edit', compact('sale', 'stocks'));
}
public function update(Request $request, $sales_id)
{
    //get retrieves an array
    //$stock = \App\Stock::where('stock_name', $request->input('stock_name'))->get();

    //first retrieves an array BUT removes everything and produces only the required field value
    $stock = Stock::where('stock_name', $request->input('stock_name'))->firstOrFail();
    $qty = $stock->stock_quantity;

    $this->validate($request, [
        'stock_name' => 'required',
        'sale_quantity' => 'required|numeric|min:1|max:'.$qty,
        'unit_selling_price' => 'required',
        'total_sales_cost' => 'required',
        'stock_profit' => 'required'
    ]);
    //create stock
    $sale = Sale::find($sales_id);
    $sale->stock_name = $request->input('stock_name');
    $sale->sale_quantity = $request->input('sale_quantity');
    $sale->unit_selling_price = $request->input('unit_selling_price');
    $sale->total_sales_cost = $request->input('total_sales_cost');
    $sale->stock_profit = $request->input('stock_profit');
    $sale->save();

    return redirect('/sales')->with('success', 'Sale Updated');
}

public function destroy($sales_id)
{
    $sale = Sale::find($sales_id);
    $sale->delete();
    return redirect('/sales')->with('success', 'Sale Removed');
}
}
Charleskimani
  • 440
  • 7
  • 25
0

According to the error shown, it may be that it is taking your variable and array data as a literal string in this line:

'sale_quantity' => 'required|numeric|min:1|max:\'.$stock[\'stock_quantity\']',

Give a try with php double quotes:

'sale_quantity' => "required|numeric|min:1|max:$stock['stock_quantity']",

Or, to make it even easier for the interpreter, assign a simple variable before the validation step:

 $qty = $stock['stock_quantity'];

and then in the validator:

'sale_quantity' => "required|numeric|min:1|max:$qty",

You may wish to consider using some type of validation on the client side to make this even stronger as well as to help users. Perhaps pass that $qty value from your edit/create methods on your controller to the blade page, and then use something like JQuery Validation to check on the form before the user even submits it to the server.

So - to solve it, something like this:

public function store(Request $request)
{
  $stock = \App\Stock::find($someIdOfYourChoiceOrFromTheForm)
  $qty = $stock->stock_quantity;

  $this->validate($request, [
    'stock_name' => 'required',
    'sale_quantity' => "required|numeric|min:1|max:$qty",
    'unit_selling_price' => 'required',
    'total_sales_cost' => 'required'
   ]);
Watercayman
  • 7,970
  • 10
  • 31
  • 49
  • You didn't use the code I wrote. You just changed the quotes. Look at how I've written it above - there are no single quotes. But, your issue is much bigger if you haven't defined the quantity before the validator - write a line above the validator to call to the database to get that `$qty` - or, follow along with what I said in the last paragraph and query for `$qty` *before* you create the form. – Watercayman Oct 05 '19 at 15:27
  • Yep - before you verify, query the database for that stock. Define it as a variable above the verification, and then you can use it (or the `$qty` thing I wrote) in your validation. You can also do the same in your edit/create methods and send to the blade page as I noted - that will allow for client side validation too. – Watercayman Oct 05 '19 at 15:46
  • Do you have any stocks in your database? If so, did you query for the `ID` for that stock? There is really no way that this would fail unless you have queried on the wrong id. That non-object error tells me that you don't have any stocks in the database, in which case you need to add a default value for `stock_quantity` in case there is no stock available. OR, is there no model **Stock**? If so, you need to at least have your models complete before trying to write a method in Laravel. Further - your image shows you queried on `'$stock_quantity'`. That's a string. That will never work. – Watercayman Oct 06 '19 at 15:14
  • If you have a working **Stock** model and you are able to get a stock model in other things - use the same code to get the stock object in the start of this method and use it to get the `$qty` as I showed above. This is just basic DB query - I don't understand why this isn't working for you if it works in other places. Copy the exact code from those other places and get your model. Then everything will work for you. – Watercayman Oct 06 '19 at 18:00
  • I have tried to add $stock_id in the areas I have indicated in the 2 pics : https://slack-files.com/TP02E38GN-FNXGN1S0H-142933afa1 https://slack-files.com/TP02E38GN-FP664JMJS-3d6b3283d9 You can check the controller file here: https://slack-files.com/TP02E38GN-FNSGKGZPV-43877e41da This is the error I am getting: Too few arguments to function App\Http\Controllers\SalesController::store(), 1 passed and exactly 2 expected Check pic here: https://slack-files.com/TP02E38GN-FP420UP40-bb74405a69 – Charleskimani Oct 07 '19 at 11:07