What I want to do is to get all charts of accounts with extra value i.e. balance from the ledgers table with the parameter of $date, Is there any proper way to do it because I am facing N+1 query problem here.
Controller
public function get(Request $request){
$date = $request->date;
$coas = COA::where('parent_id', null)->get();
//return $coas;
$coas = $coas->map(function ($coa) use ($date) {
$coa['balance'] = $coa->balance($date);
return $coa;
});
return view('website.accounts.Trial.show', compact('coas', 'date'));
}
Model
public function balance($date){
$date = new Carbon($date);
$date= $date->addHours(23)->addMinutes(59)->addSeconds(59);
$balance = Ledger::where('c_o_a_id', $this->id)
->where('created_at' ,'<=', $date)
->orderBy('created_at', 'desc')
->orderBy('id', 'desc')
->pluck('balance')
->first();
if($balance){
return $balance;
}
return 0;
}
1. Set up a relationship between COA and Ledger
COA Model
public function ledgers()
{
return $this->hasMany(Ledger::class, 'c_o_a_id');
}
Ledger Model
public function coa()
{
return $this->belongsTo(COA::class, 'c_o_a_id');
}
2. Make you balance() function use that relationship to avoid querying N+1 times
COA Model
public function balance($date){
$date = new Carbon($date);
$date = $date->addHours(23)->addMinutes(59)->addSeconds(59);
if (!$this->relationLoaded('ledgers') $this->load('ledgers');
$balance = $this->ledgers->where('created_at' ,'<=', $date)
->sort(function ($a, $b) {
return [$b->created_at, $b->id] <=> [$a->created_at, $a->id];
})
->first()
->balance;
return $balance ?: 0;
}
Controller
$coas = COA::with('ledgers')->where('parent_id', null)->get();
Related
I want to show all slideshow when the images are not blank.
public function index()
{
$sliderProducts = Product::query()->select('slider')->whereNotNull('slider');
$sliderServices = Service::query()->select('slider')->whereNotNull('slider');
$slideShows = $sliderProducts->merge($sliderServices)
->union($sliderProducts)
->union($sliderServices)
->get();
return view('Home.index', compact('slideShows'));
}
$sliderProducts = Product::query()->select('slider')->whereNotNull('slider');
$sliderServices = Service::query()->select('slider')->whereNotNull('slider');
$sliderProducts and $sliderServices will both be instances of Illuminate\Database\Eloquent\Builder class
You need to fetch the collection before trying to merge them
To get the collection you can use get() on the Builder. Try
public function index()
{
$sliderProducts = Product::query()->select('slider')->whereNotNull('slider')->get();
$sliderServices = Service::query()->select('slider')->whereNotNull('slider')->get();
$slideShows = $sliderProducts->concat($sliderServices);
return view('Home.index', compact('slideShows'));
}
Or to execute a union query you can do
public function index()
{
$sliderProducts = Product::query()->select('slider')->whereNotNull('slider');
$sliderServices = Service::query()->select('slider')->whereNotNull('slider');
$slideShows = $sliderProducts
->union($sliderServices)
->get();
return view('Home.index', compact('slideShows'));
}
I am working on a view that allows users to select a staff member then a date range and when they click the filter button, it will only show that staff member's records for that date period. I have that working but I want to implement an export to excel feature for that staff member and range but when I click export, all my records get exported to excel. Does anyone know what is the right direction to go in?
Controller:
public function exportvehicles()
{
return Excel::download(new ExportV, 'users.xlsx');
}
Model:
class ExportV implements FromCollection
{
public function collection()
{
$startDate = request()->input('startDate', '2021-01-01');
$endDate = request()->input('endDate', '2021-12-12');
return VehicleLog::join('vehicle', 'vehicleslog.vehicle_id', '=', 'vehicle.id')
->join('smsstaff', 'vehicleslog.smsstaff_key', '=', 'smsstaff.smsstaff_key')
->when(request()->input('smsstaff_key'), function ($query) {
$query->where('smsstaff.smsstaff_key', request()->input('smsstaff_key'));
})
->whereDate('log_dt', '>=', $startDate)
->whereDate('log_dt', '<=', $endDate)
->get();
}
}
You can done query on controller before sending it to an ExportV, this will make you easy to implement multiple type of filter.
Controller :
public function exportvehicles()
{
$startDate = request()->input('startDate', '2021-01-01');
$endDate = request()->input('endDate', '2021-12-12');
$item = VehicleLog::join('vehicle', 'vehicleslog.vehicle_id', '=', 'vehicle.id')
->join('smsstaff', 'vehicleslog.smsstaff_key', '=', 'smsstaff.smsstaff_key')
->when(request()->input('smsstaff_key'), function ($query) {
$query->where('smsstaff.smsstaff_key', request()->input('smsstaff_key'));
})
->whereDate('log_dt', '>=', $startDate)
->whereDate('log_dt', '<=', $endDate)
->get();
return Excel::download(new ExportV($item), 'users.xlsx');
}
ExcelV :
class ExcelV implements FromCollection
{
protected $item;
function __constuct ($item) {
$this->item = $item;
}
public function collection() {
return $this->item;
}
}
For example I can use:
$address = $user->address
which will return the addresses for the user.
// User.php (model)
public function address()
{
return $this->hasMany(Address::class, 'refer_id', 'id');
}
public function billingAddress()
{
return $this->address()
->where('type', '=', 1)
->where('refer_id', '=', $this->id)
->first();
}
However, I would like to return the BillingAddress for the user depending on this where clause. How do I do it?
EDIT:
If I use this inside... OrderController#index it returns correctly
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address', 'payment')->get();
return new OrderResource($orders);
However, If I change it to:
$orders = Order::with('order_fulfillment', 'cart.product', 'user.billingAddress', 'payment')->get();
return new OrderResource($orders);
I get this error:
Symfony\Component\Debug\Exception\FatalThrowableError
Call to a member function addEagerConstraints() on null
One option is you can use whereHas in your query. For example,
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address', 'payment')
->whereHas(
'address', function ($query) {
$query->where('type', '=', 1)
->first();
}
)->get();
return new OrderResource($orders);
This is one option. try to dd($orders) an find if its working.
You had an another option like this, in your model
public function address()
{
return $this->hasMany(Address::class, 'refer_id', 'id');
}
Add relations like
public function billingAddress()
{
return $this->hasOne(Address::class, 'refer_id', 'id')->where('type', 1);
}
And
public function shippingAddress()
{
return $this->hasOne(Address::class, 'refer_id', 'id')->where('type', 2);
}
Then in your query,
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address','user.billingAddress', 'user.shippingAddress', 'payment')->get(); return new OrderResource($orders);
public function showJobCategoryContent($id){
$jobsInfoById = DB::table('jobs')->where('category_id', '=', $id)->where('published', '=', 1)->paginate(3);
// Imagine here i got 5 data
foreach ($jobsInfoById as $jobInfoById) {
return $current=$jobInfoById->created_at;
//$trialExpires []= $current->addDays(30);
}
}
If i loop it it only show 1 data. How is it possible If use array sign then it will show 1 data.
If you want to get an array of all created_at dates, you don't need a loop.
public function showJobCategoryContent($id)
{
$jobsInfoById = DB::table('jobs')->where('category_id', '=', $id)->where('published', '=', 1)->paginate(3);
return $jobsInfoById->pluck('created_at');
}
Using the loop:
public function showJobCategoryContent($id)
{
$jobsInfoById = DB::table('jobs')->where('category_id', '=', $id)->where('published', '=', 1)->paginate(3);
$dates = [];
foreach ($jobsInfoById as $jobInfoById) {
$dates[] = $current = $jobInfoById->created_at;
}
return $dates;
}
If want to add 30 days to each date:
public function showJobCategoryContent($id)
{
$jobsInfoById = DB::table('jobs')->where('category_id', '=', $id)->where('published', '=', 1)->paginate(3);
$jobsInfoById = $jobsInfoById->map(function ($job) {
return $job->created_at->addDays(30);
});
return $jobsInfoById->pluck('created_at');
}
Have a look at Laravel collections and how they can be useful: link
So I have two functions named 'search' and 'pdfview'.
Every time I use the search function, I want to pass a query where it selects certain data to the pdfview function.
Here's my search function:
public function search(Request $request)
{
if ($request->period == 'Daily') {
$datefrom = Carbon::now()->startOfDay();
$dateto = Carbon::now()->endOfDay();
}
elseif ($request->period == 'Weekly') {
$datefrom = Carbon::now()->startOfWeek();
$dateto = Carbon::now()->endOfWeek();
}
elseif ($request->period == 'Monthly') {
$datefrom = Carbon::now()->startOfMonth();
$dateto = Carbon::now()->endOfMonth();
}
elseif ($request->period == 'Yearly') {
$datefrom = Carbon::now()->startOfYear();
$dateto = Carbon::now()->endOfYear();
}
else {
$datefrom = Carbon::parse($request->datefrom);
$dateto = Carbon::parse($request->dateto);
}
$solditems = DB::table('orders')
// ->join('orders', 'receipts.receipt_id', '=', 'orders.receipt_id')
->whereDate('orders.created_at', '>=', $datefrom)
->whereDate('orders.created_at', '<=', $dateto)
->where('status','=', 'served')
->select('orders.*', DB::raw('SUM(subtotal) as subtotal'), DB::raw('SUM(qty) as qty'))
->groupBy('item_id')
->orderBy('created_at', 'dsc')
->get();
return view('salesreports.sellingitems.index', compact('solditems'));
}
And here's my pdfview function:
public function pdfview(Request $request)
{
$solditems = DB::table('orders')
->where('status', 'served')
->select('orders.*', DB::raw('SUM(subtotal) as subtotal'), DB::raw('SUM(qty) as qty'))
->groupBy('item_id')
->orderBy('qty', 'dsc')
->get();
view()->share('solditems', $solditems);
if ($request->has('download')) {
$pdf = PDF::loadView('salesreports.sellingitems.pdf');
return $pdf->download('sellingitems-' . Carbon::now() . '.pdf');
}
return view('salesreports.sellingitems.pdf');
}
As you can see, the pdfview function has a default query for the $solditems. But I wanted that variable to come from my search function.
UPDATE: I managed to solve the problem using session.
Here's how you store with session:
session()->put('period', 'Daily');
and this is how you retrieve with session:
$period = $request->session()->get('period', 'default');
public function getSolditems()
{
if (!isset($this->solditems)) {
$solditems = DB::table('orders')
// ->join('orders', 'receipts.receipt_id', '=', 'orders.receipt_id')
->whereDate('orders.created_at','>=', $datefrom)
->whereDate('orders.created_at', '<=', $dateto)
->where('status','=', 'served')
->select('orders.*', DB::raw('SUM(subtotal) as subtotal'), DB::raw('SUM(qty) as qty'))
->groupBy('item_id')
->orderBy('created_at','dsc')
->get();
$this->solditems = $solditems;
} else {
$solditems = $this->solditems;
}
return $solditems;
}
public function search(Request $request)
{
....
$solditems = getSolditems();
....
}
public function pdfview(Request $request)
{
....
$solditems = getSolditems();
....
}
I think you can use $request->merge() method to pass $solditems data to pdfview() method from search()
public function search(Request $request)
{
....
$request->merge(['solditems'=>$solditems]);
$this->pdfview()
}
public function pdfview(Request $request)
{
$solditems = $request->get('solditems');
....
}