Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by leemahoney3

  1. Do you allow people open support tickets without being logged in? Likely that's what's happening.
  2. Hi there, In six its a little different, however the code is still in the header.tpl file. Change {if $loggedin} <li> <a href="#" data-toggle="popover" id="accountNotifications" data-placement="bottom"> {$LANG.notifications} {if count($clientAlerts) > 0} <span class="label label-info">{lang key='notificationsnew'}</span> {/if} <b class="caret"></b> </a> <div id="accountNotificationsContent" class="hidden"> <ul class="client-alerts"> {foreach $clientAlerts as $alert} <li> <a href="{$alert->getLink()}"> <i class="fas fa-fw fa-{if $alert->getSeverity() == 'danger'}exclamation-circle{elseif $alert->getSeverity() == 'warning'}exclamation-triangle{elseif $alert->getSeverity() == 'info'}info-circle{else}check-circle{/if}"></i> <div class="message">{$alert->getMessage()}</div> </a> </li> {foreachelse} <li class="none"> {$LANG.notificationsnone} </li> {/foreach} </ul> </div> </li> <li class="primary-action"> <a href="{$WEB_ROOT}/logout.php" class="btn"> {$LANG.clientareanavlogout} </a> </li> {else} <li> <a href="{$WEB_ROOT}/clientarea.php">{$LANG.login}</a> </li> {if $condlinks.allowClientRegistration} <li> <a href="{$WEB_ROOT}/register.php">{$LANG.register}</a> </li> {/if} <li class="primary-action"> <a href="{$WEB_ROOT}/cart.php?a=view" class="btn"> {$LANG.viewcart} </a> </li> {/if} To {if $loggedin} <li class="primary-action"> <a href="{$WEB_ROOT}/logout.php" class="btn"> {$LANG.clientareanavlogout} </a> </li> {else} <li> <a href="{$WEB_ROOT}/clientarea.php">{$LANG.login}</a> </li> {if $condlinks.allowClientRegistration} <li> <a href="{$WEB_ROOT}/register.php">{$LANG.register}</a> </li> {/if} <li class="primary-action"> <a href="{$WEB_ROOT}/cart.php?a=view" class="btn"> {$LANG.viewcart} </a> </li> {/if} Excuse the formatting, its messed up in the code blocks and I cant seem to fix it!
  3. Hey there, Are you using the twenty-one theme? If so, you can remove the following code from the header.tpl file located in the /templates/twenty-one/ directory. <button type="button" class="btn" data-toggle="popover" id="accountNotifications" data-placement="bottom"> <i class="far fa-flag"></i> {if count($clientAlerts) > 0} {count($clientAlerts)} <span class="d-none d-sm-inline">{lang key='notifications'}</span> {else} <span class="d-sm-none">0</span> <span class="d-none d-sm-inline">{lang key='nonotifications'}</span> {/if} </button> <div id="accountNotificationsContent" class="w-hidden"> <ul class="client-alerts"> {foreach $clientAlerts as $alert} <li> <a href="{$alert->getLink()}"> <i class="fas fa-fw fa-{if $alert->getSeverity() == 'danger'}exclamation-circle{elseif $alert->getSeverity() == 'warning'}exclamation-triangle{elseif $alert->getSeverity() == 'info'}info-circle{else}check-circle{/if}"></i> <div class="message">{$alert->getMessage()}</div> </a> </li> {foreachelse} <li class="none"> {lang key='notificationsnone'} </li> {/foreach} </ul> </div>
  4. You'd need to set up a LEMP stack or use some sort of control panel that ships with Nginx, plenty of guides on Google (e.g. https://www.linuxcapable.com/how-to-install-lemp-stack-on-debian-11-bullseye/) WHMCS was designed to work with Apache, however that does not mean it will not work with Nginx, just that you will need to make some configuration changes especially if you use the fancy urls as Nginx doesn't read .htaccess files. Take a look at https://hostup.org/blog/whmcs-friendly-urls-configuration-for-nginx/ for more information. Whatever you do, ensure you deny access to your vendor folder location ^~ /vendor/ { deny all; return 403; }
  5. I'd be inclined to think the lara theme is causing that, or perhaps another hook or module. If you switch to the default theme and try, does the same behavior occur with the dropdown?
  6. Don't believe so, not natively anyways unless there is an addon module for it. Looks to be a feature request, though I wouldn't hold my breath as the feature request was made 9 years ago... https://requests.whmcs.com/idea/billing-term-change
  7. Sorry, I meant if you remove the following from your configuredomains.tpl file, does the same issue occur {if $smarty.session.cart.domains.{$num}.type eq "transfer"}This is a transfer!!!!!{elseif $smarty.session.cart.domains.{$num}.type eq "register"}This is a new registration!!!{/if} If so, do you have any other custom code in that template or any other modules or hooks that may be conflicting with the security policy? Perhaps you may need to add more variables to the security policy such as $smarty_security_policy = [ 'system' => [ 'enabled_special_smarty_vars' => [ 'session', 'cookies', 'server' ] ] ]; You may need to play around with it, more details can be found at https://docs.whmcs.com/Smarty_Security_Policy
  8. Do you have any other addon modules or hooks that might influence the status? I've just tested the code on another install and can confirm it works. I'd suggest playing around with the hooks, especially the set_ticket_status_after_reply function to see if you can get it to work for your environment.
  9. Strange, its working for me. Can you change # Update the status of the ticket localAPI('UpdateTicket', [ 'ticketid' => $vars['ticketid'], 'status' => $status ]); To # Update the status of the ticket Capsule::table('tbltickets')->where('id', $vars['ticketid'])->update([ 'status' => $status ]); And try again? I've not used the Lara theme but can't really see how it would affect it.
  10. Hi Snake, I've just posted a solution in your other thread which should hopefully work.
  11. Hi Snake, So the following hooks should work, can add them all to one hook file in the /includes/hooks/ folder. Bit messy but don't see any other way to do this as sessions don't carry between hooks and theres no way to grab the previous status in the TicketAdminReply hook which is incredibly annoying. <?php use WHMCS\Database\Capsule; # Need to store the current status in the database function store_current_ticket_status($vars) { # Create custom database table if it does not already exist. if (!Capsule::schema()->hasTable('mod_keepticketstatus')) { try { Capsule::schema()->create('mod_keepticketstatus', function ($table) { $table->increments('id'); $table->string('ticketid'); $table->string('status'); }); } catch(\Exception $e) { logActivity("Unable to create table 'mod_keepticketstatus', the following error was returned: {$e->getMessage()}"); } } # Grab current ticket details $ticket = Capsule::table('tbltickets')->where('id', $vars['ticketid'])->first(); # Insert them into the custom table (or update if the entry is already there) Capsule::table('mod_keepticketstatus')->updateOrInsert([ 'ticketid' => $ticket->id ], [ 'status' => $ticket->status ]); } # Retrieve the current status from the database function set_ticket_status_after_reply($vars) { # Grab ticket details $ticket = Capsule::table('tbltickets')->where('id', $vars['ticketid'])->first(); # Check custom table to see if entry exists $custom = Capsule::table('mod_keepticketstatus')->where('ticketid', $ticket->id)->first(); # If it exists then use the status stored in the database, otherwise revert to the default of 'Answered' if ($custom) { $status = $custom->status; } else { $status = 'Answered'; } # Update the status of the ticket localAPI('UpdateTicket', [ 'ticketid' => $vars['ticketid'], 'status' => $status ]); } # If the status is manually changed by an admin, ensure it is updated in the custom table also function set_custom_ticket_status_on_change($vars) { # Insert them into the custom table (or update if the entry is already there) Capsule::table('mod_keepticketstatus')->updateOrInsert([ 'ticketid' => $vars['ticketid'] ], [ 'status' => $vars['status'] ]); } # If the ticket is deleted, ensure the entry is removed from the database to keep the table clean function remove_custom_ticket_status_on_delete($vars) { Capsule::table('mod_keepticketstatus')->where('ticketid', $vars['ticketId'])->delete(); } add_hook('AdminAreaViewTicketPage', 1, 'store_current_ticket_status'); add_hook('TicketAdminReply', 1, 'set_ticket_status_after_reply'); add_hook('TicketStatusChange', 1, 'set_custom_ticket_status_on_change'); add_hook('TicketDelete', 1, 'remove_custom_ticket_status_on_delete');
  12. Strange, if you remove your code from the smarty template, does the white screen remain? What version of WHMCS are you running?
  13. You'll likely need two hooks to achieve this, one for viewing the ticket and then another for when a reply is made. I'll try throw some code together later on to see if we can get this to work.
  14. Hi there, I don't really understand your query, are you looking for a hyperlink on the # 2998 in the To-Do? That's not possible as its a textarea and cannot format hyperlinks unless you were to change it to a WYSISWG editor or something else.
  15. Hi there, You need to add the following to your configuration.php file due to the Smarty Security Policy (https://docs.whmcs.com/Smarty_Security_Policy). $smarty_security_policy = [ 'system' => [ 'enabled_special_smarty_vars' => [ 'session' ], ] ]; Make sure to put your code in the {foreach $domains as $num => $domain} loop for it to work as it references $num e.g. {foreach $domains as $num => $domain} <div class="sub-heading"> <span class="primary-bg-color">{$domain.domain} ({if $smarty.session.cart.domains.{$num}.type eq "transfer"}This is a transfer!!!!!{elseif $smarty.session.cart.domains.{$num}.type eq "register"}This is a new registration!!!{/if})</span> </div> ...
  16. You could have all tickets change to a certain status when an admin replies to them, e.g. In Progress. If you don't like In Progress then you could create a new ticket status (System Settings > Support > Ticket Statuses) and set it to not auto close and show in the active tickets/awaiting reply tickets. Just change the status in the hook below to match. <?php use WHMCS\Database\Capsule; function set_ticket_status_after_reply($vars) { $status = 'In Progress'; Capsule::table('tbltickets')->where('id', $vars['ticketid'])->update([ 'status' => $status ]); } add_hook('TicketAdminReply', 1, 'set_ticket_status_after_reply'); Or if you prefer to use the API instead of a direct database call <?php function set_ticket_status_after_reply($vars) { $status = 'In Progress'; localAPI('UpdateTicket', [ 'ticketid' => $vars['ticketid'], 'status' => $status ]); } add_hook('TicketAdminReply', 1, 'set_ticket_status_after_reply');
  17. I don't think so, the dologin.php page essentially just posts through to the login page therefore if you have a captcha enabled on the login form, it will be expecting the token from the client side. Implementing the ReCaptcha should be easy enough, the resources below may help. https://developers.google.com/recaptcha/intro
  18. So instead of the ticket changing to Answered you want a way to keep certain tickets marked In Progress when you've replied to them?
  19. Hey Sean, So WHMCS does have a InvoiceCreationPreEmail hook, however there is no way for it to abort the email from being sent. Theoretically you could use the EmailPreSend hook to perform this action, as an email is always sent when an invoice is generated (unless you create an invoice and choose not to send the email). In fact, the below code will work for you. <?php use WHMCS\Database\Capsule; function cancel_invoice_under_a_certain_amount($vars) { $amount = 0.50; $notes = 'Amounts under £0.50 are not payable. This invoice has been cancelled'; $emailTemplates = ['Invoice Created', 'Credit Card Invoice Created']; $merge_fields = []; if (in_array($vars['messagename'], $emailTemplates)) { $invoice = Capsule::table('tblinvoices')->where('id', $vars['mergefields']['invoice_id'])->first(); if ($invoice->status == "Unpaid" && $invoice->total <= $amount) { localAPI('UpdateInvoice', [ 'invoiceid' => $invoice->id, 'status' => 'Cancelled', 'notes' => $notes ]); $merge_fields['abortsend'] = true; } } return $merge_fields; } add_hook('EmailPreSend', 1, 'cancel_invoice_under_a_certain_amount'); Though I don't really see the use case for this, instead of cancelling the invoice, would you not rather mark it as paid so all post payment actions would be executed?
  20. I'd imagine you'd need to manually integrate the client side JavaScript for the reCaptcha again on the custom form so that it validates when you post through to dologin.php Another alternative is to disable the captcha but you have it enabled for a reason therefore I'd advise against disabling it.
  21. Might also be the case that its connecting using the hostname and you've not update it to point to the new IP address?
  22. Hi Alinford, The way I believe it works is, it applies the subscription ID to one of the domains on the invoice however the subscription is for the total amount of the domains. That way, providing that all domains renew on the same date, the next invoice will include just those domains and the subscription will apply to that invoice for its total amount.
  23. Just to add to the above, something like the code below would work. You'd need to set up a custom email template first and then update the variables below in the code. (The department variable is the name of the new department that the ticket has changed to). $department = ''; (e.g. 'Billing') $emailTemplate = ''; (e.g. 'Custom Billing Email') You can improve on the code below, its just a starting point. <?php use WHMCS\Database\Capsule; function change_ticket_department($vars) { # Specify the name of the department (the one you want the custom email to send on when changed to) as well as the name of the email template you want to send $department = 'Billing'; $emailTemplate = 'Billing Automated Reply'; # Define some variables $ticketid = $vars['ticketid']; $deptname = $vars['deptname']; # Get the clients Id $clientId = Capsule::table('tbltickets')->where('id', $ticketid)->first()->userid; # Only send if the new department matches if($deptname == $department) { # Use the local API to send the email $command = 'SendEmail'; $postData = [ 'messagename' => $emailTemplate, 'id' => $clientId ]; $result = localAPI($command, $postData); } } # Run the hook add_hook('TicketDepartmentChange', 1, 'change_ticket_department'); ?>
  24. Hi Muneef, Are you able to load the images directly? If you right click and open them in a new tab, what shows up? It's likely a permissions error, something to do with your .htaccess or web-server configuration or the images are not there.
  25. Hi Andrea, The following hook will work, just create a new file in your includes/hooks/ directory and paste the following code: <?php use Illuminate\Database\Capsule\Manager as Capsule; if (!defined("WHMCS")) { die("This file cannot be accessed directly"); } function cancel_overdue_invoices($vars) { # How many days after an invoice's due date it should be cancelled. $duration = 90; # Get all invoices that are unpaid and meet the criteria $invoices = Capsule::table('tblinvoices')->where('status', 'Unpaid')->where('duedate', '<=', date('Y-m-d', strtotime("-{$duration} days")))->get(); # Loop through the invoices foreach ($invoices as $invoice) { # Update their statuses Capsule::table('tblinvoices')->where('id', $invoice->id)->update([ 'status' => 'Cancelled' ]); } } add_hook('DailyCronJob', 1, 'cancel_overdue_invoices'); ?> To change the amount of days from the due date before the invoice should be cancelled, simply change $duration = 90; (e.g. 90 days is the default as shown above) The hook is set to run once a day on the daily cron, if you prefer it runs on the more regular cron (however long you've set it up to run, then change the bottom part of the code from add_hook('DailyCronJob', 1, 'cancel_overdue_invoices'); To the following add_hook('AfterCronJob', 1, 'cancel_overdue_invoices'); This hook can also be viewed on my GitHub: https://github.com/leemahoney3/whmcs-cancel-overdue-invoices
  • 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