How to build a time based pricing system with overlaps - php

I am currently working on a reservation system in PHP (Laravel 5) and I can't figure out how to build a time based pricing system that calculates the totalprice with overlaps. Reservations are stored with the following fields
Reservations (Table)
begindate_time (DateTime)
enddate_time (DateTime)
price (decimal(10,2))
I have a prices table to lookup the prices for the input begintime and endtime which looks like this:
Prices (Table)
id (INT)
price (decimal(10,2))
begin_time (time)
end_time (time)
dayOfTheWeeks (varchar(255))
The begin_time/end_time can vary from 00:00:00 to 23:59:59 and the dayOfTheWeeks is a string with days for instance monday,tuesday,wednesday. I know there should only be one value for each field, but I was to lazy to make a whole table for the days of the week.
Than you have a activity that is linked to a reservation that has different prices based on the time the activity this is linked to a price_activity table, because prices can have different activity's
activity_price (Table)
id
activity_id (INT)
price_id (INT)
I tried to get the prices foreach activity and day like this, than I have them sorted and can try to loop through them and substract the endtime of the price minus the begintime of the reservation. This is what I came up with but it is not working...
foreach($activity->prices()->orderBy('begin_time','asc')->get() as $price){
$whichDayArray = explode(',',$price->dayOfTheWeeks);
if(in_array($dayToday,$whichDayArray)){
$prices = array();
if(strtotime($price->end_time) > strtotime($input['begintime']) && strtotime($price->begin_time) < strtotime($input['endtime'])){
$prices[] = array('id' => $price->id,'price' => $price->price,'beginTimePrice' => $price->begin_time, 'endTimePrice' => $price->end_time);
}
}
}
This is a lot of code and I have my prices that are overlapping my reservation now, but how do I calculate the amount of time a reservation is in a price. I think it can be done much easier and better than the above.

I've solved my own question. Hoping to help others with a similar problem, I would like to explain how I solved my problem.
After dumping my variables and making a visualization of the problem as shown below I found that the problem was related to my query.
[--pricerange1--][--pricerange2--][--pricerange2]
[----------reservation-----------]
I have to get all the prices for a activity on a given day of the between the begintime of the reservation and the endtime of a reservation, after that I have to check if there is one price, two prices or more than 2 prices. Than calculate the number of hours that a reservation is in a range and multiply it by the price a range. The code for this will look like this:
$begintijd = \Carbon\Carbon::createFromTime(16,30);
$eindtijd = \Carbon\Carbon::createFromTime(20,30);
$activiteit = \App\Activiteit::find(1);
$prijzen = $activiteit->prices()->where('eindtijd','>=',$begintijd->toTimeString())->where('begintijd','<=',$eindtijd->toTimeString())->orderBy('begintijd','asc')->get();
$prijzenArray = array();
foreach($prijzen as $prijs){
$whichDayArray = explode(',',$prijs->welkedagen);
if(in_array('maandag',$whichDayArray)){
$prijzenArray[] = array('prijs' => $prijs->prijs,'begintijdprijs' => $prijs->begintijd,'eindtijdprijs' => $prijs->eindtijd);
}
}
$countPrijzen = count($prijzenArray);
if($countPrijzen == 1){
$aantaluur = $begintijd->diffInMinutes($eindtijd) / 60;
$totaalprijs = $aantaluur * $prijzenArray[0]['prijs'];
echo('range1');
}
if($countPrijzen == 2){
$aantaluurrange1 = \Carbon\Carbon::createFromFormat('G:i',$prijzenArray[0]['eindtijdprijs'])->diffInMinutes($begintijd) / 60;
$aantaluurrange2 = $eindtijd->diffInMinutes(\Carbon\Carbon::createFromFormat('G:i',$prijzenArray[0]['eindtijdprijs'])) / 60;
$totaalprijs = ($aantaluurrange1 * $prijzenArray[0]['prijs']) + ($aantaluurrange2 * $prijzenArray[1]['prijs']);
echo('range2');
}
if($countPrijzen > 2){
$aantaluurrange1 = \Carbon\Carbon::createFromFormat('G:i',$prijzenArray[0]['eindtijdprijs'])->diffInMinutes($begintijd) / 60;
$prijsrange1 = $prijzenArray[0]['prijs'] * $aantaluurrange1;
$prijsertussen = 0;
for($prijs=1;$prijs<($countPrijzen-1);$prijs++){
$aantaluurertussen = \Carbon\Carbon::createFromFormat('G:i',$prijzenArray[$prijs]['eindtijdprijs'])->diffInMinutes(\Carbon\Carbon::createFromFormat('G:i',$prijzenArray[$prijs]['begintijdprijs'])) / 60;
$prijsertussen += $prijzenArray[$prijs]['prijs'] * $aantaluurertussen;
}
$aantaluurlaatsterange = $eindtijd->diffInMinutes(\Carbon\Carbon::createFromFormat('G:i',$prijzenArray[$countPrijzen-1]['begintijdprijs'])) / 60;
$prijslaatsterange = $prijzenArray[$countPrijzen-1]['prijs'] * $aantaluurlaatsterange;
$totaalprijs = $prijsrange1 + $prijsertussen + $prijslaatsterange;
}

Related

rowCount for items over 45 days old

I have a table and use this to show me how many days the widgets have been in stock, this is the code I am using for this
$getWidgets = $db->prepare("SELECT * FROM widgettracker WHERE id=id");
$getWidgets->execute();
$widgets = $getWidgets->fetchAll();
foreach ($widgets as $widget) {
$startDate = new DateTime();
$endDate = new DateTime($widget['dadded']);
$diff = date_diff($endDate,$startDate);
$days = (int) $diff->format('%a');
I have info boxes at the top of the screen giving me different widget info, what I wanted is one of these info boxes to give me a total of how many widgets have been in stock for 45 days +
I am using this code for other sections of the site but I hate working with days/dates and simply cannot get my head round where and how I put the count in for the ones over 45 days
$widget45days = $db->query("SELECT id FROM widgettracker WHERE widgetstatus='Widgets for Sale'");
$widget45dayscounted = $widget45days->rowCount();
The query should look like this:
SELECT *
FROM widgettracker
WHERE dadded < NOW() - INTERVAL 45 DAY;

php - how to increment a user's known earning every day for 4 months

I want to display to a user an amount per day and increment it until the next 124 days assumed to be four months.
I have a system where a user invest and a total ernable profit is calculated with the percentage ROI for such stock. Assuming someone invested in a stockA that has 20% ROI and matures in 4 months; assuming a user purchased that stockA that is sold $100 and he bought 4 units meaning he spent $400 and will earn
as follows:
$units = 4;
$cost = 100;
$roi = 20/100;
$total_invested = $units * $cost;
$profit = $total_invest * $roi;
// $profit will be $80
My problem is I want to display value of $profit/124 that is the displaying a fraction of total earning to the user daily until maturity of 4 months. I can't figure out how to do that daily not just with loop of 124 iterations.
that is if the user total earning is $80/124 giving 0.65 on the first day and increment it with same value the next day until it reached the end date which is 4 months from now
/**
*
* display and increment earning every day for 4 months or 124 days
*
*/
function display_earning() {
$profit = $profit_roi;
$dateBegin = now();
$dateEnd = "date of 4 month from now";
$earning = 0;
for ($i = 0; $i < 124; $i++) {
$earning += $profit / 124;
return $earning;
}
}
I think your problem is to update and save the updated earning of user for 4 months. To do that you need to write a server level cron-job that run on every day and a script in which you update and save the earning of user and check it has reached 4 months for that user since you started or not.
I hope you want this and that will help you. Happy Learning.
It's not clear what you want your code to do. Do you want it to give the total earned cumulatively by day x or give the total earned on any one day? If it is any one day and you don't want to take compound interest into account the earning will be the same every single day. In which case all your function has to do is return
function return_earnings($profit, $totalDays) {
return $profit / $totalDays;
}
as the amount earned each day will be the same as any other day. If you do want compound interest then you'll need to code that it. I assume you don't as there is no sign of it in the code you supplied.
I get the feeling what you are looking for instead is a list of how much was earned each day cumulatively. If that's the case, the code you've written is more appropriate but needs some modification. At the moment your code is returning $earning after the first iteration of the loop. Moving return to the end of the function should fix that.
function display_earning() {
$profit = $profit_roi;
$dateBegin = now();
$dateEnd = "date of 4 month from now";
$earning = 0;
$totalDays = 124; // You might want to change '124' in future
// and having $totalDays in the for loop makes it more
// obvious what your code is trying to do.
for ($i = 0; $i < $totalDays; $i++) {
$earning += $profit / $totalDays;
}
return $earning;
}
However now because of the line $earning += you will return the sum of earning at the end of $totalDays, ie the $profit, which you already know! You may want the cumulative earnings by a given day to be an item in an array, in which case:
function display_earning() {
$profit = $profit_roi;
$dateBegin = now();
$dateEnd = "date of 4 month from now";
$totalEarning = 0; //renamed to $totalEarning
$earningsByDay = array();
$totalDays = 124;
for ($i = 0; $i < $totalDays; $i++) {
$totalEarning += $profit / $totalDays;
$earningsByDay[$i] = $totalEarning;
}
return $earningsByDay;
}
This will now return an array with each element of the array amounting to the sum earned by that day. For example, $earningsByDay[0] will be the first day, $earningsByDay[11] will be the 10th day etc. If this is what you are looking for, you can use php's native range() function to make your life easier:
function display_earning() {
$profit = $profit_roi;
$dateBegin = now();
$dateEnd = "date of 4 month from now";
$totalEarning = 0; //renamed to $totalEarning
$earningsByDay = array();
$totalDays = 124;
return range(0, $profit, $profit/$totalDays)
}
A few final thoughts:
You say you want to display the amount earned each day. You function does not display anything it just calculates a value and returns it. That's good practise. Have your functions do one thing. Some other function can display the data from this one, or perhaps multiple functions can, each formatting it in a way that is appropriate for your current need. I can't help you with the display as I have no way of knowing what format you want. $dateEnd probably doesn't need to be in the function.
On a related note, another function name might lead to less confusion about what the function does.
I'm not sure what $dateBegin = now(); adds, unless as Moeez Saiyam suggests, you are trying to automate this somehow.
You've defined $profit = $profit_roi; without declaring what $profit_roi is in the scope of your function. I know it was in your introductory notes, but the function won't know that.
Is the function the right place to define $profit and $totalDays? They are probably passed to the function form elsewhere.
Combining these thoughts, this gives us:
function getIncrementalEarnings($profit, $totalDays) { //function renamed to clarify its purpose
return range(0, $profit, $profit/$totalDays)
}

For php does not increase

I have a table of users in a database, where I have the following fields:
id_usuario
login
passwd
dias_disponibles (Fixed users have 24 days available)
fecha_ingreso (Date entry in company)
tipo_usuario (Fixed or Temporary)
Each user can make a vacation request. The user admin is responsible for adding the new users. My problem is with temporary users. A temporary user will have the available days according to the months worked up to one year. For every month worked, dias_disponibles is increased by 2. For example, if user1 since joining the company, it has been working for 2 months now it will have 4 dias_disponibles and so on until it takes 12 months, then from there, it will always be 24 dias_disponibles . I have this function that calculates the difference of months since I joined the company until today:
function difmeses($fechaingreso){
$fechainicial = new DateTime($fechaingreso);
$fechaactual = (new DateTime)->format('Y-m-d H:i');
$fechafinal = new DateTime($fechaactual);
$diferencia = $fechainicial->diff($fechafinal);
$meses = ( $diferencia->y * 12 ) + $diferencia->m;
return $meses;
}
My question is what to use so that it increases until 12 months in the company, if it takes 12 months, stop. I have created this for, but I do not know how to continue so that it increases in 2 days available:
$mes = difmeses("2018-03-15 00:00");
for($i = 1; $mes <= 12; $i++){
mysql_query("update sec_users set dias_disponibles = dias_disponibles + 2 where login = 'user1'");
}
It does not do what I want very well.
First of all your logical problem
The problem you have is in your last part of the code
$mes = difmeses("2018-03-15 00:00");
for($i = 1; $mes <= 12; $i++){
mysql_query("update sec_users set dias_disponibles = dias_disponibles + 2 where login = 'user1'");
}
First of all, there is no need at all to use a for loop here. You overwrite the update commands of the previous runs of the loop, so at the end only the last one will be in the table. Because of this you can work with the last one without a loop.
Sencond you got a really simple formula here: Free days = (month worked * 2) max 24. Just write that down as code:
$mes = difmeses("2018-03-15 00:00");
$dias = max($mes * 2, 24);
mysql_query("UPDATE sec_users SET dias_disponibles = $dias where login = 'user1'");
Now another huge problem
Do not use the mysql_ functions. They are deprecated! Instead use the mysqli_ functions or PDO and read about prepared statements.

Calculating frequency interval for tasks

I have a cron job that gets results from the DB to check it the interval set by user falls on today's date. I am currently thinking of doing it as below :
Get the time column for the row. Ex:2017-05-25 00:00:00
Get the frequency set. Ex:Every 2 weeks.
Get the current date in above format. Ex:2017-05-31 00:00:00
Get the difference in days. Ex:6 days.
Convert the frequency set to days. Ex:2 weeks = 14 days;
Divide (difference in time(days)) by (frequency in days). Ex:6/14
This way I will only get the result to be true when 2 weeks have passed since the time set. I.e., 14/14, 28/14, 42/14,...
If the frequency is in months, I can start dividing by 30. But somehow this feels like a hacky way of doing it. So my question is if there is better way of doing this calculation to check the difference.
This is what I have done as explained by above example.
` $frequency = ; // Get the relevant fields from db
$today = date(Y-m-d H:i:s);
foreach ($frequency as $key => $value) {
$frequency_in_days;
$frequency_type = $value->type;
$frequency_repeat = $value->repeat;
if($frequency_type == 1){
$frequency_in_days = $frequency_repeat;
} elseif($frequency_type == 2) {
$frequency_in_days = $frequency_repeat * 7;
} elseif($frequency_type == 3) {
$frequency_in_days = $frequency_repeat * 30;
} elseif($frequency_type == 4) {
$frequency_in_days = $frequency_repeat * 365;
}
// Get number of days spent between start_date and today in days.
$interval = date_diff($value->start_date, $today)->format('%a');
$result = $interval % $frequency_in_days;
if ($result == 0) {
// Frequency falls today! Do the job.
}
}`
Note: The cron job runs this script. The script again needs to check if the today falls under the frequency set.
Also for argument's sake, is this the best logic to calculate the difference?
Thank you.
This will work
Table "schedule"
`last_run` timestamp,
`frequency_seconds` int
example query for tasks that should go every two weeks:
SELECT *
FROM schedule
WHERE TIMESTAMPDIFF(last_run, NOW()) >= frequency_seconds
after fetching rows update last_run to NOW()

Present Value Calculator php

The PHP script captures the values and calculates the future value. working backwards from the last month to the first, how could I compute the investment for the previous month and display the months number and the value all the way back to the first investment (Unknown). I've already figured out that I'll have to uses a formula like this "months value = (months value)/(1 + rate)" but after that I hit a road block. basically I'm trying how to figure how much do you invest today to have a balance value of $XXX after xx years at a x% interest rate?
<?php
// get the data from the form
$investment = $_POST['investment'];
$interest_rate = $_POST['interest_rate'];
$years = $_POST['years'];
// calculate the future value
$future_value = $investment;
for ($i = 1; $i <= $years; $i++) {
$future_value = ($future_value + ($future_value * $interest_rate *.01));
}
// apply currency and percent formatting
$investment_f = '$'.number_format($investment, 2);
$yearly_rate_f = $interest_rate.'%';
$future_value_f = '$'.number_format($future_value, 2);
?>
Your formula is basically this:
Start with X
For each of the Y years, increase X by Z%
This is a simple function: result = X * (1+Z%)^Y
So you know there's a specific result you want, and you know the number of years and the interest rate, and you want to calculate the base amount. Easy: X = result / (1+Z%) ^ Y
Using your variable names, you'd get
$investment = $future_value / pow(1+$interest_rate/100,$years);
Done!

Categories