Add payment after monthly schedule expired - php

I have two models, Payment and GroupStarts.
Payment has these fields:
student_id, amount_to_pay, student_paid, date_paid, due_date, group_name
On GroupStarts are:
group_name, group_start, group_end, group_status.
This is how it should work:
If payment is made for one month and it expires after month 1, it should add amount_to_pay to that for month 1 and if in month 2 student didn't paid nothing than we add + amount to pay, similar to: if student have to pay $10 and paid so owe is 0 but for next month he didn't paid so we add it to payment $10 if on month 3 he didn't paid we add $10 more to that amount.
How can I do that ?
This is code I tried:
private function getMonthlyUnpayments()
{
$payments = Payment::all();
$unpayment = 0;
$totalPayment = 0;
foreach ($payments as $key => $value) {
$unpayment += $value->amount_to_pay;
$totalPayment += $value->student_paid;
}
$studentsAllU = Student::where('is_canceled', '=', 0)->get();
$groupAllU = Gstart::where('group_status', '=', 0)->get();
$studentGroupAllU = [];
foreach ($studentsAllU as $key => $value) {
foreach ($groupAllU as $keys => $valu) {
foreach ($value->payment as $paymentID) {
if ($value->group_id == $valu->group_name) {
$studentGroupAllU[] = ['name' => $value->full_name, 'student_id' => $value->id, 'gr_id' => $value->group_id, 'paid' => $paymentID->student_paid, 'to_pay' => $paymentID->amount_to_pay, 'due_date' => $paymentID->due_date, 'group_ends' => $valu->group_end];
}
}
}
}
function nb_mois($from, $to)
{
$fromYear = date("Y", strtotime($from));
$fromMonth = date("m", strtotime($from));
$toYear = date("Y", strtotime($to));
$toMonth = date("m", strtotime($to));
if ($fromYear == $toYear) {
return ($toMonth-$fromMonth)+1;
} else {
return (12-$fromMonth)+1+$toMonth;
}
}
function createDateRangeArray($strDateFrom,$strDateTo)
{
$aryRange=array();
$iDateFrom=mktime(1,0,0,substr($strDateFrom,5,2), substr($strDateFrom,8,2),substr($strDateFrom,0,4));
$iDateTo=mktime(1,0,0,substr($strDateTo,5,2), substr($strDateTo,8,2),substr($strDateTo,0,4));
if ($iDateTo>=$iDateFrom)
{
array_push($aryRange,date('Y-m-d',$iDateFrom));
while ($iDateFrom<$iDateTo)
{
$iDateFrom+=86400;
array_push($aryRange,date('Y-m-d',$iDateFrom));
}
}
return $aryRange;
}
$dtArr = [];
$incrementer = 0;
$inc = 0;
foreach ($studentGroupAllU as $key => $value) {
if ($value['group_ends'] >= $value['due_date'] || $value['paid'] < $value['to_pay']) {
if ($value['paid'] < $value['to_pay']) {
$incrementer += ($value['to_pay'] - $value['paid']);
}
else {
$incrementer += ($value['to_pay']);
}
$dtArr[] = ['days_left' => count(createDateRangeArray($value['due_date'], $value['group_ends'])), 'group_id_d' => $value['gr_id'], 'paid' => $value['paid'], 'to_pay' => $value['to_pay'], 'student_id' => $value['student_id'], 'owe' => ($inc +=($value['to_pay'] - $value['paid'])), 'dates' => createDateRangeArray($value['due_date'], $value['group_ends']),'dates_fron_last_payment' => createDateRangeArray($value['due_date'], Carbon::now()->format('Y-m-d')), 'days_fron_last_payments' => count(createDateRangeArray($value['due_date'], Carbon::now()->format('Y-m-d')))];
}
$inc = 0;
}
function uniqueAssocArray($array, $uniqueKey) {
$arr = array();
foreach($array as $key => $item)
{
$arr[$item[$uniqueKey]][$key] = $item;
}
ksort($arr, SORT_NUMERIC);
return $arr;
}
$dd = uniqueAssocArray($dtArr, 'group_id_d');
$tpStudentGr = 0;
// dd($dtArr);
foreach ($dtArr as $key => $value) {
foreach ($value['dates'] as $k => $val) {
if ($val == Carbon::createFromFormat('Y-m-d', $val)->startOfMonth()->format('Y-m-d') && $val <= Carbon::now()->startOfMonth()->format('Y-m-d')) {
if ($value['paid'] < $value['to_pay']){
$tpStudentGr += ($value['to_pay'] - $value['paid'] + $value['to_pay']);
}
if ($value['paid'] == $value['to_pay']){
$tpStudentGr += $value['to_pay'];
}
}
}
if ($value['days_left'] > 0) {
}
}
$tpStudentGr = $unpayment - $totalPayment;
return $tpStudentGr;
}

Related

Counting tickets by hour in Laravel

I'm trying to create hourly counting groups of tickets. I have to count three tickets for each hour and insert them as a bonus while inserting the remaining ones as a malus; every hour perform this count on a table where tickets are generated. I should calculate based on two time periods, one from 7 in the morning to 15 in the afternoon and one from 15 in the afternoon to 7 in the morning. I was taking a cue from this post, but I can't see the ticket number and time, while I can see the down, up, total and uptime columns. Can anyone help me perform this? I would also like to insert the count of time between the opening and closing of each intervention
Laravel group data by odd amount of hours throughout days
$uptimeData = Ticket::whereYear('created_at', '>=', Carbon::now()->year)
->whereYear('created_at', '<=', Carbon::now()->year)
->orderBy('created_at', 'asc')
->select('ticket_Id', 'created_at')
->get();
$intervals = \Carbon\CarbonInterval::hours(1)->toPeriod('2023/01/01 07:00:00', '2023/01/01 15:00:00');
$uptimeDataTimeline = $uptimeData->groupBy(function ($item, $key) use ($intervals) {
$date = Carbon::parse($item->created_at);
foreach ($intervals as $key => $interval) {
if ($date->hour == Carbon::parse($interval)->addHours(1)->hour) {
$actualHour1 = Carbon::parse($interval)->hour;
if (strlen($actualHour1) == 1) {
$actualHour1 = "0$actualHour1";
}
return $date->format("Y-m-d $actualHour1:00:00");
} else {
if ($date->hour == Carbon::parse($interval)->addHours(1)->hour) {
$actualHour2 = Carbon::parse($interval)->subHours(1)->hour;
if (strlen($actualHour2) == 1) {
$actualHour2 = "0$actualHour2";
}
return $date->format("Y-m-d $actualHour2:00:00");
}
}
}
return $date->format('Y-m-d H:00:00');
});
$uptimeDataTimeline = $uptimeDataTimeline->map(function ($checksInPeriod, $key) {
$down = 0;
$up = 0;
$total = 0;
$uptime = 0;
$fill = '#1fc777';
foreach ($checksInPeriod as $key => $value) {
$total++;
if ($total <= 3) {
$up++;
} else {
$down++;
}
}
$uptime = floatval(number_format(round($up / $total, 5) * 100, 2, '.', ','));
if ($uptime < 100) {
$fill = '#9deab8';
}
if ($uptime < 99) {
$fill = '#fbaa49';
}
if ($uptime < 98) {
$fill = '#e0465e';
}
return [
'total_ticket_Id' => $total,
'down_ticket_Id' => $down,
'up_ticket_Id' => $up,
'uptime' => $uptime,
'fill' => $fill,
];
});

Why does this code take a long time to execute?

I would appreciate some guidance on the following issue. I am by no means an expert in php. The code below takes almost 10 seconds to execute! Is there anything I am doing that is wrong or bad practice?
$data = [];
$today = date("Y/m/d");
$ThisYear = Date('Y'); //get current Year
$ThisMonth = Date('m'); //get current month
$Tday = '01'; //first day of month
$Tmonth = '09'; //September
if (8 < $ThisMonth && $ThisMonth < 13) {
$AcYear = $ThisYear; }
else {
$AcYear = $ThisYear - 1; // sets start of academic year to be last year
}
$AcFullYear = $AcYear.'/'.$Tmonth.'/'.$Tday;
//find rank in all school
$students_rank = [];
$school_id = Student::model()->findByAttributes(['user_master_id' => Yii::app()->user->id])->school_master_id;
$criteria1 = new CDbCriteria;
$criteria1->with = array('user');
$criteria1->condition = "t.school_master_id=:school_master AND user.status ='1'";
$criteria1->params = array(':school_master' => $school_id);
$school_students_details = Student::model()->findAll($criteria1);
foreach ($school_students_details as $key => $value) {
$student_name = StudentDetails::model()->findByAttributes(['user_master_id' => $value->user_master_id]); //student details with year group
$criteria2 = new CDbCriteria;
$criteria2->with = array('homeworkMaster');
$criteria2->condition = "t.student_id=:student_id AND homeworkMaster.question_type_id<>:question_type_id";
$criteria2->params = array(':student_id' => $value->user_master_id, ':question_type_id' => 6);
$HW_assignment_track = HomeworkAssignmentTrack::model()->findAll($criteria2);
$total_HW = count((array)$HW_assignment_track);
$student_score = 0;
$student_rank = 0;
$student_total_score = 0;
$total_HW_marks = 0;
$under_deadline_HW = 0;
$criteria3 = new CDbCriteria();
$criteria3->condition = "student_id =:student_id AND status=:status AND created_at >= '$AcFullYear' AND created_at <= '$today'";
$criteria3->params = [':student_id' => $value->user_master_id, ':status' => 2];
$student_completed_HW = HomeworkStudentAnswere::model()->findAll($criteria3);
$i = 1;
foreach ($student_completed_HW as $s_c_h_K => $s_c_h_V) {
if ($s_c_h_V->homework->homework_type == 2) {
$total_HW -= 1;
} elseif ($s_c_h_V->homework->homework_type == 1) {
$HW_questions = HomeworkQuestion::model()->findAllByAttributes(['homework_master_id' => $s_c_h_V->homework_id, 'status' => 1]);
foreach ($HW_questions as $qKey => $qVal) {
if ($qVal->question_type_id ==3) {
$total_HW_marks += 2;
} else {
$total_HW_marks += $qVal->marks;
}
}
$assignment = HomeworkAssignmentTrack::model()->findByAttributes(['id' => $s_c_h_V->assignment_track_id]);
$homeworks_within_validate = Assignment::model()->findByPk($assignment->assignment_id);
if ($homeworks_within_validate->valid_date === '0' && $homeworks_within_validate->deadline >= date('Y-m-d')) {
$total_HW -= 1;
}
if ($homeworks_within_validate->valid_date === '1' || (($homeworks_within_validate->valid_date === '0') && ($homeworks_within_validate->deadline >= date('Y-m-d', strtotime($s_c_h_V->created_at))) && ($homeworks_within_validate->deadline < date('Y-m-d')))) {
if ($s_c_h_V->review_status === '2') {
$student_total_score += $s_c_h_V->score;
}
}
$homework_submit = HomeworkCompleteNotification::model()->findByAttributes(['homework_id' => $s_c_h_V->homework_id, 'assignment_track_id' => $s_c_h_V->assignment_track_id, 'student_id' => $value->user_master_id]);
if (($homeworks_within_validate->valid_date === '0') && ($homeworks_within_validate->deadline >= date('Y-m-d', strtotime($homework_submit->created_at))) && ($s_c_h_V->review_status === '2')) {
$under_deadline_HW += 10;
}
if ($total_HW_marks !=0) {
$student_score += round(($student_total_score / $total_HW_marks) * 100);
} else {
$student_score = 0;
}
}
$i += 1;
}
//add revision scores to rank score
$criteria4 = new CDbCriteria();
$criteria4->condition = "user_id =:user_id AND date_created >= '$AcFullYear' AND date_created <= '$today'";
$criteria4->params = [':user_id' => $value->user_master_id];
$revision_score = RevisionScores::model()->findAll($criteria4);
$sum = 0;
foreach($revision_score as $item) {
$sum += $item['score'];
} //end of adding revision scores
$students_rank[$key]['student_id'] = $value->user_master_id;
$students_rank[$key]['year_group'] = $student_name->year_group_id; //added year group to model array
if ($student_score > 0) {
$student_rank += round($student_score / $total_HW, 0) + $under_deadline_HW;
$students_rank[$key]['rank'] = $student_rank + $sum;
} else {
$students_rank[$key]['rank'] = $sum;
}
}
$model = $this->multid_sort($students_rank, 'rank');
$rank_score = round(array_column($model, 'rank', 'student_id')[Yii::app()->user->id],0);
$year_rank =[];
$current_st = StudentDetails::model()->findByAttributes(['user_master_id' => Yii::app()->user->id]);
$current_st_year = $current_st->year_group_id;
$rank_list = [];
foreach ($model as $key => $value) {
$rank_list[] = $value['student_id'];
if ($value['year_group'] == $current_st_year) {
$year_rank[] = $value['student_id'];
}
}
$user = Yii::app()->user->id;
$sch_position = array_search($user,$rank_list);
$yr_position = array_search($user,$year_rank);
$final_rank = $sch_position + 1;
$yr_rank = $yr_position + 1;
$sch_rank = $final_rank;
$ends = array('th','st','nd','rd','th','th','th','th','th','th');
if (($sch_rank %100) >= 11 && ($sch_rank%100) <= 13) {
$sc_abbreviation = 'th';
$yr_abbreviation = 'th';
} else {
$sc_abbreviation = $ends[$sch_rank % 10];
$yr_abbreviation = $ends[$yr_rank % 10];
}
$models = UserMaster::model()->findByPk(Yii::app()->user->id);
$year_name = $models->studentDetails->yearGroup->name;
$data['type'] = 'success';
$data['score'] = '<div>Ranking Score: '.$rank_score.'</div>';
$data['yr_rank'] = '<div><i class="fa fa-trophy rank-i"></i><span class="rank-number">' .$yr_rank. '</span><sup class="script-top" id="year_rank_abb">' .$yr_abbreviation. '</sup></div><div id="year_name">In ' .$year_name. '</div>';
$data['school_rank'] = '<div><i class="fa fa-trophy rank-i"></i><span class="rank-number">' .$sch_rank. '</span><sup class="script-top" id="year_rank_abb">' .$sc_abbreviation. '</sup></div><div id="year_name">In School</div>';
$data['rank_revise'] ='<div>'.$rank_score.'</div>';
$data['yr_rank_revise'] = '<span>'.$yr_rank.'</span><sup class="superscript" style="left:0">'.$yr_abbreviation.'</sup>';
$data['sch_rank_revise'] = '<span>'.$sch_rank.'</span><sup class="superscript" style="left:0">'.$sc_abbreviation.'</sup>';
$_SESSION['rank'] = $rank_score;
$_SESSION['accuracy'] = $rank_score;
echo json_encode($data);
exit;
The above is used in an Yii application. It runs perfectly fine on localhost, but on live site, takes over 10 seconds to execute.
Your help and guidance is appreciated.
Thank

Increment in fetch array while loop

I have trouble to increment correctly a variable in a while loop where I fetch data from my database.
This is the code:
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
//January
if ($row['month'] ==1){
if ($row['day_range'] == '01-07') {
$val1_1 = $row['duration'];
$int1_1 = $row['intensity'];
}
elseif ($row['day_range'] == '08-14') {
$val1_2 = $row['duration'];
$int1_2 = $row['intensity'];
}
elseif ($row['day_range'] == '15-21') {
$val1_3 = $row['duration'];
$int1_3 = $row['intensity'];
}
elseif ($row['day_range'] == '22-end') {
$val1_4 = $row['duration'];
$int1_4 = $row['intensity'];
}
//Avg intensity
$int1 = ($int1_1 + $int1_2 + $int1_3 + $int1_4)/4;
}
}
So I have this code for every month.
The problem here is that sometimes I don't have 4 values, so at the end when I calculate the AVG it is sometimes wrong because it always divides it by 4
What I've done :
I had the idea of incrementing a variable $i each time I have a value, like this
$i = 0;
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
//January
if ($row['month'] ==1) {
if ($row['day_range'] == '01-07') {
$val1_1 = $row['duration'];
$int1_1 = $row['intensity'];
$i++;
}
elseif ($row['day_range'] == '08-14') {
$val1_2 = $row['duration'];
$int1_2 = $row['intensity'];
$i++;
}
elseif ($row['day_range'] == '15-21') {
$val1_3 = $row['duration'];
$int1_3 = $row['intensity'];
$i++;
}
elseif ($row['day_range'] == '22-end') {
$val1_4 = $row['duration'];
$int1_4 = $row['intensity'];
$i++;
}
//Avg intensity
$int1 = ($int1_1 + $int1_2 + $int1_3 + $int1_4)/$i;
}
$i = 0;
//code for next month
}
But it doesn't work, I've echoed it and $i stays at 1.
I think it is because it fetch row by row so it never goes through all incrementations to reach the value desired.
How can I do that please?
// Here is an array to get the data of EACH month
$month = array();
$i = 0;
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
// This way, you will have $month[1] for January, $month[2] for February, etc.
$month[$row['month']][] = array(
"duration" => $row['duration'],
"intensity" => $row['intensity'];
);
}
// Now you get all the data, you can calculate the Avg intensity for each month
foreach ($month as $month_number => $data) {
$moy = count($month[$month_number]); // Will be 4 if you have 4 period, 3 if only 3, etc.
$sum = 0;
foreach ($data as $value) {
$sum += $value['intensity'];
}
$month[$month_number]['avg_intensity'] = $sum / $moy;
}
With this method you should get an array with all the data you want that look like this :
$month = array(
// January
1 => array(
0 => array(
'duration' => ...,
'intensity' => ...
),
1 => array(
'duration' => ...,
'intensity' => ...
),
...
'avg_intensity' => /* moy of all intensity of the month */
),
// February
2 => array(
...
),
...
);
Hope it helps you !
EDIT :
As suggested if the comment by Nigel Ren, you can replace
$sum = 0;
foreach ($data as $value) {
$sum += $value['intensity'];
}
By
$sum = array_sum(array_column($data, "intensity"));
Please try like
$int1_1 += $row['intensity'];
way.
That means
$i = 0;
$int1_1 = 0;
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
//January
if($row['month'] ==1){
if($row['day_range'] == '01-07'){
$val1_1 = $row['duration'];
$int1_1 += $row['intensity'];
$i++;
}
elseif($row['day_range'] == '08-14'){
$val1_2 = $row['duration'];
$int1_1 += $row['intensity'];
$i++;
}
elseif($row['day_range'] == '15-21'){
$val1_3 = $row['duration'];
$int1_1 += = $row['intensity'];
$i++;
}
elseif($row['day_range'] == '22-end'){
$val1_4 = $row['duration'];
$int1_1 += $row['intensity'];
$i++;
}
//Avg intensity
$int1 = $int1_1/$i;
}
$i=0;
//code for next month
}

How to get the label in the result of an array

The following code works as expected to get the number of patients per age group.
It also gets the highest (or most common) age group.
$count_0_19 = 0;
$count_20_29 = 0;
$count_30_39 = 0;
$count_40_49 = 0;
$count_50_59 = 0;
$count_above_60 = 0;
$curr_year = date('Y');
$sql= "SELECT pt_dob FROM ptlist WHERE mid=$userID";
$stmt = $pdo->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$result = $pdo->query($sql);
$pt_dob = $row[ 'pt_dob' ];
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
$pt_dob = explode('-', $row['pt_dob']);
$year = $pt_dob[0];
$month = $pt_dob[1];
$day = $pt_dob
$temp = abs($curr_year - $year);
if($temp >= 0 && $temp <= 19) {
$count_0_19++;
}
elseif($temp >= 20 && $temp <= 29) {
$count_20_29++;
}
elseif($temp >= 30 && $temp <= 39) {
$count_30_39++;
}
elseif($temp >= 40 && $temp <= 49) {
$count_40_49++;
}
elseif($temp >= 50 && $temp <= 59) {
$count_50_59++;
}
else {
$count_above_60++;
}
}
echo '0-19: '.$count_0_19.'<br>';
echo '20-29: '.$count_20_29.'<br>';
echo '30-39: '.$count_30_39.'<br>';
echo '40-49: '.$count_40_49.'<br>'; // example output is > 40-49: 7 (i.e. 7 patients in age group 40-49)
echo '50-59: '.$count_50_59.'<br>';
echo '60+: '.$count_above_60.'<br>';
// getting highest value
$a = array($count_0_19, $count_20_29, $count_30_39, $count_40_49, $count_50_59, $count_above_60);
$res = 0;
foreach($a as $v) {
if($res < $v)
$res = $v;
}
echo $res;
^^ This tells me that e.g. 9 patients are in the 30-39 age group - i.e. the highest number of patients are in this age group.
But $res gives me only the number (e.g. 9).
What I am asking your help with is to get $res to give me the text(or label) "30-39", instead of the number 9.
Please help.
continue from comment... you need to store $key into a variable.
$a = array('0-19'=>$count_0_19, '20-29'=>$count_20_29, '30-39'=>$count_30_39, '40-49'=>$count_40_49, '50-59'=>$count_50_59, '60+'=>$count_above_60);
$res = 0;
$label = '';
foreach($a as $key => $v) {
if($res < $v){
$res = $v;
$label = $key; //get label from key and store in a variable
}
}
echo 'label = '.$label . ' , Number = '.$res;
You can archived this by creating the array of labels and then incrementing it according and then find the greatest value form the $label array to get the key.
$label = [
"0_19" => 0,
"20_29" => 0,
"30_39" => 0,
"40_49" => 0,
"50_59" => 0,
"above_60" => 0,
];
while ($row4 = $result4->fetch(PDO::FETCH_ASSOC)) {
$pt_dob = explode('-', $row4['pt_dob']);
$year = $pt_dob[0];
$month = $pt_dob[1];
$day = $pt_dob$temp = abs($curr_year - $year);
if ($temp >= 0 && $temp <= 19) {
$label['0_19'] = $label['0_19'] +1;
}
elseif ($temp >= 20 && $temp <= 29) {
$label['20_29'] = $label['20_29'] +1;
}
elseif ($temp >= 30 && $temp <= 39) {
$label['30_39'] = $label['30_39']+1;
}
elseif ($temp >= 40 && $temp <= 49) {
$label['40_49'] = $label['40_49'] +1;
}
elseif ($temp >= 50 && $temp <= 59) {
$label['50_59'] = $label['50_59']+1;
}
else {
$label['above_60']= $label['above_60']+1;
}
}
echo $maxs = array_keys($label, max($label));
echo "<br/>";
foreach($label as $k => $v);
echo "key $k count $v <br/>";

array not displaying the correct value

$data['results'] = $this->lawmodel->getuser($lastName);
$xp = array("lvl1" => 0, "lvl2" => 256, "lvl3" => 567);
foreach ($data['results'] as $row) {
$my_xp = $row->points; // the value is 300
}
for ($i = 0; $i < count($xp); $i++) {
if ($my_xp >= $xp[$i]) {
$data['level'] = $i+1;
break;
}
else {
if (isset($xp[$i+1])) {
if ($my_xp > $xp[$i] && $my_xp <= $xp[$i + 1]) {
$data['next'] = $xp[$i+1],;
break;
}
else {
$data['next'] = $xp[$i],
break;
}
}
}
}
I have a problem the output of $data['level'] = $i+1 is always 1.. I want that it will output the key of an array that the value is equal or greater than $my_xp.
Flow:
If the points of the user is 300 it should be at lvl2.
Plss..i need help..im new in php..:(
Your array
$xp = array("lvl1" => 0, "lvl2" => 256, "lvl3" => 567);
has no integer keys
Try this code:
$data['results'] = $this->lawmodel->getuser($lastName);
$xp = array("lvl1" => 0, "lvl2" => 256, "lvl3" => 567);
$key_prefix = 'lvl';
foreach ($data['results'] as $row) {
$my_xp = $row->points; // the value is 300
}
$previous_xp = 0;
foreach ($xp as $lvl => $xp_value) {
if ($my_xp >= $xp_value) {
$data['level'] = $lvl;
} else {
if ($my_xp > $previous_xp && $my_xp <= $xp_value) {
$data['next'] = $xp_value;
} else {
$data['next'] = $previous_xp;
}
}
$previous_xp = $xp_value;
}

Categories