How to get user order data by specific month in laravel? - php

I want to user orders data by specific month in a year.
Here is my order Table
id | user_id | price | quantity | total
Here is my order model
public function user() {
return $this->belongsTo(User::class);
}
Here is my user model
public function orders(){
return $this->hasMany(Order::class);
}
In a controller, by doing this I get all user orders
$user= User::with('orders')->get();
dd($user->orders);
Now, How can I get specific month user orders detail?
I want to show all user list with their order's total amount by month.

Try this to get users with their orders' total of September:
$users = User::withSum(['orders as september_total' => function ($query) {
$query->whereMonth('created_at', '9'); // September
}, 'total'])->get();
This will place a september_total attribute on your resulting models.

Take a look at these two queries:
$users = User::query()->with(['orders' => function($q){
$q->whereRaw('MONTH(orders.created_at) = 2');
}])->get();
// eager load all orders that have been created on month 2
$users = User::query()->whereHas('orders', function($q){
$q->whereRaw('MONTH(orders.created_at) = 2');
})->get();
// you'll get all users with orders on month 2 (no eager loading)
You can of course combine with (eager load) and whereHas (filter users) in order to "only get the users that have orders on month 2 AND eager load those orders".
Of course, feel free to use another column (e.g. ordered_at) or change the month if you need to.

Related

Grouping a pivot table and getting the sum of pivot values

I'm trying to generate a monthly report in Laravel Livewire
I have a many to many relationship between books and orders with a pivot value for quantity of books in the order.
This is the database designer for the 3 tables :
These are the eloquent relationships in my App\Models\ ... .php
// In Order model
public function books(){
return $this->belongsToMany(Book::class)->withPivot('quantity');
}
// In Book model
public function orders(){
return $this->belongsToMany(Order::class)->withPivot('quantity')->as('orders');
}
Code generating the monthly report data:
public function generate($month)
{
// Gets count of orders and the sum of their totals from month by their status
$this->orderReport = Order::select(DB::raw('COUNT(*) as count,SUM(total_price) as total, status'))
->whereMonth('created_at', $month)
->groupBy('status')
->get()->keyBy('status');
// Gets number of all orders from the month
$this->totalOrders = $this->orderReport->sum('count');
// Gets number of orders and total spending of 10 users with most STATUS_SUCCESSFULL orders for the month
$this->orderUserReport = Order::select(DB::raw('COUNT(*) as count,SUM(total_price) as total, user_id'))
->whereMonth('created_at', $month)
->status(Order::STATUS_SUCCESSFULL)
->groupBy('user_id')
->orderBy('count', 'DESC')
->take(10)->get()->keyBy('user_id');
// THIS IS WHERE IM STUCK
$test = Order::whereMonth('created_at', $month)->status(Order::STATUS_SUCCESSFULL)->with('books')->get();
}
I would like to get a similar result for my products as i do for orders / users. Problem is the quantity of sold products is in the pivot table connecting Books with Orders.
So precisely what I need is the pivot table grouped by book_order.book_id with sums of book_order.quantity only where book_order.order_id is in orders with STATUS_SUCCESSFULL and whereMonth($month).
How would I go about attaining that data?
I had some trouble formulating this question in my mind so if anything is unclear please feel free to comment i'll clarify.
EDIT
$orders = Order::whereMonth('created_at', $month)->status(Order::STATUS_SUCCESSFULL)->with('books')->get();
foreach($orders as $order)
{
foreach($order->books as $book){
if(empty($this->productReport[$book->id])){
$this->productReport[$book->id] = $book->pivot->quantity;
break;
}
$this->productReport[$book->id] += $book->pivot->quantity;
}
}
ksort($this->productReport);
}
This code gives me the result I need but is ugly and inefficient, any way to reproduce this result with Eloquent or Query builder?
The above image is the result from the last snippet [book_id => quantity].

How do i calculate total amount for specific id in laravel?

I have two tables invoices and invoice_items. What I want is to sum amount for each invoice id and show in my view.
Invoice Table
id
invoice_items table
id
invoice_id
amount
I want to sum amount column for specific invoice id. I am new to laravel so how do I do that with laravel eloquent.
Because you are using one-to-many.
Solution 1:
You can use with and groupBy look like this:
$invoice = Invoice::with(['invoice_items' => function($query){
$query->groupBy('invoice_id')->select('invoice_id', DB::raw('SUM(amount) AS amount_sum'));
}])->get();
Solution 2:
Or you can use leftjoin and SUM look like this:
$invoice_query = InvoiceItem::groupBy('invoice_id')->select("invoice_id", DB::raw('SUM(amount) AS amount_sum'));
Invoice::leftjoin(DB::raw("({$invoice_query->toSql()}) AS ii"), 'ii.invoice_id', '=', 'invoices.id')
->mergeBindings($invoice_query->getQuery())
->select('invoices.*', 'amount_sum')
->get();
Solution 3:
Use accessor:
In your Invoice Model:
protected $appends = ['amount_sum'];
public function getAmountSumAttribute()
{
return $this->invoice_items()->where('invoice_id', $this->id)->sum('amount');
}
SO you can just get the sum of amounts:
Invoice::all()->toJSON();
Assuming in your Invoice model has the relation of this.
public function invoice_items() [
return $this->hasMany('App\Invoice_Items', 'invoice_id');
}
In your controller, your code should look like this.
Fetch all invoices with their invoice items total amount
$invoices = Invoice::with(['invoice_items' => function($query){
$query->sum('amount');
}])->get();
return view('invoice', compact('invoices'));
Fetch specific invoice with invoice items total amount
$invoice = Invoice::with(['invoice_items' => function($query){
$query->sum('amount');
}])->find($invoice_id);
return view('invoice', compact('invoices'));
Try with this one. I think this works
$result = \DB::table('Invoice')
->join('invoice_items', 'Invoice.id',
'=','invoice_items.invoice_id')->whereIn('Invoice.id', [1, 2, 3]))->sum('invoice_items.amount');
if somewhere i am wrong try with exchanging table name.

Laravel - Displaying fields with many to many relationship according field in pivot table

I have this database structure
table users table office_user table offices
----------- ----------------- -------------
id * id * id *
full_name user_id name
office_id
joined_at
So in my project every office has many users and user can be joined to many offices in date (joined_at)
User.php model
public function offices()
{
return $this->belongsToMany('App\Office)->withPivot('joined_at');
}
Office.php model
public function users()
{
return $this->belongsToMany('App\User)->withPivot('joined_at');
}
OfficeController.php
public function show(Office $office)
{
$users = User::with(array('phones', 'offices' , function($query)
{
$query->orderBy('joined_at', 'desc');
}))->get();
return view('dashboard.offices.show', compact(['office', 'users']));
}
I need two things :
1- Get current users list for every office
2- Count of current users in every office
I already achieve this:
<h3>{{ $office->name }}</h3><span>{{ $office->users->count() }}</span>
#foreach ($office->users as $user)
<li>{{ $user->full_name }}</li>
#endforeach
But the result is not as expected it gives me all users in certain office and count of them regardless there joined date
I want the list of last joined users to this office and count of them according joined_at field in pivot table
Thank you and Sorry for my english
But the result is not as expected it gives me all users in certain office and count of them regardless there joined date
When you do $office->users->count() that is the expected behavior because you are retrieve all the associated users of every office at any time, so given that you returned all this users, the count() executed in the collection will count all of them.
Your pivot attribute is just a timestamp, so how would you reduce the number of users returned? users that joined the office today/in the last hour/in the last 15 min maybe?
If so, you can add constrains to your count() method to get the results you want.
As an example, in the following lines we are gonna constraint the associated offices that has a joined_at that belongs to today:
public function show(Office $office)
{
$users = User::with([
'phones',
'offices' => function ($offices) {
$offices->whereDate('joined_at', '>', now()->startOfDay());
},
])->get();
return view('dashboard.offices.show', compact([office, 'users']));
}
Check this section of the documentation:
Constraining Eager Loads
Sometimes you may wish to eager load a relationship, but also specify
additional query conditions for the eager loading query. Here's an
example:
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
In this example, Eloquent will only eager load posts where the post's
title column contains the word first. You may call other query
builder methods to further customize the eager loading operation:
$users = App\User::with(['posts' => function ($query) {
$query->orderBy('created_at', 'desc');
}])->get();

How to filter data from relational table in laravel

I have three table one is orders table and another is order_status table and another is status table. Purpose of order_status table is to keep a track order's events. My table has the following column.
Order table
----------------------------
id | ref_num | name | email |
-----------------------------
Order status table has
---------------------------
order_id | status_id
---------------------
My models are like this
Order model
public function orderStatus(){
return $this->hasMany(OrderStatus::class');
}
Order status model
public function detail(){
return $this->belongsTo(Status::class,'status_id','id');
}
public function order(){
return $this->belongsTo(Order::class);
}
Now i want to get all those order which are still pending.
How can i do so ?
I tried to retrive like this but it failed
$data['orders']= Order::with(['orderStatus' =>function($q){
$q->with('detail')->latest()->where('status_id',2);
}])->latest()->take(10)->get()->toArray();
This return only one after that it does not.
Can anyone please tell me how can i sort this one ??
Thanks
PS:: one order can have multiple status such as unpaid, pending, packageging, in transit and so on but in sequence ofcouse
I added order status table image.. As u can see E7E7FF0EB7 order number has two records 1,and 2 means it was pending and then later stage got delivered.or you can say got processed. where as E02EAEA4BE has only one record of status 1. which means it is still pending.
So i want to get only those which are still pending.Not delivered.
This kinda sound complicated, hope i able to explain properly what i am trying to do.
Your model relations should be changed to a proper many to many. The schemas look correct so I'd make the following changes:
// Order model
public function statuses(){
return $this->belongsToMany(Status::class);
}
// Status model
public function orders(){
return $this->belongsToMany(Order::class);
}
This will pivot correctly on order_status.
To get pending orders the query would be:
Order::whereHas('statuses', function ($query) {
// assuming a 'name' column on statuses table
$query->where('name', 'pending');
// or using dynamic where
// $query->whereName('pending');
})->get();
Alternatively, add a scope to Order model:
public function scopePending($query) {
return $query->with(['statuses' => function ($query) {
$query->where('name', 'pending');
});
});
Usable then as: Order::pending();
Update
Try this to get all those order which are still pending..
$data['orders'] = Order::has('orderStatus', '=', 2)->whereHas('orderStatus', function ($q) {
$q->where('status_id', 2);
})->get()->toArray();
If there is two status records related to one order and one of the status value is 1 then this query will return the order record. You may update it with your exact conditions.(If you are sure that there will be only 2 status related to a order which is still pending then you may remove the second whereHas.
$data['orders'] = Order::has('orderStatus', '=', 2)->get()->toArray();
You may use the many to many relation as #DigitalDrifter suggested. I would also suggest that you should follow many to many relation.
If you are using the many to many relation then you may try the below query..
Order::has('statuses', '=', 2)->WhereHas('statuses', function ($query) {
$query->where('name', 'pending');
})->get();
or
Order::has('statuses', '=', 2)->get();

Group by user id in Model relation

I have two models: Report and User. This is what I have in my User model
public function userReport() {
return $this->hasMany('App\Report', 'user_id','id');
}
And this is in Report model
public function user() {
return $this->hasOne('App\User', 'id', 'user_id');
}
Controller
public function details( $item_id ){
$report = Item::find($item_id)->report;
return view('details', compact('report'));
}
In view
{!! $report->user->name !!}
In view I show all the users who are reported single Item .. which I query by $item_id.
The problem is that if same user is reported single item 1+ time I see this user 1+ time in the table on the page.
Is it possible to somehow grouped by user_id or count the user_id and show User1 ( 4 time reported ) ...? Where should I group them?
Update: users table
id | username | password
reports table
report_id | id | user_id | date
item table
id | user_id | category | date_added | image
Update2: Image of records in db. Here user with user_id=3 has reported item_id=14 total of 14 times. User with user_id=5 has reported same item_id=14 total of 3 times. So I should see on page user_id=3 ( 14 ) and user_id=3 ( 3 ). Instead I see 17 times user_id=3. Bellow are images
And on page
There should be several ways how to solve your problem
One way is (your controller should look like)
public function details( $item_id ){
$report = Item::find($item_id)->report->unique('user_id');
return view('details', compact('report'));
}
Second way should be to use #foreach in view and there check for unique values.
Third way should be to use foreach in controller and prepare unique data with calculated summarizes inside controller and then pass that prepared data to view.
Which soulution you want to use is just a matter of choice.
Hope it helps you
Just try this. Hope it helps
Report::where('item.id', $item_id)
->select('item.*','users.*',DB::raw('count(reports.report_id) as total'))
->join('item', 'item.id', '=', 'reports.id')
->join('users', 'users.id', '=', 'reports.user_id')
->groupBy('reports.report_id','reports.id')
->get();

Categories