i have 2 tables
invoice (id, service_inv_cat_id, etc..)
payment (id, invoice_id, amount)
I need to get the sum of amount in payment with groupby (service_inv_cat_id)
here is my code
$income_details_cat = Invoice::select('id', 'service_inv_cat_id')
->with(['service_inv_cat' => function ($q) {
$q->select('id', 'name');}])
->with(['payment' => function ($q) use ($year, $month){
$q->select('id','invoice_id', 'amount')
->whereYear('paid_date', $year)
->whereMonth('paid_date', $month)
;}])
->whereHas('payment', function ($q) use ($year,$month) {
return $q->where('type', 3)
->whereYear('paid_date', $year)
->whereMonth('paid_date', $month)
;})
->withSum(['payment' => function ($query) use ($year, $month){
$query->whereYear('paid_date', $year)
->whereMonth('paid_date', $month);
}], 'amount')
->get();
it returns the following
but I need to get the total sum of wallet,
I have tried added ->groupBy('service_inv_cat_id')
but it returns the following
it returns the sum of payment of only one record, ex wallet has higher than 200 in total with many invoices as you can see in pic 1 but its returns only one
I assume service_cat and payment belongTo payment ?
$income_details_cat = Invoice::select('invoices.id', 'invoices.service_inv_cat_id', 'payments.amount')
->join('payments', 'invoices.id', '=', 'payments.invoice_id')
->with('service_inv_cat:id,name')
->sum('payments.amount')
->where('payments.type', 3)
->whereYear('payments.paid_date', $year)
->whereMonth('payments.paid_date', $month)
->groupBy('service_inv_cat_id')
->get();
I am a bit lost to be honest but I would re-write your code like this not sure why you have so many withs for the same thing I think you would get the same result as you have now if written like this:
$income_details_cat = Invoice::select('id', 'service_inv_cat_id')
->with('service_inv_cat:id,name', 'payment:id,invoice_id,amount')
->wherHas(['payment' => fn ($q) =>
$q->where('type', 3)
->whereYear('paid_date', $year)
->whereMonth('paid_date', $month)
])
->get();
if you can show your relationships a bit clearer and explain what laser is ? I take it wallet is the sum of all amounts grouped by service_inv_cat_id
Related
I have a model called Business, a business can have several services they provide. I have another model called Payments. Payment holds a record of what service people pay for. A service can have many Payments. I intend to fetch top 10 and worst 10 businesses based on payments received. The code below works fine, but it is very inefficient. I have to loop through the whole data to retrieve the information I need. Any more efficient way of achieving this?
$businesses = Business::with(['services'])->get();
foreach($businesses as $business){
$id = $business->id;
$name = $business->display_name;
$services = $business->services;
$businessRevenue = 0;
if(count($services)>0){
foreach($services as $service){
$serviceId = $service->id;
$totalAmount = PaymentTransaction::whereHas('invoice', function($query) use ($serviceId){
$query->where('product_code_id', $serviceId);
})->where('amount_paid', ">", 0)->sum('amount_paid');
$businessRevenue= $businessRevenue + $totalAmount;
}
}
$businessArray = (object) array('id'=> $id, 'name'=> $name, 'revenue'=> $businessRevenue);
array_push($transformedBusiness, $businessArray);
}
$topBusiness = $bottomBusiness = $transformedBusiness;
usort($bottomBusiness, function($a, $b) {return strcmp($a->revenue, $b->revenue);});
usort($topBusiness, function($a, $b) {return strcmp($b->revenue, $a->revenue);});
$topBusiness = array_slice($topBusiness, 0, 10);
$bottomBusiness = array_slice($bottomBusiness, 0, 10);
return view('report.department_performance', compact('topBusiness', 'bottomBusiness'));
I guess you could use a join query to get top and lowest 10 businesses directly from database instead of looping all business records and manually calculate their revenue
For top 10 business you can use inner joins for rest of the related tables
$topBusinesses = DB::query()
->select('b.id', 'b.display_name', DB::raw('sum(p.amount_paid) as revenue')
->from('business as b')
->join('service as s', 'b.id', '=', 's.business_id')
->join('invoice as i', 's.id', '=', 'i.product_code_id')
->join('payment_transaction as p', function ($join) {
$join->on('p.id', '=', 'i.payment_transaction')
->where('p.amount_paid', '>', 0);
})
->groupBy('b.id', 'b.display_name')
->orderByDesc('revenue')
->limit(10)
->get();
For lowest 10 business use left joins for invoice and payment_transaction so that if there are no records in these table for a business you will still get these business records
$lowestBusinesses = DB::query()
->select('b.id', 'b.display_name', DB::raw('coalesce(sum(p.amount_paid),0) as revenue')
->from('business as b')
->join('service as s', 'b.id', '=', 's.business_id')
->leftJoin('invoice as i', 's.id', '=', 'i.product_code_id')
->leftJoin('payment_transaction as p', function ($join) {
$join->on('p.id', '=', 'i.payment_transaction')
->where('p.amount_paid', '>', 0);
})
->groupBy('b.id', 'b.display_name')
->orderBy('revenue')
->limit(10)
->get();
I have used MySQL coalesce function to show 0 value in case sum() returns null, If you are using any other database you can use an alternate function.
I need to sum every paid_amount inside of each expense_payment_liab instead of returning all these
individual paid_amount as it can be seen in images for clear view.So far my query looks like this:
Model Relation is like Voucher has many Expenses and Expenses has many Expensepaymentliab.
This is so far what I tried:
$expense = Voucher::where('voucher_date', $request->date)
->where('account_id', 1)
->with(['expenses' => function ($expense) use ($date) {
$expense->with(['expPaymentLiab' => function ($inner) use ($date) {
return $inner->select('paid_amount', 'expense_id')->where('paid_date', '=', $date);
//need to return the sum of paid_amount.
// I've also tried this
//$inner->sum('paid_amount')
// $inner->sum('paid_amount', 'expense_id')
}]);
$expense->select('id', 'date', 'total_amount', 'voucher_id');
}])->get();
These are the images please check
Need to sum such paid_amount field.
You can use withCount to sum the paid_amount field.
Voucher::where('voucher_date', $request->date)
->where('account_id', 1)
->with(['expenses' => function ($expense) use ($date) {
// select the columns first, so the subquery column can be added later.
$expense->select('id', 'date', 'total_amount', 'voucher_id');
$expense->withCount(['expPaymentLiab AS paid_sum' => function ($query) use ($date) {
return $query->select(DB::raw('SUM(paid_amount)'))->where('paid_date', '=', $date);
}]);
}])
->get();
I want to filter ONLY nested values in dealTransactions.
In plain English, Merchant wants only dealTransactions have provided dates with Deals.
I tried something like below but it does not work.
dates = ['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05'];
$merchant = Merchant::with(['deals.dealTransactions'])->where('slug', $slug)
->whereHas('deals.dealTransactions', function($query) use ($dates) {
foreach($dates as $date) {
$query->where('date', '=', $date);
}
})
->first();
deal_transactions table
id, deal_id, date
deals table
id, merchant_id,
merchants table
id, many columns for merchant
Thank you
You should be able to do this with a eager load constraint on the nested relationship:
$merchant = Merchant::where('slug', $slug)
->with(['deals.dealTransactions' => function ($query) use ($dates) {
$query->whereIn('date', $dates);
}])->first();
If I understood correctly your schema, this might help:
// Here you define the scope that will be used to select & eager load.
$transactionsScope = function ($q) use ($dates) {
return $q->whereIn('date', $dates);
};
// All merchant of slug in/with that transaction's scope.
$merchant = Merchant::where('slug', $slug)
->whereHas('deals', function ($q) use ($transactionsScope) {
return $q->whereHas('dealTransactions', $transactionsScope);
})
->with(['deals' => function ($q) use ($transactionsScope) {
return $q->with('dealTransactions', $transactionsScope);
}])
->firstOrFail();
I have this function that help me to find sum of two rows and get output of total cost So again I want to get sum of the output(total cost).
public function getUsageData(Request $request)
{
$start_date = $request->get('start_date');
$end_date = $request->get('end_date');
$particulars =DB::table('particulars')
->join('reqs', 'particulars.particular_id', "=", 'reqs.particular_id')
->whereBetween('date_issued', [$start_date, $end_date])
->select('particulars.item_name','particulars.unit','particulars.price','reqs.quantity_issued',
DB::raw('sum(particulars.price*reqs.quantity_issued)AS total_cost'))
->groupBy('particulars.particular_id')
->get();
}
I get sum of two row that form Total cost. I want to get sum of total cost column at the bottom so as to make it easy to understand for user without calculating it.
Try with this code else share the table structure please
$particulars =DB::table('particulars as A')
->leftjoin('reqs as B', function ($join) {
$join->on('A.particular_id', '=', 'B.particular_id');
})
->whereBetween('A.date_issued', [$start_date, $end_date]) // i have taken date issued from table particulars as you have not mentioned else you can change A.date_issued as B.date_issued .
->select('A.item_name','A.unit','A.price','B.quantity_issued',DB::raw('sum(A.price*B.quantity_issued) as total_cost'))
->groupBy('A.particular_id')
->get();
I am building a website where i have a booking mechanism.
The user can book a hotel room for X days if the room is available.
I am using:
Laravel 5.4
MySql
The room is unavailable if:
It is already booked by another user
The admin has set it as unavailable
The room capacity is less or equal to the number of travellers
If have 3 tables to store those data:
Rent: Contains the booking infos, such as rentStartDate and rentEndDate (as DateTime) and other fields (userId, rentalId, ...)
Unavailabilities: When the admin set a room as unavailable, it's stored here. I have the fields unavailabilityStartDate, unavailabilityEndDate (as DateTime) and rentalId
Rentals: This table contain all the infos regarding the room (capacity ,name, location, ...)
I am struggling to build a Eloquent query to check if the room is available before processing the user payment. Here is what i have for now:
public function isAvailableAtDates($rentalId, $startDate, $endDate, $capacity) {
$from = min($startDate, $endDate);
$till = max($startDate, $endDate);
$result = DB::table('rentals')
->where([
['rentals.rentalId', '=', $rentalId],
['rentals.rentalCapacity', '>=', $capacity]
])
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('unavailabilities.rentalId')
->from('unavailabilities')
->where([
['unavailabilities.rentalId', '=', $rentalId],
['unavailabilityStartDate', '>=', $from],
['unavailabilityEndDate', '<=', $till],
]);
})
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('rent.rentalId')
->from('rent')
->where([
['rent.rentalId', '=', $rentalId],
['rentStartDate', '>=', $from],
['rentEndDate', '<=', $till]
]);
})
->select('rentals.rentalId')
->get();
return count($result) == 1;
}
Let's say I have a row inside Unavailabilities with:
unavailabilityStartDate = 2017-04-26 00:00:00
unavailabilityEndDate = 2017-04-30 00:00:00
When calling the method with some dates outside of the range stored in Unavailabilities, i'm getting the expected result. When calling it with the exact same dates, i'm getting no result (which is what i want).
So far so good!
The problem is if i'm calling it with a start date between 26 of April and 30th and a end date later in May, i am still getting a result even tho i shouldn't.
Could anyone help me with that?
This is not a laravel, nor a mysql issue.
try this:
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('unavailabilities.rentalId')
->from('unavailabilities')
->where([
['unavailabilities.rentalId', '=', $rentalId],
['unavailabilityStartDate', '<=', $till],
['unavailabilityEndDate', '>=', $from],
]);
})
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('rent.rentalId')
->from('rent')
->where([
['rent.rentalId', '=', $rentalId],
['rentStartDate', '<=', $till],
['rentEndDate', '>=', $from]
]);
})
You need all rent and unavailabilities records that had been started before $till and hadn't been ended before $from date.
Try to draw a time diagram.