Отправка счетов и накладных вместе с e-mail уведомлением о заказе

Довольно часто покупатели интернет-магазина являются юридическими лицами и просят выслать им счет на оплату заказа. Почему бы не формировать счет автоматически и отсылать его вместе с письмом-подтверждением заказа? Для b2b сайта издательства «Росмэн» мы реализовали данный функционал.
[spoiler]
Идея

Будем формировать файл счета после создания заказа и перед отправкой письма-подтверждения, на основе xls-шаблона используя PHPExcel. При отправке письма-подтверждения о заказе — будем прикреплять файл счета к письму.

Реализация

1. Создадим шаблоны необходимых документов (счетов, актов, накладных и т.п.) в формате Excel — внесем в них все нужные параметры в виде "заглушек", в них будут выводиться данные конкретного заказа — номер заказа, секция магазина, дата, менеджер заказа, список товаров, сумма и т.п.:
edc30de325139cd4631ad069dec3ea1b.png

2. В файле /bitrix/php_interface/init.php создадим обработчик события OnBeforeEventAddHandler - для того, чтобы отправить письмо с аттачами (за идею, как в "Битриксе" реализовать отправку письма с аттачем, спасибо Антону Долганину):
function OnBeforeEventAddHandler($event, $lid, $arFields) {
   if ($event == "SALE_NEW_ORDER") {
      include("make_xls.php");
       $arXLSfiles = scandir(dirname(__FILE__).'/orders/'.$arOrder['ID']);
      include("mail_attach.php");
      SendAttache($event, $lid, $arFields, $arXLSfiles);
      return false;
   }
}
Если почтовое событие - SALE_NEW_ORDER (новый заказ в магазине), то подключаем код make_xls.php (см. пункт 3) - для создания Excel-файлов (подставляя данные заказа в xls-шаблон). В качестве аттачей - берем все xls-файлы, которые сформированы после выполнения файла make_xls.php в папке /orders/'.$arOrder['ID']/; mail_attach.php - содержит функцию отправки письма с аттачем SendAttache.

return false - необходимо для блокировки отправки письма "Битриксом", т.к. иначе будут проходить два письма - одно отправленное функцией SendAttache (с аттачами), второе - отправленное "Битриксом" (без аттачей)

3. Файл make_xls.php - создание Excel-файлов. Полный код приводить здесь не буду, основные моменты:

Собираем данные о заказе, пользователе, скидке заказа, корзине и т.п.:
if($arFields['ORDER_ID']) {

   //Заказ:
   $arOrder = CSaleOrder::GetByID($arFields['ORDER_ID']);

   //Пользователь:
   global $USER;
   $rsUser = CUser::GetList(($by), ($order), array("ID"=>$USER->GetID()), array("SELECT" => array("ADMIN_NOTES","UF_*")));
   $arUser = $rsUser->GetNext();

   //Менеджер пользователя:
   $rsManager = CUserFieldEnum::GetList(array(), array("ID" => $arUser["UF_MANAGER"]));
   $arManager = $rsManager->GetNext();
   
   //Скидки пользователя:
   foreach($arUser as $key=>$value) {
      ...
   }
   
   //Корзина:
   $dbBasketItems = CSaleBasket::GetList(array("NAME" => "ASC"), array("ORDER_ID" => $arFields["ORDER_ID"]), false, false, array("ID", "PRODUCT_ID", "QUANTITY", "PRICE", "NAME")); 
   while ($arBasketItem = $dbBasketItems->GetNext()) {
      ...
   }
}
Формируем xls-файл:
include_once dirname(__FILE__) . '/PHPExcel.php';
include_once dirname(__FILE__) . '/PHPExcel.addon.php';

mkdir(dirname(__FILE__).'/orders/'.$arOrder['ID'], 0755, true);

PHPExcelAddon::convert(dirname(__FILE__).'/order_template.xls',array (
   'order' => "Заказ №".$arOrder['ID'],
   'section' => $arSectionGroupsNames[$sgid],
   'datetime' =>  $arOrder['DATE_INSERT'],
   'client_name' => $arUser['NAME'].' '.$arUser['LAST_NAME'],
   'manager_name' => $arManager['VALUE'],
   'client_email' => $arUser['EMAIL'],
   'manager_email' => $arManager['XML_ID'],
   'basket.articles_ADDROWS' => $arBasketArticles,
   'basket.names' => $arBasketNames,
   'basket.quantities' => $arBasketQuantities,
   'basket.summs' => $arBasketPrices,
   'basket.discounts' => $arBasketDiscounts,
   'total_summ' => $total_summ,
),'orders/'.$arOrder['ID'].'/Заказ_'.$arOrder['ID'].'_'.$arSectionGroupsNames[$sgid]);
PHPExcel.addon.php - идея взята из статьи на habrahabr:
class PHPExcelAddon {
   public function __construct () {}
   public static function convert ($file, $data=array (), $filename='file') {
      $objPHPExcel = PHPExcel_IOFactory::load( $file );
      $objPHPExcel->setActiveSheetIndex(0);
      $aSheet = $objPHPExcel->getActiveSheet();
      foreach($aSheet->getRowIterator() as $row){
         ...
      }
      $objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
      $objWriter->save(dirname($file).'/'.$filename.'.xlsx');
      $objPHPExcel->disconnectWorksheets();
      unset($objPHPExcel);
   }
}
 
В результате, получаем письма-уведомления, к которым сразу же прикреплены необходимые клиенту файлы документов его заказа.

PS: Как вариант, можно формировать документы для клиентов в pdf, используя html-формы документов, доступные в интерфейсе управления заказами (или создавая свои):
d3efc19a310fae473f5b83737fb3aa5b.png

Но это уже другая история. :)