TBroMEM
Member-
Posts
55 -
Joined
-
Last visited
Content Type
Profiles
Forums
Events
Hotfixes
Everything posted by TBroMEM
-
Does anyone have any insights on how the client portal is determining $enabledTypes? The odd thing I am dealing with is that with one of the instances that has the same custom gateway(s) configured, it is only showing to two options anticipated. When I disable out two custom gateway modules (deselect display on order form), the invalid Credit Card option disappears from the other. All I I can seem to surmise is that we somehow miscoded something in our gateway module that trips up the logic with account-paymentmethods-manage.tpl. To resolve, given we do NOT have any other gateway modules in place, I could safely remark out the following section (which I will be testing). {if $enabledTypes['localCreditCard']} <label class="form-check form-check-inline"> <input type="radio" class="icheck-button" name="type" value="localcard"{if ($editMode && $payMethod->isCreditCard() && !$payMethod->isTokenised()) || (!$editMode && $paymentMethodType != 'bankacct')} checked{/if}{if $editMode} disabled{/if}> {lang key='paymentMethodsManage.creditCard'} </label> {/if}
-
If we have a gateway module configured (in this case a custom gateway), how does the client portal page (.../index.php?rp=/account/paymentmethods) know whether to show Add New Credit Card and Add New Bank Account? Also, if you get to /index.php?rp=/account/paymentmethods/add how does it know how to distinguish what to show, such as a tokenGateway, localCreditCard, or bankAccount? I am spinning my wheels trying to figure this out.
-
I did a postman POST to the WHMCS api using GetPayMethods action and the item in question shows without any gateway. It is a ghost card. { "result": "success", "clientid": "12345", "paymethods": [ { "id": 1234, "type": "CreditCard", "description": "Test using Credit Card option", "gateway_name": "", "contact_type": "Contact", "contact_id": 1234, "card_last_four": "XXXX", "expiry_date": "XXXX", "start_date": "", "issue_number": "", "card_type": "Visa", "remote_token": "", "last_updated": "02/17/2025 17:44" } } The other samples show type as RemoteCreditCard with an assigned token. How in the world is the Credit Card option showing up when adding pay method when there is only two active token based (CC and ACH) gateway choices configured?
-
We added a custom payment gateway module some years ago, but I just noticed something (and it has apparently been this way since inception). We have two gateways, one for CC and one for ACH. We also have option enabled for Mail-in Payment in some instances (we have more than one). In some cases, there are other gateways listed in our config, but they are all listed as 'Do Not Use'. In some cases, when adding a payment method (e.g. /index.php?rp=/account/paymentmethods/add), it shows up as follows: 'Credit Card (A)' 'Credit Card' 'Bank Account' Credit Card (A) is our custom gateway module, Bank Account is tied to our ACH gateway, but I have no clue what Credit Card is for. When utilized, there is the typical form to submit card info, and it submits into the WHMCS instance, but it is not associated with our custom CC option, which calls out to a gateway api with info to get and store token. Interestingly enough, in another instance, which happens to ONLY have our custom gateway modules enabled, it only shows as: 'Credit Card (A)' 'Bank Account' I am trying to understand how this would even happen. I had inspected the element and found the options referenced under inputPaymentMethodType, showing the three (Credit Card (A), Credit Card, Bank Account), and found it referenced in account-paymentmethods-manage.tpl for the related theme template. I noted some logic related to $enabledTypes (tokenGateways, LocalCreditCard, and bankAccount). I can associate Credit Card (A) to tokenGateways, and our ACH/Echeck gateway to bankAccount, but not sure where the website would determine we have a localCreditCard enabled. How is that even determined? <div class="form-group row"> <label for="inputPaymentMethodType" class="col-md-4 control-label">{lang key='paymentMethods.type'}</label> <div class="col-md-8"> {if $enabledTypes['tokenGateways']} {foreach $tokenGateways as $tokenGateway} <label class="form-check form-check-inline"> <input type="radio" class="icheck-button" name="type" value="token_{$tokenGateway}" data-tokenised="true" data-gateway="{$tokenGateway}"{if $editMode && $payMethod->isCreditCard() && $payMethod->gateway_name == $tokenGateway} checked{/if}{if $editMode} disabled{/if}> {$gatewayDisplayNames[$tokenGateway]} </label> {/foreach} {/if} {if $enabledTypes['localCreditCard']} <label class="form-check form-check-inline"> <input type="radio" class="icheck-button" name="type" value="localcard"{if ($editMode && $payMethod->isCreditCard() && !$payMethod->isTokenised()) || (!$editMode && $paymentMethodType != 'bankacct')} checked{/if}{if $editMode} disabled{/if}> {lang key='paymentMethodsManage.creditCard'} </label> {/if} {if $enabledTypes['bankAccount']} <label class="form-check form-check-inline"> <input type="radio" class="icheck-button" name="type" value="bankacct"{if ($editMode && !$payMethod->isCreditCard()) || ($paymentMethodType == 'bankacct')} checked{/if}{if $editMode} disabled{/if}> {lang key='paymentMethodsManage.bankAccount'} </label> {/if} </div> </div> Does anyone have any insights in regards to the section related to localCreditCard? The big question is how can it work in one instance and not in another. I compared the two instances and they have the same noted code.
-
Can data capsule code be added with local api requests?
TBroMEM replied to TBroMEM's topic in Developer Corner
@pRieStaKos Yes, but that is the very point I am driving at. Each one would have a distinct invoice with duedate set on tblinvoice. What was in my thinking is if you have one (1) invoice generated that only reflects one due date (visible to client and app), what does it serve the cron to look for duedates on tblinvoiceitems? It only needs to get the duedate from tblinvoice to then compare to the relid from the tblinvoiceitems. Nonetheless we found the fix and will be applying in our trial signup api code. -
Can data capsule code be added with local api requests?
TBroMEM replied to TBroMEM's topic in Developer Corner
@pRieStaKos @DennisHermannsen In our testing, the cron references the duedate on the tblinvoiceitems to determine whether an invoice is due, compared to the client product next due date (reference via tblinvoiceitems.relid) or continuous invoice generation, along with automation settings. This was confirmed by support as well who related the following: "The way the invoicing (cron) logic in WHMCS works, is that it goes through each service looking at the next due date. It then checks the tblinvoiceitems table to see if an existing invoice already exists for that date (looking at the tblinvoiceitems.duedate) value. If an invoice with that due date is present, another invoice will not be generated." We have had some trial code which was updating the duedate for the invoice created by order, to set out one month using UpdateInvoice api. Yet, the daily cron kept creating a duplicate invoice due with same duedate as the invoice created by order and updated with new due date (same date set with the client product next due date). We found that the duedate in tblinvoiceitems was NOT being updated via the UpdateInvoice API. Consequently when the next cron ran, it sees the original due date (from trial signup - day of signup) associated to the invoice line (rather than due date set out one month via API) and generates a duplicate invoice due. Now, the UpdateInvoice api updates the duedate on tblinvoice and reflects that way in the application, but the cron is not using that to determine if an invoice is due for a related client product. We tested with new code (adding capsule code after the localapi submit - within the function called) and set the correct duedate for the related tblinvoiceitems line. When we ran the cron, it did not generate a duplicate invoice. Problem solved. On the flip side, I am not sure why the Cron would be coded to look at the duedate on an invoice line, rather than the duedate on the invoice itself. I did not think you could have one invoice with multiple due dates (even if multiple services). Where in the app can you see one invoice, with multiple duedates per invoice line? Essentially, it would appear that the cron should look at the duedate on tblinvoice rather than tblinvoiceitems when assessing whether an invoice is due. -
Can data capsule code be added with local api requests?
TBroMEM replied to TBroMEM's topic in Developer Corner
We confirmed that using local API that the using UpdateInvoice to update duedate is NOT propagating down the updated duedate to tblinvoiceitems. It only touches tblinvoice.duedate. Does anyone have any thoughts on whether we can add database capsule code to our custom PHP (which initiates local API function/calls) to the same function called to update the invoice due date and invoice items (description, etc.)? If so, please provide some guidance. -
Can data capsule code be added with local api requests?
TBroMEM replied to TBroMEM's topic in Developer Corner
Our existing updateinvoice internal API request updats the duedate and the invoice items (description, etc.) but the duedate is not propagating down to the tblinvoiceitems, which causes duplicate invoice to be generate when the cron runs on the following day. We think there is an issue in the updateinvoice internal api method so splitting out the update of duedate and invoice item description. If this does not prove fruitful we would want to simply update the tblinvoiceitems.duedate directly through capsule just after initial updateinvoice request. I am trying to get ahead of it. -
We have some custom PHP deployed to our environment so we can make requests from an external app. The custom PHP includes various functions that uses localAPI. We would like to add data capsule code to update some additional values in tblinvoiceitems, to get around issue we had encountered in updating duedate (not propagating duedate on tblinvoiceitems). Is it suitable to add the additional data capsule update code just after this but before function termination? This is pseudo code. There is additional code initializing and setting environment variables such as the LocalAPI request public function updateinfo($invoiceId, $dueDate, ...) { { //define data } $data = [ 'invoiceid' => (int) $invoiceId, 'duedate' => date('Y-m-d', strtotime($dueDate)), 'itemdescription' => $itemDescriptions, 'itemamount' => $itemAmounts, 'itemtaxed' => $itemTaxeds ]; $this->api('UpdateInvoice', $data); // can data capsule code suitable be added here to update tblinvoiceitems? }
-
Looking for add-on that displays the database table schemas
TBroMEM replied to TBroMEM's topic in Third Party Add-ons
@pRieStaKos Thanks for directing me to this folder. This is helpful. I could have found it if I had dug around further. -
Looking for add-on that displays the database table schemas
TBroMEM replied to TBroMEM's topic in Third Party Add-ons
Thanks for the ideas. I had hoped for an actual low effort solution that simply reveals the schema, such as to an Full Admin logged into the WHMCS Admin app. If push comes to shove, I will simply request working session with out IT resource to evaluate the datatables themselves on MySQL (or access the server to get to PhpMyAdmin on the server to create a database ER diagram (ERD) from Designer. I will select the latter as a workaround, given there is no add-on available. -
Looking for add-on that displays the database table schemas
TBroMEM replied to TBroMEM's topic in Third Party Add-ons
Hello Bear - I may have title of system admin but it is only for the application not the server. Now, we had been working to update WHMCS in-app, and I had downloaded the installer and found the install.sql. I opened the file and found some schema details, but it does not seem to include all (such as tblpaymethods). If there are no add-ons available that can be deployed/configured in the WHMCS application itself, I will redirect my inquiries to internal IT resources. I suppose also, as you had indicated, I could take alternate approaches. -
Looking for add-on that displays the database table schemas
TBroMEM replied to TBroMEM's topic in Third Party Add-ons
Hello Bear. I don't have access to the WHMCS server so was hoping for an add-on that could be deployed/configured in the WHMCS application(s) itself so a system admin as myself can login and view those details. Thanks for the info. -
Options we are considering. a. getting unpaid invoices for the applicable client and then triggering gateway charge, suspecting can get from tblinvoices and use CapturePayment API request. b. sending notification to admin users (or admin users in certain group) when client updates their payment method. How would we connect to tblpaymethods to find out if the client added a payment method? I cannot find much info related to the table.
-
Although the Contact.php has breadcrumb of Pre-Sales Contact Us, we are considering it more of an entry point for billing inquiries, but it would be more beneficial if it could default some values based on the signed-in user. Name - preload with the users name Email Address - preload with the users email address Subject - preload with 'Billing inquiry from {client name} | {user name} Message: Client Id: {client id} Client Name: {client name} Etc. Is this even possible?
-
Supposedly there is no module addon to aid a system admin in deploying new hooks (or even configured themes) within the admin app. This would be nice to have.
-
@DennisHermannsen It would be easier for an Admin to deploy a new hook (or even a new theme) via the Admin app. At the present, I have to coordinate with our IT resource to moving in changes on our WHMCS server. Maybe this is more of a direct question for WHMCS to advise if this is even feasible.
-
I had updated the php code. Once I am able to get it deployed and tested I will provide a status update. On the flip side, is anyone awae of an addon to allow admins to deploy hooks via the Admin app?
-
The code that at referenced in previous reply did not pass muster in testing. I did not reference the correct field identifier within the tblinvoices capsule. Should have been id not 'invoiceid'. Will be testing again. I am still not sure invoiceid is the correct column to reference in tblorders. We will see. Below is excerpt with change highlighted. add_hook('AcceptOrder', 1, function($vars) { $orderId = $vars['orderid']; // fetch invoice id from order $order = Capsule::table('tblorders')->where('id', $orderId)->first(); $orderInvoiceId = $order->invoiceid; // Fetch duedate from order invoice $invoice = Capsule::table('tblinvoices')->where('id', $orderInvoiceId)->first(); $invoiceDueDate = $invoice->duedate;
-
Incidentally, I had crafted a new hook based on AcceptOrder. It is listed below. I will be testing tonight and will document results. <?php if (!defined("WHMCS")) die("This file cannot be accessed directly"); use Illuminate\Database\Capsule\Manager as Capsule; /* * Hook to update invoice items due dates for invoice linked to new Order * But only if the tblinvoiceitems duedate does not equal the tblinvoice duedate. */ add_hook('AcceptOrder', 1, function($vars) { $orderId = $vars['orderid']; // fetch invoice id from order $order = Capsule::table('tblorders')->where('id', $orderId)->first(); $orderInvoiceId = $order->invoiceid; // Fetch duedate from order invoice $invoice = Capsule::table('tblinvoices')->where('invoiceid', $orderInvoiceId)->first(); $invoiceDueDate = $invoice->duedate; // Log activity logActivity('Invoice ' . $orderInvoiceId . ' from order ' . $order . ' selected for eval by hook acceptOrderUpdInvItemsDueDate'); // Update the due date in tblinvoiceitems foreach (Capsule::table('tblinvoiceitems')->where('invoiceid', $orderInvoiceId)->get() as $line) { //Vars for conditions and logging activity $id = $line->id; $description = $line->description; $invItemDueDate = $line->duedate; if($invoiceDueDate != $invItemDueDate) { // Update due date on invoice line $queryResult = Capsule::table('tblinvoiceitems')->where('id', $id)->update(['duedate' => $invoiceDueDate]); // Log activity logActivity('Invoice ' . $orderInvoiceId . ' line with description ' . $description . ' updated with due date ' . $invoiceDueDate . ' by hook acceptOrderUpdInvItemsDueDate: due date mismatch'); } else {logActivity('Invoice ' . $invoiceId . ' line with description ' . $description . ' not qualified by hook acceptOrderUpdInvItemsDueDate: due dates match'); } } }); ?>
-
I am trying to workaround a challenge with the following hook based on invoicecreation. I am considering transitioning to the AcceptOrder hook, but need to know if the tblorders includes invoiceid (created with order). That may be a better design. Essentially, within the external app API flow, once order is created, it updates the client product (tblhosting) with a due date 30 days out, and then updates the invoice with new date. Initially the invoice sets due dates on invoice line same as invoice date (on initial create). BUT, when it updates due date again (30 days out), the system is not updating duedate on tblinvoiceitems. There is no bandwidth for our dev to workout the backend coding, so I am trying to resolve with a hook. Below is my latest code, which works, but it is still not setting the right due date. I thought by pulling due date from the tblhosting record tied to the tblinvoiceitems lines would resolve. I cannot really increase the sleep (was hoping it gave time for nextduedate to be set) because it delays the action in the external app, and that is client facing. <?php if (!defined("WHMCS")) die("This file cannot be accessed directly"); //alternate use WHMCS\Database\Capsule; use Illuminate\Database\Capsule\Manager as Capsule; /* * Hook to update invoice items due dates from Invoice create * Invoice created by an order/invoice created from external app via API */ add_hook('InvoiceCreation', 1, function($vars) { $invoiceId = $vars['invoiceid']; $source = $vars['source']; // 'autogen' or 'adminarea' $adminuser = $vars['user']; logActivity('Invoice ' . $invoiceId . ' created by ' . $adminuser . ' from ' . $source . ' selected for eval by hook updateInvoiceItemsDueDate'); // Update the due date in tblinvoiceitems foreach (Capsule::table('tblinvoiceitems')->where('invoiceid', $invoiceId)->get() as $line) { //Vars for invoice item $id = $line->id; $relid = $line->relid; if ($adminuser === 9){ sleep(10); // Pauses script execution for 30 seconds. Allow time for edit of invoice created with new due date // Fetch nextduedate from client product $hostingProductId = Capsule::table('tblhosting')->where('id', $relid)->first(); //pluck('packageid'); $nextDueDate = $hostingProductId->nextduedate; // Update due date on invoice line $queryResult = Capsule::table('tblinvoiceitems')->where('id', $id)->update(['duedate' => $nextduedate]); // Fetch description from invoice line // $invLine = Capsule::table('tblinvoiceitems')->where('id', $id)->first(); // $description = $invLine->description; // Log activity logActivity('Invoice ' . $invoiceId . ' line ' . $id . ' updated with due date ' . $nextDueDate . ' by hook updateInvoiceItemsDueDate'); } elseif ($source === "adminarea"){ logActivity('Invoice ' . $invoiceId . ' unqualified for update by hook updateInvoiceItemsDueDate'); } } }); ?> This is the result from Activity Log.
-
To resolve, I created a new child theme, and then took some applicable template files and replicated the edits made previously using tpls from updated default twenty-one theme. Deployed and working fine. This was much more simple than trying to try and figure it out incrementally with the 8.2 custom theme.
-
I had also found updates in the theme.css (and minimized theme.min.css) that related to this content, and when I added it in, it then displayed the information in correct format, but still having issues. To resolve, I believe I am going to refactor the current custom theme, reverting it back to twenty-one (8.10) and then working back in the changes we had put in place (which were a few).
