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

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.

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].

Laravel Livewire Filter Number of Transaction by User

I am using Laravel Livewire for my project. In my project there are three tables. Users, Orders, and Order details. Users are allowed to have multiple orders. In my Orders table each order is saved with user_id. I have generated a Users Table and now i am building a filter in which I want to query users tables that which users have more orders. I want to pass an integer value to filter the users.
i.e If I pass 10 then it will filter users who have ordered more than 10 orders
I have also passed the Relation to Orders Model in my User Model Like this
public function orders()
{
return $this->hasMany(Order::class, 'user_id');
}
I am trying like this but its not returning required result
if ($orders_num = ($filters['orders_num'] ?? false))
$user = $user->orders()->count('user_id');
There are several ways.
Use Eloquent withCount(), in combination with condition.
$threshold = 10;
$users = User::withCount('orders')
->get()
->where('orders_count', '>', $threshold);
Use Eloquent has()
$users = User::has('orders', '>', $threshold)
->get();
Use Collection::map()
$users = User::with('orders')
->get()
->filter(function ($user) use ($threshold) {
return $user->orders->count() > $threshold;
});

Laravel eloquent restrict withCount with whereHas or another

I have 3 models Supplier, Purchase and PurchaseDetail.
To join the Supplier model with PurchaseDetail through Purchase I have created a hasManyThrough relation.
hasManyThrough inside Supplier model:
public function detail_purchases(){
return $this->hasManyThrough(PurchaseDetail::class, Purchase::class);
}
The relationship works well and I can count the quantities purchased from sellers as follows:
$collectors = Supplier::withCount(['detail_purchases as qty_sold' => function($query) {
return $query->select(\DB::raw('SUM(qty)'))
->where('unit', '=', 'kg');
}])
->where('supplier_type','=','persona_natural')
->orderBy('qty_sold','desc')
->get();
SQL Query output:
select `suppliers`.*, (
select SUM(qty)
from `purchase_details`
inner join `purchases` on `purchases`.`id` = `purchase_details`.`purchase_id`
where `suppliers`.`id` = `purchases`.`supplier_id`
and `unit` = 'kg'
and `purchases`.`deleted_at` is null
) as `qty_sold`
from `suppliers`
where `supplier_type` = 'persona_natural'
order by `qty_sold` desc;
Output rows:
My problem is that this query is bringing me sellers that I did not make purchases from them, I don't know why they infiltrate the query if it is assumed that the hasManyThrough relationship only joins those who are registered in Purchase or made purchases from them.
Also the Supplier model has another relation called purchases:
public function purchases() {
return $this->hasMany(Purchase::class, 'supplier_id');
}
And the model Purchase has a relation hasMany with PurchaseDetail :
public function details(){
return $this->hasMany(PurchaseDetail::class, 'purchase_id');
}
Updated
Using whereHas now I can get all the suppliers that I did purchases however the qty_sold is not appearing in the results:
$collectors = Supplier::whereHas('purchases', function($query){
$query->withCount(['details as qty_sold' => function($query){
$query->select(\DB::raw('SUM(qty)'))
->where('unit', '=', $this->unit);
}]);
})
->where('supplier_type','=','persona_natural')
->get();
This selection is important because I want to know how many kgs of all products I purchased.
Thanks #Tony
In your updated query can you move the withCount out of the subquery? So you would have Supplier::withCount(...)->whereHas('purchases')..
Ok, I fixed it, adding first the whereHas directive the I used the hasManyThrough
relation with withCount. Of this way only suppliers that has purchases are selection.
$collectors = Supplier::whereHas('purchases')
->withCount([
'detail_purchases as qty_sold' => function($query){
$query->select(\DB::raw('SUM(qty)'))
->where('unit', '=', 'kg');
}
])
->where('supplier_type','=', 'persona_natural')
->get();

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

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.

How to get parents data that only has a child data in laravel

I'm trying to get all the data from the parent that only has a child. Please see my code below.
$customers = Customer::with(['items' => function($query){
return $query->where('status', 2);
}])->get();
dd($customers);
But the code above returns all the customer. By the way, I'm using laravel 4.2.
Items Table:
Customer Table:
with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.
has() is to filter the selecting model based on a relationship. So it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.
e.g :
$users = Customer::has('items')->get();
// only Customer that have at least one item are contained in the collection
whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.
e.g
$users = Customer::whereHas('items', function($q){
$q->where('status', 2);
})->get();
// only customer that have item status 2
Adding group by to calculating sum
this is another example from my code :
Customer::select(['customer.name', DB::raw('sum(sale.amount_to_pay) AS total_amount'), 'customer.id'])
->where('customer.store_id', User::storeId())
->join('sale', 'sale.customer_id', '=', 'customer.id')
->groupBy('customer.id', 'customer.name')
->orderBy('total_amount', 'desc')
->take($i)
->get()
in your case :
Customer::select(['customer_id', DB::raw('sum(quantity) AS total')])
->whereHas('items', function ($q) {
$q->where('status', 2);
})
->groupBy('customer_id')
->get();
whereHas() allow you to filter data or query for the related model in your case
those customer that have items and it status is 2
afetr getting data we are perform ->groupBy('customer_id')
The GROUP BY statement is often used with aggregate functions (COUNT, MAX, MIN, SUM, AVG) to group the result-set by one or more columns.
select(['customer_id', DB::raw('sum(quantity) AS total')]) this will select customer id and calculate the sum of quantity column
You should use whereHas not with to check child existence.
$customers = Customer::whereHas('items', function($query){
return $query->where('status', 2);
})->get();
dd($customers);
I assume you already defined proper relationship between Customer and Item.
You should try this:
$customers = Customer::whereHas('items', function($query){
$query->where('status', 2);
})->get();
dd($customers);
Customer::select(['items.customer_id',DB::raw('count(items.id) AS total_qty')])
->join('items', 'items.user_id', '=', 'customer.customer_id')
->groupBy('items.customer_id')
->havingRaw('total_qty > 2')
->get();
OR
$data=DB::select("select `items`.`customer_id`, count(items.id) AS total_qty
from `customers`
inner join `items`
on `items`.`customer_id` = `customers`.`customer_id`
group by `items`.`customer_id` having total_qty >= 2");
correct table name and column name.

Categories