<?php

namespace Modules\Invoices\InvoicesList;

class Controller extends \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing
{

	/**
	 * Indicates if the entity execution should use or not a transaction.
	 * @var Boolean
	 */
	protected $useSqlTransaction=true;

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::initialize()
	 */
	protected function initialize()
	{
		parent::initialize();

		$this->actionsCfg['getAjaxMenu'] =	[ 'checkSection' => false, 'checkOption' => false ];

		$this->actionsCfg['cashInvoice'] =	[ 'checkSection' => false, 'checkOption' => false ];
		$this->actionsCfg['update'] =		[ 'checkSection' => true, 'checkOption' => false ];
		$this->actionsCfg['details'] =		[ 'checkSection' => true, 'checkOption' => false ];
		$this->actionsCfg['duplicate'] =	[ 'checkSection' => true, 'checkOption' => true ];
		$this->actionsCfg['reverse'] =		[ 'checkSection' => true, 'checkOption' => true ];
		$this->actionsCfg['cumulate'] =		[ 'checkSection' => true, 'checkOption' => false ];
		$this->actionsCfg['compensate'] =	[ 'checkSection' => true, 'checkOption' => false];
		$this->actionsCfg['sendAlert'] =	[ 'checkSection' => true, 'checkOption' => false ];

		// clean default options
		unset($this->actionsCfg['insert'], $this->actionsCfg['delete']);

	}

	protected function actionGetAjaxMenu($R)
	{
		$options = new \App\Mvc\View\Utils\RowOptions\Container\Simple();
		$options->appendItems($this->getAllDefinedOptions()->getContainer('specialOptions')->getAll());

		$view = new \App\Utils\Views\MenuDropdown($this->populateOptions($options, [$R['id'], ]));
		return new \Engine\Mvc\Response\Html($view->renderHtml());
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::alterListParams()
	 */
	protected function index_alterListParams($R)
	{
		$filters = [];

		// overwrite the responsible user and date interval if the id order filter is filled
		if ($R['filters']['idReservation'] and $R['filters']['idReservationType']=='id') {
			$filters['resIdOfficeUser']['id'] = '0|0';

			// if the single item option is used (not the bulk one) the filter from request it will be a string
			if (!is_array($R['filters']['idReservation'])) {
				$R['filters']['idReservation'] = [$R['filters']['idReservation']];
			}

			$startDate = DATE_LIMIT_MAX;
			$endDate = DATE_LIMIT_MIN;

			foreach ($R['filters']['idReservation'] as $idOrder) {
				$idOrder = (int)\App\Utils\Db\TablesUtils::getInstance()->switchIdReservationConversion($idOrder, 'normal');
				$orderDate = \Entity\Order::select($idOrder)->date;
				$date = \Engine\DateTime::createFromIsoDate($orderDate);
				$startDate = min($startDate, $date->modify('- 1 month')->formatDateIso());
				$endDate = max($endDate, $date->modify('+12 months')->formatDateIso());
			}

			$filters['invoiceDate'] = [
				'start' 	=> $startDate,
				'end' 		=> min($endDate, \Engine\DateTime::createFromIsoDate(TODAY_ISO)->modify('+ 1 month')->formatDateIso()),
			];

			$filters['idReservation'] = implode(', ', $R['filters']['idReservation']);
		}
		// overwrite the responsible user and date interval if the id service filter is filled
		elseif ($R['filters']['idReservation'] and $R['filters']['idReservationType']=='idService') {
			$filters['resIdOfficeUser']['id'] = '0|0';

			$serviceEnt = \Entity\Service::select($R['filters']['idReservation']);
			$serviceDate = $serviceEnt->addTime;

			$date = \Engine\DateTime::createFromTimestamp($serviceDate);
			$filters['invoiceDate'] = [
				'start' 	=> $date->modify('- 1 month')->format('Y-m-d'),
				'end' 		=> min(TODAY_ISO, $date->modify('+11 months')->format('Y-m-d'))
			];
		}


		// FILTER TEMPORARY INVOICES ASSOCIATED TO THE CUMULATIVE INVOICE (AND REVERSE) ///////////
		if ($R['filters']['idCumulativeInvoice']) {
			$invoiceEnt = \Entity\Invoice::select($R['filters']['idCumulativeInvoice']);
			$invoiceDateStart = DATE_LIMIT_MAX;
			$invoiceDateEnd = DATE_LIMIT_MIN;
			$filterInvoiceIdsList = [];

			// we do not filter if the invoice is voided
			if (!$invoiceEnt->voidTime) {
				// if the invoice is a cumulative one - we look for the temporary invoices
				if ($invoiceEnt->cumulativeInvoice) {
					$filterInvoiceIdsList = $invoiceEnt->cumulatedInvoicesIdsList;
					foreach ($invoiceEnt->cumulatedInvoicesIdsList as $tempInvId) {
						$tempInvEnt = \Entity\Invoice::select($tempInvId);

						if ($tempInvEnt->invoiceDate <= $invoiceDateStart) {
							$invoiceDateStart = $tempInvEnt->invoiceDate;
						}
						if ($tempInvEnt->invoiceDate >= $invoiceDateEnd) {
							$invoiceDateEnd = $tempInvEnt->invoiceDate;
						}
					}
				}

				// if the invoice is a cumulated temporary - we look at the cumulative
				if ($invoiceEnt->cumulatedOnInvoiceId) {
					$cumulativeInvEnt = $invoiceEnt->cumulatedOnInvoice;
					$invoiceDateStart = $invoiceDateEnd = $cumulativeInvEnt->invoiceDate;
					$filterInvoiceIdsList = [$invoiceEnt->cumulatedOnInvoiceId];
				}


				$filters['idInvoice'] = implode(',', $filterInvoiceIdsList);
				$filters['invoiceDate']['start'] = $invoiceDateStart;
				$filters['invoiceDate']['end'] = $invoiceDateEnd;
			}
		}

		if ($filters) {
			$this->listingParams->mergeFilters($filters);
			$this->listingParams->save();
		}
	}

	/**
	 * The list of columns which support ordering.
	 * @var array
	 */
	protected $listOrderingColumns = ['invoiceNumber', 'invoiceDate', 'dueDate', 'addTime', 'fulfillmentDate'];

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::actionList_getModelOutput()
	 */
	protected function actionList_getModelOutput($R)
	{
		$filters = $this->getListingParams()->getFilters();

		if (!\Engine\DateTime::createFromIsoDate($filters['invoiceDate']['start'])->isValid() || !\Engine\DateTime::createFromIsoDate($filters['invoiceDate']['end'])->isValid()) {
			throw new \Engine\Mvc\ControllerException($this->lang['index']['messages']['invoiceDate_mandatory']);
		}

		$maxDateLimit = \Engine\DateTime::createFromIsoDate($filters['invoiceDate']['start'])->add(\Engine\DateInterval::createFromIntervalSpec("P{$this->cfg['listingParams']['filters']['invoiceDate']['maxDifference']}D"));
		if ( $maxDateLimit->formatDateIso() < $filters['invoiceDate']['end'] ) {
			throw new \Engine\Mvc\ControllerException($this->lang['index']['messages']['invoiceDate_invalidInterval']);
		}

		return parent::actionList_getModelOutput($R);
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionDefineParams()
	 */
	protected function optionDefineParams(\App\Mvc\View\Utils\RowOptions\Option\Option $option, $selection)
	{
		$selectionSize = count($selection);

		switch($option->getId()) {

			case 'remoteLoad': case 'details': case 'tasksOnInvoice': case 'documentsBulkDownload':
			break;

			case 'reservationFilter':
				if ( !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToSection('Modules/Orders/OrdersList') ) {
					$option->setDisabled();
					$option->addMessage('warning', $this->globalLang['noAccessToSection']);
				}
			break;

			case 'servicesFilter':
				if ( !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToSection('Modules/Orders/ServicesList') ) {
					$option->setDisabled();
					$option->addMessage('warning', $this->globalLang['noAccessToSection']);
				}
			break;

			case 'temporaryInvoicesFilter':
				foreach ($selection as $selectedItem) {
					$invoiceEnt = \Entity\Invoice::select($selectedItem);
					if ((!$invoiceEnt->cumulativeInvoice and !$invoiceEnt->cumulatedOnInvoiceId) or $invoiceEnt->voidTime) {
						$option->setDisabled();
						$option->addMessage('warning', $this->lang['options']['reasons']['temporaryInvoicesFilter']['notCumulative']);
					}
				}
				break;

			case 'cashInvoice':
			break;

			case 'issue':
				if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('invoiceDocumentsManagement')) {
					$option->setDisabled()->addMessage('warning', $this->globalLang['noAccessToOption']);
				}
				elseif (!\App\Config\IssueDocuments::getInstance()->getInvoiceDocsList()) {
					$option->setDisabled()->addMessage('warning', $this->lang['options']['reasons']['manageDocuments']['noDocuments']);
				}

				foreach ($selection as $selectedItem) {
					// determine option icon
					$option->determineIconGeneratedDocuments($selectedItem);
				}
			break;


			case 'duplicate':
				foreach ($selection as $selectedItem) {
					if (!$option->determineOperationAvailability(\Entity\Invoice::duplicate($selectedItem))) {
						break;
					}
				}
			break;

			case 'sendAlert':
				foreach ($selection as $selectedItem) {
					$invoiceEnt = \Entity\Invoice::select($selectedItem);
					if ($invoiceEnt->voidTime) {
						$option->setDisabled()->addMessage('warning', $this->lang['options']['reasons']['sendAlert']['invVoided']);
					}
					if (!$invoiceEnt->issueTime) {
						$option->setDisabled()->addMessage('warning', $this->lang['options']['reasons']['sendAlert']['invNotIssued']);
					}
					if (!$invoiceEnt->idCustomer) {
						$option->setDisabled()->addMessage('warning', $this->lang['options']['reasons']['sendAlert']['invClientNotCust']);
					}
					if (!in_array($invoiceEnt->cashedStatus, ['n', 'p'])) {
						$option->setDisabled()->addMessage('warning', $this->lang['options']['reasons']['sendAlert']['invCashed']);
					}
					if ($invoiceEnt->printTotal<=0) {
						$option->setDisabled()->addMessage('warning', $this->lang['options']['reasons']['sendAlert']['negativeTotal']);
					}
				}
			break;

			case 'reverse':
				foreach ($selection as $selectedItem) {
					if (!$option->determineOperationAvailability(\Entity\Invoice::reverse($selectedItem))) {
						break;
					}
				}
			break;

			case 'addRemarksBulk': case 'invoiceAdd': case 'reExportXml': case 'reExportXmlBulk':
				break;

			case 'clientInvoiceCashBulk': case 'assocImportDoc':
				try {
					$distributeImpDocsBulk = new \Modules\Documents\ImportedDocuments\BulkDistributeImportedDocs\ClientInvoiceModel($selection);
					$distributeImpDocsBulk->isAvailable(false);
				} catch (\App\MessagesException $e) {
					$option->setDisabled();
					$option->addMessage('warning', $e->getMessagesCollector()->getMessageBulk());
				}
			break;

			case 'update':
				foreach ($selection as $selectedItem) {
					$invoice = \Entity\Invoice::select($selectedItem);
					if ($invoice->issueTime) {
						if (!$option->determineOperationAvailability(\Entity\Invoice::updateIssued($selectedItem))) {
							break;
						}
					} else {
						if (!$option->determineOperationAvailability(\Entity\Invoice::update($selectedItem))) {
							break;
						}
					}
				}
			break;

			case 'void': case 'voidBulk':

				foreach ($selection as $selectedItem) {

					try {
						$cancelInvoiceEnt = \Entity\Invoice::cancel($selectedItem); // skip "block cashed invoices" messages, as the user can void an invoice and cancel the cashing docs as well
						$cancelInvoiceEnt->isAvailable();
					} catch (\App\Entity\Exception $ex) {
						foreach($ex->getMessagesCollector()->getMessages() as $msg) {
							if ($msg->getCode()!='cancel_invoiceCashed') {
								$option->addMessage($msg->getType(), $msg->getText());
								$option->setDisabled();
							}
						}
					}
					// break if option is already disabled
					if ($option->isDisabled()) {
						break;
					}
				}
			break;

			case 'compensate':
				try {
					$compensate = new \App\Utils\Invoices\Compensate\Client\Compensate($selection);
					$compensate->isAvailable(false);
				} catch (\App\MessagesException $e) {
					$option->setDisabled()->addMessage('warning', $e->getMessagesCollector()->getMessageBulk());
					break;
				}
			break;

			case 'cumulate':
				if ($selectionSize == 0) {
					$option->setDisabled();
				}
				elseif ($selectionSize == 1) {
					$option->setDisabled();
					$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['onlyOneSelected']);
				}
				else {
					$tooltipData = [
						'count' => 		0,
						'amount' => 	0.0,
						'currency' => 	null,
					];

					$firstInvoiceEntity = \Entity\Invoice::select($selection[0]);

					for ($i = 0; $i < count($selection); $i++) {
						$invoiceEntity = \Entity\Invoice::select($selection[$i]);
						$tooltipData['count']+= 	1;
						$tooltipData['amount']+= 	$invoiceEntity->printTotal;
						$tooltipData['currency']= 	$invoiceEntity->currency;

						// check if invoice exists
						if (!$invoiceEntity->recordExists()) {
							$option->setDisabled(true);
							$option->addMessage('warning', sprintf($this->lang['index']['options']['reasons']['cumulate']['invalidId'], $selection[$i]));
							break;
						}

						// check if invoice is not already cancelled
						if ($invoiceEntity->voidTime) {
							$option->setDisabled(true);
							$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['invoiceCancelled']);
							break;
						}

						// check already cumulated and not cumulative
						if ($invoiceEntity->cumulatedOnInvoiceId and !$invoiceEntity->cumulatedInvoicesIds) {
							$option->setDisabled(true);
							$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['cumulatedAndNotCumulative']);
							break;
						}

						// check not issued
						if ($invoiceEntity->issueTime) {
							$option->setDisabled(true);
							$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['invoiceIssued']);
							break;
						}

						// check not issued
						if (!$invoiceEntity->temporary) {
							$option->setDisabled(true);
							$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['invoiceNotTemp']);
							break;
						}

						// check currency
						if ($invoiceEntity->currency != $firstInvoiceEntity->currency) {
							$option->setDisabled(true);
							$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['differentCurrencies']);
							break;
						}

						// check client
						$currentClientKey = $invoiceEntity->idCustomer.$invoiceEntity->idCorporate.$invoiceEntity->idCorporateOffice;
						$firstClientKey = $firstInvoiceEntity->idCustomer.$firstInvoiceEntity->idCorporate.$firstInvoiceEntity->idCorporateOffice;

						if ($currentClientKey != $firstClientKey) {
							if ($invoiceEntity->idCustomer.$invoiceEntity->idCorporate == $firstInvoiceEntity->idCustomer.$firstInvoiceEntity->idCorporate) {
								$option->setDisabled(true);
								$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['useOnlyOneCorpOffice']);
								break;
							}
							else {
								$option->setDisabled(true);
								$option->addMessage('warning', $this->lang['index']['options']['reasons']['cumulate']['useOnlyOneClient']);
								break;
							}
						}
					}

					if (!$option->isDisabled()) {
						$option->addMessage('info', sprintf("Cumulate %d invoices, totalling %s %s", $tooltipData['count'], \Engine\Smarty\Modifiers\NumberFormat::create($tooltipData['amount']), $tooltipData['currency']));
					}
				}

			break;

			default:
				return false;
		}
		return true;

	}





	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract::optionGetEntityName()
	 */
	protected function optionGetEntityName($id)
	{
		if (\Entity\Invoice::select($id)->invoiceNumber) {
			return \Entity\Invoice::select($id)->invoiceNumber;
		} else {
			return '#'.$id;
		}
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::insert_getDefaultFormData()
	 */
	protected function insert_getDefaultFormData($R)
	{
		$formData = [];

		return $formData;
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::insert_createEntityObject()
	 */
	protected function insert_createEntityObject($formData)
	{
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::update_getDefaultFormData()
	 */
	protected function update_getDefaultFormData($idEntity)
	{
		return [];
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::update_createEntityObject()
	 */
	protected function update_createEntityObject($formData)
	{
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedEntityListing::delete_createEntityObject()
	 */
	protected function delete_createEntityObject($idRecord)
	{
	}


	/**
	 * Duplicate an invoice
	 * @param array $R
	 * @throws \Exception
	 * @return \Engine\Mvc\Response\Html
	 */
	public function actionDuplicate($R)
	{
		$msgs = \App\MessagesCollector::create();

		if ($R['listing']['selection']) {
			$this->setListingSelection($R['listing']['selection']);
		}
		$selIds = $this->getListingSelection()->getList();

		// do not allow duplication of multiple invoices  (extra-check, option button should be disabled anyways)
		if (count($selIds)>1) {
			throw new \Exception("You are not allowed to duplicate more than one invoice at a time.");
		}

		// perfom the actual action on selected items
		foreach ($selIds as $id) {

			\DB::startTransaction();

			try {

				$invoiceEntity = \Entity\Invoice::duplicate($id);
				$invoiceEntity->save();

				\DB::commitTransaction();

				// adds success message(s)
				foreach($invoiceEntity->getMessages()->getMessages() as $msg) {
					$msgs->addMessage($msg);
				}

			}
			catch (\App\Entity\Exception $ex) {
				// rollback transaction
				\DB::rollbackTransaction();
				$msgs->appendMessages($ex->getMessagesCollector());
			}
		}

		// re-display the page content
		return $this->executeListRecords($R, $msgs);
	}


	/**
	 * Reverse an invoice
	 * @param array $R
	 * @throws \Exception
	 * @return \Engine\Mvc\Response\Html
	 */
	public function actionReverse($R)
	{
		$msgs = \App\MessagesCollector::create();

		if ($R['listing']['selection']) {
			$this->setListingSelection($R['listing']['selection']);
		}
		$selIds = $this->getListingSelection()->getList();

		// do not allow reversing of multiple invoices  (extra-check, option button should be disabled anyways)
		if (count($selIds)>1) {
			throw new \Exception("You are not allowed to reverse more than one invoice at a time.");
		}

		// perfom the actual action on selected items
		foreach ($selIds as $id) {

			\DB::startTransaction();

			try {
				$invoiceEntity = \Entity\Invoice::reverse($id);
				$invoiceEntity->invoiceDate = TODAY_ISO;
				$invoiceEntity->idUser = CURRENT_ID_USER;
				$invoiceEntity->idOffice = CURRENT_ID_OFFICE;
				$invoiceEntity->save();

				\DB::commitTransaction();

				// adds success message(s)
				foreach($invoiceEntity->getMessages()->getMessages() as $msg) {
					$msgs->addMessage($msg);
				}
			}
			catch (\App\Entity\Exception $ex) {
				// rollback transaction
				\DB::rollbackTransaction();
				$msgs->appendMessages($ex->getMessagesCollector());
			}

		}

		// re-display the page content
		return $this->executeListRecords($R, $msgs);
	}

	public function actionCumulate($R)
	{
		$msgs = \App\MessagesCollector::create();

		if ($R['listing']['selection']) {
			$this->setListingSelection($R['listing']['selection']);
		}
		$selIds = $this->getListingSelection()->getList();

		// perfom the actual action on selected items
		\DB::startTransaction();

		// if cumulative, void the parent first and replace its Id with the children Ids
		$newIds = [];
		foreach ($selIds as $idInvoice) {
			$invEnt = \Entity\Invoice::select($idInvoice);
			$cumulatedInvoicesIds = $invEnt->cumulatedInvoicesIdsList;
			if ($cumulatedInvoicesIds) {
				try {
					$voidEnt = \Entity\Invoice::cancel($idInvoice);
					$voidEnt->voidReason = 'autoVoidBySystem';
					$voidEnt->save();
				}
				catch (\App\Entity\Exception $ex) {
					\DB::rollbackTransaction();
					$msgs->appendMessages($ex->getMessagesCollector());
					return $this->executeListRecords($R, $msgs);
				}

				foreach ($cumulatedInvoicesIds as $cumulatedInvoiceId) {
					$newIds[] = (Int)$cumulatedInvoiceId;
				}
			}
			else {
				$newIds[] = (Int)$idInvoice;
			}

			// remove this record from the internal list
			$this->getListingSelection()->delete([$idInvoice]);
		}
		$selIds = array_unique($newIds);

		try {
			// get first invoice
			$firstIdInvoice = reset($selIds);
			$firstInvoiceEntity = \Entity\Invoice::selectForUpdate($firstIdInvoice);

			// decide on the FOP - we get it from the first invoice or form app default
			$formOfPayment = $firstInvoiceEntity->formOfPayment;
			if (!$formOfPayment) {
				$formOfPayment = \App\Config\FormsOfPayment::getInstance()->getDefaultItem();
			}

			// get the invoice series fromcompany profile or the most recently added invoice (from the selection)
			$idInvoiceSeries = \App\EntityPreference\Corporate::getInstance($firstInvoiceEntity->idCorporate)->invoiceSeries;
			if (!$idInvoiceSeries) {
				$maxAddTime = 0;
				$idInvoiceSeries = 0;
				foreach ($selIds as $idTempInvoice) {
					$tempInvEnt = \Entity\Invoice::selectForUpdate($idTempInvoice);
					if ($tempInvEnt->addTime>$maxAddTime and $tempInvEnt->idInvoiceSeries) {
						$maxAddTime = $tempInvEnt->addTime;
						$idInvoiceSeries = $tempInvEnt->idInvoiceSeries;
					}
				}
			}

			$invoiceEntity = \Entity\Invoice::cumulate();
			$invoiceEntity->invoicesList = 		$selIds;
			$invoiceEntity->invoiceDate = 		TODAY_ISO;
			$invoiceEntity->formOfPayment = 	$formOfPayment;
			$invoiceEntity->idInvoiceSeries = 	$idInvoiceSeries;
			$invoiceEntity->fulfillmentDate = 	$invoiceEntity->get_defaultFulfillmentDate();
			$invoiceEntity->dueDate = 			$invoiceEntity->get_defaultDueDate();

			// get bank account from corporate profile or else the agency default
			$idBankAccount = 0;
			if ($firstInvoiceEntity->idCorporate) {
				$idBankAccount = \App\EntityPreference\Corporate::getInstance($firstInvoiceEntity->idCorporate)->agencyBankAccount;
			}
			if (!$idBankAccount) {
				$idBankAccount = \Entity\Office::current()->idDefaultBankAccount;
			}
			$invoiceEntity->idBankAccount = $idBankAccount;

			// invoice resposible
			$invoiceEntity->idUser = 	CURRENT_ID_USER;
			$invoiceEntity->idOffice = 	CURRENT_ID_OFFICE;

			$invoiceEntity->save();

			\DB::commitTransaction();

			// adds success message(s)
			foreach($invoiceEntity->getMessages()->getMessages() as $msg) {
				$msgs->addMessage($msg);
			}
		}
		catch (\App\Entity\Exception $ex) {
			// rollback transaction
			\DB::rollbackTransaction();
			$msgs->appendMessages($ex->getMessagesCollector());
		}

		// re-display the page content
		return $this->executeListRecords($R, $msgs);

	}


	/**
	 * Send the individual collection profile email.
	 * @param array $R
	 */
	public function actionSendAlert($R)
	{
		$msgs = \App\MessagesCollector::create();
		$this->setListingSelection($R['listing']['selection']);

		$ids = $this->getListingSelection()->getList();

		foreach ($ids as $id){

			try {

				$emailData = new \App\ClientCollection\Customer\EmailData($id);
				$emailData->process();

				$emailSend = new \App\ClientCollection\Customer\EmailSend($emailData);
				$emailSend->send();

				$msgs->addSuccess($this->lang['sendAlert']['success']);

			} catch (\App\MessagesException $e) {
				$msgs->appendMessages( $e->getMessagesCollector() );
			} catch (\RuntimeException $e) {
				$msgs->addWarning($this->lang['sendAlert']['error'].$e->getMessage());
			}

		}

		return $this->executeListRecords($R, $msgs);

	}

}
