I am using the jQuery datatables plugin and adding the column valores_receber (values_to_receive) using a foreach loop that do the sum but in a separate way as you can see in the following code.
public function anyDataReceber() {
$clientes = Partner::whereHas('faturamentos', function($q){
$q->where('status', '<>', 'CANCELADO');
})
->orWhereHas('faturamentosLivres', function ($q) {
$q->where('status','<>','CANCELADO');
})
->with('faturamentos')
->with('faturamentosLivres');
return Datatables::of($clientes)
->addColumn('valores_receber', function ($clientes) {
$total = 0;
foreach($clientes->faturamentos as $fatura1) {
if ($fatura1->status != 'CANCELADO') $total += $fatura1->total_usd - $fatura1->valor_pago;
}
foreach($clientes->faturamentosLivres as $fatura2) {
if ($fatura2->status != 'CANCELADO') $total += $fatura2->total_usd - $fatura2->valor_pago;
}
return number_format($total,2,',','.');
})
->addColumn('action', function ($clientes) {
$actions = '';
$actions = '<a href="/admin/financeiro-matriz/contas-receber/'.$clientes->id.'" class="btn btn-xs btn-primary"><i class="fa fa-eye"></i> Visualizar</a>';
return $actions;
})
->make(true);
}
The problem here is that the datatable can not order the column valores_receber because this very column does not exist in the result query from Eloquent.
I researched about the SUM() function from mySQL but I can't make a solution using Eloquent and the tables relationships.
I checked the following answers that should be in the right track but are using normal SQL instead and from what I researched it needs some sort of join or union statements, but how to perform that in Eloquent?
- How to calculate sum of two columns from two different tables without where clause?
- How to sum data of two different columns of two different tables?
So for the datatable to be able to order the column valores_receber, I need that column to show up in the results of some sort of Eloquent statement.
What I am trying to achieve is:
- make the query using Eloquent that sums the values of the columns total_usd that is present in both tables faturamentos and faturamentos_livres (invoices and free_invoices)
- those tables need to be restricted by the status column that must be any value but CANCELADO (Canceled). This status column is an ENUM type
EDIT: I am using DB:raw() as suggested by @d1c1pl3 but I still want to know an elegant solution using Eloquent. What follows is my ugly attempt, that works, using raw queries and it is based on this answer: https://stackoverflow.com/a/7432219/2465086
public function anyDataReceber() {
// 1 - getting all IDs of clients that have faturamentos or faturamentosLivres
$clientes = Partner::whereHas('faturamentos', function($q){
$q->where('status', '<>', 'CANCELADO');
})
->orWhereHas('faturamentosLivres', function ($q) {
$q->where('status','<>','CANCELADO');
})
->with('faturamentos')
->with('faturamentosLivres')
->pluck('id')
->toArray();
// 2 - Converting to string for use in the query
$ids = implode(',',$clientes);
// 3 - the ugly query that I want to do using Eloquent. It filters by the status and filters by clients´ ids returned before. It is not appealing either because it uses subselects and a join
$result = DB::select(DB::raw(
'SELECT partners.client, cliente_id, (SUM(t.total_usd) - SUM(t.valor_pago)) AS valores_receber
FROM (SELECT cliente_id, total_usd, valor_pago FROM faturamentos WHERE status <> "CANCELADO" AND cliente_id IN ('.$ids.')
UNION ALL
SELECT cliente_id, total_usd, valor_pago FROM faturamentos_livres WHERE status <> "CANCELADO" AND cliente_id IN ('.$ids.')) t
JOIN partners ON partners.id= cliente_id
GROUP BY cliente_id'
));
// 4 - converting to Collection because the Datatables class expects it
$result = collect($result);
// 5 - The return is the only part that is easy to read and feels like it is in the right track
return Datatables::of($result)
->editColumn('valores_receber', function ($result) {
return number_format($result->valores_receber,2,',','.');
})
->addColumn('action', function ($result) {
$actions = '';
$actions = '<a href="/admin/financeiro-matriz/contas-receber/'.$result->cliente_id.'" class="btn btn-xs btn-primary"><i class="fa fa-eye"></i> Visualizar</a>';
return $actions;
})
->make(true);
}