Jump to content

Resend Order Confirmation


Recommended Posts

As the title states using PrestaShop 1.6.1.2 :)

 

Is there any way to resend an order confirmation to a customer after the order is placed?

 

Had a customer call me yesterday claiming to not having received their confirmation and asked if i could resend it.

First time since we opened the shop 3 months ago this happened and i suspect he simply deleted the mail by mistake.

 

However to my surprise i can not for the life of me find out how to resend him the order confirmation....

Maybe I'm just being stupid about it but after spending to good part of a day and a half searching the web and trying to figure this out I'm desperate for help.

 

Surely this must be a built in function in the system?

 

If it's not built in, any pointers to a module is appreciated.

 

 

Oh and first time poster I'm not sure if this is the right forum to post this question in, so apologies if it's not. :)

Link to comment
Share on other sites

  • 7 months later...
  • 4 months later...

As the title states using PrestaShop 1.6.1.2 :)

 

Is there any way to resend an order confirmation to a customer after the order is placed?

 

Had a customer call me yesterday claiming to not having received their confirmation and asked if i could resend it.

First time since we opened the shop 3 months ago this happened and i suspect he simply deleted the mail by mistake.

 

However to my surprise i can not for the life of me find out how to resend him the order confirmation....

Maybe I'm just being stupid about it but after spending to good part of a day and a half searching the web and trying to figure this out I'm desperate for help.

 

Surely this must be a built in function in the system?

 

If it's not built in, any pointers to a module is appreciated.

 

 

Oh and first time poster I'm not sure if this is the right forum to post this question in, so apologies if it's not. :)

 

Hi Vingless, 

 

Have you found a solution ?

 

Thanks

Link to comment
Share on other sites

  • 3 weeks later...
  • 3 years later...
  • 1 year later...

Basically you can't.
The function that sends the order email is inside the classes/PaymentModule.php > validateOrder()

In my version row is 827:

 

Mail::Send(
  (int)$order->id_lang,
  'order_conf',
  Context::getContext()->getTranslator()->trans(
  'Order confirmation',
  array(),
  'Emails.Subject',
  $orderLanguage->locale
  ),
  $data,
  $this->context->customer->email,
  $this->context->customer->firstname.' '.$this->context->customer->lastname,
  null,
  null,
  $file_attachement,
  null, _PS_MAIL_DIR_, false, (int)$order->id_shop
);


The problem is that the vars used inside the template are created in this enormous function, and you can't call this function just to send email because the same function does a lot of other things related to order creation (stock updating, hooks, etc).

The one of the 2 solutions you have, is to re-build your own function copying the pieces of code you need from this validateOrder function.

So, basically, you will have 2 order confirmation "building" in the same prestashop, and that's a really bad thing because you have to mantain two different functions, if one day you decide to edit some variables or some piece of code in the order confirmation email you'll have to remember this and do the job 2 times.

The best solution (talking about code) is to edit prestashop class and add a sendConfirmationEmail() function, take all these pieces of code inside the validateOrder and place that inside this new function.

Then, inside validateOrder function you can call your new function $this->sendConfirmationEmail(xxx);

But this is bad because you won't be able to update prestashop anymore.

So.. 

Solution 1: basically you don't re-send the email confirmation but you send an email which use order confirmation template (order_conf) and you manually create all the variables needed to populate this template.

Solution 2: you edit the prestashop class with all his consequences.

I think the best solution (the same that the module someone linked uses) is the first one, you can do it by creating a module and the company must have a developer ready to fix it after a prestashop update for any changes in this template variables or other updates.

Edited by Pandal (see edit history)
Link to comment
Share on other sites

<?php

class [YourModuleName]ConfirmationEmailModuleFrontController extends ModuleFrontController
{
  public function initContent()
  { 
    if(!Tools::getValue("id_order")){
      die('Missing get parameter id_order');
    }

    self::sendOrderConfirmationEmail(intval(Tools::getValue("id_order")));
  }

  private static function sendOrderConfirmationEmail($id_order)
  {

    $order = new Order($id_order);
    $context = Context::getContext();
    $invoice = new Address($order->id_address_invoice);
    $delivery = new Address($order->id_address_delivery);
    $delivery_state = $delivery->id_state ? new State((int) $delivery->id_state) : false;
    $invoice_state = $invoice->id_state ? new State((int) $invoice->id_state) : false;
    $carrier = $order->id_carrier ? new Carrier($order->id_carrier) : false;
    $customer = $order->getCustomer();
    $orderLanguage = new Language((int) $order->id_lang);
    $currency = new Currency($order->id_currency);
    
    $product_var_tpl_list = array();
    
    foreach ($order->getProducts() as $product) {

      $vars = array();
      $vars['unit_price'] = Tools::displayPrice($product['unit_price_tax_incl'], $currency, false);
      $vars['price'] = Tools::displayPrice($product['total_price_tax_incl'], $currency, false);
      $vars['reference'] = $product['reference'];
      $vars['name'] = $product['product_name'];
      $vars['quantity'] = $product['product_quantity'];
      $vars['customization'] = array();

      array_push($product_var_tpl_list, $vars);
    }

    $cart = Cart::getCartByOrderId($order->id);

    $cart_rules = $cart->getCartRules();
    $cart_rules_var_tpl_list = array();

    foreach($cart_rules as $rule){
      $vars = array();

      if($order->id_currency != $rule['reduction_currency']){
        $conversion_rate = floatval(Db::getInstance()->getRow("SELECT conversion_rate FROM ps_currency WHERE id_currency = {$order->id_currency}")['conversion_rate']);
        $vars['voucher_reduction'] = $rule['reduction_amount'] * $conversion_rate;
      }
      else{
        $vars['voucher_reduction'] = $rule['reduction_amount'];
      }

      $vars['voucher_reduction'] = Tools::displayPrice($vars['voucher_reduction'], $currency, false);
      $vars['voucher_name'] = $rule['description'];

      array_push($cart_rules_var_tpl_list, $vars);
    }

    $product_list_html = self::getEmailTemplateContent('order_conf_product_list.tpl', Mail::TYPE_HTML, $product_var_tpl_list);
    $cart_rules_list_html = self::getEmailTemplateContent('order_conf_cart_rules.tpl', Mail::TYPE_HTML, $cart_rules_var_tpl_list);  

    $data = array(
      '{products}' => $product_list_html,
      '{discounts}' => $cart_rules_list_html,
      '{firstname}' => $customer->firstname,
      '{lastname}' => $customer->lastname,
      '{email}' => $customer->email,
      '{delivery_block_txt}' => self::getFormatedAddress($delivery, "\n"),
      '{invoice_block_txt}' => self::getFormatedAddress($invoice, "\n"),
      '{delivery_block_html}' => self::getFormatedAddress($delivery, '<br />', array(
          'firstname' => '<span style="font-weight:bold;">%s</span>',
          'lastname' => '<span style="font-weight:bold;">%s</span>',
      )),
      '{invoice_block_html}' => self::getFormatedAddress($invoice, '<br />', array(
          'firstname' => '<span style="font-weight:bold;">%s</span>',
          'lastname' => '<span style="font-weight:bold;">%s</span>',
      )),
      '{delivery_company}' => $delivery->company,
      '{delivery_firstname}' => $delivery->firstname,
      '{delivery_lastname}' => $delivery->lastname,
      '{delivery_address1}' => $delivery->address1,
      '{delivery_address2}' => $delivery->address2,
      '{delivery_city}' => $delivery->city,
      '{delivery_postal_code}' => $delivery->postcode,
      '{delivery_country}' => $delivery->country,
      '{delivery_state}' => $delivery->id_state ? $delivery_state->name : '',
      '{delivery_phone}' => ($delivery->phone) ? $delivery->phone : $delivery->phone_mobile,
      '{delivery_other}' => $delivery->other,
      '{invoice_company}' => $invoice->company,
      '{invoice_vat_number}' => $invoice->vat_number,
      '{invoice_firstname}' => $invoice->firstname,
      '{invoice_lastname}' => $invoice->lastname,
      '{invoice_address2}' => $invoice->address2,
      '{invoice_address1}' => $invoice->address1,
      '{invoice_city}' => $invoice->city,
      '{invoice_postal_code}' => $invoice->postcode,
      '{invoice_country}' => $invoice->country,
      '{invoice_state}' => $invoice->id_state ? $invoice_state->name : '',
      '{invoice_phone}' => ($invoice->phone) ? $invoice->phone : $invoice->phone_mobile,
      '{invoice_other}' => $invoice->other,
      '{order_name}' => $order->getUniqReference(),
      '{date}' => Tools::displayDate(date('Y-m-d H:i:s'), null, 1),
      '{carrier}' => ($order->isVirtual() || !isset($carrier->name)) ?
          $this->module->trans('No carrier', array(), 'Admin.Payment.Notification') : $carrier->name,
      '{payment}' => Tools::substr($order->payment, 0, 255),
      '{total_paid}' => Tools::displayPrice($order->total_paid, $currency, false),
      '{total_products}' => Tools::displayPrice(
          Product::getTaxCalculationMethod() == PS_TAX_EXC ? $order->total_products :
              $order->total_products_wt,
          $currency
      ),
      '{total_discounts}' => Tools::displayPrice($order->total_discounts, $currency),
      '{total_shipping}' => Tools::displayPrice($order->total_shipping, $currency),
      '{total_shipping_tax_excl}' => Tools::displayPrice($order->total_shipping_tax_excl, $currency),
      '{total_shipping_tax_incl}' => Tools::displayPrice($order->total_shipping_tax_incl, $currency),
      '{total_wrapping}' => Tools::displayPrice($order->total_wrapping, $currency),
      '{total_tax_paid}' => Tools::displayPrice(($order->total_products_wt - $order->total_products) +
          ($order->total_shipping_tax_incl - $order->total_shipping_tax_excl), $currency),
    );

    $res = Mail::Send(
      (int)$order->id_lang,
      'order_conf',
      $context->getTranslator()->trans(
          'Order confirmation',
          array(),
          'Emails.Subject',
          $orderLanguage->locale
      ),
      $data,
      $customer->email,
      $customer->firstname.' '.$customer->lastname,
      null,
      null,
      false,
      null, _PS_MAIL_DIR_, false, (int)$order->id_shop
    );

    die(json_encode(array("success" => ($res ? true : false), "result" => $res)));
  }

  private static function getEmailTemplateContent($template_name, $mail_type, $var)
  {
    $email_configuration = Configuration::get('PS_MAIL_TYPE');
    if ($email_configuration != $mail_type && $email_configuration != Mail::TYPE_BOTH) {
        return '';
    }
    
    $pathToFindEmail = array(
        _PS_THEME_DIR_.'mails'.DIRECTORY_SEPARATOR.Context::getContext()->language->iso_code.DIRECTORY_SEPARATOR.$template_name,
        _PS_THEME_DIR_.'mails'.DIRECTORY_SEPARATOR.'en'.DIRECTORY_SEPARATOR.$template_name,
        _PS_MAIL_DIR_.Context::getContext()->language->iso_code.DIRECTORY_SEPARATOR.$template_name,
        _PS_MAIL_DIR_.'en'.DIRECTORY_SEPARATOR.$template_name,
    );

    foreach ($pathToFindEmail as $path) {
        if (Tools::file_exists_cache($path)) {
          Context::getContext()->smarty->assign('list', $var);
            return Context::getContext()->smarty->fetch($path);
        }
    }

    return '';
  }

  private static function getFormatedAddress(Address $the_address, $line_sep, $fields_style = array())
  {
    return AddressFormat::generateAddress($the_address, array('avoid' => array()), $line_sep, ' ', $fields_style);
  }

}

Here is a working controller that re-sends the email.

If you want you can take this and create a module by adding a re-send button in backoffice order showing hook.

I use it by code so I don't need a button, but feel free to add it and post the module here to help other people.

Edited by Pandal (see edit history)
Link to comment
Share on other sites

  • 2 months later...
On 8/18/2021 at 9:02 AM, Pandal said:

Here is a working controller that re-sends the email.

If you want you can take this and create a module by adding a re-send button in backoffice order showing hook.

I use it by code so I don't need a button, but feel free to add it and post the module here to help other people.

Thanks for posting your code!

Do you have any idea of how to attach the invoice or packing slip to the email?

Link to comment
Share on other sites

Objects of Mail class have their way of adding files as attachments.

static public function Send($id_lang, $template, $subject, $templateVars, $to, $toName = NULL, $from = NULL, $fromName = NULL, $fileAttachment = NULL, $modeSMTP = NULL, $templatePath = _PS_MAIL_DIR_)

This  is the signature of the Send function for the Mail class.

You can check the code in /classes/Mail.php

Or here in github

Edited by Pandal (see edit history)
Link to comment
Share on other sites

Thanks for the input @Pandal.

I did some digging, searching and merging and this seems fine to attach both invoice and delivery slip in a mail;

 

            $context = Context::getContext();

            $pdf_inv = new PDF($order->getInvoicesCollection(), PDF::TEMPLATE_INVOICE, $context->smarty);
            $attachment_invoice['content'] = $pdf_inv->render(false);
            $attachment_invoice['name']    = Configuration::get('PS_INVOICE_PREFIX', (int)$order->id_lang, null, $order->id_shop).sprintf('%06d', $order->invoice_number).'.pdf';
            $attachment_invoice['mime']    = 'application/pdf';            
            
            $pdf_del = new PDF($order->getInvoicesCollection(), PDF::TEMPLATE_DELIVERY_SLIP, $context->smarty);
            $attachement_delivery['content'] = $pdf_del->render(false);
            $attachement_delivery['name']    = Configuration::get('PS_DELIVERY_PREFIX', (int)$order->id_lang, null, $order->id_shop).sprintf('%06d', $order->delivery_number).'.pdf';
            $attachement_delivery['mime']    = 'application/pdf';

            $attachement_inv_del             = array($attachment_invoice, $attachement_delivery);
            

            $templateVars = array(
                '{firstname}' => $customer->firstname,
                '{lastname}' => $customer->lastname,
                '{id_order}' => $order->id,
                '{order_name}' => $order->getUniqReference(),
                '{invoice_number}' => Configuration::get('PS_INVOICE_PREFIX', (int) $order->id_lang, null, $order->id_shop) . sprintf('%06d', $order->invoice_number),
                '{delivery_number}' => Configuration::get('PS_DELIVERY_PREFIX', (int) $order->id_lang, null, $order->id_shop) . sprintf('%06d', $order->delivery_number),
            );              


if (Tools::isSubmit('submitSendInvoice')) {                        
            Mail::Send(
                (int)$order->id_lang, 
                'order_conf', 
                Mail::l('Invoice for your order', 
                (int)$order->id_lang), 
                $templateVars,
                $customer->email, 
                $customer->firstname.' '.$customer->lastname, 
                null, 
                null, 
                $attachement_inv_del, 
                null,
                _PS_MAIL_DIR_, 
                true, 
                (int)$order->id_shop
                );
}

 

Edited by redrum (see edit history)
Link to comment
Share on other sites

  • 4 weeks later...

Hi,

bit new to coding unfortunately. I figured that I need to insert into

/www/adminxxx/themes/default/template/controllers/orders/helpers/view/view.tpl

this bit of code

<a href="{$current_index}&amp;submitResendConf&amp;id_order={$order->id}&amp;token={$smarty.get.token|escape:'html':'UTF-8'}"><i class="icon-mail-reply"></i>&nbsp;&nbsp;Resend order confirmation</a>

but how do I make it work with your code? Or even better, how to make a module out of it?

Edited by mr_absinthe
typo (see edit history)
Link to comment
Share on other sites

On 11/14/2021 at 5:10 PM, mr_absinthe said:

Hi,

bit new to coding unfortunately. I figured that I need to insert into

/www/adminxxx/themes/default/template/controllers/orders/helpers/view/view.tpl
 

this bit of code

<a href="{$current_index}&amp;submitResendConf&amp;id_order={$order->id}&amp;token={$smarty.get.token|escape:'html':'UTF-8'}"><i class="icon-mail-reply"></i>&nbsp;&nbsp;Resend order confirmation</a>
 

but how do I make it work with your code? Or even better, how to make a module out of it?

If you want to create a module that shows a button in the back-office and sends a request to a page that re-send the confirmation email, you should be able to work with hooks, php (symfony), smarty and jquery ajax too.. 

Is not so easy to create if you are new to coding, maybe someone did it basing his solution in the code posted by @redrum and me. If someone did this please post the module it would be useful for non-developer users.

In these months I have no time to code out of my working hours in my company so I can't help you at the moment!

  • Like 1
Link to comment
Share on other sites

52 minutes ago, Pandal said:

Is not so easy to create if you are new to coding, maybe someone did it basing his solution in the code posted by @redrum and me. If someone did this please post the module it would be useful for non-developer users.

In these months I have no time to code out of my working hours in my company so I can't help you at the moment!

I did some dirty hard coded stuff to test it on my sandbox environment. To be able to share it I would have to extract it and make a proper module of it.
Unfortunately my time is extremely limited right now. But when I find some time I will see if I can complete it and upload a module.

  • Like 2
Link to comment
Share on other sites

  • 2 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...