Jump to content

Edit invoice email template


Recommended Posts

Hello,

 

I need to edit invoice email template. I made idn domain registration, and when user registers idn domain invoice is sent to him as an email, but domain is written in punycode encoded version and I don't want my user to see encoded domain, I want it to be readable for user.

 

So I need to edit {$invoice_html_contents} in email template.

 

I tried these hooks: PreInvoicingGenerateInvoiceItems, InvoiceCreationPreEmail but when I print $vars array, it's all empty, how am I supposed to edit it ?

 

Also, one more thing, these hooks work when user registers domain himself, but I also need to find a hook that's run when I manually click 'Send Email' button in my admin area and send user a new invoice mail.

 

Can anyone help ?

Link to comment
Share on other sites

the quick way, to avoid the need for using a hook, would be to just edit the invoice email template and modify {$invoice_html_contents} by using Smarty Replace to change specific substrings...

 

{$invoice_html_contents|replace:'.xn--node':'.გე'}

if you are selling multiple different IDN's, then you can use multiple replaces in the template...

 

{$invoice_html_contents|replace:'.xn--node':'.გე'|replace:'.xn--80adxhks':'.москва'}

this will work whether you create the order, or the client does...

Link to comment
Share on other sites

yeah, I know. building it into whmcs is so messy :D

 

I have a punycode class file that decodes and even ecnodes, but I can't include it to email template.

 

I've searched for hooks before but couldn't solve it and then thought I could decode it straight in the email template but what I tried didn't work so I asked staff members via ticket and they told me to use hooks, I gave it another try but none of the hooks gave me access to {$invoice_html_contents}, some of them printed empty arrays and some of them just printed invoice id and stuff.

 

{$invoice_html_contents} is this in the email that's sent to user after registering domain:

 

Domain Registration - xn--1odaaa.xn--node - 1 Year/s (07/03/2017 - 06/03/2018)

 

 

I guess I can work around with invoice id in hook, like get invoice items form database using invoice id and then check if it includes '.xn--node' and if it does, I'd decode the whole domain then. But thought maybe there's anotehr way around, like simplier way without getting info from database and doing all the check and all.

Link to comment
Share on other sites

if you want my advice, forget about $invoice_html_contents - all that is is a pretty version of the $invoice_items array for the template... even if you could modify it, where does it get you? it would just fix the output in the email template - not the pdf invoice; not the html invoice, not how it's shown in the client area etc.

 

if you can get your hook to modify the invoice item description(s) in the database, they it will be used throughout the site - including inside $invoice_html_contents - therefore, I would have thought PreInvoicingGenerateInvoiceItems would be the one to use.

 

plus, there's still the option of doing it completely in the email template, using Smarty, if you wish....

 

https://forum.whmcs.com/showthread.php?126354-PHP-code-inside-the-EMAIL-template-how-do-I-accomplish-that-Unicode-domain-to-IDN-ASCII&p=506174#post506174

Link to comment
Share on other sites

I've just tried to do it as you suggested, but since {$invoice_html_contents} is this string:

Domain Registration - xn--1odaaa.xn--node - 1 Year/s (07/03/2017 - 06/03/2017 )

 

I have to split it and it says "modifier 'explode' not allowed by security setting".

 

I also tried to use $Invoice_items but first I need to see what's in the array, so I tried to print it with print_r and it said "modifier 'print_r' not allowed by security setting".

 

I edited $smarty_security_policy array:

'mail' => array(

'php_functions' => array(

'explode',

'print_r'

),

 

also tried including file with $trusted_dir but it said file isn't readable, I modified $smarty_security_policy for $trusted_dir but still have that error

Link to comment
Share on other sites

Just came up with the idea to change punycode domains in database. like get invoice description, that is {$invoice_html_contents} in email template, with EmailPreSend hook and check if it includes punycode domain and if it does, I'd decode it and write decoded version into database. I guess it won't mess anything up with the system.

Link to comment
Share on other sites

I've just tried to do it as you suggested, but since {$invoice_html_contents} is this string:

bear in mind that if the client has registered multiple domains, or multiple products with domains, in the order then the string will be more than one line!

 

I have to split it and it says "modifier 'explode' not allowed by security setting".

I also tried to use $Invoice_items but first I need to see what's in the array, so I tried to print it with print_r and it said "modifier 'print_r' not allowed by security setting".

I edited $smarty_security_policy array:

also tried including file with $trusted_dir but it said file isn't readable, I modified $smarty_security_policy for $trusted_dir but still have that error

i'd have just used foreach loops to see the output - though there are many subarrays in there, so you'd need to nest them.... or just added {debug} and examined the array in the popup.

 

Just came up with the idea to change punycode domains in database. like get invoice description, that is {$invoice_html_contents} in email template, with EmailPreSend hook and check if it includes punycode domain and if it does, I'd decode it and write decoded version into database. I guess it won't mess anything up with the system.

isn't that what I said above? :idea:

 

with regards to converting without a class, the following would work to convert the first occurrence of an IDN domain...

 

    $invoiceitems  = 'Domain Registration - xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019)';
   $step1 = strstr($invoiceitems, 'xn--');
   $step2 = strstr($step1, ' ', true);
   $idn = idn_to_utf8($step2);
   $replacement = str_replace($step2, $idn, $invoiceitems);

   echo '<br> original = '.$invoiceitems; // original invoice item
   echo '<br> step 1 = '.$step1; // remove everything before domain
   echo '<br> step 2 = '.$step2; // remove everything after domain
   echo '<br> idn = '.$idn; // convert domain
   echo '<br> replacement = '.$replacement; //  replacement string

 

original = Domain Registration - xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019)

step 1 = xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019)

step 2 = xn--1odaaa.xn--node

idn = რრრრ.გე

replacement = Domain Registration - რრრრ.გე - 2 Year/s (07/03/2017 - 06/03/2019)

which you could trim down further...

 

    $invoiceitems  = 'Domain Registration - xn--1odaaa.xn--node - 2 Year/s (07/03/2017 - 06/03/2019)';
   $domain = strstr(strstr($invoiceitems, 'xn--'), ' ', true);
   $replacement = str_replace($domain, idn_to_utf8($domain), $invoiceitems);

... or ultimately to just one line...

 

$replacement = str_replace(strstr(strstr($invoiceitems, 'xn--'), ' ', true), idn_to_utf8(strstr(strstr($invoiceitems, 'xn--'), ' ', true)), $invoiceitems);

the above is written in PHP, but you could convert it to Smarty if you wanted to use it in a template - web or email (as long as you made the appropriate changes to the security policy). :idea:

Link to comment
Share on other sites

Modifying Smarty is a mess cuz no matter I modify security policy or not, there's still an error. so I made it with EmailPreSend hook and then used GetInvoice API inside hook that I passed invoice_id caught by EmailPreSend hook, so I got the $description and modified it and printed into email template, but now I have to edit 'Order Confirmation' email template and I guess I have to do it like that I just need a correct API for it.

Link to comment
Share on other sites

Any ideas how to add my variable to 'Order Confirmation' email template ?

 

I used $merge fields array: $merge_fields['idn_domain'] = $idn; then printed {$idn_domain} in my 'Order Confirmation' email template and it printed nothing.

 

I did the same for 'Customer Invoice' email template and it worked fine.

Link to comment
Share on other sites

if it's an EmailPreSend hook, then the variable should be available in all client (not admin) email templates, e.g if I use the following hook, the variables are available in the Order Confirmation template...

 

<?php

function hook_emailvars($vars) {

  $merge_fields = [];
   $merge_fields['my_custom_var'] = "My Custom Var";
   $merge_fields['my_custom_var2'] = "My Custom Var2";

   return $merge_fields;
}
add_hook("EmailPreSend",1,"hook_emailvars");  
add_hook("EmailTplMergeFields",1,"hook_emailvars"); 
?>

i'll likely need to see your code to spot if there are any obvious errors in there, but i'd be worried what the variable value would be if there were two (or more) IDN domains in the order? :?:

Link to comment
Share on other sites

This is the hook, I used for 'Customer Invoice' email template:

 

add_hook('EmailPreSend', 1, function($vars) {

 

$command = 'GetInvoice';

$postData = array(

'invoiceid' => $vars['relid'],

);

 

$adminUsername = 'Voland';

 

$results = localAPI($command, $postData, $adminUsername);

 

$original_description = $results['items']['item'][0]['description'];

$description = strstr($original_description, 'xn--');

$domain = strstr($description, ' ', true); if (strpos($domain, '.xn--node')) {

include("itdcapi.php");

$idn = $Punycode->decode($domain);

 

$description = str_replace($domain, $idn, $original_description);

$merge_fields = array();

$merge_fields['description'] = $description;

$merge_fields['idn_domain'] = $idn;

return $merge_fields;

 

}

 

});

 

$merge_fields['idn_domain'] = $idn; << I used this line to assign decoded domain name to array's 'idn_domain' variable and printed $idn_domain in 'Order Confirmation' email but it doesn't work.

 

 

I tried like you told me too:

function hook_emailvars($vars) {

 

$command = 'GetInvoice';

$postData = array(

'invoiceid' => $vars['relid'],

);

$adminUsername = 'Username';

 

$results = localAPI($command, $postData, $adminUsername);

 

$original_description = $results['items']['item'][0]['description'];

$description = strstr($original_description, 'xn--');

domain = strstr($description, ' ', true); if (strpos($domain, '.xn--node')) {

include("itdcapi.php");

$idn = $Punycode->decode($domain);

 

$description = str_replace($domain, $idn, $original_description);

$merge_fields = array();

$merge_fields['description'] = $description;

$merge_fields['idn_domain'] = $idn;

return $merge_fields;

}

}

add_hook("EmailPreSend",1,"hook_emailvars");

add_hook("EmailTplMergeFields",1,"hook_emailvars");

 

still it doesn't work.

Link to comment
Share on other sites

I tried like you told me too

hey don't bring me into it, I never suggested using the API - that was your idea. :)

 

have you tried outputting each of the variables as mergefields - at least then you should be able to tell where it's failing... perhaps relid is the issue. :?:

Link to comment
Share on other sites

yeah API was my idea, I just did what you suggested about 'EmailTplMergeFields' hook :D

 

have you tried outputting each of the variables as mergefields - at least then you should be able to tell where it's failing... perhaps relid is the issue. :?:

when I var_dump mergefields array it shows that there's 'description' and 'idn_domain' elements in it but 'idn_domain' doesn't print in 'Order Confirmation' email template.

Link to comment
Share on other sites

yeah API was my idea, I just did what you suggested about 'EmailTplMergeFields' hook :D

well that just adds it to the Merge Fields table at the bottom - so doesn't interfere with the functionality of the hook in any way.

 

when I var_dump mergefields array it shows that there's 'description' and 'idn_domain' elements in it but 'idn_domain' doesn't print in 'Order Confirmation' email template.

ok, so if I hard-code the variables in the hook, I can pass them to the order confirmation template without issue...

 

<?php

# Add Merge Fields To Email Templates
# Written by brian!

function hook_emailvars($vars) {

   $domain = "xn--1odaaa.xn--node";
   $idn = idn_to_utf8($domain); 
   $merge_fields = [];
   $merge_fields['original_domain'] = $domain;
   $merge_fields['idn_domain'] = $idn;

   return $merge_fields;
}
add_hook("EmailPreSend",1,"hook_emailvars");  
add_hook("EmailTplMergeFields",1,"hook_emailvars"); 
?>

if I then add the following to the order confirmation email...

 

domain = {$original_domain}
idn = {$idn_domain}

it will output the values correctly...

 

yA3o1om.png

so passing the merge fields isn't the issue, it must be the source of the data and/or any manipulation done to it.

 

whilst it makes sense to use getinvoice for an invoice template, invoiceid might not exist in a general template (nor do I even think the template uses the invoice item description anyway), so you might be better off using another API, e.g getorders and working through its output... it might end up being easier as you should be able to get the domain by itself, so you won't need to do any manipulation just to isolate it from the description. :idea:

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • 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