Merge items in laravel collections with same id and sum other columns - laravel

I have a collection like this:
I want to merge or unifi the "rows" that have the same "referencia" and sum the last columns if exists...(t1_total,t2_total,t3_total...)
foreach ($compo_escandallo as $row) {
$scandal->subtotal = $scandal->subtotal + $row->importe;
if ($row->um == "M") { /**&& $row->merma != 0 */
($row->merma) / 100;
} else {
$row->merma;
}
if ($row->tipo == "MMPP") {
$total_mmpp = $total_mmpp + $row->importe;
}
if ($row->xtalla == "X") {
//$consumo = 0;
foreach ($tallas as $talla){
if($talla->tallan=="001" or $talla->tallan=="075" or $talla->tallan=="S"){
$row->t1_total = ($this->floatvalue($row->t1) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="002" or $talla->tallan=="080" or $talla->tallan=="M"){
$row->t2_total = ($this->floatvalue($row->t2) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="003" or $talla->tallan=="085" or $talla->tallan=="L"){
$row->t3_total = ($this->floatvalue($row->t3) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="004" or $talla->tallan=="090" or $talla->tallan=="XL"){
$row->t4_total = ($this->floatvalue($row->t4) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="005" or $talla->tallan=="095" or $talla->tallan=="XXL"){
$row->t5_total = ($this->floatvalue($row->t5) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="006" or $talla->tallan=="100"){
$row->t6_total = ($this->floatvalue($row->t6) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="007" or $talla->tallan=="105"){
$row->t7_total = ($this->floatvalue($row->t7) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="008" or $talla->tallan=="110"){
$row->t8_total = ($this->floatvalue($row->t8) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="009" or $talla->tallan=="115"){
$row->t9_total = ($this->floatvalue($row->t9) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="010" or $talla->tallan=="120"){
$row->t10_total = ($this->floatvalue($row->t10) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}elseif($talla->tallan=="011" or $talla->tallan=="125"){
$row->t11_total = ($this->floatvalue($row->t11) + ($this->floatvalue($row->merma)/100)) * $this->floatvalue($row->veces);
}
}
}
}
$filtered_collection = $compo_escandallo->filter(function ($item) {
return $item->xtalla == 'X';
})->values();
Not in all cases have 11 totals, sometimes have 3 or 4 totals only, as see in picture. How can i do this? I try some examples in stackoverflow as:
`$unique = $compo_escandallo->unique('referencia');
$unique->transform(function ($item, $key) use ($compo_escandallo) {
//dd($item->referencia);
$id = $item->referencia;
$item->referencia = $compo_escandallo->sum(function ($product) use ($id) {
dd($product);
if($product->referencia == $id){
return $product->t1_total;
}
});
return $item;
});
return $unique->all();`
But not work as i expect and no return the collection as i need.
Thank you in advance for any help.

You can use groupBy method of the collection and then map the totals something like :-
use Illuminate\Support\Collection;
// $data = your fetched item from the db
$collected_data = new Collection($data)->groupBy('referencia');
// now that you have the data sorted according the ref, sum their totals
$collected_data = $collected_data->eachSpread(function ($item, $key) {
return $item['grand_total', $item->sum('t1_total', 't3_total')];
});
hope that helps, tweak the variables and the nesting of the code to your specific need.

Related

Sorting League Standings table

Am doing a league management system where the system generates fixtures and assign each match to an official who later enters results. Now when i have set everything possible for the log table but when i pass the results, am getting the some few errors : Too few arguments to function App\Models\Gamescores::updateStandings(), 0 passed in E:\Video\laraVids\laraProjects\HAM\app\Models\Gamescores.php on line 28 and exactly 1 expected
here is my code for the sorting of the league
class Gamescores extends Model
{
use HasFactory;
protected $table = 'gamescores';
protected $fillable = [
'games_id',
'away_score',
'home_score',
];
public function game()
{
return $this->belongsTo(Game::class, 'games_id');
}
public static function boot()
{
parent::boot();
static::created(function ($gamescore) {
$gamescore->updateStandings();
});
}
public function updateStandings($league_id)
{
// Get all gamescores for the specified league
$gameScores = Gamescores::whereHas('game', function ($query) use ($league_id) {
$query->where('league_id', $league_id);
})->get();
// Loop through each gamescore and update the log table for each team
foreach ($gameScores as $gameScore) {
$game = Games::find($gameScore->games_id);
$league_id = $game->league_id;
$home_team_id = $game->home_team;
$away_team_id = $game->away_team;
$home_team_log = Logtable::where('team_id', $home_team_id)->first();
if ($home_team_log !== null) {
$home_team_log->played += 1;
if ($gameScore->home_score > $gameScore->away_score) {
$home_team_log->won += 1;
$home_team_log->points += 3;
} else if ($gameScore->home_score == $gameScore->away_score) {
$home_team_log->drawn += 1;
$home_team_log->points += 1;
} else {
$home_team_log->lost += 1;
}
$home_team_log->goals_for += $gameScore->home_score;
$home_team_log->goals_against += $gameScore->away_score;
$home_team_log->goal_difference = $home_team_log->goals_for - $home_team_log->goals_against;
$home_team_log->save();
}
$away_team_log = Logtable::where('team_id', $away_team_id)->first();
if ($away_team_log !== null) {
$away_team_log->played += 1;
if ($gameScore->away_score > $gameScore->home_score) {
$away_team_log->won += 1;
$away_team_log->points += 3;
} else if ($gameScore->home_score == $gameScore->away_score) {
$away_team_log->drawn += 1;
$away_team_log->points += 1;
} else {
$away_team_log->lost += 1;
}
$away_team_log->goals_for += $gameScore->away_score;
$away_team_log->goals_against += $gameScore->home_score;
$away_team_log->goal_difference = $away_team_log->goals_for - $away_team_log->goals_against;
$away_team_log->save();
}
}
}
}
thats my model where am passing the method to genererate the results
public function fixtureToView($league)
{
// Fetch all rows from the games table, including the related official model
$games = Games::where('league_id', $league)->get();
// Extract the values for the role column as an array
$pluckedFixtures = $games->pluck('Fixture')->toArray();
// Count the number of occurrences of each value in the array
$counts = array_count_values($pluckedFixtures);
// Initialize an empty array to store the duplicate keys and values
$fixtures = collect([]);
// Iterate over the counts array
foreach ($counts as $key => $count) {
// If the count is greater than 1, add the key and value to the duplicates array
$fixtures->push($games->where('Fixture', $key));
}
// In your controller
$gamescores = Gamescores::all();
foreach ($gamescores as $gamescore) {
$game = Games::find($gamescore->games_id);
$league_id = $game->league_id;
$gamescore->updateStandings($league_id);
if($gamescore->games_id){
$game = Games::find($gamescore->games_id);
$league_id = $game->league_id;
$gamescore->updateStandings($league_id);
}
}
$standings = Logtable::all();
$standings = $standings->sortByDesc('points');
// return view('standings', compact('standings'));
return view(
'admin.league.fixtures.index',
compact('fixtures', 'standings')
);
thats my controller where am passing the method to retrieve it in the view, what i want is the log table to get the Id of the league where the games/matches belong to
the error am getting this error

issue with reduce time to open in laravel

I am making a report in which user can check due balance of them invoice day wise like between 1-30 days how many amount due. between 30-60 days how many amount due etc for that I have make below function.
I don't know how can I optimize this process time.
public function yajraAgingARSummaryByDueDate()
{
$customerData = GenerateInvoice::select('orders.customer_id','customers.first_name', 'customers.last_name','customers.terms','customers.account_id','customers.account_suffix','invoice.due_date','invoice.invoice_number')
->leftJoin('orders','orders.id','=','invoice.order_id')
->leftJoin('customers', 'customers.id', 'orders.customer_id')
->whereDate('invoice.due_date','<=',date('Y-m-d'))
->whereNotNull('orders.customer_id')
->where('invoice.is_invoice_paid','=','no')
->whereNull('invoice.deleted_at')
->groupBy('orders.customer_id')
->get();
$resultArr = [];
if(count($customerData))
{
foreach($customerData as $key => $row)
{
$current = 0;
$b_1_30 = 0;
$b_31_60 = 0;
$b_61_90 = 0;
$b_over_90 = 0;
$total_ar = 0;
$balance = 0;
$invoiceData = GenerateInvoice::select('invoice.id')
->leftJoin('orders','orders.id','=','invoice.order_id')
->where('orders.customer_id',$row['customer_id'])
->whereDate('invoice.due_date','<=',date('Y-m-d'))
->whereNotNull('orders.customer_id')
->whereNull('invoice.deleted_at')
->where('invoice.is_invoice_paid','=','no')
->get();
if(count($invoiceData))
{
foreach($invoiceData as $row1)
{
$data = GenerateInvoice::select(DB::raw("abs(DATEDIFF(STR_TO_DATE(due_date, '%Y-%m-%d'),CURDATE())) AS Days"),'orders.total_order_value','payments.payment_amount')
->selectRaw(' (select sum(auto_cash_distributions.payment_amount) from auto_cash_distributions where auto_cash_distributions.order_id = invoice.order_id and payment_amount is not null ) as acd_payament_amount ')
->leftJoin('orders','orders.id','=','invoice.order_id')
->leftJoin('payments','payments.order_id','=','orders.id')
->where('invoice.id',$row1['id'])
->whereNotNull('orders.customer_id')
->whereNull('invoice.deleted_at')
->whereNull('payments.deleted_at')
->where('invoice.is_invoice_paid','=','no')
// ->groupBy('payments.invoice_id')
->first();
$days = $data['Days'];
$acd_payament_amount = !(empty($data['acd_payament_amount'])) ? $data['acd_payament_amount'] : 0;
$payment_amount = $data['payment_amount'] + $acd_payament_amount;
$amount = $data['total_order_value'] - $payment_amount;
// H 30/12
$amount = $amount;
$balance =$balance + $amount;
$total_ar = $total_ar + $amount;
// $total_ar = $amount;
if($days>90)
{
$b_over_90 = $b_over_90 + $amount;
}
else if($days <=90 && $days>=61)
{
$b_61_90 = $b_61_90 + $amount;
}
else if($days <=60 && $days>=31)
{
$b_31_60 = $b_31_60 + $amount;
}
else if($days <=30 && $days>=1)
{
$b_1_30 = $b_1_30 + $amount;
}
else
{
$current = $current + $amount;
}
}
}
$resultArr[$key]['account_id'] = $row['account_id'];
$resultArr[$key]['account_suffix'] = $row['account_suffix'];
$resultArr[$key]['first_name'] = $row['first_name'];
$resultArr[$key]['terms'] = $row['terms'];
$resultArr[$key]['due_date'] = $row['due_date'];
$resultArr[$key]['invoice_number'] = $row['invoice_number'];
$resultArr[$key]['balance'] = number_format($balance,2,'.','');
$resultArr[$key]['current'] = number_format($current,2,'.','');
$resultArr[$key]['b_1_30'] = number_format($b_1_30,2,'.','');
$resultArr[$key]['b_31_60'] = number_format($b_31_60,2,'.','');
$resultArr[$key]['b_61_90'] = number_format($b_61_90,2,'.','');
$resultArr[$key]['b_over_90'] = number_format($b_over_90,2,'.','');
$resultArr[$key]['total_ar'] = number_format($total_ar,2,'.','');
}
}
return Datatables::of($resultArr)
->addColumn('due_date',function($sql){
return !empty($sql['due_date']) ? date(get_config('date_format'),strtotime($sql['due_date'])) : '';
})
->addIndexColumn()
->rawColumns(['due_date'])
->make(true);
}
but this code is taking to much time to open. can anybody help me to optimize this code?

doctrine query with parameters having multiple values

I want to make a doctrine query in which each parameters can have multiple values (coming from a select multiple).
I have a table with a 'type' parameter that can have value of 1, 2, 3 or 4 and an 'online' parameter that can be 0 or 1.
My query so far is the following :
$query = $this->createQueryBuilder('properties');
if (array_key_exists('type', $searchValues)) {
$types = $searchValues['type'];
$iterator = 0;
foreach ($types as $type) {
if ($iterator == 0) {
$query->andWhere('properties.idPropertyType = ' . $type);
} else {
$query->orWhere('properties.onlineProperties = ' . $type);
}
$iterator++;
}
}
if (array_key_exists('status', $searchValues)) {
$status = $searchValues['status'];
$iterator = 0;
foreach ($status as $statu) {
if ($iterator == 0) {
$query->andwhere('properties.onlineProperties = ' . $statu);
} else {
$query->andWhere('properties.onlineProperties = ' . $statu);
}
$iterator++;
}
}
$properties = $query->getQuery()->getResult();
In the case of a search with parameter type = 1 and online = 0 and 1, I have results where type is another value than 1. I understand the reason why but I cannot figure out a proper way to make my query.
You don't need to build your query by hand manually, just use the (in) function from the QueryBuilder class. Try this:
$query = $this->createQueryBuilder('properties');
if(array_key_exists('type', $searchValues)){
$types = $searchValues['type'];
$query->andWhere($query->expr()->in('properties.idPropertyType', $types));
}
if(array_key_exists('status', $searchValues)){
$status = $searchValues['status'];
$query->andwhere($query->expr()->in('properties.onlineProperties', $status));
}
$properties = $query->getQuery()->getResult();

How to get Select max value in codeigniter

Controller:
$next_id = $this->o->next_id();
$data['next_id']=$next_id;
Model:
public function next_id(){
$this->db->select_max('p_ori_id');
$max = $this->db->get('orientation_master');
if($max==0){
$next_id = 1;
}else{
$next_id = 1+$max;
}
return $next_id;
}
Return Error:
Object of class CI_DB_mysqli_result could not be converted to int
Please solve problem..
No offense to #pradeep but you may have some unexpected results if you don't have any rows. I suggest:
public function next_id()
{
$this->db->select_max('p_ori_id', 'max');
$query = $this->db->get('orientation_master');
if ($query->num_rows() == 0) {
return 1;
}
$max = $query->row()->max;
return $max == 0 ? 1 : $max + 1;
}
Hope this will help you:
public function next_id()
{
$this->db->select_max('p_ori_id', 'max');
$query = $this->db->get('orientation_master');
// Produces: SELECT MAX(p_ori_id) as max FROM orientation_master
$max = $query->row()->max;
if($max == 0){
$next_id = 1;
}else{
$next_id = $max+1;
}
return $next_id;
}
For more : https://www.codeigniter.com/user_guide/database/query_builder.html
You are getting that error becuase $max is a result set object and not an integer record value like you're trying to use it.
You can try this function to get the next id.
Modified function:
public function next_id(){
$this->db->select_max('p_ori_id', 'max');
$result = $this->db->get('orientation_master');
$row = $result->row_array();
$next_id = isset($row['max']) ? ($row['max']+1) : 1;
return $next_id;
}
If the column is auto increment, you can use the below code instead.
Alternative:
public function next_id() {
$sql_string = "SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '".$this->db->dbprefix."orientation_master'";
$query = $this->db->query($sql_string);
$row = $query->row_array();
return $row['auto_increment'];
}

Logical algorithm to generate paths

I'm trying to develop an algorithm to create a symfony template service.
I want to check if a template exists in a subset of paths, ordered.
Given an array of parameter like this (already ordered like I want):
$params = ['O', 'U', 'W', 'P']
How can I output this array?
$urls = [
'O/U/W/P/template',
'O/U/W/template',
'O/U/P/template',
'O/U/template',
'O/W/P/template',
'O/W/template',
'O/P/template',
'O/template',
'U/W/P/template',
'U/W/template',
'U/P/template',
'U/template',
'W/P/template',
'W/template',
'P/template',
'template'
];
I can perform for a little list of parameters (like everyone can do it I suppose) with a code like this :
private function getPaths($template, $params)
{
$urls = [];
$alreadyPerform = [];
$paramsCounter = count($params);
for ($i = 0; $i < $paramsCounter; $i++) {
for ($j = 0; $j < $paramsCounter; $j++) {
if ($i !== $j && !in_array($params[$j], $alreadyPerform, true)) {
$urls[] = sprintf(
'/%s/%s/%s.html.twig', $params[$i], $params[$j], $template
);
}
}
$alreadyPerform[] = $params[$i];
$urls[] = sprintf('/%s/%s.html.twig', $params[$i], $template);
}
$urls[] = sprintf('%s.html.twig', $template);
return $urls;
}
This function work like I wanted until today (max 3 parameters), but I want to add one parameters today, maybe more after.
Thank you very much for your help !
Cheers.
Using recursion, you can do the following:
/**
* #param array $elements
* #param array $extra
*
* #return Generator
*/
function gen(array $elements, array $extra = []): \Generator {
foreach ($elements as $i => $head) {
foreach (gen(array_slice($elements, $i + 1), $extra) as $tail) {
yield array_merge([$head], $tail);
}
}
yield $extra;
}
demo: https://3v4l.org/gJB8q
Or without recursion:
/**
* #param array $elements
*
* #return Generator
*/
function gen2(array $elements): \Generator {
for ($num = count($elements), $i = pow(2, $num) - 1; $i >= 1; $i -= 2) {
$r = [];
for ($j = 0; $j < $num; $j += 1) {
if ($i & (1 << ($num - $j - 1))) {
$r[] = $elements[$j];
}
}
yield $r;
}
}
demo: https://3v4l.org/grKXo
Consider using the following package:
https://github.com/drupol/phpermutations
Just a very basic example of what it can do:
$permutations = new \drupol\phpermutations\Generators\Permutations(['A', 'B', 'C'], 2);
foreach ($permutations->generator() as $permutation) {
echo implode('/', $permutation);
echo "\n";
}
A/B
B/A
A/C
C/A
B/C
C/B

Resources