Timepicker that removes times as they're selected (ajax) - ajax

I'm building a booking form for a moving business that uses a calendar combined with a start and end time. I built the timepicker with Formidable Pro, and it allows me to check "unique" on time fields which automatically removes them on the selected date. However it doesn't automatically remove the times from within the range between start and end times (ie: if someone chooses to rent a truck from 1am-3am I need 1am,2am,and 3am to be removed from future options but right now it only removes 1am and 3am) . I need to write ajax to remove the in-between times from the options. I'm not sure where to begin. This is the current ajax_time_ options function. Any push in the right direction would be appreciated.
function ajax_time_options(){
global $frmpro_settings, $frmdb, $wpdb;
//posted vars = $time_field, $date_field, $step, $start, $end, $date, $clock
extract($_POST);
$time_key = str_replace('field_', '', $time_field);
$date_key = str_replace('field_', '', $date_field);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($date)))
$date = FrmProAppHelper::convert_date($date, $frmpro_settings->date_format, 'Y-m-d');
$date_entries = FrmEntryMeta::getEntryIds("fi.field_key='$date_key' and meta_value='$date'");
$opts = array('' => '');
$time = strtotime($start);
$end = strtotime($end);
$step = explode(':', $step);
$step = (isset($step[1])) ? ($step[0] * 3600 + $step[1] * 60) : ($step[0] * 60);
$format = ($clock) ? 'H:i' : 'h:i A';
while($time <= $end){
$opts[date($format, $time)] = date($format, $time);
$time += $step;
}
if($date_entries and !empty($date_entries)){
$used_times = $wpdb->get_col("SELECT meta_value FROM $frmdb->entry_metas it LEFT JOIN $frmdb->fields fi ON (it.field_id = fi.id) WHERE fi.field_key='$time_key' and it.item_id in (". implode(',', $date_entries).")");
if($used_times and !empty($used_times)){
$number_allowed = apply_filters('frm_allowed_time_count', 1, $time_key, $date_key);
$count = array();
foreach($used_times as $used){
if(!isset($opts[$used]))
continue;
if(!isset($count[$used]))
$count[$used] = 0;
$count[$used]++;
if((int)$count[$used] >= $number_allowed)
unset($opts[$used]);
}
unset($count);
}
}
echo json_encode($opts);
die();
}

Related

Getting non overlapping between two dates with Carbon

UseCase: Admin assigns tasks to People. Before we assign them we can see their tasks in a gantt chart. According to the task assign date and deadline, conflict days (overlap days) are generated between tasks.
I wrote this function to get overlapping dates between two dates. But now I need to get non overlapping days between two dates, below is the function I wrote.
$tasks = Assign_review_tasks::where('assigned_to', $employee)
->where('is_active', \Constants::$REVIEW_ACTIVE)
->whereNotNull('permit_id')->get();
$obj['task'] = count($tasks);
// count($tasks));
if (count($tasks) > 0) {
if (count($tasks) > 1) {
$start_one = $tasks[count($tasks) - 1]->start_date;
$end_one = $tasks[count($tasks) - 1]->end_date;
$end_two = $tasks[count($tasks) - 2]->end_date;
$start_two = $tasks[count($tasks) - 2]->start_date;
if ($start_one <= $end_two && $end_one >= $start_two) { //If the dates overlap
$obj['day'] = Carbon::parse(min($end_one, $end_two))->diff(Carbon::parse(max($start_two, $start_one)))->days + 1; //return how many days overlap
} else {
$obj['day'] = 0;
}
// $arr[] = $obj;
} else {
$obj['day'] = 0;
}
} else {
$obj['day'] = 0;
}
$arr[] = $obj;
start_date and end_date are taken from database,
I tried modifying it to,
(Carbon::parse((min($end_one, $end_two))->add(Carbon::parse(max($start_two, $start_one))))->days)->diff(Carbon::parse(min($end_one, $end_two))->diff(Carbon::parse(max($start_two, $start_one)))->days + 1);
But it didn't work, in simple terms this is what I want,
Non conflicting days = (end1-start1 + end2-start2)- Current overlapping days
I'm having trouble translate this expression . Could you help me? Thanks in advance
before trying to reimplement complex stuff I recommend you take a look at enhanced-period for Carbon
composer require cmixin/enhanced-period
CarbonPeriod::diff macro method is what I think you're looking for:
use Carbon\CarbonPeriod;
use Cmixin\EnhancedPeriod;
CarbonPeriod::mixin(EnhancedPeriod::class);
$a = CarbonPeriod::create('2018-01-01', '2018-01-31');
$b = CarbonPeriod::create('2018-02-10', '2018-02-20');
$c = CarbonPeriod::create('2018-02-11', '2018-03-31');
$current = CarbonPeriod::create('2018-01-20', '2018-03-15');
foreach ($current->diff($a, $b, $c) as $period) {
foreach ($period as $day) {
echo $day . "\n";
}
}
This will output all the days that are in $current but not in any of the other periods. (E.g. non-conflicting days)

Loop through collection in laravel and get specific data from the collection

I'm trying to go through a collection and I need to get a list of products according to certain keys. but I get the following error when I print the list with dd:
"array_key_exists(): The first argument should be either a string or an integer"
this is my function
public function reemplazaCostoZona($zona, $destino, $especie, $costo, $transporCollect){
$productos = $transporCollect->where([['zona',$zona],['destino', $destino],['especie',$especie]])
->pluck('producto');
dd($productos );
}
Collection:
I need to obtain the list of products for destination zone and species, That is to say that for my example of collection, for zone 1 destination 5 specie 1 I would have in my list product 1 and there may be more.
function where Im obtain collection:
public function storeTranspor3($request){
DB::table('transpor')->truncate();
$var = DB::select("select flu.zona, flu.destino, flu.producto, pro.especie, sup.codigo, dtr.cod_fundo, sup.sup_ha, dtr.dist_pavimento, dtr.dist_no_pavimento, dtr.peaje
from flujos flu
left join super sup on (sup.zona = flu.zona)
left join d_transporte dtr on (dtr.cod_fundo = (sup.codigo / 1000000) and dtr.destino = flu.destino)
left join productos pro on (pro.producto = flu.producto)
left join especies esp on (esp.especie = pro.especie)
order by flu.zona, dtr.cod_fundo, flu.producto, flu.destino, sup.codigo");
$tansporCollect = collect();
$tansporCollectsinCosto = collect();
foreach ($var as $f) {
if($f->codigo != null){
if($f->especie == 1){
$a = 0.177548*$f->dist_no_pavimento;
$b = 0.0746*$f->dist_pavimento;
$c = 0.0333*$f->peaje;
$costoFundo = ($a + $b + 1.1191 + 0.399 + $c)*$f->sup_ha;
}
else{
$a = 0.1652*$f->dist_no_pavimento;
$b = 0.0694*$f->dist_pavimento;
$c = 0.0357*$f->peaje;
$costoFundo = ($a + $b + 1.0421 + 0.599 + $c)*$f->sup_ha;
}
$tansporC =[
'zona' => $f->zona,
'destino' => $f->destino,
'producto' => $f->producto,
'especie' => $f->especie,
'costo' => $costoFundo
];
$tansporCollect->push($tansporC);
$tansporsinCosto = [
'zona' => $f->zona,
'destino' => $f->destino,
'producto' => $f->producto,
'especie' => $f->especie,
];
$tansporCollectsinCosto->push($tansporsinCosto);
}
}
$zonas = $tansporCollect->pluck('zona')->unique();
$destinos = $tansporCollect->pluck('destino')->unique();
$especies = $tansporCollect->pluck('especie')->unique();
$transporCollectUnique = $tansporCollectsinCosto->unique();
foreach($zonas as $zon){
$costoZona = $tansporCollect->where('zona',$zon);
foreach($destinos as $destin){
$costoDestino = $costoZona->where('destino',$destin);
foreach($especies as $espec){
$costoEspecie = $costoDestino->where('especie',$espec)->avg('costo');
/*HERE IM CALL OTHER FUNCTION */
$this->reemplazaCostoZona($zon, $destin, $espec, $costoEspecie, $transporCollectUnique);
}
}
}
}
I'm with laravel 5.8
You are not using the where function of collections correctly. For collections you need the following:
$productos = $transporCollect->where('zona', $zona)
->where('destino', $destino)
->where('especie',$especie)
->pluck('producto');
Hope that helps!

Lumen: Auto increment and Reset Transaction_ID Automatically every month

I trying to generate random transaction_id, with format "2000-yymmm-0000".
I already know how to set the transaction_id, but I have a problem with the auto-increment from "2000-yymm-0000" to "2000-yymm-0001", and reseting automatically to "2000-yymm-0000" at every new month.
I put this logic in different path of controller.
PS: I'm using Lumen 6.0 with Laravel 6.0.
I'm trying to create the increment with:
$number = sprintf('%04d', 0000);
$number++;
but it didn't work.
$year = 2000;
$time = date('ym');
$number = sprintf('%04d', 0000);
$transaction_id = $year . '-' . $time . '-' . $number;
$transaction_data = explode('-', $transaction_id);
$month = date("m", strtotime($transaction_data[0]));
I expect the result to automatically increment every time a new data is stored to the database. But the actual result is transaction_id being having always the same value 2000-yymm-0000.
What am I doing wrong?
I know it's weird to answer my own question, but i already find the solution.
in Models/Order.php
i create a function like this.
public function count()
{
$this->where(transaction_id)->count();
}
after that i call the function from Model/Order.php to OrdersController.php
public function create(Request $request)
{
$year = 2000;
$date = date('ym');
$total_data = $this->table->count();
$number = str_pad($total_data + 1, 4, 0, STR_PAD_LEFT);
$transaction_id = $year . '-' . $date . '-' . $number;
return $this->success('count all transaction id', $t_id);
}

laravel get items from two separate table and merge the result with pagination

I have two tables, one of them is "posts" and the other one is "notifications". I want to show the users a list of posts and notifications with pagination. how can I do that efficiently?
I have this code that works fine but it is not efficient because I get all the data and then slice them. I want to do the pagination, using MYSQL
public function list_post_notification(Request $request , $page_number = 1 , $per_page=10 , $brand_id = null ){
$brand =$this->brandRepository->getMagazinBrand() ;
$posts = $brand->posts()->orderBy('posts.created_at' , 'desc')->take($page_number * $per_page) ;
$notifs = $brand->notifications()->orderBy('notifications.created_at' , 'desc')->take($page_number * $per_page) ;
$result = [] ;
foreach ($posts->get() as $k=>$v){
$item = [
'type'=>'post' ,
'uuid'=>$v->uuid,
'title'=>$v->title,
'created_at'=>strtotime($v->created_at),
'creator'=>$v->brand->fa_name,
'brand_id'=>$v->brand->id,
];
$result[$item['created_at']] =$item ;
}
foreach ($notifs->get() as $k=>$v){
$item = [
'type'=>'notification' ,
'uuid'=>$v->uuid,
'title'=>$v->title,
'created_at'=>strtotime($v->created_at),
'creator'=>$v->brand->fa_name,
'brand_id'=>$v->brand->id,
];
$result[$item['created_at']] =$item ;
}
krsort($result) ;
$start = 0 ;
if ($page_number > 1)
$start = ($page_number -1 ) * $per_page ;
return response()
->json(array_slice($result , $start , $per_page)) ;
}
You can merge all your items and create one Collection.
$resultCollection = collect($result).
Than use forPage method.

Display "time ago" instead of datetime in PHP Codeigniter

I would like to display a time format like twitter and FB (Posted 3 hours ago, Posted 2 minutes ago and so on...)
I've tried this piece of code without success :
function format_interval($timestamp, $granularity = 2) {
$units = array('1 year|#count years' => 31536000, '1 week|#count weeks' => 604800, '1 day|#count days' => 86400, '1 hour|#count hours' => 3600, '1 min|#count min' => 60, '1 sec|#count sec' => 1);
$output = '';
foreach ($units as $key => $value) {
$key = explode('|', $key);
if ($timestamp >= $value) {
$floor = floor($timestamp / $value);
$output .= ($output ? ' ' : '') . ($floor == 1 ? $key[0] : str_replace('#count', $floor, $key[1]));
$timestamp %= $value;
$granularity--;
}
if ($granularity == 0) {
break;
}
}
I use this function with a callback into another function like : $this->format_interval(); and pass it to my View
My current format date is : 2012-07-26 09:31:pm and already stored in my DB
Any help will be very appreciated!
The Date Helper's timespan() method just does that:
The most common purpose for this function is to show how much time has elapsed from some point in time in the past to now.
Given a timestamp, it will show how much time has elapsed in this format:
1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes
So, in your example, all you need to do is convert your date to a timestamp and do something like this:
$post_date = '13436714242';
$now = time();
// will echo "2 hours ago" (at the time of this post)
echo timespan($post_date, $now) . ' ago';
Try something like this in a my_date_helper.php file (source: Codeigniter Forums):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if( ! function_exists('relative_time'))
{
function relative_time($datetime)
{
$CI =& get_instance();
$CI->lang->load('date');
if(!is_numeric($datetime))
{
$val = explode(" ",$datetime);
$date = explode("-",$val[0]);
$time = explode(":",$val[1]);
$datetime = mktime($time[0],$time[1],$time[2],$date[1],$date[2],$date[0]);
}
$difference = time() - $datetime;
$periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade");
$lengths = array("60","60","24","7","4.35","12","10");
if ($difference > 0)
{
$ending = $CI->lang->line('date_ago');
}
else
{
$difference = -$difference;
$ending = $CI->lang->line('date_to_go');
}
for($j = 0; $difference >= $lengths[$j]; $j++)
{
$difference /= $lengths[$j];
}
$difference = round($difference);
if($difference != 1)
{
$period = strtolower($CI->lang->line('date_'.$periods[$j].'s'));
} else {
$period = strtolower($CI->lang->line('date_'.$periods[$j]));
}
return "$difference $period $ending";
}
}
The format is a little different than the one you're using in your database (why do you mark times with pm/am rather than just use 24 hour times and convert for the frontend?). Either way, shouldn't take much work to get it working.
I had a function that solved this like this:
$int_diff = (time() - $int_time);
$str_this_year = date('Y-01-01', $int_time);
$str_weekday = t('time_weekday_'.strtolower(date('l', $int_time)));
$str_month = t('time_month_'.strtolower(date('F', $int_time)));
$arr_time_formats = array( '-90 seconds' => t('time_a_minute_at_most'),
'-45 minutes' => t('time_minutes_ago', ceil($int_diff / (60))),
'-70 minutes' => t('time_an_hour_at_most'),
'-8 hours' => t('time_hours_ago', ceil($int_diff / (60 * 60))),
'today' => t('time_hours_ago', ceil($int_diff / (60 * 60))),
'yesterday' => t('time_yesterday', date('H:i', $int_time)),
'-4 days' => t('time_week_ago', $str_weekday, date('H:i', $int_time)),
$str_this_year => t('time_date', date('j', $int_time), $str_month, date('H:i', $int_time)),
0 => t('time_date_year', date('j', $int_time), $str_month, date('Y', $int_time), date('H:i', $int_time)));
if ($boo_whole)
return $arr_time_formats[0];
foreach(array_keys($arr_time_formats) as $h)
if ($int_time >= strtotime($h))
return $arr_time_formats[$h];
Basicly t() is a function combined with $this->lang->line() and sprintf(). The idea here is to give keys that's runned through strtotime() till you reach the closest time, with 0 being the fallback.
This approach is really good since you can easy adjust the times with a nice overview. I could give more piece of the code, but it feels like doing too much of the work :) Basicly this is just the theory behind how you can do it.
<?php
$this->load->helper('date');
//client created date get from database
$date=$client_list->created_date;
// Declare timestamps
$last = new DateTime($date);
$now = new DateTime( date( 'Y-m-d h:i:s', time() )) ;
// Find difference
$interval = $last->diff($now);
// Store in variable to be used for calculation etc
$years = (int)$interval->format('%Y');
$months = (int)$interval->format('%m');
$days = (int)$interval->format('%d');
$hours = (int)$interval->format('%H');
$minutes = (int)$interval->format('%i');
// $now = date('Y-m-d H:i:s');
if($years > 0)
{
echo $years.' Years '.$months.' Months '.$days.' Days '. $hours.' Hours '.$minutes.' minutes ago.' ;
}
else if($months > 0)
{
echo $months.' Months '.$days.' Days '. $hours.' Hours '.$minutes.' minutes ago.' ;
}
else if($days > 0)
{
echo $days.' Days '.$hours.' Hours '.$minutes.' minutes ago.' ;
}
else if($hours > 0)
{
echo $hours.' Hours '.$minutes.' minutes ago.' ;
}
else
{
echo $minutes.' minutes ago.' ;
}
?>

Resources