Jump to content

dynamicidx

Retired Forum Member
  • Posts

    5
  • Joined

  • Last visited

About dynamicidx

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

dynamicidx's Achievements

Junior Member

Junior Member (1/3)

0

Reputation

  1. Very good information and thank you for all this time and information. To me, quotes are very important and the first impression for any sales agent. Very very important that WHMCS corrects this asap. I am sure there are a lot of people who did not notice this but now will. My sales team pointed it out to me of course.
  2. WHMCS quotes don't show the quantities on items that aren't whole numbers. If you create a quote for a client and login to view the quote, the numbers don't add up unless you only use whole numbers. All quotes have this problem and have been for as long as I can remember. The PDF version is correct, though. It looks like the first column (Qty) and last column (Total) are missing from the printable version, which is the version that our clients see when the follow the link in the WHMCS quote email. Does anyone have a way to correct this? I wrote WHMCS and here is what they said. I am glad they are going to fix this but my sales people are not happy and want it resolved quickly.
  3. TomoTech, I want to thank you for taking time with this post. I looked all over and even asked WHMCs if they could help but understandably I was directed to this channel. I finally decided I would just buckle down and do it on my own as I knew it would not be hard just that I did not really have the time. But be that as it may. I wrote the following Hook. I am going to share this as I am sure it can be coded up better and if anyone has the insight and wishes to do so please do. I am also sure it can be optimized as I did not spend much time on it. I also added to it a list of active tickets for a give client to make it eaiser to jump around. Once again, please excuse the curdeness as I have not yet had the time to clean up or document the hook as I normally would. <?php /** * Prevent Staff access to certian areas.. * * @author DynamicIDX * @copyright Copyright (c) SENTQ 2018 * @link http://www.whmcms.com/ */ if (!defined("WHMCS")) die("This file cannot be accessed directly"); use WHMCS\Session; use WHMCS\Ticket\Watchers; use Illuminate\Database\Capsule\Manager as Capsule; function hook_verify_sales_agent($vars) { //Where the custom field name is: Sales Rep of type Drow Down with values of "Dynamic IDX,Nina Tewell,Roger Grant,Haley Blankenship,Kim Conger" //So the Check would not look if the admin had full rights. Other wise it would take the staff/admins full name and compare it to the field values. //Depending on the hook, we have to lookup the user id based on what we have. //Ticket id so look up the id from ticket.. $fullAdmin = ['1','5','8','10']; $allowedSalesAgents = ['everyone','mls association']; $debug_out = ''; $msg_out = ''; $where_are_we = ''; //foreach($vars as $k => $v) //{ // $debug_out.= '['.$k.'] = ('.$v.')<br>'; //} $theurlpath = $_SERVER['REQUEST_URI']; $debug_out.=' Path('.$theurlpath.') '; $adminUserID = Session::get('adminid'); if ($adminUserID > 0) $debug_out.=' AdminID('.$adminUserID.') '; else { return ; } // //This section needs to be cleaned up with a simple function call.. on my todo. // $the_action = $_GET['action']; $debug_out.=' page('.$the_action.') '; if (strpos($theurlpath, 'affiliates') !== false) { $where_are_we = 'affiliates'; $theAffID = $_GET['id']; $theUser = Capsule::table('tblaffiliates')->where('id', '=', $theAffID) ->value('clientid'); } else if (isset($vars['userid'])) { $where_are_we = 'user'; $theUser = $vars['userid']; } else if (isset($_GET['userid'])) { $where_are_we = 'user'; $theUser = $_GET['userid']; } else if (isset($vars['ticketid']) || $the_action == 'viewticket' || $the_action == 'view') { $where_are_we = 'ticket'; if ($the_action == 'viewticket' || $the_action == 'view') { $theTicket = $_GET['id']; $theUser = Capsule::table('tbltickets')->where('id', '=', $theTicket) ->value('userid'); } else { $theTicket = $vars['ticketid']; $theUser = Capsule::table('tbltickets')->where('tid', '=', $theTicket) ->value('userid'); } $debug_out .= ' TicketID: ['.$theTicket.'] Userid ['.$theUser.'] '; //If ticket does not have a userid, lets try to locate the name... if ($theUser == 0 || empty($theUser)) { $theUserEmail = Capsule::table('tbltickets')->where('id', '=', $theTicket) ->value('email'); $thecontactname = Capsule::table('tbltickets')->where('id', '=', $theTicket) ->value('name'); $theUser = Capsule::table('tblcontacts')->where('email', '=', $theUserEmail) ->value('userid'); $debug_out .= ' Ticket email ['.$theUserEmail.'] '; $msg_out .= $thecontactname.' is a sub account. <br/>'; } } else if (isset($vars['id']) || $the_action == 'edit') { $where_are_we = 'invoice'; if ($the_action == 'edit') $theInvoice = $_GET['id']; else $theInvoice = $vars['id']; $theUser = Capsule::table('tblinvoices')->where('id', '=', $theInvoice) ->value('userid'); } else { $where_are_we = 'user'; $theUser = $vars['userid']; } //Get custom field value from client.. if ($theUser > 0 && !empty($theUser)) { $fieldid = Capsule::table('tblcustomfields')->where('fieldname', '=', 'Sales Rep')->where('type', '=', 'client') ->value('id'); $salesrepname = Capsule::table('tblcustomfieldsvalues')->where('fieldid', '=', "$fieldid")->where('relid', '=', $theUser)->value('value'); $salesrepname_nocap = strtolower($salesrepname); $salesrepname_nocap = trim($salesrepname_nocap); //Get client name..and build a link to their profile.. if ($where_are_we != 'user') { $client_firstname = Capsule::table('tblclients')->where('id', '=', $theUser)->value('firstname'); $client_lastname = Capsule::table('tblclients')->where('id', '=', $theUser)->value('lastname'); $client_name = $client_firstname.' '.$client_lastname; $client_link = "<strong><a target='_blank' href='clientssummary.php?userid=".$theUser."'>View ".$client_name."</a></strong>"; $msg_out .='Click to view '.$client_link.'\'s account!<br/>'; } $debug_out .= "UserID:[".$theUser."] FieldID:[".$fieldid."] SalesRep:[".$salesrepname."]<br/>"; } else { $debug_out .= "[".$theUser."] Ticket not associated with any account"; } //Get Admins information based on the id. $admin_username = Capsule::table('tbladmins')->where('id', '=', $adminUserID)->value('username'); $admin_firstname = Capsule::table('tbladmins')->where('id', '=', $adminUserID)->value('firstname'); $admin_lastname = Capsule::table('tbladmins')->where('id', '=', $adminUserID)->value('lastname'); $admin_full_name = strtolower($admin_firstname).' '.strtolower($admin_lastname); $admin_full_name = trim($admin_full_name); //First we have a few admin id's that we don't need to restrict anything so just ignore them. //We also have some demo clients that we want all our sales agents to see so we don't restrict those either. if (!in_array($adminUserID,$fullAdmin) && !in_array($salesrepname_nocap,$allowedSalesAgents)) { //if not a full admin then see if the names match. If not then we know they are not allowed to view this clients info. if ($salesrepname_nocap == $admin_full_name) { $msg_out .= "This is your client!<br/>"; } else { $msg_out .= "Not your client!<br/>"; header('Location: https://info.dynamicidx.com/admin/accessdenied.php'); //redirect the to home page for now.. Want to make this an access denied page.. } } else { if ($theUser > 0) $msg_out .= "[".$salesrepname."]'s client<br/>"; else $msg_out .= "Ticket not assiged to any client account<br/>"; //echo "<br>Found Full Name [".$admin_full_name."] Admin [".$adminUserID."] First name [".$admin_firstname."] Last name [".$admin_lastname."] Username [".$admin_username."]"; } //if we are on the user profile we should show the active tickets.. if ($where_are_we == 'user' || $where_are_we == 'ticket') { //They can view this client so lets show active tickets.. //If viewing a ticket we will exclude the one we are looking at... if ($where_are_we != 'ticket' && $theUser> 0) { $tickets = Capsule::table('tbltickets') ->where('userid', $theUser) ->whereNotIn('status', ['Closed']) ->orderBy('date', 'desc') ->take(10) ->get(); } else if ($theTicket > 0 && $theUser> 0) { $tickets = Capsule::table('tbltickets') ->where('userid', $theUser) ->whereNotIn('status', ['Closed']) ->where('id', '<>',$theTicket) ->orderBy('date', 'desc') ->take(10) ->get(); } if (count($tickets)> 0) { $msg_out.='============================================================='; $msg_out.='<br/>[Top ['.count($tickets).'] Active Tickets for this client]'; $msg_out.='<br/>=============================================================<br/>'; foreach ($tickets as $ticket) { $msg_out .= '<p class="mytitleannoun"><i class="fa fa-file-text-o" aria-hidden="true" style="margin-right:15px;"></i><a style="margin-right:15px;" href="/admin/supporttickets.php?action=viewticket&id='.$ticket->id.'">('.$ticket->status.') '.$ticket->title.'</a><span> '.$ticket->department.'</span><font color="#b3b3b3"> '.fromMySQLDate($ticket->date).'</font></p>'; } } } //Get staff's name trying to access page. //return $debug_out.' '.$msg_out; return $msg_out; } add_hook("AdminAreaClientSummaryPage", 1, "hook_verify_sales_agent"); add_hook("AdminClientProfileTabFields", 1, "hook_verify_sales_agent"); add_hook("AdminClientServicesTabFields", 1, "hook_verify_sales_agent"); add_hook("AdminAreaViewTicketPage", 1, "hook_verify_sales_agent"); add_hook("ViewInvoiceDetailsPage", 1, "hook_verify_sales_agent");
  4. I was having the same issues. I finally found the issue was with an addon called Fast track. Once I disabled it the system was back to normal right away. I have notified WHMCS in a service ticket about this.
  5. I wanted a way to show the top tickets with private notes. I found myself getting lost with notes flying all over the place. This is just a little something I threw together so please feel free to use and rebuild it if you like. I wanted to add tabs but just no time. Just a note, I have no issues with criticism so if you see a better way please let me know as I am new to whmcs widgets but love to learn. <?php //Courtesy of Mark Fitzgerald //May, 6 2017 //version 1.0.0 //Tested with WHMCS 7.1+ //Database Access ref: https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset // /* This little widget will simply pull the top notes from the private notes thread and display them. It will include the 4 prior private post as well so you can follow along. Is very handy to keep up with an at-a-glance of what is going on during the day. Have fun and you are more than welcome to modify this to what every needs you wish. Note: would love to modify it a bit more to use group by for the tickets but did not have the time to learn everything about Laravel today. */ use Illuminate\Database\Capsule\Manager as Capsule; add_hook('AdminHomeWidgets', 1, function() { return new DIDXPrivateNotesWidget(); }); /** * Private Notes last posted To you. */ class DIDXPrivateNotesWidget extends \WHMCS\Module\AbstractWidget { protected $title = 'Top 10 Private Ticket Post <a href="supporttickets.php?view=Open" class="btn btn-link btn-xs">View All »</a>'; protected $description = ''; protected $weight = 150; protected $columns = 2; protected $cache = false; protected $cacheExpiry = 120; protected $requiredPermission = ''; //Will just format the date stamp in a nice way is all. Sorta like WHMCS human function. //I found this function a while back but cant' remember where though I have made a number of changes to it. public function format_stamp($datetime, $show_full = false) { $aTime_line = array('y' => 'year','m' => 'month','w' => 'week','d' => 'day','h' => 'hour','i' => 'minute','s' => 'second'); $long_ago = new DateTime($datetime); $date_now = new DateTime; $diff_in_time = $date_now->diff($long_ago); $diff_in_time->w = floor($diff_in_time->d / 7); $diff_in_time->d -= $diff_in_time->w * 7; foreach ($aTime_line as $key => &$value) { if ($diff_in_time->$key) $value = $diff_in_time->$key . ' ' . $value . ($diff_in_time->$key > 1 ? 's' : ''); else unset($aTime_line[$key]); } if (!$show_full) $aTime_line = array_slice($aTime_line, 0, 1); $return_value = $aTime_line ? implode(', ', $aTime_line) . ' ago' : 'just now'; return $return_value; } public function getData() { return array(); } public function generateOutput($data) { $the_div_output = ""; $notes_same_group = 0; $idlist = ""; //Get a list of private tickes order by date. Would like to later use a group by to do this so I can do away //with the if statement below and then lower the take to just 10... foreach (Capsule::table('tblticketnotes')->orderBy('date', 'desc')->take(20)->get() as $privatenotes) { //If statement, bad code to only show ticket once, Should be a groupby but did not have time to learn laravel's system completely today. if (strstr($idlist,",".$privatenotes->ticketid.",")) $notes_same_group++;//Might use this later on. else { $idlist .= ",".$privatenotes->ticketid.","; $tid = $privatenotes->ticketid; $noteid = $privatenotes->id; $notedate = $privatenotes->date; $postedby = $privatenotes->admin; $notemsg = $privatenotes->message; //You can modify this to truncate the string if you don't wish to show it all. I had it at 100 but team did not like it. if (strlen($notemsg) > 1000) { $notemsg = substr($notemsg,0,1000)."..."; } $ticketlink = "supporttickets.php?action=view&id=$tid"; //Find the top x replies per ticket. Wish they had a flag to show which ones were private, would be nice. $reply_str = ''; //Look up the ticket id and date <= to it. this will give you the from to... foreach (Capsule::table('tblticketnotes')->orderBy('date', 'desc')->take(3) ->where([ ['ticketid', '=', $tid],['id', '<', $noteid]])->get()as $ticketreplies) { $replymsg = $ticketreplies->message; if (strlen($replymsg) > 30) { $replymsg = substr($replymsg,0,1000)."..."; } $reply_str.= "<Br/>"; $reply_str.= "<div><span class='data color-black'>".$ticketreplies->admin." (".$this->format_stamp($ticketreplies->date).") - </span> <span class='data color-orange'>"".$replymsg.""<span></div><Br/>"; } //Get ticket so I can get the users id. Odd they don't keep this in the notes table. $userid = ''; foreach(Capsule::table('tbltickets')->WHERE ('id', '=', $tid)->take(1)->get() as $ticketinfo) { $userid = $ticketinfo->userid; } //Check user id and if we have one, build a url so we can link to it. if (!empty($userid)) { $userlink = "clientssummary.php?userid=".$userid; //Get this users infomaton. foreach(Capsule::table('tblclients')->WHERE ('id', '=', $userid)->take(1)->get() as $whoami) { $fname = $whoami->firstname; $lname = $whoami->lastname; $cname = $whoami->companyname; $theuser = "$fname $lname"; } } else { $userid = "No User"; } //Add to the output string that you will ref below. $the_div_output .= " <div class='feed-element'> <div><small class='text-muted'><a href='".$userlink."'>Client: " . $theuser . "</a></small><small class='pull-right text-navy'><a href='".$ticketlink."'>Ticket #".$tid."</a></small></div> <div><a href='".$ticketlink."'>".$postedby."</a><span class='data color-black'> (".$this->format_stamp($notedate).") - <span class='data color-orange'>".$notemsg." </span></span></div>" . $reply_str . " </div><hr width='100%'>"; } } if (!empty($the_div_output)) { return <<<EOF <div class="widget-content-padded"> $the_div_output </div> EOF; } } //public function generateOutput($data) } //class
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated