Adding order with order item - cruds of order

Step 01: Adding add button just above of table element in list of products

<div class="row">
	<div class="col-md-4">
		<h2 class="">All Orders</h2>
	</div>
	<div class="col-md-8 pt-1">
		<a class="btn btn-sm btn-primary float-end" href="{{ route('orders.create') }}"> Add Order</a>
	</div>             
</div> 

Step 02: In OrderController, adding create() method

// at the top 
use App\Models\FrameWidth;
use App\Models\Product;
use App\Models\Profile;

public function create( Request $request ) {
	$meta_title = 'Add Order';

	$products  = Product::orderBy( 'sequence', 'asc' )->get(); 
	$profilers = Profile::orderBy( 'sequence', 'asc' )->get(); 
	$fwidths = FrameWidth::orderBy( 'sequence', 'asc' )->get();

	return view( 'orders.create', compact( 'meta_title', 'products', 'profilers', 'fwidths' ) );
}

Step 03: Adding create.blade.php under resources/view/orders folder and putting following snippet inside blade section directive extending app layout

<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
        <h2 class="float-start">Add Order</h2>
        <div class="float-end">
            <a class="btn btn-sm btn-primary" href="{{ route('orders.index') }}"> Back to orders</a>
        </div>
        <div class="clearfix"></div>
        <div class="card ">
            <div class="card-body">
            <form method="post" action="{{ route('orders.store') }}" id="orderCrfrm" method="post"> 
                @csrf 
                <input type="hidden" name="url_process_cost" value="{{ url('').'/order_items/cal_cost' }}" />              
                <div class="form-group mb-2">                
                    <label for="title">Company Name &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="company_name" class="form-control" placeholder="company name" title="company name" type="text" id="company_name" value="{{ old('company_name') }}" /> 
                    @if ($errors->has('company_name')) 
                        <span class="text-danger">{{ $errors->first('company_name') }}</span> 
                    @endif
                </div>
                <div class="form-group mb-2">                
                    <label for="title">Phone Number &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="phone_number" class="form-control" placeholder="phone number" title="phone number" type="text" id="phone_number" value="{{ old('phone_number') }}" /> 
                    @if ($errors->has('phone_number')) 
                        <span class="text-danger">{{ $errors->first('phone_number') }}</span> 
                    @endif
                </div>
                <div class="form-group mb-2">                
                    <label for="title">Email &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="email" class="form-control" placeholder="email" title="email" type="text" id="email" value="{{ old('email') }}" /> 
                    @if ($errors->has('email')) 
                        <span class="text-danger">{{ $errors->first('email') }}</span> 
                    @endif
                </div>
                <div class="form-group mb-2">                
                    <label for="title">Job / PO Number &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="job_number" class="form-control" placeholder="job number" title="job number" type="text" id="job_number" value="{{ old('job_number') }}" /> 
                    @if ($errors->has('job_number')) 
                        <span class="text-danger">{{ $errors->first('job_number') }}</span> 
                    @endif
                </div>
                <div class="form-group mb-2">                
                    <label for="title">Choose Product &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <select name="product" class="form-control product-select2 ">
                        <option value="">--</option>
                        @foreach ($products as $product)
                            @php
                                $selected = $product->id == old('product') ? 'selected' : '';
                            @endphp
                            <option value="{{ $product->id }}" {{ $selected }}>{{ $product->name }} -
                                ${{ number_format($product->cost, 2) }} / sf</option>
                        @endforeach
                    </select>
                    @if ($errors->has('product'))
                        <span class="text-danger">{{ $errors->first('product') }}</span>
                    @endif
                </div>   
                <div class="form-group mb-2">                
                    <label for="title">Choose Profile &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <select name="profile_id" class="form-control">
                        <option value="">--</option>
                        @foreach ($profilers as $profiler)
                            @php
                                $selected = $profiler->id == old('profile_id') ? 'selected' : '';
                            @endphp
                            <option value="{{ $profiler->id }}" {{ $selected }}>{{ $profiler->name }} </option>
                        @endforeach
                    </select>
                    @if ($errors->has('profile_id'))
                        <span class="text-danger">{{ $errors->first('profile_id') }}</span>
                    @endif
                </div>  
                <div class="form-group mb-2">                
                    <label for="title">Frame Width &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <select name="frame_width" class="form-control">
                        <option value="">--</option>
                        @foreach ($fwidths as $frame_width)
                            @php
                                $selected = $frame_width->id == old('frame_width') ? 'selected' : '';
                            @endphp
                            <option value="{{ $frame_width->id }}" {{ $selected }}>{{ $frame_width->name }} </option>
                        @endforeach
                    </select>
                    @if ($errors->has('frame_width'))
                        <span class="text-danger">{{ $errors->first('frame_width') }}</span>
                    @endif
                </div>   
                <div class="form-group mb-2">                
                    <label for="title">Width ( In Inches )&nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="width" class="form-control" placeholder="width" title="width" type="text" id="width" value="{{ old('width') }}" /> 
                    @if ($errors->has('width')) 
                        <span class="text-danger">{{ $errors->first('width') }}</span> 
                    @endif
                </div> 
                <div class="form-group mb-2">                
                    <label for="title">Height ( In Inches )&nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="height" class="form-control" placeholder="height" title="height" type="text" id="height" value="{{ old('height') }}" /> 
                    @if ($errors->has('height')) 
                        <span class="text-danger">{{ $errors->first('height') }}</span> 
                    @endif
                </div>                         
                <div class="form-group mb-2">                
                    <label for="title">Total Square Feet </label>
                    <br>
                    <input name="total_square_feet" class="form-control" style="background-color:darkgray;" placeholder="total square feet" title="total square feet" type="text" readonly  /> 
                </div>       
                <div class="form-group mb-2">                
                    <label for="title">Quantity &nbsp;<span class="text-danger">*</span></label>
                    <br>
                    <input name="quantity" class="form-control" placeholder="quantity" title="quantity" type="text" id="quantity" value="{{ old('quantity') }}" /> 
                    @if ($errors->has('quantity')) 
                        <span class="text-danger">{{ $errors->first('quantity') }}</span> 
                    @endif
                </div> 
                <div class="form-group mb-2">                
                    <label for="title">Cost </label>
                    <br>
                    <input name="product_cost" class="form-control" style="background-color:darkgray;" placeholder="cost" title="cost" type="text" readonly  /> 
                </div>    
                <div class="form-group mb-2">                
                    <label for="title">Additional Request</label>
                    <br>
                    <textarea class="form-control" rows="3" name="additional_request" placeholder="Additional Request"></textarea>
                </div>                                                                                                                                                                               
                <input class="btn btn-sm btn-primary" class="form-control" type="submit" name="action" value="Add to Cart">
            </form>
            </div>
        </div>
        </div>
    </div>
</div>

Please note, we will populate total_square_feet form input value with js calculation as well which will be width multiplied by height and this result will be again divided by 144.
Additionally, we will also be using form input value such as product, frame width, width, height and quantity in Javascript code so that we can calculate the cost of product based on these values using ajax call method in the server taking url_process_cost and token value of form input value. We will be laying out js code of this in following.

Step 04: Creating js file process.js under resources/js/orders folder for frontend code processing with javascript and jquery during order creation

const order = {
    create : () => {
          
        $('.product-select2').select2(); // populating select dropdown with auto suggestion while typing

        $('input[name="height"],input[name="width"]').change(function() {
            calculateSqFeet();
        });

        function calculateSqFeet() {
            let width = $('input[name=width]').val();
            let height = $('input[name=height]').val();
            if ((width != '') && (height != '')) {
                let tsf = (width * height) / 144;
                $('input[name=total_square_feet]').val(tsf.toFixed(2));
            }
        }

        /////////////////////////////////////  

        $('input[name="quantity"],select[name="frame_width"],select[name="product"]').change(function() {
            calculateCost();
        });

        function calculateCost() {
            let csrf_token = $('#orderCrfrm').find('input[name=_token]').val();
            let calCostUrl = $('#orderCrfrm').find('input[name=url_process_cost]').val();
            let quantity = $('input[name=quantity]').val();
            let fwidth = $('select[name=frame_width]').val();
            let total_square_feet = $('input[name=total_square_feet]').val();
            let productId = $('select[name=product]').val();

            if ((quantity != '') && (fwidth != '') &&
                (total_square_feet != '') && (productId != '')
            ) {
                $.ajax({
                    headers: {
                        'X-CSRF-TOKEN': ''+ csrf_token +''
                    },
                    url: ""+ calCostUrl +"",
                    method: "POST",
                    data: {
                        quantity: quantity,
                        total_square_feet: total_square_feet,
                        productId: productId,
                        fwidth: fwidth
                    },
                    success: function(data) {
                        $('input[name=product_cost]').val(data);
                    }
                });
            }
        }

        ////////////////////////////////////////////////////////////        
    }
}

export default order;

Please note above that we have not created order_items/cal_cost yet which we will be creating in later posts. For the time being when ajax call is made with this url an error will be shown in ajax response.

Step 05: Now importing process.js back in app.js and using relevant order method

window.bootstrap = require('bootstrap/dist/js/bootstrap.bundle.js');
window.$ = window.jQuery = require('jquery'); 
window.select2 = require('select2');


import bsModel from './utilities/modal';
import ordering from './utilities/ordering';
import order from './orders/process';


bsModel.delete();

ordering.change();

order.create();

Step 06: We always need to run npm run watch for watching our changes. Change upto this point will throw error suggesting install select2 plugin. We can do it by following npm command

npm install select2

Step 07: We also need to add select2 css files for the project and it can done with following changes in resources/sass/app.scss. Now build will show these changes successful

@import "~select2/src/scss/core";

Step 08: Changing Order.php model

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    use HasFactory;

    protected $fillable = [
        'company_name', 'phone_number', 'job_number', 'email', 'status'
    ];
    

    public function order_items() {
        return $this->hasMany( OrderItem::class );
    }      
}

Step 09: Changing OrderItem.php model

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class OrderItem extends Model
{
    use HasFactory;

    protected $fillable = [
        'order_id', 'product_id', 'profile_id', 'frame_width_id' ,'width', 'height', 'total_square_feet', 'quantity', 'cost', 'additional_request'
    ];

    public function order() {
        return $this->belongsTo( Order::class );
    } 
    
    public function product() {
        return $this->belongsTo( Product::class );
    }    

    public function calculateTotSqFeet( $width, $height ) {
        return number_format(( $width * $height )/144,2);
    }

}

Step 10: Back in OrderController adding store() method like below for saving order and order items and redirecting to orders list page after addition

// at the top 
use App\Models\Order;
use App\Models\OrderItem;

public function store( Request $request ) {

	$request->validate( ['company_name' => 'required', 'phone_number' => 'required', 'email'    => 'required', 'job_number' => 'required', 'product' => 'required', 'profile_id' => 'required',
								'width'  => 'required', 'height'       => 'required', 'quantity' => 'required', 'frame_width' => 'required'] );

	
	$order = Order::create([
		'company_name' => $request->company_name,
		'phone_number' => $request->phone_number,
		'job_number' => $request->job_number,
		'email' => $request->email,
		'status' => 0,
	]);    

	$item = new OrderItem();
	$item->create([
		'order_id' => $order->id,
		'product_id' => $request->post( 'product' ),
		'profile_id' => $request->post( 'profile_id' ),
		'frame_width_id' => $request->post( 'frame_width' ),
		'width' => $request->post( 'width' ),
		'height' => $request->post( 'height' ),
		'total_square_feet' => $item->calculateTotSqFeet( $request->post( 'width' ), $request->post( 'height' ) ),
		'quantity' => $request->post( 'quantity' ),
		'cost' => Product::where('id',$request->post( 'product' ))->first()->cost,
		'additional_request' => $request->post( 'additional_request' ),
	]);         

	return redirect()->route( 'orders.index' )->with( 'success', 'Item added to Cart successfully.' );
} 

Related Posts


Building mini ecommerce in Laravel

Listing rows of users - crud

Adding user data - crud of users

Editing user data - crud of users

Deleting user data - crud of users

Listing rows of products - crud

Listing rows of profiles - crud

Listing rows of orders - crud

Listing rows of order items - crud